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

org.chocosolver.memory.structure.OneWordS32BitSet Maven / Gradle / Ivy

The newest version!
/*
 * This file is part of choco-solver, http://choco-solver.org/
 *
 * Copyright (c) 2024, IMT Atlantique. All rights reserved.
 *
 * Licensed under the BSD 4-clause license.
 *
 * See LICENSE file in the project root for full license information.
 */
package org.chocosolver.memory.structure;

import org.chocosolver.memory.IEnvironment;
import org.chocosolver.memory.IStateBitSet;
import org.chocosolver.memory.IStateInt;


public class OneWordS32BitSet implements IStateBitSet {

    /*
     * BitSets are packed into arrays of "word."  Currently a word is
     * an int, which consists of 32 bits, requiring 6 address bits.
     * The choice of word size is determined purely by performance concerns.
     */
    private final static int ADDRESS_BITS_PER_WORD = 5;
    private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;

    /* Used to shift left or right for a partial word mask */
    private static final int WORD_MASK = 0xffffffff;

    /**
     * The internal field corresponding to the serialField "bits".
     */
    private final IStateInt word;

    /**
     * Creates a bit set whose initial size is 32.
     * All bits are initially false.
     *
     * @param environment backtrackable environment
     * @throws NegativeArraySizeException if the specified initial size
     *                                    is negative.
     */
    public OneWordS32BitSet(IEnvironment environment) {
        word = environment.makeInt(0);
    }

    /**
     * Checks that index is a valid range of bit indices.
     *
     * @param index index
     */
    private static void checkIndex(int index) {
        if (index < 0)
            throw new IndexOutOfBoundsException("fromIndex < 0: " + index);
        if (index > 31)
            throw new IndexOutOfBoundsException("fromIndex > 31: " + index);
    }

    /**
     * Checks that fromIndex ... toIndex is a valid range of bit indices.
     *
     * @param fromIndex starting index
     * @param toIndex   ending index
     */
    private static void checkRange(int fromIndex, int toIndex) {
        checkIndex(fromIndex);
        checkIndex(toIndex);
        if (fromIndex > toIndex)
            throw new IndexOutOfBoundsException("fromIndex: " + fromIndex + " > toIndex: " + toIndex);
    }

