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

src.it.unimi.dsi.bits.AbstractBitVector Maven / Gradle / Ivy

package it.unimi.dsi.bits;

import java.io.Serializable;
import java.util.NoSuchElementException;

/*
 * DSI utilities
 *
 * Copyright (C) 2007-2017 Sebastiano Vigna
 *
 *  This library is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU Lesser General Public License as published by the Free
 *  Software Foundation; either version 3 of the License, or (at your option)
 *  any later version.
 *
 *  This library 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 Lesser General Public License
 *  for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, see .
 *
 */

import it.unimi.dsi.fastutil.BigList;
import it.unimi.dsi.fastutil.Size64;
import it.unimi.dsi.fastutil.booleans.AbstractBooleanBigList;
import it.unimi.dsi.fastutil.longs.AbstractLongBigList;
import it.unimi.dsi.fastutil.longs.AbstractLongSortedSet;
import it.unimi.dsi.fastutil.longs.LongBidirectionalIterator;
import it.unimi.dsi.fastutil.longs.LongBigList;
import it.unimi.dsi.fastutil.longs.LongBigListIterator;
import it.unimi.dsi.fastutil.longs.LongComparator;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.longs.LongSortedSet;

/** An abstract implementation of a {@link BitVector}.
 *
 * 

This abstract implementation provides almost all methods: you have to provide just * {@link it.unimi.dsi.fastutil.booleans.BooleanList#getBoolean(int)} and * {@link BitVector#length()}. No attributes are defined. * *

Note that the integer-set view provided by {@link #asLongSet()} is not cached: if you * want to cache the result of the first call, you must do your own caching. * *

Warning: this class has several optimised methods * that assume that {@link #getLong(long, long)} is implemented efficiently when its * arguments are multiples of {@link Long#SIZE} (see, e.g., the implementation * of {@link #compareTo(BitVector)} and {@link #longestCommonPrefixLength(BitVector)}). * If you want speed up the processing of your own {@link BitVector} implementations, * just implement {@link #getLong(long, long)} so that it is fast under the above conditions. */ public abstract class AbstractBitVector extends AbstractBooleanBigList implements BitVector { @Override protected void ensureRestrictedIndex(final long index) { if (index < 0) throw new IndexOutOfBoundsException("Index (" + index + ") is negative"); if (index >= length()) throw new IndexOutOfBoundsException("Index (" + index + ") is greater than or equal to length (" + (length()) + ")"); } @Override protected void ensureIndex(final long index) { if (index < 0) throw new IndexOutOfBoundsException("Index (" + index + ") is negative"); if (index > length()) throw new IndexOutOfBoundsException("Index (" + index + ") is greater than length (" + (length()) + ")"); } public void set(final int index) { set(index, true); } public void clear(final int index) { set(index, false); } public void flip(final int index) { set(index, ! getBoolean(index)); } @Override public void set(final long index) { set(index, true); } @Override public void clear(final long index) { set(index, false); } @Override public void flip(final long index) { set(index, ! getBoolean(index)); } @Override public void fill(final boolean value) { for(long i = length(); i-- != 0;) set(i, value); } @Override public void fill(final int value) { fill(value != 0); } @Override public void flip() { for(long i = length(); i-- != 0;) flip(i); } @Override public void fill(final long from, final long to, final boolean value) { BitVectors.ensureFromTo(length(), from, to); for(long i = to; i-- != from;) set(i, value); } @Override public void fill(final long from, final long to, final int value) { fill(from, to, value != 0); } @Override public void flip(final long from, final long to) { BitVectors.ensureFromTo(length(), from, to); for(long i = to; i-- != from;) flip(i); } @Override public int getInt(final long index) { return getBoolean(index) ? 1 : 0; } @Override public long getLong(final long from, final long to) { if (to - from > 64) throw new IllegalArgumentException("Range too large for a long: [" + from + ".." + to + ")"); long result = 0; for(long i = from; i < to; i++) if (getBoolean(i)) result |= 1L << i - from; return result; } public boolean getBoolean(final int index) { return getBoolean((long)index); } public boolean removeBoolean(final int index) { return removeBoolean((long)index); } public boolean set(final int index, final boolean value) { return set((long)index, value); } public void add(final int index, final boolean value) { add((long)index, value); } @Override public boolean removeBoolean(final long index) { throw new UnsupportedOperationException(); } @Override public boolean set(final long index, final boolean value) { throw new UnsupportedOperationException(); } @Override public void add(final long index, final boolean value) { throw new UnsupportedOperationException(); } @Override public void set(final long index, final int value) { set(index, value != 0); } @Override public void add(final long index, final int value) { add(index, value != 0); } @Override public boolean add(final boolean value) { add(length(), value); return true; } @Override public void add(final int value) { add(value != 0); } @Override public BitVector append(final long value, final int k) { for(int i = 0; i < k; i++) add((value & 1L << i) != 0); return this; } @Override public BitVector append(final BitVector bv) { final long length = bv.length(); final long l = length - length % Long.SIZE; long i; for(i = 0; i < l; i += Long.SIZE) append(bv.getLong(i, i + Long.SIZE), Long.SIZE); if (i < length) append(bv.getLong(i, length), (int)(length - i)); return this; } @Override public BitVector copy() { return copy(0, length()); } @Override public BitVector copy(final long from, final long to) { BitVectors.ensureFromTo(length(), from, to); final long length = to - from; final long l = length - length % Long.SIZE; final long bits[] = new long[(int)((length + Long.SIZE - 1) / Long.SIZE)]; long i; for(i = 0; i < l; i += Long.SIZE) bits[(int)(i / Long.SIZE)] = getLong(from + i, from + i + Long.SIZE); if (i < length) bits[(int)(i / Long.SIZE)] = getLong(from + i, to); return LongArrayBitVector.wrap(bits, length); } /** Returns an instance of {@link LongArrayBitVector} containing a copy of this bit vector. * * @return an instance of {@link LongArrayBitVector} containing a copy of this bit vector. */ @Override public BitVector fast() { return copy(); } @Override public long count() { long c = 0; for(long i = length(); i-- != 0;) c += getInt(i); return c; } @Override public long firstOne() { return nextOne(0); } @Override public long lastOne() { return previousOne(length()); } @Override public long firstZero() { return nextZero(0); } @Override public long lastZero() { return previousZero(length()); } @Override public long nextOne(final long index) { final long length = length(); for(long i = index; i < length; i++) if (getBoolean(i)) return i; return -1; } @Override public long previousOne(final long index) { for (long i = index; i-- != 0;) if (getBoolean(i)) return i; return -1; } @Override public long nextZero(final long index) { final long length = length(); for(long i = index; i < length; i++) if (! getBoolean(i)) return i; return -1; } @Override public long previousZero(final long index) { for (long i = index; i-- != 0;) if (! getBoolean(i)) return i; return -1; } @Override public long longestCommonPrefixLength(final BitVector v) { final long minLength = Math.min(length(), v.length()); final long l = minLength - minLength % Long.SIZE; long w0, w1; long i; for(i = 0; i < l; i += Long.SIZE) { w0 = getLong(i, i + Long.SIZE); w1 = v.getLong(i, i + Long.SIZE); if (w0 != w1) return i + Long.numberOfTrailingZeros(w0 ^ w1); } w0 = getLong(i, minLength); w1 = v.getLong(i, minLength); if (w0 != w1) return i + Long.numberOfTrailingZeros(w0 ^ w1); return minLength; } @Override public boolean isPrefix(final BitVector v) { return longestCommonPrefixLength(v) == length(); } @Override public boolean isProperPrefix(final BitVector v) { return isPrefix(v) && length() < v.length(); } @Override public BitVector and(final BitVector v) { for(long i = Math.min(length(), v.length()); i-- != 0;) if (! v.getBoolean(i)) clear(i); return this; } @Override public BitVector or(final BitVector v) { for(long i = Math.min(length(), v.length()); i-- != 0;) if (v.getBoolean(i)) set(i); return this; } @Override public BitVector xor(final BitVector v) { for(long i = Math.min(length(), v.length()); i-- != 0;) if (v.getBoolean(i)) flip(i); return this; } @Deprecated @Override public int size() { final long length = length(); if (length > Integer.MAX_VALUE) throw new IllegalStateException("The number of bits of this bit vector (" + length + ") exceeds Integer.MAX_INT"); return (int)length; } /** {@inheritDoc} *

This implementation just returns {@link #length()}. */ @Override public long size64() { return length(); } @Override public void clear() { length(0); } @Override public BitVector replace(final BitVector bv) { clear(); final long fullBits = bv.length() - bv.length() % Long.SIZE; for(long i = 0; i < fullBits; i += Long.SIZE) append(bv.getLong(i, i + Long.SIZE), Long.SIZE); if (bv.length() % Long.SIZE != 0) append(bv.getLong(fullBits, bv.length()), (int)(bv.length() - fullBits)); return this; } @Override public boolean equals(final Object o) { if (! (o instanceof BitVector)) return false; final BitVector v = (BitVector)o; final long length = length(); if (length != v.length()) return false; final long fullLength = length - length % Long.SIZE; for(long i = 0; i < fullLength; i += Long.SIZE) if (getLong(i, i + Long.SIZE) != v.getLong(i, i + Long.SIZE)) return false; return getLong(fullLength, length) == v.getLong(fullLength, length); } @Override public boolean equals(final BitVector v, final long start, final long end) { long startFull = start - start % LongArrayBitVector.BITS_PER_WORD; final long endFull = end - end % LongArrayBitVector.BITS_PER_WORD; final int startBit = (int)(start & LongArrayBitVector.WORD_MASK); final int endBit = (int)(end & LongArrayBitVector.WORD_MASK); if (startFull == endFull) return ((getLong(startFull, Math.min(length(), startFull + Long.SIZE)) ^ v.getLong(startFull, Math.min(v.length(), startFull + Long.SIZE))) & ((1L << (endBit - startBit)) - 1) << startBit) == 0; if (((getLong(startFull, startFull + Long.SIZE) ^ v.getLong(startFull, startFull += Long.SIZE)) & (-1L << startBit)) != 0) return false; while(startFull < endFull) if (getLong(startFull, startFull + Long.SIZE) != v.getLong(startFull, startFull += Long.SIZE)) return false; return ((getLong(startFull, Math.min(length(), startFull + Long.SIZE)) ^ v.getLong(startFull, Math.min(v.length(), startFull + Long.SIZE))) & (1L << endBit) - 1) == 0; } @Override public int hashCode() { final long length = length(); final long fullLength = length - length % Long.SIZE; long h = 0x9e3779b97f4a7c13L ^ length; for(long i = 0; i < fullLength; i += Long.SIZE) h ^= (h << 5) + getLong(i, i + Long.SIZE) + (h >>> 2); if (length != fullLength) h ^= (h << 5) + getLong(fullLength, length) + (h >>> 2); return (int)((h >>> 32) ^ h); } @Override public long[] bits() { final long[] bits = new long[(int)((length() + LongArrayBitVector.BITS_PER_WORD - 1) >> LongArrayBitVector.LOG2_BITS_PER_WORD)]; final long length = length(); for(long i = 0; i < length; i++) if (getBoolean(i)) bits[(int)(i >> LongArrayBitVector.LOG2_BITS_PER_WORD)] |= 1L << i; return bits; } /** An integer sorted set view of a bit vector. * *

This class implements in the obvious way an integer set view * of a bit vector. The vector is enlarged as needed (i.e., when * a one beyond the current size is set), but it is never shrunk. */ public static class LongSetView extends AbstractLongSortedSet implements LongSet, Serializable, Size64 { protected final BitVector bitVector; private static final long serialVersionUID = 1L; private final long from; private final long to; public LongSetView(final BitVector bitVector, final long from, final long to) { if (from > to) throw new IllegalArgumentException("Start index (" + from + ") is greater than end index (" + to + ")"); this.bitVector = bitVector; this.from = from; this.to = to; } @Override public boolean contains(final long index) { if (index < 0) throw new IllegalArgumentException("The provided index (" + index + ") is negative"); if (index < from || index >= to) return false; return index < bitVector.length() && bitVector.getBoolean(index); } @Override public boolean add(final long index) { if (index < 0) throw new IllegalArgumentException("The provided index (" + index + ") is negative"); if (index < from || index >= to) return false; final long length = bitVector.length(); if (index >= length) bitVector.length(index + 1); final boolean oldValue = bitVector.getBoolean(index); bitVector.set(index); return ! oldValue; } @Override public boolean remove(final long index) { final long length = bitVector.length(); if (index >= length) return false; final boolean oldValue = bitVector.getBoolean(index); bitVector.clear(index); return oldValue; } @Override public void clear() { bitVector.clear(); } @Override public long size64() { return bitVector.count(); } @Override @Deprecated public int size() { // This minimisation is necessary for implementations not supporting long indices. final long size = bitVector.subVector(from, Math.min(to, bitVector.length())).count(); if (size > Integer.MAX_VALUE) throw new IllegalStateException("Set is too large to return an integer size"); return (int)size; } @Override public LongBidirectionalIterator iterator() { return iterator(0); } private final class LongSetViewIterator implements LongBidirectionalIterator { long pos, last = -1, nextPos = -1, prevPos = -1; private LongSetViewIterator(long from) { pos = from; } @Override public boolean hasNext() { if (nextPos == -1 && pos < bitVector.length()) nextPos = bitVector.nextOne(pos); return nextPos != -1; } @Override public boolean hasPrevious() { if (prevPos == -1 && pos > 0) prevPos = bitVector.previousOne(pos); return prevPos != -1; } @Override public long nextLong() { if (! hasNext()) throw new NoSuchElementException(); last = nextPos; pos = nextPos + 1; nextPos = -1; return last; } @Override public long previousLong() { if (! hasPrevious()) throw new NoSuchElementException(); pos = prevPos; prevPos = -1; return last = pos; } @Override public void remove() { if (last == -1) throw new IllegalStateException(); bitVector.clear(last); } } @Override public LongBidirectionalIterator iterator(final long from) { return new LongSetViewIterator(from); } @Override public long firstLong() { return bitVector.nextOne(from); } @Override public long lastLong() { return bitVector.previousOne(Math.min(bitVector.length(), to)); } @Override public LongComparator comparator() { return null; } @Override public LongSortedSet headSet(final long to) { return to < this.to ? new LongSetView(bitVector, from, to) : this; } @Override public LongSortedSet tailSet(final long from) { return from > this.from ? new LongSetView(bitVector, from, to) : this; } @Override public LongSortedSet subSet(long from, long to) { to = to < this.to ? to : this.to; from = from > this.from ? from : this.from; if (from == this.from && to == this.to) return this; return new LongSetView(bitVector, from, to); } } /** A list-of-integers view of a bit vector. * *

This class implements in the obvious way a view * of a bit vector as a list of integers of given width. The vector is enlarged as needed (i.e., when * adding new elements), but it is never shrunk. */ public static class LongBigListView extends AbstractLongBigList implements LongBigList, Serializable { private static final long serialVersionUID = 1L; /** The underlying bit vector. */ protected final BitVector bitVector; /** The width in bit of an element of this list view. */ protected final int width; /** A bit mask containing {@link #width} bits set to one. */ protected final long fullMask; public LongBigListView(final BitVector bitVector, final int width) { this.width = width; this.bitVector = bitVector; fullMask = width == Long.SIZE ? -1 : (1L << width) - 1; } @Override @Deprecated public int size() { final long length = length(); if (length > Integer.MAX_VALUE) throw new IllegalStateException("The number of elements of this bit list (" + length + ") exceeds Integer.MAX_INT"); return (int)length; } @Override public long size64() { return width == 0 ? 0 : bitVector.length() / width; } /* @deprecated Please use {@link #size64()}. */ @Deprecated public long length() { return size64(); } @Override public void size(final long newSize) { bitVector.length(newSize * width); } /* @deprecated Please use {@link #size(long)}. */ @Deprecated public LongBigList length(final long newSize) { size(newSize); return this; } // TODO: implement set()/remove() private final class LongBigListIteratorView implements LongBigListIterator { private long pos = 0; @Override public boolean hasNext() { return pos < length(); } @Override public boolean hasPrevious() { return pos > 0; } @Override public long nextLong() { if (! hasNext()) throw new NoSuchElementException(); return getLong(pos++); } @Override public long previousLong() { if (! hasPrevious()) throw new NoSuchElementException(); return getLong(--pos); } @Override public long nextIndex() { return pos; } @Override public long previousIndex() { return pos - 1; } } @Override public it.unimi.dsi.fastutil.longs.LongBigListIterator listIterator() { return new LongBigListIteratorView(); } public void add(int index, long value) { add((long)index, value); } @Override public void add(long index, long value) { if (width != Long.SIZE && value > fullMask) throw new IllegalArgumentException(); for(int i = 0; i < width; i++) bitVector.add((value & 1L << i) != 0); } @Override public long getLong(long index) { final long start = index * width; return bitVector.getLong(start, start + width); } public long getLong(int index) { return getLong((long)index); } // TODO @Override public long removeLong(final long index) { throw new UnsupportedOperationException(); } @Override public long set(long index, long value) { if (width != Long.SIZE && value > fullMask) throw new IllegalArgumentException(); long oldValue = getLong(index); final long start = index * width; for(int i = width; i-- != 0;) bitVector.set(i + start, (value & 1L << i) != 0); return oldValue; } @Override public LongBigList subList(long from, long to) { return bitVector.subVector(from * width, to * width).asLongBigList(width); } } @Override public BitVector length(long newLength) { final long length = length(); if (length < newLength) for(long i = newLength - length; i-- != 0;) add(false); else for(long i = length; i-- != newLength;) removeBoolean(i); return this; } @Override public void size(long newSize) { length(newSize); } @Override public LongSortedSet asLongSet() { return new LongSetView(this, 0, Long.MAX_VALUE); } @Override public LongBigList asLongBigList(final int width) { return new LongBigListView(this, width); } @Override public BitVector subVector(final long from, final long to) { return new SubBitVector(this, from, to); } @Override public BitVector subVector(final long from) { return subVector(from, length()); } @Override public int compareTo(final BigList list) { if (list instanceof BitVector) return compareTo((BitVector)list); return super.compareTo(list); } public int compareTo(final BitVector v) { final long minLength = Math.min(length(), v.length()); final long l = minLength - minLength % Long.SIZE; long w0, w1, xor; long i; for(i = 0; i < l; i += Long.SIZE) { w0 = getLong(i, i + Long.SIZE); w1 = v.getLong(i, i + Long.SIZE); xor = w0 ^ w1; if (xor != 0) return (xor & -xor & w0) == 0 ? -1 : 1; } w0 = getLong(i, minLength); w1 = v.getLong(i, minLength); xor = w0 ^ w1; if (xor != 0) return (xor & -xor & w0) == 0 ? -1 : 1; return Long.signum(length() - v.length()); } /** Returns a string representation of this vector. * *

Note that this string representation shows the bit of index 0 at the leftmost position. * @return a string representation of this vector, with the bit of index 0 on the left. */ @Override public String toString() { final StringBuffer s = new StringBuffer(); final long size = size64(); for(long i = 0; i < size; i++) s.append(getInt(i)); return s.toString(); } /** A subvector of a given bit vector, specified by an initial and a final bit. */ public static class SubBitVector extends AbstractBitVector implements BitVector { final protected BitVector bitVector; protected long from; protected long to; public SubBitVector(final BitVector l, final long from, final long to) { BitVectors.ensureFromTo(l.length(), from, to); this.from = from; this.to = to; bitVector = l; } @Override public boolean getBoolean(final long index) { ensureIndex(index); return bitVector.getBoolean(from + index); } @Override public int getInt(final long index) { return getBoolean(index) ? 1 : 0; } @Override public boolean set(final long index, final boolean value) { ensureIndex(index); return bitVector.set(from + index, value); } @Override public void set(final long index, final int value) { set(index, value != 0); } @Override public void add(final long index, final boolean value) { ensureIndex(index); bitVector.add(from + index, value); to++; } @Override public void add(final long index, final int value) { add(index, value != 0); to++; } @Override public void add(final int value) { bitVector.add(to++, value); } @Override public boolean removeBoolean(final long index) { ensureIndex(index); to--; return bitVector.removeBoolean(from + index); } @Override public BitVector copy(final long from, final long to) { BitVectors.ensureFromTo(length(), from, to); return bitVector.copy(this.from + from, this.from + to); } @Override public BitVector subVector(final long from, final long to) { BitVectors.ensureFromTo(length(), from, to); return new SubBitVector(bitVector, this.from + from, this.from + to); } @Override public long getLong(final long from, final long to) { BitVectors.ensureFromTo(length(), from, to); return bitVector.getLong(from + this.from, to + this.from); } @Override public long length() { return to - from; } @Override public long size64() { return length(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy