/* * This file is part of mlDHT. * * mlDHT is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * mlDHT is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with mlDHT. If not, see <http://www.gnu.org/licenses/>. */ package lbms.plugins.mldht.kad.utils; import java.nio.ByteBuffer; import java.util.Arrays; public final class BitVector { private final byte[] vector; private final int bits; public BitVector(BitVector toCopy) { bits = toCopy.bits; vector = toCopy.vector.clone(); } public BitVector(int numBits, byte[] rawData) { if(numBits > rawData.length * 8) throw new IllegalArgumentException("raw data array too small to represent the requested number of bits"); bits = numBits; vector = rawData.clone(); } public BitVector(int numberOfBits) { bits = numberOfBits; vector = new byte[numberOfBits/8 + (numberOfBits % 8 != 0 ? 1 : 0)]; } public void set(int n) { vector[n/8] |= 0x01 << n % 8; } public boolean get(int n) { return (vector[n/8] & 0x01 << n % 8) != 0; } /** * reads an arbitrary (even non-aligned) range of bits (up to 32) and interprets them as int (bigendian) */ public int rangeToInt(int bitOffset, int numOfBits) { int result = 0; int baseShift = numOfBits - 8 + bitOffset % 8; int byteIdx = bitOffset/8; while(baseShift >= 0) { result |= vector[byteIdx] << baseShift; byteIdx++; baseShift -= 8; } if(baseShift < 0) result |= vector[byteIdx] >>> Math.abs(baseShift); result &= 0xFFFFFFFF >>> 32 - numOfBits; return result; } public int size() { return bits; } public void clear() { Arrays.fill(vector, (byte)0); } public int bitcount() { int c = 0; for(int i = 0;i<bits;i++) { if((vector[i/8] & (0x01 << i % 8)) != 0) c++; } return c; } public static int unionAndCount(BitVector... vectors) { if(vectors.length == 0) return 0; int c = 0; int bits = vectors[0].size(); byte union = 0; for(int i = 0;i<bits;i++) { if(i % 8 == 0) { int idx = i/8; union = (byte) 0x00; for(BitVector v : vectors) union |= v.vector[idx]; } if((union & (0x01 << i % 8)) != 0) c++; } return c; } @Override public String toString() { StringBuilder b = new StringBuilder(2 * bits/8); for (int i = 0; i < vector.length; i++) { if (i % 4 == 0 && i > 0) { b.append(' '); } int nibble = (vector[i] & 0xF0) >> 4; b.append((char)(nibble < 0x0A ? '0'+nibble : 'A'+nibble-10 )); nibble = vector[i] & 0x0F; b.append((char)(nibble < 0x0A ? '0'+nibble : 'A'+nibble-10 )); } return b.toString(); } public static int intersectAndCount(BitVector... vectors) { int c = 0; int bits = vectors[0].size(); byte intersection = 0; for(int i = 0;i<bits;i++) { if(i % 8 == 0) { int idx = i/8; intersection = (byte) 0xFF; for(BitVector v : vectors) intersection &= v.vector[idx]; } if((intersection & (0x01 << i % 8)) != 0) c++; } return c; } public byte[] getSerializedFormat() { return vector.clone(); } public ByteBuffer toBuffer() { return ByteBuffer.wrap(vector).asReadOnlyBuffer(); } public static void main(String[] args) { BitVector bv = new BitVector(40, new byte[] {(byte) 0xF0,(byte) 0xFF,(byte) 0xFF,(byte) 0xFF,(byte) 0xFF,(byte) 0xFF,(byte) 0xFF,(byte) 0xFF,(byte) 0xFF}); System.out.println(bv.rangeToInt(7, 2)); } }