    /**
     * Sets the bit at the specified index to true.
     *
     * @param bitIndex a bit index.
     * @throws IndexOutOfBoundsException if the specified index is negative.
     * @since JDK1.0
     */
    @Override
    public void set(int bitIndex) {
        checkIndex(bitIndex);

        word.set(word.get() | (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
     */
    @Override
    public void set(int bitIndex, boolean value) {
        if (value)
            set(bitIndex);
        else
            clear(bitIndex);
    }

    /**
     * Sets the bits from the specified fromIndex (inclusive) to the
     * specified toIndex (exclusive) to true.
     *
     * @param fromIndex index of the first bit to be set.
     * @param toIndex   index after the last bit to be set.
     * @throws IndexOutOfBoundsException if fromIndex is negative,
     *                                   or toIndex is negative, or fromIndex is
     *                                   larger than toIndex.
     * @since 1.4
     */
    @Override
    public void set(int fromIndex, int toIndex) {
        checkRange(fromIndex, toIndex);

        if (fromIndex == toIndex)
            return;

        int firstWordMask = WORD_MASK << fromIndex;
        int lastWordMask = WORD_MASK >>> -toIndex;
        word.set(word.get() | (firstWordMask & lastWordMask));
    }

    /**
     * Sets the bit specified by the index to false.
     *
     * @param bitIndex the index of the bit to be cleared.
     * @throws IndexOutOfBoundsException if the specified index is negative.
     * @since JDK1.0
     */
    @Override
    public void clear(int bitIndex) {
        checkIndex(bitIndex);

        word.set(word.get() & ~(1 << bitIndex));
    }

    /**
     * Sets the bits from the specified fromIndex (inclusive) to the
     * specified toIndex (exclusive) to false.
     *
     * @param fromIndex index of the first bit to be cleared.
     * @param toIndex   index after the last bit to be cleared.
     * @throws IndexOutOfBoundsException if fromIndex is negative,
     *                                   or toIndex is negative, or fromIndex is
     *                                   larger than toIndex.
     * @since 1.4
     */
    @Override
    public void clear(int fromIndex, int toIndex) {
        checkRange(fromIndex, toIndex);

        if (fromIndex == toIndex)
            return;

        int firstWordMask = WORD_MASK << fromIndex;
        int lastWordMask = WORD_MASK >>> -toIndex;
        word.set(word.get() & ~(firstWordMask & lastWordMask));
    }

    /**
     * Sets all of the bits in this BitSet to false.
     *
     * @since 1.4
     */
    @Override
    public void clear() {
        word.set(0);
    }

    /**
     * Returns the value of the bit with the specified index. The value
     * is true if the bit with the index bitIndex
     * is currently set in this BitSet; otherwise, the result
     * is false.
     *
     * @param bitIndex the bit index.
     * @return the value of the bit with the specified index.
     * @throws IndexOutOfBoundsException if the specified index is negative.
     */
    @Override
    final public boolean get(final int bitIndex) {
        return bitIndex < 32 && ((word.get() & (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.
     * 

*

To iterate over the {@code true} bits in a {@code BitSet}, * use the following loop: *

*

 {@code
     * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
     *     // operate on index i here
     * }}
* * @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 */ @Override public int nextSetBit(int fromIndex) { if (fromIndex < 0) { fromIndex = 0; } if (fromIndex >= 32) return -1; int word = this.word.get() & (WORD_MASK << fromIndex); if (word != 0) return Integer.numberOfTrailingZeros(word); else return -1; } /** * 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 */ @Override public int nextClearBit(int fromIndex) { // Neither spec nor implementation handle bitsets of maximal length. // See 4816253. if (fromIndex < 0) { fromIndex = 0; } if (fromIndex >= 32) return fromIndex; int word = ~this.word.get() & (WORD_MASK << fromIndex); if (word != 0) return Integer.numberOfTrailingZeros(word); else return BITS_PER_WORD; } /** * Returns the index of the nearest bit that is set to {@code true} * that occurs on or before the specified starting index. * If no such bit exists, or if {@code -1} is given as the * starting index, then {@code -1} is returned. *

*

To iterate over the {@code true} bits in a {@code BitSet}, * use the following loop: *

*

 {@code
     * for (int i = bs.length(); (i = bs.previousSetBit(i-1)) >= 0; ) {
     *     // operate on index i here
     * }}
* * @param fromIndex the index to start checking from (inclusive) * @return the index of the previous set bit, or {@code -1} if there * is no such bit * @throws IndexOutOfBoundsException if the specified index is less * than {@code -1} * @since 1.7 */ @Override public int prevSetBit(int fromIndex) { if (fromIndex < 0) { return -1; } if (fromIndex >= 32) return length() - 1; int word = this.word.get() & (WORD_MASK >>> -(fromIndex + 1)); if (word != 0) return BITS_PER_WORD - 1 - Integer.numberOfLeadingZeros(word); else return -1; } /** * Returns the index of the nearest bit that is set to {@code false} * that occurs on or before the specified starting index. * If no such bit exists, or if {@code -1} is given as the * starting index, then {@code -1} is returned. * * @param fromIndex the index to start checking from (inclusive) * @return the index of the previous clear bit, or {@code -1} if there * is no such bit * @throws IndexOutOfBoundsException if the specified index is less * than {@code -1} * @since 1.7 */ @Override public int prevClearBit(int fromIndex) { if (fromIndex < 0) { return -1; } if (fromIndex >= 32) return fromIndex; int word = ~this.word.get() & (WORD_MASK >>> -(fromIndex + 1)); if (word != 0) return BITS_PER_WORD - 1 - Integer.numberOfLeadingZeros(word); else return -1; } /** * Returns the "logical size" of this BitSet: the index of * the highest set bit in the BitSet plus one. Returns zero * if the BitSet contains no set bits. * * @return the logical size of this BitSet. * @since 1.2 */ public int length() { return (BITS_PER_WORD - Integer.numberOfLeadingZeros(word.get())); } /** * Returns true if this BitSet contains no bits that are set * to true. * * @return boolean indicating whether this BitSet is empty. * @since 1.4 */ @Override public boolean isEmpty() { return word.get() == 0; } /** * Returns the number of bits set to true in this * BitSet. * * @return the number of bits set to true in this * BitSet. * @since 1.4 */ @Override public int cardinality() { return Integer.bitCount(word.get()); } @Override public int hashCode() { int h = 1234; h ^= word.get(); return (h >> 14) ^ h; } /** * Returns the number of bits of space actually in use by this * 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. */ @Override public int size() { return BITS_PER_WORD; } @Override public boolean equals(Object obj) { if (!(obj instanceof OneWordS32BitSet)) return false; if (this == obj) return true; OneWordS32BitSet set = (OneWordS32BitSet) obj; // Check word in use by both BitSets return word == set.word; } @Override public String toString() { StringBuilder b = new StringBuilder(6 * BITS_PER_WORD + 2); b.append('{'); int i = nextSetBit(0); if (i != -1) { b.append(i); for (i = nextSetBit(i + 1); i >= 0; i = nextSetBit(i + 1)) { int endOfRun = nextClearBit(i); do { b.append(", ").append(i); } while (++i < endOfRun); } } b.append('}'); return b.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy