607 lines
14 KiB
Java
Raw Normal View History

2021-07-16 17:12:20 -05:00
/*
* @(#) $(JCGO)/goclsp/clsp_fix/java/util/BitSet.java --
* Int-based implementation of the standard BitSet class.
**
* Project: JCGO (http://www.ivmaisoft.com/jcgo/)
* Copyright (C) 2001-2007 Ivan Maidanski <ivmai@ivmaisoft.com>
* All rights reserved.
**
* Class specification origin: GNU Classpath v0.93
*/
/*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
**
* This software 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 (GPL) for more details.
**
* Linking this library statically or dynamically with other modules is
* making a combined work based on this library. Thus, the terms and
* conditions of the GNU General Public License cover the whole
* combination.
**
* As a special exception, the copyright holders of this library give you
* permission to link this library with independent modules to produce an
* executable, regardless of the license terms of these independent
* modules, and to copy and distribute the resulting executable under
* terms of your choice, provided that you also meet, for each linked
* independent module, the terms and conditions of the license of that
* module. An independent module is a module which is not derived from
* or based on this library. If you modify this library, you may extend
* this exception to your version of the library, but you are not
* obligated to do so. If you do not wish to do so, delete this
* exception statement from your version.
*/
package java.util;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class BitSet
implements Cloneable, Serializable
{
private static final long serialVersionUID = 7997698588986878753L;
private static final int INDEX_SHIFT = 5;
private long[] bits;
private transient int unitsInUse;
private transient int[] intBits;
public BitSet()
{
this(64);
}
public BitSet(int nbits)
{
if (nbits < 0)
throw new NegativeArraySizeException("" + nbits);
intBits = new int[(((nbits - 1) >> INDEX_SHIFT) + 2) & ~1];
}
public int length()
{
recalculateUnitsInUse();
int i = unitsInUse;
return i > 0 ? (i << INDEX_SHIFT) -
numberOfLeadingZeros(intBits[i - 1]) : 0;
}
public boolean isEmpty()
{
recalculateUnitsInUse();
return unitsInUse == 0;
}
public void set(int bitIndex)
{
if (bitIndex < 0)
throw new IndexOutOfBoundsException("" + bitIndex);
int i = bitIndex >> INDEX_SHIFT;
if (unitsInUse <= i)
ensureCapacity(i + 1);
intBits[i] |= 1 << bitIndex;
}
public void set(int fromIndex, int toIndex)
{
if (fromIndex < 0 || toIndex < fromIndex)
throw new IndexOutOfBoundsException("" + fromIndex + ", " + toIndex);
if (fromIndex < toIndex)
{
int i = fromIndex >> INDEX_SHIFT;
int j = (toIndex - 1) >> INDEX_SHIFT;
if (unitsInUse <= j)
ensureCapacity(j + 1);
int[] intBits = this.intBits;
if (i < j)
{
intBits[i] |= -1 << fromIndex;
intBits[j] |= (2 << (toIndex - 1)) - 1;
while (++i < j)
intBits[i] = -1;
}
else intBits[i] |= (-1 << fromIndex) & ((2 << (toIndex - 1)) - 1);
}
}
public void set(int bitIndex, boolean value)
{
if (value)
set(bitIndex);
else clear(bitIndex);
}
public void set(int fromIndex, int toIndex, boolean value)
{
if (value)
set(fromIndex, toIndex);
else clear(fromIndex, toIndex);
}
public void clear()
{
int i = unitsInUse;
if (i > 0)
{
int[] intBits = this.intBits;
unitsInUse = 0;
do
{
intBits[--i] = 0;
} while (i > 0);
}
}
public void clear(int bitIndex)
{
if (bitIndex < 0)
throw new IndexOutOfBoundsException("" + bitIndex);
int i = bitIndex >> INDEX_SHIFT;
if (unitsInUse > i)
intBits[i] &= ~(1 << bitIndex);
}
public void clear(int fromIndex, int toIndex)
{
if (fromIndex < 0 || toIndex < fromIndex)
throw new IndexOutOfBoundsException("" + fromIndex + ", " + toIndex);
if (fromIndex < toIndex)
{
int i = fromIndex >> INDEX_SHIFT;
int j = unitsInUse - 1;
if (i <= j)
{
int[] intBits = this.intBits;
int k = (toIndex - 1) >> INDEX_SHIFT;
if (j >= k)
j = k;
if (i < j)
{
intBits[i] &= (1 << fromIndex) - 1;
intBits[j] &= -2 << (toIndex - 1);
while (++i < j)
intBits[i] = 0;
}
else intBits[i] &= ((1 << fromIndex) - 1) | (-2 << (toIndex - 1));
}
}
}
public boolean get(int bitIndex)
{
if (bitIndex < 0)
throw new IndexOutOfBoundsException("" + bitIndex);
int i = bitIndex >> INDEX_SHIFT;
return unitsInUse > i && (intBits[i] & (1 << bitIndex)) != 0;
}
public BitSet get(int fromIndex, int toIndex)
{
if (fromIndex < 0 || toIndex < fromIndex)
throw new IndexOutOfBoundsException("" + fromIndex + ", " + toIndex);
BitSet set = new BitSet(toIndex - fromIndex);
if (fromIndex < toIndex)
{
int i = fromIndex >> INDEX_SHIFT;
int j = unitsInUse;
if (i < j)
{
int[] intBits = this.intBits;
int[] intBits2 = set.intBits;
int k = (toIndex - 1) >> INDEX_SHIFT;
if (j >= k)
j = k;
k = j - i;
set.unitsInUse = k + 1;
if ((fromIndex & ((1 << INDEX_SHIFT) - 1)) != 0)
{
int v = intBits[i];
if (k > 0)
{
int revShift = -fromIndex;
k = 0;
do
{
int w = intBits[++i];
intBits2[k++] = (v >>> fromIndex) | (w << revShift);
v = w;
} while (i < j);
}
intBits2[k] = (((2 << (toIndex - 1)) - 1) & v) >>> fromIndex;
}
else
{
if (k > 0)
System.arraycopy(intBits, i, intBits2, 0, k);
intBits2[k] = intBits[j] & ((2 << (toIndex - 1)) - 1);
}
}
}
return set;
}
public void flip(int bitIndex)
{
if (bitIndex < 0)
throw new IndexOutOfBoundsException("" + bitIndex);
int i = bitIndex >> INDEX_SHIFT;
if (unitsInUse <= i)
ensureCapacity(i + 1);
intBits[i] ^= 1 << bitIndex;
}
public void flip(int fromIndex, int toIndex)
{
if (fromIndex < 0 || toIndex < fromIndex)
throw new IndexOutOfBoundsException("" + fromIndex + ", " + toIndex);
if (fromIndex < toIndex)
{
int i = fromIndex >> INDEX_SHIFT;
int j = (toIndex - 1) >> INDEX_SHIFT;
if (unitsInUse <= j)
ensureCapacity(j + 1);
int[] intBits = this.intBits;
if (i < j)
{
intBits[i] ^= -1 << fromIndex;
intBits[j] ^= (2 << (toIndex - 1)) - 1;
while (++i < j)
intBits[i] ^= -1;
}
else intBits[i] ^= (-1 << fromIndex) & ((2 << (toIndex - 1)) - 1);
}
}
public void and(BitSet set)
{
if (set != this)
{
set.recalculateUnitsInUse();
recalculateUnitsInUse();
int i = unitsInUse;
int j = set.unitsInUse;
int[] intBits = this.intBits;
int[] intBits2 = set.intBits;
if (i > j)
{
unitsInUse = j;
do
{
intBits[--i] = 0;
} while (i > j);
}
while (i-- > 0)
intBits[i] &= intBits2[i];
}
}
public void andNot(BitSet set)
{
if (set != this)
{
set.recalculateUnitsInUse();
recalculateUnitsInUse();
int i = unitsInUse;
int[] intBits = this.intBits;
int[] intBits2 = set.intBits;
int j = set.unitsInUse;
if (i >= j)
i = j;
while (i-- > 0)
intBits[i] &= ~intBits2[i];
}
else clear();
}
public void or(BitSet set)
{
if (set != this)
{
set.recalculateUnitsInUse();
recalculateUnitsInUse();
int i = unitsInUse;
int j = set.unitsInUse;
if (i < j)
ensureCapacity(j);
int[] intBits = this.intBits;
int[] intBits2 = set.intBits;
while (i < j)
{
j--;
intBits[j] = intBits2[j];
}
while (j-- > 0)
intBits[j] |= intBits2[j];
}
}
public void xor(BitSet set)
{
if (set != this)
{
set.recalculateUnitsInUse();
recalculateUnitsInUse();
int i = unitsInUse;
int j = set.unitsInUse;
if (i < j)
ensureCapacity(j);
int[] intBits = this.intBits;
int[] intBits2 = set.intBits;
while (i < j)
{
j--;
intBits[j] = intBits2[j];
}
while (j-- > 0)
intBits[j] ^= intBits2[j];
}
else clear();
}
public boolean intersects(BitSet set)
{
if (set == this)
return true;
set.recalculateUnitsInUse();
recalculateUnitsInUse();
int i = unitsInUse;
int[] intBits = this.intBits;
int[] intBits2 = set.intBits;
int j = set.unitsInUse;
if (i >= j)
i = j;
while (i-- > 0)
if ((bits[i] & intBits2[i]) != 0)
return true;
return false;
}
public int nextClearBit(int bitIndex)
{
if (bitIndex < 0)
throw new IndexOutOfBoundsException("" + bitIndex);
int i = bitIndex >> INDEX_SHIFT;
int j = unitsInUse;
if (i < j)
{
int[] intBits = this.intBits;
int v = intBits[i] | ((1 << bitIndex) - 1);
while (++i < j && v == -1)
v = intBits[i];
bitIndex = numberOfTrailingZeros(~v) + ((i - 1) << INDEX_SHIFT);
}
return bitIndex;
}
public int nextSetBit(int bitIndex)
{
if (bitIndex < 0)
throw new IndexOutOfBoundsException("" + bitIndex);
int i = bitIndex >> INDEX_SHIFT;
int j = unitsInUse;
if (i < j)
{
int[] intBits = this.intBits;
int v = intBits[i] & (-1 << bitIndex);
while (v == 0 && ++i < j)
v = intBits[i];
if (i < j)
return numberOfTrailingZeros(v) + (i << INDEX_SHIFT);
}
return -1;
}
public int size()
{
return intBits.length << INDEX_SHIFT;
}
public int cardinality()
{
recalculateUnitsInUse();
int i = unitsInUse;
int count = 0;
int[] intBits = this.intBits;
while (i-- > 0)
count += bitCount(intBits[i]);
return count;
}
public int hashCode()
{
recalculateUnitsInUse();
int h = 1234;
int[] intBits = this.intBits;
for (int i = (unitsInUse + 1) >> 1; i > 0; i--)
{
int v = intBits[(i - 1) << 1];
h ^= (mulHigh(v, i) + intBits[(i << 1) - 1] * i) ^ (v * i);
}
return h;
}
public boolean equals(Object obj)
{
if (obj != this)
{
if (!(obj instanceof BitSet))
return false;
BitSet set = (BitSet) obj;
recalculateUnitsInUse();
set.recalculateUnitsInUse();
int i = unitsInUse;
if (set.unitsInUse != i)
return false;
int[] intBits = this.intBits;
int[] intBits2 = set.intBits;
while (i-- > 0)
if (intBits[i] != intBits2[i])
return false;
}
return true;
}
public Object clone()
{
BitSet result;
try
{
result = (BitSet) super.clone();
}
catch (CloneNotSupportedException e)
{
throw new InternalError();
}
int[] intBits = this.intBits;
System.arraycopy(intBits, 0, result.intBits = new int[intBits.length], 0,
unitsInUse);
return result;
}
private void writeObject(ObjectOutputStream output)
throws IOException
{
int[] intBits = this.intBits;
long[] bits = new long[intBits.length >> 1];
int i = (unitsInUse + 1) >> 1;
while (i-- > 0)
bits[i] = ((long) intBits[(i << 1) + 1] << 32) |
(long) intBits[i << 1] & 0xffffffffL;
this.bits = bits;
output.defaultWriteObject();
this.bits = null;
}
private void readObject(ObjectInputStream input)
throws IOException, ClassNotFoundException
{
input.defaultReadObject();
long[] bits = this.bits;
int i = bits.length;
this.bits = null;
int[] intBits = new int[i << 1];
unitsInUse = i << 1;
while (i-- > 0)
{
long v = bits[i];
intBits[i << 1] = (int) v;
intBits[(i << 1) + 1] = (int) (v >>> 32);
}
this.intBits = intBits;
recalculateUnitsInUse();
}
public String toString()
{
StringBuilder buffer = new StringBuilder();
buffer.append('{');
int[] intBits = this.intBits;
int len = unitsInUse;
boolean next = false;
for (int i = 0; i < len; i++)
{
int v = intBits[i];
for (int j = 0; v != 0; j++)
{
if ((v & 1) != 0)
{
if (next)
buffer.append(',').append(' ');
buffer.append((i << INDEX_SHIFT) | j);
next = true;
}
v >>>= 1;
}
}
return buffer.append('}').toString();
}
private void ensureCapacity(int unitsRequired)
{
int[] intBits = this.intBits;
if (intBits.length < unitsRequired)
{
int newLen = intBits.length << 1;
if (newLen < 0)
newLen = -1 >>> 1;
if (unitsRequired + 1 > newLen)
newLen = (unitsRequired + 1) & ~1;
int[] newBits = new int[newLen];
System.arraycopy(intBits, 0, newBits, 0, unitsInUse);
this.intBits = newBits;
}
unitsInUse = unitsRequired;
}
private void recalculateUnitsInUse()
{
int i = unitsInUse - 1;
if (i >= 0)
{
int[] intBits = this.intBits;
if (intBits[i] == 0)
{
while (i-- > 0)
if (intBits[i] != 0)
break;
unitsInUse = i + 1;
}
}
}
private static int numberOfLeadingZeros(int value)
{
value |= value >>> 1;
value |= value >>> 2;
value |= value >>> 4;
value |= value >>> 8;
return bitCount(~((value >>> 16) | value));
}
private static int numberOfTrailingZeros(int value)
{
return bitCount((-value & value) - 1);
}
private static int bitCount(int value)
{
if (((value + 1) >> 1) == 0)
return value != 0 ? 32 : 0;
value = ((value >> 1) & 0x55555555) + (value & 0x55555555);
value = ((value >> 2) & 0x33333333) + (value & 0x33333333);
value = ((value >> 4) & 0xf0f0f0f) + (value & 0xf0f0f0f);
value = ((value >> 8) & 0xff00ff) + (value & 0xff00ff);
return ((value >> 16) & 0xffff) + (value & 0xffff);
}
private static int mulHigh(int valueA, int valueB)
{
int highA = valueA >>> 16;
int highB = valueB >>> 16;
valueA &= 0xffff;
int lowB = valueB & 0xffff;
valueA = ((valueA * lowB) >>> 16) + valueA * highB;
lowB *= highA;
valueA += lowB;
highA = highA * highB + (valueA >>> 16);
if ((valueA ^ lowB) >= 0)
lowB = valueA - lowB;
if (lowB < 0)
highA += 0x10000;
return highA;
}
}