public class BitSet implements Cloneable, java.io.Serializable { private static final int ADDRESS_BITS_PER_WORD = 6; private static final int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD; private static final int BIT_INDEX_MASK = BITS_PER_WORD - 1; private static final long WORD_MASK = 0xffffffffffffffffL; private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("bits", long[].class), }; private long[] words; private transient int wordsInUse = 0; private transient boolean sizeIsSticky = false; private static int wordIndex(int bitIndex) { return bitIndex >> ADDRESS_BITS_PER_WORD; } private void checkInvariants() { assert(wordsInUse == 0 || words[wordsInUse - 1] != 0); assert(wordsInUse >= 0 && wordsInUse <= words.length); assert(wordsInUse == words.length || words[wordsInUse] == 0); } private void recalculateWordsInUse() { int i; for (i = wordsInUse-1; i >= 0; i--) if (words[i] != 0) break; wordsInUse = i+1; // The new logical size } public BitSet() { //默认64位 initWords(BITS_PER_WORD); sizeIsSticky = false; } public BitSet(int nbits) { // nbits can't be negative; size 0 is OK if (nbits < 0) throw new NegativeArraySizeException("nbits < 0: " + nbits); initWords(nbits); sizeIsSticky = true; } private void initWords(int nbits) { words = new long[wordIndex(nbits-1) + 1]; } private BitSet(long[] words) { this.words = words; this.wordsInUse = words.length; checkInvariants(); } public static BitSet valueOf(long[] longs) { int n; for (n = longs.length; n > 0 && longs[n - 1] == 0; n--) ; return new BitSet(Arrays.copyOf(longs, n)); } public static BitSet valueOf(LongBuffer lb) { //返回副本 lb = lb.slice(); int n; for (n = lb.remaining(); n > 0 && lb.get(n - 1) == 0; n--) ; long[] words = new long[n]; lb.get(words); return new BitSet(words); } public static BitSet valueOf(byte[] bytes) { return BitSet.valueOf(ByteBuffer.wrap(bytes)); } public static BitSet valueOf(ByteBuffer bb) { bb = bb.slice().order(ByteOrder.LITTLE_ENDIAN); int n; //首个不为0的index for (n = bb.remaining(); n > 0 && bb.get(n - 1) == 0; n--) ; long[] words = new long[(n + 7) / 8]; bb.limit(n); int i = 0; while (bb.remaining() >= 8) words[i++] = bb.getLong(); for (int remaining = bb.remaining(), j = 0; j < remaining; j++) words[i] |= (bb.get() & 0xffL) << (8 * j); return new BitSet(words); } public byte[] toByteArray() { int n = wordsInUse; if (n == 0) return new byte[0]; int len = 8 * (n-1); //直到最后一个不为0的字节 for (long x = words[n - 1]; x != 0; x >>>= 8) len++; byte[] bytes = new byte[len]; ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); for (int i = 0; i < n - 1; i++) bb.putLong(words[i]); for (long x = words[n - 1]; x != 0; x >>>= 8) bb.put((byte) (x & 0xff)); return bytes; } public long[] toLongArray() { return Arrays.copyOf(words, wordsInUse); } private void ensureCapacity(int wordsRequired) { if (words.length < wordsRequired) { // Allocate larger of doubled size or required size int request = Math.max(2 * words.length, wordsRequired); words = Arrays.copyOf(words, request); sizeIsSticky = false; } } /** * Ensures that the BitSet can accommodate a given wordIndex, * temporarily violating the invariants. The caller must * restore the invariants before returning to the user, * possibly using recalculateWordsInUse(). * @param wordIndex the index to be accommodated. */ private void expandTo(int wordIndex) { int wordsRequired = wordIndex+1; if (wordsInUse < wordsRequired) { //Math.max(2 * words.length, wordsRequired); ensureCapacity(wordsRequired); wordsInUse = wordsRequired; } } private static void checkRange(int fromIndex, int toIndex) { if (fromIndex < 0) throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); if (toIndex < 0) throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex); if (fromIndex > toIndex) throw new IndexOutOfBoundsException("fromIndex: " + fromIndex + " > toIndex: " + toIndex); } //index的补码 public void flip(int bitIndex) { if (bitIndex < 0) throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); int wordIndex = wordIndex(bitIndex); expandTo(wordIndex); words[wordIndex] ^= (1L << bitIndex); recalculateWordsInUse(); checkInvariants(); } public void flip(int fromIndex, int toIndex) { checkRange(fromIndex, toIndex); if (fromIndex == toIndex) return; int startWordIndex = wordIndex(fromIndex); int endWordIndex = wordIndex(toIndex - 1); expandTo(endWordIndex); long firstWordMask = WORD_MASK << fromIndex; //移位操作符左边如果是int类型,则操作符右边的数只有低5位有效(右边的数会首先与0x1f做AND运算),如果操作符左边是long类型,右边的数就只取低6位为有效位。 //假设-5L,-5在内存中的表示为0xfffffffb,取低6位有效,那么实际有效值是0x3b,换成十进制就是59,也就是把-1L右移59位,可见,表达式的结果正好是低5位全1,高位全0。 long lastWordMask = WORD_MASK >>> -toIndex; if (startWordIndex == endWordIndex) { // Case 1: One word words[startWordIndex] ^= (firstWordMask & lastWordMask); } else { // Case 2: Multiple words // Handle first word words[startWordIndex] ^= firstWordMask; // Handle intermediate words, if any for (int i = startWordIndex+1; i < endWordIndex; i++) words[i] ^= WORD_MASK; // Handle last word words[endWordIndex] ^= lastWordMask; } recalculateWordsInUse(); checkInvariants(); } public void set(int bitIndex) { if (bitIndex < 0) throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); int wordIndex = wordIndex(bitIndex); expandTo(wordIndex); words[wordIndex] |= (1L << bitIndex); // Restores invariants checkInvariants(); } public void set(int bitIndex, boolean value) { if (value) set(bitIndex); else clear(bitIndex); } public void set(int fromIndex, int toIndex) { checkRange(fromIndex, toIndex); if (fromIndex == toIndex) return; // Increase capacity if necessary int startWordIndex = wordIndex(fromIndex); int endWordIndex = wordIndex(toIndex - 1); expandTo(endWordIndex); long firstWordMask = WORD_MASK << fromIndex; long lastWordMask = WORD_MASK >>> -toIndex; if (startWordIndex == endWordIndex) { // Case 1: One word words[startWordIndex] |= (firstWordMask & lastWordMask); } else { // Case 2: Multiple words // Handle first word words[startWordIndex] |= firstWordMask; // Handle intermediate words, if any for (int i = startWordIndex+1; i < endWordIndex; i++) words[i] = WORD_MASK; // Handle last word (restores invariants) words[endWordIndex] |= lastWordMask; } checkInvariants(); } public void set(int fromIndex, int toIndex, boolean value) { if (value) set(fromIndex, toIndex); else clear(fromIndex, toIndex); } public void clear(int bitIndex) { if (bitIndex < 0) throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); int wordIndex = wordIndex(bitIndex); if (wordIndex >= wordsInUse) return; words[wordIndex] &= ~(1L << bitIndex); recalculateWordsInUse(); checkInvariants(); } public void clear(int fromIndex, int toIndex) { checkRange(fromIndex, toIndex); if (fromIndex == toIndex) return; int startWordIndex = wordIndex(fromIndex); if (startWordIndex >= wordsInUse) return; int endWordIndex = wordIndex(toIndex - 1); if (endWordIndex >= wordsInUse) { toIndex = length(); endWordIndex = wordsInUse - 1; } long firstWordMask = WORD_MASK << fromIndex; long lastWordMask = WORD_MASK >>> -toIndex; if (startWordIndex == endWordIndex) { // Case 1: One word words[startWordIndex] &= ~(firstWordMask & lastWordMask); } else { // Case 2: Multiple words // Handle first word words[startWordIndex] &= ~firstWordMask; // Handle intermediate words, if any for (int i = startWordIndex+1; i < endWordIndex; i++) words[i] = 0; // Handle last word words[endWordIndex] &= ~lastWordMask; } recalculateWordsInUse(); checkInvariants(); } public void clear() { while (wordsInUse > 0) words[--wordsInUse] = 0; } public boolean get(int bitIndex) { if (bitIndex < 0) throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex); checkInvariants(); int wordIndex = wordIndex(bitIndex); return (wordIndex < wordsInUse) && ((words[wordIndex] & (1L << bitIndex)) != 0); } public BitSet get(int fromIndex, int toIndex) { checkRange(fromIndex, toIndex); checkInvariants(); int len = length(); // If no set bits in range return empty bitset if (len <= fromIndex || fromIndex == toIndex) return new BitSet(0); // An optimization if (toIndex > len) toIndex = len; BitSet result = new BitSet(toIndex - fromIndex); int targetWords = wordIndex(toIndex - fromIndex - 1) + 1; int sourceIndex = wordIndex(fromIndex); //是否对齐 boolean wordAligned = ((fromIndex & BIT_INDEX_MASK) == 0); // Process all words but the last word for (int i = 0; i < targetWords - 1; i++, sourceIndex++) result.words[i] = wordAligned ? words[sourceIndex] : (words[sourceIndex] >>> fromIndex) | (words[sourceIndex+1] << -fromIndex); // Process the last word long lastWordMask = WORD_MASK >>> -toIndex; result.words[targetWords - 1] = ((toIndex-1) & BIT_INDEX_MASK) < (fromIndex & BIT_INDEX_MASK) ? /* straddles source words */ ((words[sourceIndex] >>> fromIndex) | (words[sourceIndex+1] & lastWordMask) << -fromIndex) : ((words[sourceIndex] & lastWordMask) >>> fromIndex); // Set wordsInUse correctly result.wordsInUse = targetWords; result.recalculateWordsInUse(); result.checkInvariants(); return result; } public int nextSetBit(int fromIndex) { if (fromIndex < 0) throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); checkInvariants(); int u = wordIndex(fromIndex); if (u >= wordsInUse) return -1; long word = words[u] & (WORD_MASK << fromIndex); while (true) { if (word != 0) return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word); if (++u == wordsInUse) return -1; word = words[u]; } } public int nextClearBit(int fromIndex) { // Neither spec nor implementation handle bitsets of maximal length. // See 4816253. if (fromIndex < 0) throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex); checkInvariants(); int u = wordIndex(fromIndex); if (u >= wordsInUse) return fromIndex; long word = ~words[u] & (WORD_MASK << fromIndex); while (true) { if (word != 0) return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word); if (++u == wordsInUse) return wordsInUse * BITS_PER_WORD; word = ~words[u]; } } public int previousSetBit(int fromIndex) { if (fromIndex < 0) { if (fromIndex == -1) return -1; throw new IndexOutOfBoundsException( "fromIndex < -1: " + fromIndex); } checkInvariants(); int u = wordIndex(fromIndex); if (u >= wordsInUse) return length() - 1; long word = words[u] & (WORD_MASK >>> -(fromIndex+1)); while (true) { if (word != 0) return (u+1) * BITS_PER_WORD - 1 - Long.numberOfLeadingZeros(word); if (u-- == 0) return -1; word = words[u]; } } public int previousClearBit(int fromIndex) { if (fromIndex < 0) { if (fromIndex == -1) return -1; throw new IndexOutOfBoundsException( "fromIndex < -1: " + fromIndex); } checkInvariants(); int u = wordIndex(fromIndex); if (u >= wordsInUse) return fromIndex; long word = ~words[u] & (WORD_MASK >>> -(fromIndex+1)); while (true) { if (word != 0) return (u+1) * BITS_PER_WORD -1 - Long.numberOfLeadingZeros(word); if (u-- == 0) return -1; word = ~words[u]; } } public int length() { if (wordsInUse == 0) return 0; return BITS_PER_WORD * (wordsInUse - 1) + (BITS_PER_WORD - Long.numberOfLeadingZeros(words[wordsInUse - 1])); } public boolean isEmpty() { return wordsInUse == 0; } public boolean intersects(BitSet set) { for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--) if ((words[i] & set.words[i]) != 0) return true; return false; } public int cardinality() { int sum = 0; for (int i = 0; i < wordsInUse; i++) sum += Long.bitCount(words[i]); return sum; } public void and(BitSet set) { if (this == set) return; while (wordsInUse > set.wordsInUse) words[--wordsInUse] = 0; // Perform logical AND on words in common for (int i = 0; i < wordsInUse; i++) words[i] &= set.words[i]; recalculateWordsInUse(); checkInvariants(); } public void or(BitSet set) { if (this == set) return; int wordsInCommon = Math.min(wordsInUse, set.wordsInUse); if (wordsInUse < set.wordsInUse) { ensureCapacity(set.wordsInUse); wordsInUse = set.wordsInUse; } // Perform logical OR on words in common for (int i = 0; i < wordsInCommon; i++) words[i] |= set.words[i]; // Copy any remaining words if (wordsInCommon < set.wordsInUse) System.arraycopy(set.words, wordsInCommon, words, wordsInCommon, wordsInUse - wordsInCommon); // recalculateWordsInUse() is unnecessary checkInvariants(); } public void xor(BitSet set) { int wordsInCommon = Math.min(wordsInUse, set.wordsInUse); if (wordsInUse < set.wordsInUse) { ensureCapacity(set.wordsInUse); wordsInUse = set.wordsInUse; } // Perform logical XOR on words in common for (int i = 0; i < wordsInCommon; i++) words[i] ^= set.words[i]; // Copy any remaining words if (wordsInCommon < set.wordsInUse) System.arraycopy(set.words, wordsInCommon, words, wordsInCommon, set.wordsInUse - wordsInCommon); recalculateWordsInUse(); checkInvariants(); } public void andNot(BitSet set) { // Perform logical (a & !b) on words in common for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--) words[i] &= ~set.words[i]; recalculateWordsInUse(); checkInvariants(); } public int hashCode() { long h = 1234; for (int i = wordsInUse; --i >= 0; ) h ^= words[i] * (i + 1); return (int)((h >> 32) ^ h); } public int size() { return words.length * BITS_PER_WORD; } public boolean equals(Object obj) { if (!(obj instanceof BitSet)) return false; if (this == obj) return true; BitSet set = (BitSet) obj; checkInvariants(); set.checkInvariants(); if (wordsInUse != set.wordsInUse) return false; // Check words in use by both BitSets for (int i = 0; i < wordsInUse; i++) if (words[i] != set.words[i]) return false; return true; } public Object clone() { if (! sizeIsSticky) trimToSize(); try { BitSet result = (BitSet) super.clone(); result.words = words.clone(); result.checkInvariants(); return result; } catch (CloneNotSupportedException e) { throw new InternalError(e); } } private void trimToSize() { if (wordsInUse != words.length) { words = Arrays.copyOf(words, wordsInUse); checkInvariants(); } } private void writeObject(ObjectOutputStream s) throws IOException { checkInvariants(); if (! sizeIsSticky) trimToSize(); ObjectOutputStream.PutField fields = s.putFields(); fields.put("bits", words); s.writeFields(); } private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { ObjectInputStream.GetField fields = s.readFields(); words = (long[]) fields.get("bits", null); // Assume maximum length then find real length // because recalculateWordsInUse assumes maintenance // or reduction in logical size wordsInUse = words.length; recalculateWordsInUse(); sizeIsSticky = (words.length > 0 && words[words.length-1] == 0L); // heuristic checkInvariants(); } public String toString() { checkInvariants(); int numBits = (wordsInUse > 128) ? cardinality() : wordsInUse * BITS_PER_WORD; StringBuilder b = new StringBuilder(6*numBits + 2); b.append('{'); int i = nextSetBit(0); if (i != -1) { b.append(i); while (true) { if (++i < 0) break; if ((i = nextSetBit(i)) < 0) break; int endOfRun = nextClearBit(i); do { b.append(", ").append(i); } while (++i != endOfRun); } } b.append('}'); return b.toString(); } //待补 /** * Returns a stream of indices for which this {@code BitSet} * contains a bit in the set state. The indices are returned * in order, from lowest to highest. The size of the stream * is the number of bits in the set state, equal to the value * returned by the {@link #cardinality()} method. * * <p>The stream binds to this bit set when the terminal stream operation * commences (specifically, the spliterator for the stream is * <a href="Spliterator.html#binding"><em>late-binding</em></a>). If the * bit set is modified during that operation then the result is undefined. * * @return a stream of integers representing set indices * @since 1.8 */ public IntStream stream() { class BitSetSpliterator implements Spliterator.OfInt { private int index; // current bit index for a set bit private int fence; // -1 until used; then one past last bit index private int est; // size estimate private boolean root; // true if root and not split // root == true then size estimate is accurate // index == -1 or index >= fence if fully traversed // Special case when the max bit set is Integer.MAX_VALUE BitSetSpliterator(int origin, int fence, int est, boolean root) { this.index = origin; this.fence = fence; this.est = est; this.root = root; } private int getFence() { int hi; if ((hi = fence) < 0) { // Round up fence to maximum cardinality for allocated words // This is sufficient and cheap for sequential access // When splitting this value is lowered hi = fence = (wordsInUse >= wordIndex(Integer.MAX_VALUE)) ? Integer.MAX_VALUE : wordsInUse << ADDRESS_BITS_PER_WORD; est = cardinality(); index = nextSetBit(0); } return hi; } @Override public boolean tryAdvance(IntConsumer action) { Objects.requireNonNull(action); int hi = getFence(); int i = index; if (i < 0 || i >= hi) { // Check if there is a final bit set for Integer.MAX_VALUE if (i == Integer.MAX_VALUE && hi == Integer.MAX_VALUE) { index = -1; action.accept(Integer.MAX_VALUE); return true; } return false; } index = nextSetBit(i + 1, wordIndex(hi - 1)); action.accept(i); return true; } @Override public void forEachRemaining(IntConsumer action) { Objects.requireNonNull(action); int hi = getFence(); int i = index; int v = wordIndex(hi - 1); index = -1; while (i >= 0 && i < hi) { action.accept(i); i = nextSetBit(i + 1, v); } // Check if there is a final bit set for Integer.MAX_VALUE if (i == Integer.MAX_VALUE && hi == Integer.MAX_VALUE) { action.accept(Integer.MAX_VALUE); } } @Override public OfInt trySplit() { int hi = getFence(); int lo = index; if (lo < 0) { return null; } // Lower the fence to be the upper bound of last bit set // The index is the first bit set, thus this spliterator // covers one bit and cannot be split, or two or more // bits hi = fence = (hi < Integer.MAX_VALUE || !get(Integer.MAX_VALUE)) ? previousSetBit(hi - 1) + 1 : Integer.MAX_VALUE; // Find the mid point int mid = (lo + hi) >>> 1; if (lo >= mid) { return null; } // Raise the index of this spliterator to be the next set bit // from the mid point index = nextSetBit(mid, wordIndex(hi - 1)); root = false; // Don't lower the fence (mid point) of the returned spliterator, // traversal or further splitting will do that work return new BitSetSpliterator(lo, mid, est >>>= 1, false); } @Override public long estimateSize() { getFence(); // force init return est; } @Override public int characteristics() { // Only sized when root and not split return (root ? Spliterator.SIZED : 0) | Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED; } @Override public Comparator<? super Integer> getComparator() { return null; } } return StreamSupport.intStream(new BitSetSpliterator(0, -1, 0, true), false); } private int nextSetBit(int fromIndex, int toWordIndex) { int u = wordIndex(fromIndex); // Check if out of bounds if (u > toWordIndex) return -1; long word = words[u] & (WORD_MASK << fromIndex); while (true) { if (word != 0) return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word); // Check if out of bounds if (++u > toWordIndex) return -1; word = words[u]; } } }
BitSet
猜你喜欢
转载自blog.csdn.net/qq_14978401/article/details/79944193
今日推荐
周排行