+/*
+ * Some portions of this file have been modified by Robert Hanson hansonr.at.stolaf.edu 2012-2017
+ * for use in SwingJS via transpilation into JavaScript using Java2Script.
+ *
+ * Copyright 1995-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javajs.util;
+
+import javajs.api.JSONEncodable;
+
+
+
+/**
+ *
+ * a fast 32-bit BitSet optimized for Java2Script -- about 25 times faster than
+ * java.util.BitSet
+ *
+ * @author Bob Hanson hansonr@stolaf.edu
+ *
+ * Additions by Bob Hanson to allow for JavaScript mix of int/long Note
+ * that Firefox (Sept 2012) does not really treat "Int32Array" as such,
+ * because any element can be pushed into being a 64-bit number, which
+ * really isn't because the last 8 bits are not usable.
+ *
+ * This class implements a vector of bits that grows as needed. Each
+ * component of the bit set has a {@code boolean} value. The bits of a
+ * {@code BitSet} are indexed by nonnegative integers. Individual
+ * indexed bits can be examined, set, or cleared. One {@code BitSet} may
+ * be used to modify the contents of another {@code BitSet} through
+ * logical AND, logical inclusive OR, and logical exclusive OR
+ * operations.
+ *
+ * <p>
+ * By default, all bits in the set initially have the value {@code
+ * false}.
+ *
+ * <p>
+ * Every bit set has a current size, which is the number of bits of
+ * space currently in use by the bit set. Note that the size is related
+ * to the implementation of a bit set, so it may change with
+ * implementation. The length of a bit set relates to logical length of
+ * a bit set and is defined independently of implementation.
+ *
+ * <p>
+ * Unless otherwise noted, passing a null parameter to any of the
+ * methods in a {@code BitSet} will result in a {@code
+ * NullPointerException}.
+ *
+ * <p>
+ * A {@code BitSet} is not safe for multithreaded use without external
+ * synchronization.
+ *
+ * @author Arthur van Hoff
+ * @author Michael McCloskey
+ * @author Martin Buchholz
+ * @since JDK1.0
+ */
+public class BS implements Cloneable, JSONEncodable {
+ /*
+ * BitSets are packed into arrays of "words."
+ *
+ * An int, which consists of 32 bits, requiring 5 address bits, is used for
+ * the JavaScript port.
+ */
+ private final static int ADDRESS_BITS_PER_WORD = 5;
+ private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
+ protected final static int BIT_INDEX_MASK = BITS_PER_WORD - 1;
+
+ /* Used to shift left or right for a partial word mask */
+ protected static final int WORD_MASK = 0xffffffff;
+
+
+ /**
+ * The internal field corresponding to the serialField "bits".
+ */
+ protected int[] words;
+
+ /**
+ * The number of words in the logical size of this BitSet.
+ */
+ protected transient int wordsInUse = 0;
+
+ /**
+ * Whether the size of "words" is user-specified. If so, we assume the user
+ * knows what he's doing and try harder to preserve it.
+ */
+ private transient boolean sizeIsSticky = false;
+
+ /* use serialVersionUID from JDK 1.0.2 for interoperability */
+ //private static final long serialVersionUID = 7997698588986878753L;
+
+ /**
+ * Given a bit index, return word index containing it.
+ * @param bitIndex
+ * @return b
+ */
+ protected static int wordIndex(int bitIndex) {
+ return bitIndex >> ADDRESS_BITS_PER_WORD;
+ }
+
+ /**
+ * Sets the field wordsInUse to the logical size in words of the bit set.
+ * WARNING:This method assumes that the number of words actually in use is
+ * less than or equal to the current value of wordsInUse!
+ */
+ protected void recalculateWordsInUse() {
+ // Traverse the bitset until a used word is found
+ int i;
+ for (i = wordsInUse - 1; i >= 0; i--)
+ if (words[i] != 0)
+ break;
+
+ wordsInUse = i + 1; // The new logical size
+ }
+
+ /**
+ * Creates a new bit set. All bits are initially {@code false}.
+ */
+ public BS() {
+ initWords(BITS_PER_WORD);
+ sizeIsSticky = false;
+ }
+
+ /**
+ * Creates a bit set whose initial size is large enough to explicitly
+ * represent bits with indices in the range {@code 0} through {@code nbits-1}.
+ * All bits are initially {@code false}.
+ *
+ * @param nbits
+ * the initial size of the bit set
+ * @return bs
+ * @throws NegativeArraySizeException
+ * if the specified initial size is negative
+ */
+ public static BS newN(int nbits) {
+ BS bs = new BS();
+ bs.init(nbits);
+ return bs;
+ }
+
+ protected void init(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 int[wordIndex(nbits - 1) + 1];
+ }
+
+ /**
+ * Ensures that the BitSet can hold enough words.
+ *
+ * @param wordsRequired
+ * the minimum acceptable number of words.
+ */
+ 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);
+ setLength(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.
+ */
+ protected void expandTo(int wordIndex) {
+ int wordsRequired = wordIndex + 1;
+ if (wordsInUse < wordsRequired) {
+ ensureCapacity(wordsRequired);
+ wordsInUse = wordsRequired;
+ }
+ }
+
+
+ /**
+ * Sets the bit at the specified index to {@code true}.
+ *
+ * @param bitIndex
+ * a bit index
+ * @throws IndexOutOfBoundsException
+ * if the specified index is negative
+ * @since JDK1.0
+ */
+ public void set(int bitIndex) {
+ if (bitIndex < 0)
+ throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+ int wordIndex = wordIndex(bitIndex);
+ expandTo(wordIndex);
+
+ words[wordIndex] |= (1 << bitIndex); // Restores invariants
+
+ }
+
+ /**
+ * Sets the bit at the specified index to the specified value.
+ *
+ * @param bitIndex
+ * a bit index
+ * @param value
+ * a boolean value to set
+ * @throws IndexOutOfBoundsException
+ * if the specified index is negative
+ * @since 1.4
+ */
+ public void setBitTo(int bitIndex, boolean value) {
+ if (value)
+ set(bitIndex);
+ else
+ clear(bitIndex);
+ }
+
+ /**
+ * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+ * specified {@code toIndex} (exclusive) to {@code true}.
+ *
+ * @param fromIndex
+ * index of the first bit to be set
+ * @param toIndex
+ * index after the last bit to be set
+ * @throws IndexOutOfBoundsException
+ * if {@code fromIndex} is negative, or {@code toIndex} is negative,
+ * or {@code fromIndex} is larger than {@code toIndex}
+ * @since 1.4
+ */
+ public void setBits(int fromIndex, int toIndex) {
+
+ if (fromIndex == toIndex)
+ return;
+
+ // Increase capacity if necessary
+ int startWordIndex = wordIndex(fromIndex);
+ int endWordIndex = wordIndex(toIndex - 1);
+ expandTo(endWordIndex);
+
+ int firstWordMask = WORD_MASK << fromIndex;
+ int 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;
+ }
+ }
+
+ /**
+ * Sets the bit specified by the index to {@code false}.
+ *
+ * @param bitIndex
+ * the index of the bit to be cleared
+ * @throws IndexOutOfBoundsException
+ * if the specified index is negative
+ * @since JDK1.0
+ */
+ public void clear(int bitIndex) {
+ if (bitIndex < 0)
+ throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+ int wordIndex = wordIndex(bitIndex);
+ if (wordIndex >= wordsInUse)
+ return;
+
+ words[wordIndex] &= ~(1 << bitIndex);
+
+ recalculateWordsInUse();
+ }
+
+ /**
+ * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+ * specified {@code toIndex} (exclusive) to {@code false}.
+ *
+ * @param fromIndex
+ * index of the first bit to be cleared
+ * @param toIndex
+ * index after the last bit to be cleared
+ * @throws IndexOutOfBoundsException
+ * if {@code fromIndex} is negative, or {@code toIndex} is negative,
+ * or {@code fromIndex} is larger than {@code toIndex}
+ * @since 1.4
+ */
+ public void clearBits(int fromIndex, int 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;
+ }
+
+ int firstWordMask = WORD_MASK << fromIndex;
+ int 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();
+ }
+
+ /**
+ * Sets all of the bits in this BitSet to {@code false}.
+ *
+ * @since 1.4
+ */
+ public void clearAll() {
+ while (wordsInUse > 0)
+ words[--wordsInUse] = 0;
+ }
+
+ /**
+ * Returns the value of the bit with the specified index. The value is {@code
+ * true} if the bit with the index {@code bitIndex} is currently set in this
+ * {@code BitSet}; otherwise, the result is {@code false}.
+ *
+ * @param bitIndex
+ * the bit index
+ * @return the value of the bit with the specified index
+ * @throws IndexOutOfBoundsException
+ * if the specified index is negative
+ */
+ public boolean get(int bitIndex) {
+ if (bitIndex < 0)
+ throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+ int wordIndex = wordIndex(bitIndex);
+ return (wordIndex < wordsInUse)
+ && ((words[wordIndex] & (1 << bitIndex)) != 0);
+ }
+
+ /**
+ * Returns the index of the first bit that is set to {@code true} that occurs
+ * on or after the specified starting index. If no such bit exists then
+ * {@code -1} is returned.
+ *
+ * <p>
+ * To iterate over the {@code true} bits in a {@code BitSet}, use the
+ * following loop:
+ *
+ * <pre>
+ * @code
+ * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
+ * // operate on index i here
+ * }}
+ * </pre>
+ *
+ * @param fromIndex
+ * the index to start checking from (inclusive)
+ * @return the index of the next set bit, or {@code -1} if there is no such
+ * bit
+ * @throws IndexOutOfBoundsException
+ * if the specified index is negative
+ * @since 1.4
+ */
+ public int nextSetBit(int fromIndex) {
+ if (fromIndex < 0)
+ throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+
+ int u = wordIndex(fromIndex);
+ if (u >= wordsInUse)
+ return -1;
+
+ int word = words[u] & (WORD_MASK << fromIndex);
+
+ while (true) {
+ if (word != 0)
+ return (u * BITS_PER_WORD) + Integer.numberOfTrailingZeros(word);
+ if (++u == wordsInUse)
+ return -1;
+ word = words[u];
+ }
+ }
+
+ /**
+ * Returns the index of the first bit that is set to {@code false} that occurs
+ * on or after the specified starting index.
+ *
+ * @param fromIndex
+ * the index to start checking from (inclusive)
+ * @return the index of the next clear bit
+ * @throws IndexOutOfBoundsException
+ * if the specified index is negative
+ * @since 1.4
+ */
+ 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);
+
+ int u = wordIndex(fromIndex);
+ if (u >= wordsInUse)
+ return fromIndex;
+
+ int word = ~words[u] & (WORD_MASK << fromIndex);
+
+ while (true) {
+ if (word != 0)
+ return (u * BITS_PER_WORD) + Integer.numberOfTrailingZeros(word);
+ if (++u == wordsInUse)
+ return wordsInUse * BITS_PER_WORD;
+ word = ~words[u];
+ }
+ }
+
+ /**
+ * Returns the "logical size" of this {@code BitSet}: the index of the highest
+ * set bit in the {@code BitSet} plus one. Returns zero if the {@code BitSet}
+ * contains no set bits.
+ *
+ * @return the logical size of this {@code BitSet}
+ * @since 1.2
+ */
+ public int length() {
+ if (wordsInUse == 0)
+ return 0;
+
+ return BITS_PER_WORD * (wordsInUse - 1)
+ + (BITS_PER_WORD - Integer.numberOfLeadingZeros(words[wordsInUse - 1]));
+ }
+
+ /**
+ * Returns true if this {@code BitSet} contains no bits that are set to
+ * {@code true}.
+ *
+ * @return boolean indicating whether this {@code BitSet} is empty
+ * @since 1.4
+ */
+ public boolean isEmpty() {
+ return wordsInUse == 0;
+ }
+
+ /**
+ * Returns true if the specified {@code BitSet} has any bits set to {@code
+ * true} that are also set to {@code true} in this {@code BitSet}.
+ *
+ * @param set
+ * {@code BitSet} to intersect with
+ * @return boolean indicating whether this {@code BitSet} intersects the
+ * specified {@code BitSet}
+ * @since 1.4
+ */
+ public boolean intersects(BS set) {
+ for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
+ if ((words[i] & set.words[i]) != 0)
+ return true;
+ return false;
+ }
+
+ /**
+ * Returns the number of bits set to {@code true} in this {@code BitSet}.
+ *
+ * @return the number of bits set to {@code true} in this {@code BitSet}
+ * @since 1.4
+ */
+ public int cardinality() {
+ int sum = 0;
+ for (int i = 0; i < wordsInUse; i++)
+ sum += Integer.bitCount(words[i]);
+ return sum;
+ }
+
+ /**
+ * Performs a logical <b>AND</b> of this target bit set with the argument bit
+ * set. This bit set is modified so that each bit in it has the value {@code
+ * true} if and only if it both initially had the value {@code true} and the
+ * corresponding bit in the bit set argument also had the value {@code true}.
+ *
+ * @param set
+ * a bit set
+ */
+ public void and(BS 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();
+ }
+
+ /**
+ * Performs a logical <b>OR</b> of this bit set with the bit set argument.
+ * This bit set is modified so that a bit in it has the value {@code true} if
+ * and only if it either already had the value {@code true} or the
+ * corresponding bit in the bit set argument has the value {@code true}.
+ *
+ * @param set
+ * a bit set
+ */
+ public void or(BS 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);
+
+ }
+
+ /**
+ * Performs a logical <b>XOR</b> of this bit set with the bit set argument.
+ * This bit set is modified so that a bit in it has the value {@code true} if
+ * and only if one of the following statements holds:
+ * <ul>
+ * <li>The bit initially has the value {@code true}, and the corresponding bit
+ * in the argument has the value {@code false}.
+ * <li>The bit initially has the value {@code false}, and the corresponding
+ * bit in the argument has the value {@code true}.
+ * </ul>
+ *
+ * @param set
+ * a bit set
+ */
+ public void xor(BS 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();
+ }
+
+ /**
+ * Clears all of the bits in this {@code BitSet} whose corresponding bit is
+ * set in the specified {@code BitSet}.
+ *
+ * @param set
+ * the {@code BitSet} with which to mask this {@code BitSet}
+ * @since 1.2
+ */
+ public void andNot(BS 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();
+ }
+
+ /**
+ * Returns a hash code value for this bit set. The hash code depends only on
+ * which bits have been set within this <code>BitSet</code>. The algorithm
+ * used to compute it may be described as follows.
+ * <p>
+ * Suppose the bits in the <code>BitSet</code> were to be stored in an array
+ * of <code>long</code> integers called, say, <code>words</code>, in such a
+ * manner that bit <code>k</code> is set in the <code>BitSet</code> (for
+ * nonnegative values of <code>k</code>) if and only if the expression
+ *
+ * <pre>
+ * ((k >> 6) < words.length) && ((words[k >> 6] & (1 << (bit & 0x3F))) != 0)
+ * </pre>
+ *
+ * is true. Then the following definition of the <code>hashCode</code> method
+ * would be a correct implementation of the actual algorithm:
+ *
+ * <pre>
+ * public int hashCode() {
+ * long h = 1234;
+ * for (int i = words.length; --i >= 0;) {
+ * h ˆ= words[i] * (i + 1);
+ * }
+ * return (int) ((h >> 32) ˆ h);
+ * }
+ * </pre>
+ *
+ * Note that the hash code values change if the set of bits is altered.
+ * <p>
+ * Overrides the <code>hashCode</code> method of <code>Object</code>.
+ *
+ * @return a hash code value for this bit set.
+ */
+ @Override
+ public int hashCode() {
+ long h = 1234;
+ for (int i = wordsInUse; --i >= 0;)
+ h ^= words[i] * (i + 1);
+
+ return (int) ((h >> 32) ^ h);
+ }
+
+ /**
+ * Returns the number of bits of space actually in use by this {@code BitSet}
+ * to represent bit values. The maximum element in the set is the size - 1st
+ * element.
+ *
+ * @return the number of bits currently in this bit set
+ */
+ public int size() {
+ return words.length * BITS_PER_WORD;
+ }
+
+ /**
+ * Compares this object against the specified object. The result is {@code
+ * true} if and only if the argument is not {@code null} and is a {@code
+ * Bitset} object that has exactly the same set of bits set to {@code true} as
+ * this bit set. That is, for every nonnegative {@code int} index {@code k},
+ *
+ * <pre>
+ * ((BitSet) obj).get(k) == this.get(k)
+ * </pre>
+ *
+ * must be true. The current sizes of the two bit sets are not compared.
+ *
+ * @param obj
+ * the object to compare with
+ * @return {@code true} if the objects are the same; {@code false} otherwise
+ * @see #size()
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof BS))
+ return false;
+ if (this == obj)
+ return true;
+
+ BS set = (BS) obj;
+
+ 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;
+ }
+
+ /**
+ * Cloning this {@code BitSet} produces a new {@code BitSet} that is equal to
+ * it. The clone of the bit set is another bit set that has exactly the same
+ * bits set to {@code true} as this bit set.
+ *
+ * @return a clone of this bit set
+ * @see #size()
+ */
+ @Override
+ public Object clone() {
+ if (!sizeIsSticky && wordsInUse != words.length)
+ setLength(wordsInUse);
+ return copy(this);
+ }
+
+ /**
+ * Attempts to reduce internal storage used for the bits in this bit set.
+ * Calling this method may, but is not required to, affect the value returned
+ * by a subsequent call to the {@link #size()} method.
+ * @param n
+ */
+ private void setLength(int n) {
+ /**
+ * @j2sNative
+ * if (n == this.words.length) return;
+ * if (n == this.wordsInUse) {
+ * this.words = Clazz.array(-1, this.words, 0, n);
+ * return;
+ * }
+ */
+ {}
+ int[] a = new int[n];
+ System.arraycopy(words, 0, a, 0, wordsInUse);
+ words = a;
+ }
+
+ /**
+ * Returns a string representation of this bit set. For every index for which
+ * this {@code BitSet} contains a bit in the set state, the decimal
+ * representation of that index is included in the result. Such indices are
+ * listed in order from lowest to highest, separated by ", " (a comma and
+ * a space) and surrounded by braces, resulting in the usual mathematical
+ * notation for a set of integers.
+ *
+ * <p>
+ * Example:
+ *
+ * <pre>
+ * BitSet drPepper = new BitSet();
+ * </pre>
+ *
+ * Now {@code drPepper.toString()} returns "{}".
+ * <p>
+ *
+ * <pre>
+ * drPepper.set(2);
+ * </pre>
+ *
+ * Now {@code drPepper.toString()} returns "{2}".
+ * <p>
+ *
+ * <pre>
+ * drPepper.set(4);
+ * drPepper.set(10);
+ * </pre>
+ *
+ * Now {@code drPepper.toString()} returns "{2, 4, 10}".
+ *
+ * @return a string representation of this bit set
+ */
+ @Override
+ public String toString() {
+ return escape(this, '(', ')');
+ }
+
+ private final static int[] emptyBitmap = new int[0];
+
+ /**
+ * fast copy
+ *
+ * @param bitsetToCopy
+ * @return bs
+ */
+ public static BS copy(BS bitsetToCopy) {
+ BS bs;
+ /**
+ * Clazz.clone will copy wordsInUse and sizeIsSticky,
+ * but just a pointer to the words array.
+ *
+ * @j2sNative
+ *
+ * bs = Clazz.clone(bitsetToCopy);
+ *
+ */
+ {
+ bs = new BS();
+ }
+ int wordCount = bitsetToCopy.wordsInUse;
+ if (wordCount == 0) {
+ bs.words = emptyBitmap;
+ } else {
+
+ /**
+ * Clazz.clone will copy wordsInUse and sizeIsSticky,
+ * but just a pointer to the words array.
+ *
+ * @j2sNative
+ *
+ * bs.words = Clazz.array(-1, bitsetToCopy.words, 0, bs.wordsInUse = wordCount);
+ *
+ */
+ {
+ bs.words = new int[bs.wordsInUse = wordCount];
+ System.arraycopy(bitsetToCopy.words, 0, bs.words, 0, wordCount);
+ }
+
+ }
+ return bs;
+ }
+
+ /**
+ *
+ * @param max
+ * @return n bits below max
+ */
+ public int cardinalityN(int max) {
+ int n = cardinality();
+ for (int i = length(); --i >= max;)
+ if (get(i))
+ n--;
+ return n;
+ }
+
+ @Override
+ public String toJSON() {
+
+ int numBits = (wordsInUse > 128 ? cardinality() : wordsInUse
+ * BITS_PER_WORD);
+ SB b = SB.newN(6 * numBits + 2);
+ b.appendC('[');
+
+ int i = nextSetBit(0);
+ if (i != -1) {
+ b.appendI(i);
+ for (i = nextSetBit(i + 1); i >= 0; i = nextSetBit(i + 1)) {
+ int endOfRun = nextClearBit(i);
+ do {
+ b.append(", ").appendI(i);
+ } while (++i < endOfRun);
+ }
+ }
+
+ b.appendC(']');
+ return b.toString();
+ }
+
+ public static String escape(BS bs, char chOpen, char chClose) {
+ if (bs == null)
+ return chOpen + "{}" + chClose;
+ SB s = new SB();
+ s.append(chOpen + "{");
+ int imax = bs.length();
+ int iLast = -1;
+ int iFirst = -2;
+ int i = -1;
+ while (++i <= imax) {
+ boolean isSet = bs.get(i);
+ if (i == imax || iLast >= 0 && !isSet) {
+ if (iLast >= 0 && iFirst != iLast)
+ s.append((iFirst == iLast - 1 ? " " : ":") + iLast);
+ if (i == imax)
+ break;
+ iLast = -1;
+ }
+ if (bs.get(i)) {
+ if (iLast < 0) {
+ s.append((iFirst == -2 ? "" : " ") + i);
+ iFirst = i;
+ }
+ iLast = i;
+ }
+ }
+ s.append("}").appendC(chClose);
+ return s.toString();
+ }
+
+ public static BS unescape(String str) {
+ char ch;
+ int len;
+ if (str == null || (len = (str = str.trim()).length()) < 4
+ || str.equalsIgnoreCase("({null})")
+ || (ch = str.charAt(0)) != '(' && ch != '['
+ || str.charAt(len - 1) != (ch == '(' ? ')' : ']')
+ || str.charAt(1) != '{' || str.indexOf('}') != len - 2)
+ return null;
+ len -= 2;
+ for (int i = len; --i >= 2;)
+ if (((ch = str.charAt(i)) < 48 || ch > 57) && ch != ' ' && ch != '\t'
+ && ch != ':')
+ return null;
+ int lastN = len;
+ while (48 <= (ch = str.charAt(--lastN)) && ch <= 57) {
+ // loop
+ }
+ if (++lastN == len)
+ lastN = 0;
+ else
+ try {
+ lastN = Integer.parseInt(str.substring(lastN, len));
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ BS bs = BS.newN(lastN);
+ lastN = -1;
+ int iPrev = -1;
+ int iThis = -2;
+ for (int i = 2; i <= len; i++) {
+ switch (ch = str.charAt(i)) {
+ case '\t':
+ case ' ':
+ case '}':
+ if (iThis < 0)
+ break;
+ if (iThis < lastN)
+ return null;
+ lastN = iThis;
+ if (iPrev < 0)
+ iPrev = iThis;
+ bs.setBits(iPrev, iThis + 1);
+ iPrev = -1;
+ iThis = -2;
+ break;
+ case ':':
+ iPrev = lastN = iThis;
+ iThis = -2;
+ break;
+ default:
+ if (48 <= ch && ch <= 57) {
+ if (iThis < 0)
+ iThis = 0;
+ iThis = (iThis * 10) + (ch - 48);
+ }
+ }
+ }
+ return (iPrev >= 0 ? null : bs);
+ }
+
+}