001/* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * Sonar is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020package org.sonar.duplications.block; 021 022import java.nio.ByteBuffer; 023import java.nio.IntBuffer; 024import java.util.Arrays; 025 026/** 027 * Represents hash for {@link Block}. Immutable. 028 * 029 * TODO Godin: would be better to rename to BlockHash, 030 * also maybe we can incorporate it into Block to reduce memory footprint during detection of duplicates 031 */ 032public final class ByteArray { 033 034 private final byte[] bytes; 035 036 /** 037 * Cache for hash code. 038 */ 039 private int hash; 040 041 public ByteArray(String hexString) { 042 int len = hexString.length(); 043 this.bytes = new byte[len / 2]; 044 for (int i = 0; i < len; i += 2) { 045 bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i + 1), 16)); 046 } 047 } 048 049 public ByteArray(byte[] bytes) { 050 this.bytes = new byte[bytes.length]; 051 System.arraycopy(bytes, 0, this.bytes, 0, bytes.length); 052 } 053 054 public ByteArray(long value) { 055 this.bytes = new byte[] { 056 (byte) (value >>> 56), 057 (byte) (value >>> 48), 058 (byte) (value >>> 40), 059 (byte) (value >>> 32), 060 (byte) (value >>> 24), 061 (byte) (value >>> 16), 062 (byte) (value >>> 8), 063 (byte) value }; 064 } 065 066 public ByteArray(int value) { 067 this.bytes = new byte[] { 068 (byte) (value >>> 24), 069 (byte) (value >>> 16), 070 (byte) (value >>> 8), 071 (byte) value }; 072 } 073 074 public ByteArray(int[] intArray) { 075 ByteBuffer bb = ByteBuffer.allocate(intArray.length * 4); 076 for (int i : intArray) { 077 bb.putInt(i); 078 } 079 this.bytes = bb.array(); 080 } 081 082 public int[] toIntArray() { 083 int size = (bytes.length / 4) + (bytes.length % 4 == 0 ? 0 : 1); // Pad the size to multiple of 4 084 ByteBuffer bb = ByteBuffer.allocate(size * 4); 085 bb.put(bytes); 086 bb.rewind(); 087 IntBuffer ib = bb.asIntBuffer(); 088 int[] result = new int[size]; 089 ib.get(result); 090 return result; 091 } 092 093 private static final String HEXES = "0123456789abcdef"; 094 095 public String toHexString() { 096 StringBuilder hex = new StringBuilder(2 * bytes.length); 097 for (byte b : bytes) { 098 hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F))); 099 } 100 return hex.toString(); 101 } 102 103 @Override 104 public String toString() { 105 return toHexString(); 106 } 107 108 @Override 109 public boolean equals(Object o) { 110 if (this == o) { 111 return true; 112 } 113 if (o == null || getClass() != o.getClass()) { 114 return false; 115 } 116 ByteArray other = (ByteArray) o; 117 return Arrays.equals(bytes, other.bytes); 118 } 119 120 @Override 121 public int hashCode() { 122 int h = hash; 123 int len = bytes.length; 124 if (h == 0 && len > 0) { 125 h = Arrays.hashCode(bytes); 126 hash = h; 127 } 128 return h; 129 } 130 131}