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

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

There is a newer version: 4.10.17
Show newest version
/*
 * This file is part of choco-solver, http://choco-solver.org/
 *
 * Copyright (c) 2022, 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.IStateLong;


public class OneWordS64BitSet implements IStateBitSet {

    /*
    * BitSets are packed into arrays of "word."  Currently a word is
    * a long, which consists of 64 bits, requiring 6 address bits.
    * The choice of word size is determined purely by performance concerns.
    */
    private final static int ADDRESS_BITS_PER_WORD = 6;
    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 long WORD_MASK = 0xffffffffffffffffL;

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

    /**
     * Creates a bit set whose initial size is large enough to explicitly
     * represent bits with indices in the range 0 through
     * nbits-1. All bits are initially false.
     *
     * @param environment backtrackable environment
     * @param nbits       the initial size of the bit set.
     * @throws NegativeArraySizeException if the specified initial size
     *                                    is negative.
     */
    public OneWordS64BitSet(IEnvironment environment, int nbits) {
        // nbits can't be negative; size 0 is OK
        if (nbits < 0)
            throw new NegativeArraySizeException("nbits < 0: " + nbits);
        if (nbits > 64)
            throw new ArrayIndexOutOfBoundsException("nbits > 64: " + nbits);

        word = environment.makeLong(0);
    }

    /**
     * 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) {
        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);
    }

    /**
     * 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
     */
    public void set(int bitIndex) {
        if (bitIndex < 0)
            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);

        word.set(word.get() | (1L << bitIndex)); // Restores invariants
        //checkInvariants();
    }

    /**
     * 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 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
     */
    public void set(int fromIndex, int toIndex) {
        checkRange(fromIndex, toIndex);

        if (fromIndex == toIndex)
            return;

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

    /**
     * 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
     */
    public void clear(int bitIndex) {
        if (bitIndex < 0)
            throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);

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

    /**
     * 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
     */
    public void clear(int fromIndex, int toIndex) {
        checkRange(fromIndex, toIndex);

        if (fromIndex == toIndex)
            return;

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

    /**
     * Sets all of the bits in this BitSet to false.
     *
     * @since 1.4
     */
    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.
     */
    final public boolean get(final int bitIndex) {
        //if (bitIndex < 0)
        //    throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);

        //checkInvariants();
        return bitIndex < 64 && ((word.get() & (1L << 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 */ public int nextSetBit(int fromIndex) { if (fromIndex < 0) { fromIndex = 0; } if (fromIndex >= 64) return -1; long word = this.word.get() & (WORD_MASK << fromIndex); if (word != 0) return Long.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 */ public int nextClearBit(int fromIndex) { // Neither spec nor implementation handle bitsets of maximal length. // See 4816253. if (fromIndex < 0) { fromIndex = 0; } if (fromIndex >= 64) return fromIndex; long word = ~this.word.get() & (WORD_MASK << fromIndex); if (word != 0) return Long.numberOfTrailingZeros(word); else return 0; } /** * 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 */ public int prevSetBit(int fromIndex) { if (fromIndex < 0) { return -1; } if (fromIndex >= 64) return length() - 1; long word = this.word.get() & (WORD_MASK >>> -(fromIndex + 1)); if (word != 0) return BITS_PER_WORD - 1 - Long.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 */ public int prevClearBit(int fromIndex) { if (fromIndex < 0) { return -1; } if (fromIndex >= 64) return fromIndex; long word = ~this.word.get() & (WORD_MASK >>> -(fromIndex + 1)); if (word != 0) return BITS_PER_WORD - 1 - Long.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 - Long.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 */ 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 */ public int cardinality() { return Long.bitCount(word.get()); } public int hashCode() { long h = 1234; h ^= word.get(); return (int) ((h >> 32) ^ 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. */ public int size() { return BITS_PER_WORD; } public boolean equals(Object obj) { if (!(obj instanceof OneWordS64BitSet)) return false; if (this == obj) return true; OneWordS64BitSet set = (OneWordS64BitSet) obj; //checkInvariants(); //set.checkInvariants(); // Check word in use by both BitSets return word == set.word; } 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