All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.tommyettinger.ds.OffsetBitSet Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2022-2025 See AUTHORS file.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.tommyettinger.ds;

import com.github.tommyettinger.digital.BitConversion;

import com.github.tommyettinger.ds.support.util.IntAppender;
import com.github.tommyettinger.ds.support.util.IntIterator;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Arrays;
import java.util.NoSuchElementException;

/**
 * A bit set, which can be seen as a set of integer positions greater than some starting number,
 * that has changeable offset, or starting position. If you know the integer positions will all
 * be greater than or equal to some minimum value, such as -128, 0, or 1000, then you can use an offset
 * of that minimum value to save memory. This is important because every possible integer position, whether
 * contained in the bit set or not, takes up one bit of memory (rounded up to a multiple of 32), but
 * positions less than the offset simply aren't stored, and the bit set can grow to fit positions arbitrarily
 * higher than the offset. Allows comparison via bitwise operators to other bit sets, as long as the offsets
 * are the same.
 * 
* This was originally Bits in libGDX. Many methods have been renamed to more-closely match the Collection API. * This has also had the offset functionality added. It was changed from using {@code long} to store 64 bits in * one value, to {@code int} to store 32 bits in one value, because GWT is so slow at handling {@code long}. * * @author mzechner * @author jshapcott * @author tommyettinger */ public class OffsetBitSet implements PrimitiveSet.OfInt { /** * The raw bits, each one representing the presence or absence of an integer at a position. */ protected int[] bits; /** * This is the lowest integer position that this OffsetBitSet can store. * If all positions are at least equal to some value, using that for the offset can save space. */ protected int offset = 0; @Nullable protected transient OffsetBitSetIterator iterator1; @Nullable protected transient OffsetBitSetIterator iterator2; /** * Creates a bit set with an initial size that can store positions between 0 and 31, inclusive, without * needing to resize. This has an offset of 0 and can resize to fit larger positions. */ public OffsetBitSet () { bits = new int[1]; } /** * Creates a bit set whose initial size is large enough to explicitly represent bits with indices in the range 0 through * bitCapacity-1. This has an offset of 0 and can resize to fit larger positions. * * @param bitCapacity the initial size of the bit set */ public OffsetBitSet (int bitCapacity) { bits = new int[bitCapacity + 31 >>> 5]; } /** * Creates a bit set whose initial size is large enough to explicitly represent bits with indices in the range {@code start} through * {@code end-1}. This has an offset of {@code start} and can resize to fit larger positions. * * @param start the lowest value that can be stored in the bit set * @param end the initial end of the range of the bit set */ public OffsetBitSet (int start, int end) { offset = start; bits = new int[end + 31 - start >>> 5]; } /** * Creates a bit set from another bit set. This will copy the raw bits and will have the same offset. * * @param toCopy bitset to copy */ public OffsetBitSet (OffsetBitSet toCopy) { this.bits = new int[toCopy.bits.length]; System.arraycopy(toCopy.bits, 0, this.bits, 0, toCopy.bits.length); this.offset = toCopy.offset; } /** * Creates a bit set from any primitive int collection, such as a {@link IntList} or {@link IntSet}. * The offset of the new bit set will be the lowest int in the collection, which you should be aware of * if you intend to use the bitwise methods such as {@link #and(OffsetBitSet)} and {@link #or(OffsetBitSet)}. * * @param toCopy the primitive int collection to copy */ public OffsetBitSet (PrimitiveCollection.OfInt toCopy) { if(toCopy.isEmpty()){ offset = 0; bits = new int[1]; return; } int start = Integer.MAX_VALUE, end = Integer.MIN_VALUE; for(IntIterator it = toCopy.iterator(); it.hasNext();) { int n = it.next(); start = Math.min(start, n); end = Math.max(end, n + 1); } offset = start; bits = new int[end + 31 - start >>> 5]; addAll(toCopy); } /** * Creates a bit set from an entire int array. * The offset of the new bit set will be the lowest int in the collection, which you should be aware of * if you intend to use the bitwise methods such as {@link #and(OffsetBitSet)} and {@link #or(OffsetBitSet)}. * * @param toCopy the non-null int array to copy */ public OffsetBitSet (int[] toCopy){ this(toCopy, 0, toCopy.length); } /** * Creates a bit set from an int array, starting reading at an offset and continuing for a given length. * The offset of the new bit set will be the lowest int in the collection, which you should be aware of * if you intend to use the bitwise methods such as {@link #and(OffsetBitSet)} and {@link #or(OffsetBitSet)}. * * @param toCopy the int array to copy * @param off which index to start copying from toCopy * @param length how many items to copy from toCopy */ public OffsetBitSet (int[] toCopy, int off, int length) { if(toCopy.length == 0){ offset = 0; bits = new int[1]; return; } int start = Integer.MAX_VALUE, end = Integer.MIN_VALUE; for(int i = off, e = off + length; i < e; i++) { int n = toCopy[i]; start = Math.min(start, n); end = Math.max(end, n + 1); } offset = start; bits = new int[end + 31 - start >>> 5]; addAll(toCopy, off, length); } /** * Gets the lowest integer position that this OffsetBitSet can store. * If all positions are at least equal to some value, using that for the offset can save space. */ public int getOffset () { return offset; } /** * Changes the offset without considering the previous value. This effectively adds {@code newOffset - getOffset()} * to every int stored in this, in constant time. This also changes the minimum value in the process. * @param newOffset the value to use instead of the current offset */ public void setOffset(int newOffset) { this.offset = newOffset; } /** * Adds {@code addend} to the current offset, effectively adding to every int stored in this, in constant time. * This also changes the minimum value in the process. * @param addend the value to add to the current offset */ public void changeOffset(int addend) { this.offset += addend; } /** * This gets the internal {@code int[]} used to store bits in bulk. This is not meant for typical usage; it may be * useful for serialization or other code that would typically need reflection to access the internals here. This * may and often does include padding at the end. * @return the raw int array used to store positions, one bit per on and per off position */ public int[] getRawBits () { return bits; } /** * This allows setting the internal {@code int[]} used to store bits in bulk. This is not meant for typical usage; it * may be useful for serialization or other code that would typically need reflection to access the internals here. * Be very careful with this method. If bits is null or empty, it is ignored; this is the only error validation this does. * @param bits a non-null, non-empty int array storing positions, typically obtained from {@link #getRawBits()} */ public void setRawBits (int[] bits) { if (bits != null && bits.length != 0) { this.bits = bits; } } /** * Returns true if the given position is contained in this bit set. * If the index is less than the {@link #getOffset() offset}, this returns false. * @param index the index of the bit * @return whether the bit is set */ public boolean contains (int index) { index -= offset; if(index < 0) return false; final int word = index >>> 5; if (word >= bits.length) return false; return (bits[word] & (1 << index)) != 0; } /** Deactivates the given position and returns true if the bit set was modified * in the process. If the index is less than the {@link #getOffset() offset}, * this does not modify the bit set and returns false. * @param index the index of the bit * @return true if this modified the bit set */ public boolean remove (int index) { index -= offset; if(index < 0) return false; final int word = index >>> 5; if (word >= bits.length) return false; int oldBits = bits[word]; bits[word] &= ~(1 << index); return bits[word] != oldBits; } /** Activates the given position and returns true if the bit set was modified * in the process. If the index is less than the {@link #getOffset() offset}, * this does not modify the bit set and returns false. * @param index the index of the bit * @return true if this modified the bit set */ public boolean add (int index) { index -= offset; if(index < 0) return false; final int word = index >>> 5; checkCapacity(word); int oldBits = bits[word]; bits[word] |= 1 << index; return bits[word] != oldBits; } public boolean addAll(int[] indices) { return addAll(indices, 0, indices.length); } public boolean addAll (int[] indices, int off, int length) { if(length <= 0 || off < 0 || off + length > indices.length) return false; boolean changed = false; for (int i = off, n = off + length; i < n; i++) { changed |= add(indices[i]); } return changed; } public boolean addAll(short[] indices) { return addAll(indices, 0, indices.length); } public boolean addAll (short[] indices, int off, int length) { if(length <= 0 || off < 0 || off + length > indices.length) return false; boolean changed = false; for (int i = off, n = off + length; i < n; i++) { changed |= add(indices[i]); } return changed; } public boolean addAll(byte[] indices) { return addAll(indices, 0, indices.length); } public boolean addAll (byte[] indices, int off, int length) { if(length <= 0 || off < 0 || off + length > indices.length) return false; boolean changed = false; for (int i = off, n = off + length; i < n; i++) { changed |= add(indices[i]); } return changed; } public boolean addAll(char[] indices) { return addAll(indices, 0, indices.length); } public boolean addAll (char[] indices, int off, int length) { if(length <= 0 || off < 0 || off + length > indices.length) return false; boolean changed = false; for (int i = off, n = off + length; i < n; i++) { changed |= add(indices[i]); } return changed; } public boolean addAll(PrimitiveCollection.OfInt indices) { IntIterator it = indices.iterator(); boolean changed = false; while (it.hasNext()){ changed |= add(it.nextInt()); } return changed; } /** * Returns an iterator for the keys in the set. Remove is supported. *

* Use the {@link OffsetBitSetIterator} constructor for nested or multithreaded iteration. */ @Override public OffsetBitSetIterator iterator () { if (iterator1 == null || iterator2 == null) { iterator1 = new OffsetBitSetIterator(this); iterator2 = new OffsetBitSetIterator(this); } if (!iterator1.valid) { iterator1.reset(); iterator1.valid = true; iterator2.valid = false; return iterator1; } iterator2.reset(); iterator2.valid = true; iterator1.valid = false; return iterator2; } /** * Sets the given int position to true, unless the position is less * than the {@link #getOffset() offset} (then it does nothing). * @param index the index of the bit to set */ public void activate (int index) { index -= offset; if(index < 0) return; final int word = index >>> 5; checkCapacity(word); bits[word] |= 1 << index; } /** * Sets the given int position to false, unless the position is less * than the {@link #getOffset() offset} (then it does nothing). * @param index the index of the bit to clear */ public void deactivate (int index) { index -= offset; if(index < 0) return; final int word = index >>> 5; if (word >= bits.length) return; bits[word] &= ~(1 << index); } /** * Changes the given int position from true to false, or from false to true, * unless the position is less than the {@link #getOffset() offset} (then it * does nothing). * @param index the index of the bit to flip */ public void toggle (int index) { index -= offset; if(index < 0) return; final int word = index >>> 5; checkCapacity(word); bits[word] ^= 1 << index; } private void checkCapacity (int index) { if (index >= bits.length) { int[] newBits = new int[1 << -BitConversion.countLeadingZeros(index)]; // resizes to next power of two size that can fit index System.arraycopy(bits, 0, newBits, 0, bits.length); bits = newBits; } } /** * Clears the entire bitset, removing all contained ints. Doesn't change the capacity. */ public void clear () { Arrays.fill(bits, 0); } /** * Gets the capacity in bits, including both true and false values, and including any false values that may be * after the last contained position, but does not include the offset. Runs in O(1) time. * @return the number of bits currently stored, not the highest set bit; doesn't include offset either */ public int numBits () { return bits.length << 5; } /** * Returns the "logical extent" of this bitset: the index of the highest set bit in the bitset plus one. Returns zero if the * bitset contains no set bits. If this has any set bits, it will return an int at least equal to {@code offset}. * Runs in O(n) time. * * @return the logical extent of this bitset */ public int length () { int[] bits = this.bits; for (int word = bits.length - 1; word >= 0; --word) { int bitsAtWord = bits[word]; if (bitsAtWord != 0) { return (word + 1 << 5) - BitConversion.countLeadingZeros(bitsAtWord) + offset; } } return 0; } /** * Returns the size of the set, or its cardinality; this is the count of distinct activated positions in the set. * Note that unlike most Collection types, which typically have O(1) size() runtime, this runs in O(n) time, where * n is on the order of the capacity. * * @return the count of distinct activated positions in the set. */ public int size() { int[] bits = this.bits; int count = 0; for (int word = bits.length - 1; word >= 0; --word) { count += Integer.bitCount(bits[word]); } return count; } /** * Checks if there are any positions contained in this at all. Run in O(n) time, but usually takes less. * @return true if this bitset contains at least one bit set to true */ public boolean notEmpty () { return !isEmpty(); } /** * Checks if there are no positions contained in this at all. Run in O(n) time, but usually takes less. * @return true if this bitset contains no bits that are set to true */ public boolean isEmpty () { int[] bits = this.bits; int length = bits.length; for (int i = 0; i < length; i++) { if (bits[i] != 0) { return false; } } return true; } /** * Returns the index of the first bit that is set to true that occurs on or after the specified starting index. If no such bit * exists then {@link #getOffset() - 1} is returned. * @param fromIndex the index to start looking at * @return the first position that is set to true that occurs on or after the specified starting index */ public int nextSetBit (int fromIndex) { fromIndex -= offset; if(fromIndex < 0) return offset - 1; int[] bits = this.bits; int word = fromIndex >>> 5; int bitsLength = bits.length; if (word >= bitsLength) return offset - 1; int bitsAtWord = bits[word] & -1 << fromIndex; // shift implicitly is masked to bottom 31 bits if (bitsAtWord != 0) { return BitConversion.countTrailingZeros(bitsAtWord) + (word << 5) + offset; // countTrailingZeros() uses an intrinsic candidate, and should be extremely fast } for (word++; word < bitsLength; word++) { bitsAtWord = bits[word]; if (bitsAtWord != 0) { return BitConversion.countTrailingZeros(bitsAtWord) + (word << 5) + offset; } } return offset - 1; } /** * Returns the index of the first bit that is set to false that occurs on or after the specified starting index. If no such bit * exists then {@code numBits() + getOffset()} is returned. * * @param fromIndex the index to start looking at * @return the first position that is set to true that occurs on or after the specified starting index */ public int nextClearBit (int fromIndex) { fromIndex -= offset; if(fromIndex < 0) return (bits.length << 5) + offset; int[] bits = this.bits; int word = fromIndex >>> 5; int bitsLength = bits.length; if (word >= bitsLength) return (bits.length << 5) + offset; int bitsAtWord = bits[word] | (1 << fromIndex) - 1; // shift implicitly is masked to bottom 31 bits if (bitsAtWord != -1) { return BitConversion.countTrailingZeros(~bitsAtWord) + (word << 5) + offset; // countTrailingZeros() uses an intrinsic candidate, and should be extremely fast } for (word++; word < bitsLength; word++) { bitsAtWord = bits[word]; if (bitsAtWord != -1) { return BitConversion.countTrailingZeros(~bitsAtWord) + (word << 5) + offset; // countTrailingZeros() uses an intrinsic candidate, and should be extremely fast } } return (bits.length << 5) + offset; } /** * Performs a logical AND of this target bit set with the argument bit set. This bit set is modified so that each bit * in it has the value true if and only if it both initially had the value true and the corresponding bit in the bit set * argument also had the value true. Both this OffsetBitSet and {@code other} must have the same offset. * * @param other another OffsetBitSet; must have the same offset as this */ public void and (OffsetBitSet other) { if(offset == other.offset) { int commonWords = Math.min(bits.length, other.bits.length); for (int i = 0; commonWords > i; i++) { bits[i] &= other.bits[i]; } if (bits.length > commonWords) { for (int i = commonWords, s = bits.length; s > i; i++) { bits[i] = 0; } } } else { throw new UnsupportedOperationException("The offset of both OffsetBitSet objects must be the same to call and()."); } } /** * Clears all the bits in this bit set whose corresponding bit is set in the specified bit set. * This can be seen as an optimized version of {@link PrimitiveCollection.OfInt#removeAll(OfInt)} that only works if * both OffsetBitSet objects have the same {@link #offset}. Both this OffsetBitSet and {@code other} must have the same offset. * * @param other another OffsetBitSet; must have the same offset as this */ public void andNot (OffsetBitSet other) { if(offset == other.offset) { for (int i = 0, j = bits.length, k = other.bits.length; i < j && i < k; i++) { bits[i] &= ~other.bits[i]; } } else { throw new UnsupportedOperationException("The offset of both OffsetBitSet objects must be the same to call andNot()."); } } /** * Performs a logical OR of this bit set with the bit set argument. This bit set is modified so that a bit in it has * the value true if and only if it either already had the value true or the corresponding bit in the bit set argument has the * value true. Both this OffsetBitSet and {@code other} must have the same offset. * * @param other another OffsetBitSet; must have the same offset as this */ public void or (OffsetBitSet other) { if(offset == other.offset) { int commonWords = Math.min(bits.length, other.bits.length); for (int i = 0; commonWords > i; i++) { bits[i] |= other.bits[i]; } if (commonWords < other.bits.length) { checkCapacity(other.bits.length); for (int i = commonWords, s = other.bits.length; s > i; i++) { bits[i] = other.bits[i]; } } } else { throw new UnsupportedOperationException("The offset of both OffsetBitSet objects must be the same to call or()."); } } /** * Performs a logical XOR of this bit set with the bit set argument. This bit set is modified so that a bit in it has * the value true if and only if one of the following statements holds: *

    *
  • The bit initially has the value true, and the corresponding bit in the argument has the value false.
  • *
  • The bit initially has the value false, and the corresponding bit in the argument has the value true.
  • *
* Both this OffsetBitSet and {@code other} must have the same offset. * * @param other another OffsetBitSet; must have the same offset as this */ public void xor (OffsetBitSet other) { if(offset == other.offset) { int commonWords = Math.min(bits.length, other.bits.length); for (int i = 0; commonWords > i; i++) { bits[i] ^= other.bits[i]; } if (commonWords < other.bits.length) { checkCapacity(other.bits.length); for (int i = commonWords, s = other.bits.length; s > i; i++) { bits[i] = other.bits[i]; } } } else { throw new UnsupportedOperationException("The offset of both OffsetBitSet objects must be the same to call xor()."); } } /** * Returns true if the specified BitSet has any bits set to true that are also set to true in this BitSet. * Both this OffsetBitSet and {@code other} must have the same offset. * * @param other another OffsetBitSet; must have the same offset as this * @return boolean indicating whether this bit set intersects the specified bit set */ public boolean intersects (OffsetBitSet other) { if(offset == other.offset) { int[] bits = this.bits; int[] otherBits = other.bits; for (int i = Math.min(bits.length, otherBits.length) - 1; i >= 0; i--) { if ((bits[i] & otherBits[i]) != 0) { return true; } } return false; } else { throw new UnsupportedOperationException("The offset of both OffsetBitSet objects must be the same to call intersects()."); } } /** Returns true if this bit set is a super set of the specified set, i.e. it has all bits set to true that are also set to * true in the specified BitSet. If this OffsetBitSet and {@code other} have the same offset, this is much more efficient, but * it will work even if the offsets are different. * * @param other another OffsetBitSet * @return boolean indicating whether this bit set is a super set of the specified set */ public boolean containsAll (OffsetBitSet other) { if (offset == other.offset) { int[] bits = this.bits; int[] otherBits = other.bits; int otherBitsLength = otherBits.length; int bitsLength = bits.length; for (int i = bitsLength; i < otherBitsLength; i++) { if (otherBits[i] != 0) { return false; } } for (int i = Math.min(bitsLength, otherBitsLength) - 1; i >= 0; i--) { if ((bits[i] & otherBits[i]) != otherBits[i]) { return false; } } return true; } else return ((PrimitiveCollection.OfInt)this).containsAll(other); } @Override public int hashCode () { final int limit = (length() + 31 - offset >>> 5); int hash = offset; for (int i = 0; i < limit; i++) { hash += bits[i]; } return hash; } @Override public boolean equals (Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; OffsetBitSet other = (OffsetBitSet)obj; if(offset != other.offset) return false; int[] otherBits = other.bits; int commonWords = Math.min(bits.length, otherBits.length); for (int i = 0; commonWords > i; i++) { if (bits[i] != otherBits[i]) return false; } if (bits.length == otherBits.length) return true; return length() == other.length(); } /** * Given a StringBuilder, this appends part of the toString() representation of this OffsetBitSet, without allocating a String. * This does not include the opening {@code [} and closing {@code ]} chars, and only appends the int positions in this OffsetBitSet, * each pair separated by the given delimiter String. You can use this to choose a different delimiter from what toString() uses. * @param builder a StringBuilder that will be modified in-place and returned * @param delimiter the String that separates every pair of integers in the result * @return the given StringBuilder, after modifications */ public StringBuilder appendContents (StringBuilder builder, String delimiter) { int curr = nextSetBit(offset); builder.append(curr); while ((curr = nextSetBit(curr+1)) != offset - 1) { builder.append(delimiter).append(curr); } return builder; } /** * Given a StringBuilder, this appends the toString() representation of this OffsetBitSet, without allocating a String. * This includes the opening {@code [} and closing {@code ]} chars; it uses {@code ", "} as its delimiter. * @param builder a StringBuilder that will be modified in-place and returned * @return the given StringBuilder, after modifications */ public StringBuilder appendTo (StringBuilder builder) { return appendContents(builder.append('['), ", ").append(']'); } /** * Appends to a StringBuilder from the contents of this PrimitiveCollection, but uses the given {@link IntAppender} * to convert each item to a customizable representation and append them to a StringBuilder. To use * the default String representation, you can use {@code StringBuilder::append} as an appender. * * @param sb a StringBuilder that this can append to * @param separator how to separate items, such as {@code ", "} * @param brackets true to wrap the output in square brackets, or false to omit them * @param appender a function that takes a StringBuilder and an int, and returns the modified StringBuilder * @return {@code sb}, with the appended items of this PrimitiveCollection */ @Override public StringBuilder appendTo (StringBuilder sb, String separator, boolean brackets, IntAppender appender) { if (isEmpty()) {return brackets ? sb.append("[]") : sb;} if (brackets) {sb.append('[');} int curr = nextSetBit(offset); appender.apply(sb, curr); while ((curr = nextSetBit(curr+1)) != offset - 1) { sb.append(separator); appender.apply(sb, curr); } if (brackets) {sb.append(']');} return sb; } @Override public String toString () { return toString(", ", true); } public static class OffsetBitSetIterator implements IntIterator { static private final int INDEX_ILLEGAL = -1, INDEX_ZERO = -1; public boolean hasNext; final OffsetBitSet set; int nextIndex, currentIndex; boolean valid = true; public OffsetBitSetIterator (OffsetBitSet set) { this.set = set; reset(); } public void reset () { currentIndex = INDEX_ILLEGAL + set.offset; nextIndex = INDEX_ZERO + set.offset; findNextIndex(); } void findNextIndex () { nextIndex = set.nextSetBit(nextIndex + 1); hasNext = nextIndex != INDEX_ILLEGAL + set.offset; } /** * Returns {@code true} if the iteration has more elements. * (In other words, returns {@code true} if {@link #next} would * return an element rather than throwing an exception.) * * @return {@code true} if the iteration has more elements */ @Override public boolean hasNext () { if (!valid) {throw new RuntimeException("#iterator() cannot be used nested.");} return hasNext; } @Override public void remove () { if (currentIndex < 0) { throw new IllegalStateException("next must be called before remove."); } set.deactivate(currentIndex); currentIndex = INDEX_ILLEGAL + set.offset; } @Override public int nextInt () { if (!hasNext) {throw new NoSuchElementException();} if (!valid) {throw new RuntimeException("#iterator() cannot be used nested.");} int key = nextIndex; currentIndex = nextIndex; findNextIndex(); return key; } /** * Returns a new {@link IntList} containing the remaining items. * Does not change the position of this iterator. */ public IntList toList () { IntList list = new IntList(set.size()); int currentIdx = currentIndex, nextIdx = nextIndex; boolean hn = hasNext; while (hasNext) { list.add(nextInt()); } currentIndex = currentIdx; nextIndex = nextIdx; hasNext = hn; return list; } /** * Append the remaining items that this can iterate through into the given PrimitiveCollection.OfInt. * Does not change the position of this iterator. * @param coll any modifiable PrimitiveCollection.OfInt; may have items appended into it * @return the given primitive collection */ public PrimitiveCollection.OfInt appendInto(PrimitiveCollection.OfInt coll) { int currentIdx = currentIndex, nextIdx = nextIndex; boolean hn = hasNext; while (hasNext) {coll.add(nextInt());} currentIndex = currentIdx; nextIndex = nextIdx; hasNext = hn; return coll; } } /** * Static builder for an OffsetBitSet; this overload does not allocate an * array for the index/indices, but only takes one index. This always has * an offset of 0. * @param index the one position to place in the built bit set; must be non-negative * @return a new OffsetBitSet with the given item */ public static OffsetBitSet with(int index) { OffsetBitSet s = new OffsetBitSet(index+1); s.add(index); return s; } /** * Static builder for an OffsetBitSet; this overload allocates an array for * the indices unless given an array already, and can take many indices. This * always has an offset of 0. * @param indices the positions to place in the built bit set; must be non-negative * @return a new OffsetBitSet with the given items */ public static OffsetBitSet with(int... indices) { OffsetBitSet s = new OffsetBitSet(); s.addAll(indices); return s; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy