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

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

Go to download

The DSI utilities are a mish mash of classes accumulated during the last ten years in projects developed at the DSI (Dipartimento di Scienze dell'Informazione, i.e., Information Sciences Department), now DI (Dipartimento di Informatica, i.e., Informatics Department), of the Universita` degli Studi di Milano.

There is a newer version: 2.7.3
Show newest version
package it.unimi.dsi.bits;

/*		 
 * DSI utilities
 *
 * Copyright (C) 2007-2016 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.booleans.AbstractBooleanBigList;
import it.unimi.dsi.fastutil.longs.AbstractLongBidirectionalIterator;
import it.unimi.dsi.fastutil.longs.AbstractLongBigList;
import it.unimi.dsi.fastutil.longs.AbstractLongBigListIterator;
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.LongComparator;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.longs.LongSortedSet;

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

/** 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 java.util.List#size()}. 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 { 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() ) + ")" ); } 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 ) ); } public void set( final long index ) { set( index, true ); } public void clear( final long index ) { set( index, false ); } public void flip( final long index ) { set( index, ! getBoolean( index ) ); } public void fill( final boolean value ) { for( long i = length(); i-- != 0; ) set( i, value ); } public void fill( final int value ) { fill( value != 0 ); } public void flip() { for( long i = length(); i-- != 0; ) flip( i ); } 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 ); } public void fill( final long from, final long to, final int value ) { fill( from, to, value != 0 ); } public void flip( final long from, final long to ) { BitVectors.ensureFromTo( length(), from, to ); for( long i = to; i-- != from; ) flip( i ); } public int getInt( final long index ) { return getBoolean( index ) ? 1 : 0; } 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 ); } public boolean removeBoolean( final long index ) { throw new UnsupportedOperationException(); } public boolean set( final long index, final boolean value ) { throw new UnsupportedOperationException(); } public void add( final long index, final boolean value ) { throw new UnsupportedOperationException(); } public void set( final long index, final int value ) { set( index, value != 0 ); } public void add( final long index, final int value ) { add( index, value != 0 ); } public boolean add( final boolean value ) { add( length(), value ); return true; } public void add( final int value ) { add( value != 0 ); } public BitVector append( final long value, final int k ) { for( int i = 0; i < k; i++ ) add( ( value & 1L << i ) != 0 ); return this; } 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; } public BitVector copy() { return copy( 0, size() ); } 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. */ public BitVector fast() { return copy(); } public long count() { long c = 0; for( long i = length(); i-- != 0; ) c += getInt( i ); return c; } public long firstOne() { return nextOne( 0 ); } public long lastOne() { return previousOne( length() ); } public long firstZero() { return nextZero( 0 ); } public long lastZero() { return previousZero( length() ); } public long nextOne( final long index ) { final long length = length(); for( long i = index; i < length; i++ ) if ( getBoolean( i ) ) return i; return -1; } public long previousOne( final long index ) { for ( long i = index; i-- != 0; ) if ( getBoolean( i ) ) return i; return -1; } public long nextZero( final long index ) { final long length = length(); for( long i = index; i < length; i++ ) if ( ! getBoolean( i ) ) return i; return -1; } public long previousZero( final long index ) { for ( long i = index; i-- != 0; ) if ( ! getBoolean( i ) ) return i; return -1; } 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; } public boolean isPrefix( final BitVector v ) { return longestCommonPrefixLength( v ) == length(); } public boolean isProperPrefix( final BitVector v ) { return isPrefix( v ) && length() < v.length(); } public BitVector and( final BitVector v ) { for( long i = Math.min( size64(), v.size64() ); i-- != 0; ) if ( ! v.getBoolean( i ) ) clear( i ); return this; } public BitVector or( final BitVector v ) { for( int i = Math.min( size(), v.size() ); i-- != 0; ) if ( v.getBoolean( i ) ) set( i ); return this; } public BitVector xor( final BitVector v ) { for( int i = Math.min( size(), v.size() ); i-- != 0; ) if ( v.getBoolean( i ) ) flip( i ); return this; } @Deprecated 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; } public void size( final int newSize ) { length( newSize ); } public long size64() { return length(); } public void clear() { length( 0 ); } 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; } 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 ); } 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; } 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 ); } 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 { 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; } 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.size() && bitVector.getBoolean( index ); } 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 int size = bitVector.size(); if ( index >= size ) bitVector.length( index + 1 ); final boolean oldValue = bitVector.getBoolean( index ); bitVector.set( index ); return ! oldValue; } public boolean remove( final long index ) { final int size = bitVector.size(); if ( index >= size ) return false; final boolean oldValue = bitVector.getBoolean( index ); bitVector.clear( index ); return oldValue; } @Override public void clear() { bitVector.clear(); } 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; } public LongBidirectionalIterator iterator() { return iterator( 0 ); } private final class LongSetViewIterator extends AbstractLongBidirectionalIterator { long pos, last = -1, nextPos = -1, prevPos = -1; private LongSetViewIterator( long from ) { pos = from; } public boolean hasNext() { if ( nextPos == -1 && pos < bitVector.length() ) nextPos = bitVector.nextOne( pos ); return nextPos != -1; } public boolean hasPrevious() { if ( prevPos == -1 && pos > 0 ) prevPos = bitVector.previousOne( pos ); return prevPos != -1; } public long nextLong() { if ( ! hasNext() ) throw new NoSuchElementException(); last = nextPos; pos = nextPos + 1; nextPos = -1; return last; } public long previousLong() { if ( ! hasPrevious() ) throw new NoSuchElementException(); pos = prevPos; prevPos = -1; return last = pos; } public void remove() { if ( last == -1 ) throw new IllegalStateException(); bitVector.clear( last ); } } public LongBidirectionalIterator iterator( final long from ) { return new LongSetViewIterator( from ); } public long firstLong() { return bitVector.nextOne( from ); } public long lastLong() { return bitVector.previousOne( Math.min( bitVector.length(), to ) ); } public LongComparator comparator() { return null; } public LongSortedSet headSet( final long to ) { return to < this.to ? new LongSetView( bitVector, from, to ) : this; } public LongSortedSet tailSet( final long from ) { return from > this.from ? new LongSetView( bitVector, from, to ) : this; } 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; } public long length() { return width == 0 ? 0 : bitVector.length() / width; } 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; } public long size64() { return length(); } public LongBigList length( final long newSize ) { bitVector.length( newSize * width ); return this; } public void size( final long newSize ) { length( newSize ); } // TODO: implement set()/remove() private final class LongBigListIterator extends AbstractLongBigListIterator { private long pos = 0; public boolean hasNext() { return pos < length(); } 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 ); } public long nextIndex() { return pos; } public long previousIndex() { return pos - 1; } } @Override public it.unimi.dsi.fastutil.longs.LongBigListIterator listIterator() { return new LongBigListIterator(); } public void add( int index, long value ) { add( (long)index, value ); } 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 ); } 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 public long removeLong( final long index ) { throw new UnsupportedOperationException(); } 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; } public long set( int index, long value ) { return set( (long)index, value ); } public LongBigList subList( long from, long to ) { return bitVector.subVector( from * width, to * width ).asLongBigList( width ); } } 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; } public void size( long newSize ) { length( newSize ); } public LongSortedSet asLongSet() { return new LongSetView( this, 0, Long.MAX_VALUE ); } public LongBigList asLongBigList( final int width ) { return new LongBigListView( this, width ); } public SubBitVector subList( final int from, final int to ) { return new SubBitVector( this, from, to ); } public BitVector subVector( final long from, final long to ) { return new SubBitVector( this, from, to ); } 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. */ 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; } public boolean getBoolean( final long index ) { ensureIndex( index ); return bitVector.getBoolean( from + index ); } public int getInt( final long index ) { return getBoolean( index ) ? 1 : 0; } public boolean set( final long index, final boolean value ) { ensureIndex( index ); return bitVector.set( from + index, value ); } public void set( final long index, final int value ) { set( index, value != 0 ); } public void add( final long index, final boolean value ) { ensureIndex( index ); bitVector.add( from + index, value ); to++; } public void add( final long index, final int value ) { add( index, value != 0 ); to++; } public void add( final int value ) { bitVector.add( to++, value ); } public boolean removeBoolean( final long index ) { ensureIndex( index ); to--; return bitVector.removeBoolean( from + index ); } public BitVector copy( final long from, final long to ) { BitVectors.ensureFromTo( length(), from, to ); return bitVector.copy( this.from + from, this.from + to ); } public BitVector subVector( final long from, final long to ) { BitVectors.ensureFromTo( length(), from, to ); return new SubBitVector( bitVector, this.from + from, this.from + to ); } public long getLong( final long from, final long to ) { BitVectors.ensureFromTo( length(), from, to ); return bitVector.getLong( from + this.from, to + this.from ); } public long length() { return to - from; } public long size64() { return length(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy