// // Copyright (C) 2010 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.util; import gov.nasa.jpf.JPFException; /** * a fixed size BitSet with 256 bits. * * The main motivation for this class is to minimize memory size while maximizing * performance and keeping a java.util.BitSet compatible interface. The only * deviation from the standard BitSet is that we assume more cardinality() calls * than set()/clear() calls, i.e. we want to cache this value * * Instances of this class do not allocate any additional memory, we keep all * data in builtin type fields */ public class BitSet256 implements FixedBitSet, Cloneable { public static final int INDEX_MASK = 0xffffff00; long l0, l1, l2, l3; int cardinality; public BitSet256 (){ // nothing in here } public BitSet256 (int i){ set(i); } public BitSet256 (int... idx){ for (int i : idx){ set(i); } } public int longSize(){ return 4; } public long getLong(int i){ switch (i){ case 0: return l0; case 1: return l1; case 2: return l2; case 3: return l3; default: throw new IndexOutOfBoundsException("BitSet64 has no long index " + i); } } public BitSet256 clone() { try { return (BitSet256) super.clone(); } catch (CloneNotSupportedException ex) { throw new JPFException("BitSet256 clone failed"); } } private final int computeCardinality (){ int n= Long.bitCount(l0); n += Long.bitCount(l1); n += Long.bitCount(l2); n += Long.bitCount(l3); return n; } //--- public interface (much like java.util.BitSet) public void set (int i){ if ((i & INDEX_MASK) == 0) { long bitPattern = (1L << i); switch (i >> 6) { case 0: if ((l0 & bitPattern) == 0L) { cardinality++; l0 |= bitPattern; } break; case 1: if ((l1 & bitPattern) == 0L) { cardinality++; l1 |= bitPattern; } break; case 2: if ((l2 & bitPattern) == 0L) { cardinality++; l2 |= bitPattern; } break; case 3: if ((l3 & bitPattern) == 0L) { cardinality++; l3 |= bitPattern; } } } else { throw new IndexOutOfBoundsException("BitSet256 index out of range: " + i); } } public void clear (int i){ if ((i & INDEX_MASK) == 0) { long bitPattern = (1L << i); switch (i >> 6) { case 0: if ((l0 & bitPattern) != 0L) { cardinality--; l0 &= ~bitPattern; } break; case 1: if ((l1 & bitPattern) != 0L) { cardinality--; l1 &= ~bitPattern; } break; case 2: if ((l2 & bitPattern) != 0L) { cardinality--; l2 &= ~bitPattern; } break; case 3: if ((l3 & bitPattern) != 0L) { cardinality--; l3 &= ~bitPattern; } } } else { throw new IndexOutOfBoundsException("BitSet256 index out of range: " + i); } } public void set (int i, boolean val){ if (val) { set(i); } else { clear(i); } } public boolean get (int i){ if ((i & INDEX_MASK) == 0) { long bitPattern = (1L << i); switch (i >> 6) { case 0: return ((l0 & bitPattern) != 0); case 1: return ((l1 & bitPattern) != 0); case 2: return ((l2 & bitPattern) != 0); case 3: return ((l3 & bitPattern) != 0); } } throw new IndexOutOfBoundsException("BitSet256 index out of range: " + i); } public int cardinality() { return cardinality; } public int size() { return cardinality; } /** * number of bits we can store */ public int capacity() { return 256; } /** * index of highest set bit + 1 */ public int length() { if (l3 != 0){ return 256 - Long.numberOfLeadingZeros(l3); } else if (l2 != 0){ return 192 - Long.numberOfLeadingZeros(l2); } else if (l1 != 0){ return 128 - Long.numberOfLeadingZeros(l1); } else if (l1 != 0){ return 64 - Long.numberOfLeadingZeros(l0); } else { return 0; } } public boolean isEmpty() { return (cardinality == 0); } public void clear() { l0 = l1 = l2 = l3 = 0L; cardinality = 0; } public int nextSetBit (int fromIdx){ if ((fromIdx & INDEX_MASK) == 0) { int i; int i0 = fromIdx & 0x3f; switch (fromIdx >> 6){ case 0: if ((i=Long.numberOfTrailingZeros(l0 & (0xffffffffffffffffL << i0))) <64) return i; if ((i=Long.numberOfTrailingZeros(l1)) <64) return i + 64; if ((i=Long.numberOfTrailingZeros(l2)) <64) return i + 128; if ((i=Long.numberOfTrailingZeros(l3)) <64) return i + 192; break; case 1: if ((i=Long.numberOfTrailingZeros(l1 & (0xffffffffffffffffL << i0))) <64) return i + 64; if ((i=Long.numberOfTrailingZeros(l2)) <64) return i + 128; if ((i=Long.numberOfTrailingZeros(l3)) <64) return i + 192; break; case 2: if ((i=Long.numberOfTrailingZeros(l2 & (0xffffffffffffffffL << i0))) <64) return i + 128; if ((i=Long.numberOfTrailingZeros(l3)) <64) return i + 192; break; case 3: if ((i=Long.numberOfTrailingZeros(l3 & (0xffffffffffffffffL << i0))) <64) return i + 192; } return -1; } else { //throw new IndexOutOfBoundsException("BitSet256 index out of range: " + fromIdx); return -1; } } public int nextClearBit (int fromIdx){ if ((fromIdx & INDEX_MASK) == 0) { int i; int i0 = fromIdx & 0x3f; switch (fromIdx >> 6){ case 0: if ((i=Long.numberOfTrailingZeros(~l0 & (0xffffffffffffffffL << i0))) <64) return i; if ((i=Long.numberOfTrailingZeros(~l1)) <64) return i + 64; if ((i=Long.numberOfTrailingZeros(~l2)) <64) return i + 128; if ((i=Long.numberOfTrailingZeros(~l3)) <64) return i + 192; break; case 1: if ((i=Long.numberOfTrailingZeros(~l1 & (0xffffffffffffffffL << i0))) <64) return i + 64; if ((i=Long.numberOfTrailingZeros(~l2)) <64) return i + 128; if ((i=Long.numberOfTrailingZeros(~l3)) <64) return i + 192; break; case 2: if ((i=Long.numberOfTrailingZeros(~l2 & (0xffffffffffffffffL << i0))) <64) return i + 128; if ((i=Long.numberOfTrailingZeros(~l3)) <64) return i + 192; break; case 3: if ((i=Long.numberOfTrailingZeros(~l3 & (0xffffffffffffffffL << i0))) <64) return i + 192; } return -1; } else { //throw new IndexOutOfBoundsException("BitSet256 index out of range: " + fromIdx); return -1; } } public void and (BitSet256 other){ l0 &= other.l0; l1 &= other.l1; l2 &= other.l2; l3 &= other.l3; cardinality = computeCardinality(); } public void andNot (BitSet256 other){ l0 &= ~other.l0; l1 &= ~other.l1; l2 &= ~other.l2; l3 &= ~other.l3; cardinality = computeCardinality(); } public void or (BitSet256 other){ l0 |= other.l0; l1 |= other.l1; l2 |= other.l2; l3 |= other.l3; cardinality = computeCardinality(); } public boolean equals (Object o){ if (o instanceof BitSet256){ BitSet256 other = (BitSet256)o; if (l0 != other.l0) return false; if (l1 != other.l1) return false; if (l2 != other.l2) return false; if (l3 != other.l3) return false; return true; } else { // <2do> we could compare to a normal java.util.BitSet here return false; } } public void hash(HashData hd){ hd.add(hashCode()); } /** * answer the same hashCodes as java.util.BitSet */ public int hashCode() { long hc = 1234; hc ^= l0; hc ^= l1*2; hc ^= l2*3; hc ^= l3*4; return (int) ((hc >>32) ^ hc); } public String toString() { StringBuilder sb = new StringBuilder(); sb.append('{'); boolean first = true; for (int i=nextSetBit(0); i>= 0; i = nextSetBit(i+1)){ if (!first){ sb.append(','); } else { first = false; } sb.append(i); } sb.append('}'); return sb.toString(); } }