fastutil-7.0.2/drv/AVLTreeMap.drv 0000644 0000000 0000000 00000254513 12502267505 015420 0 ustar root wheel /* * Copyright (C) 2002-2014 Sebastiano Vigna * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package PACKAGE; import it.unimi.dsi.fastutil.objects.AbstractObjectSortedSet; import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; import it.unimi.dsi.fastutil.objects.ObjectListIterator; import it.unimi.dsi.fastutil.objects.ObjectSortedSet; import VALUE_PACKAGE.VALUE_COLLECTION; import VALUE_PACKAGE.VALUE_ABSTRACT_COLLECTION; import VALUE_PACKAGE.VALUE_ITERATOR; import java.util.Comparator; import java.util.Iterator; import java.util.Map; import java.util.SortedMap; import java.util.NoSuchElementException; #if #values(primitive) import VALUE_PACKAGE.VALUE_LIST_ITERATOR; #endif /** A type-specific AVL tree map with a fast, small-footprint implementation. * *
The iterators provided by the views of this class are type-specific {@linkplain
* it.unimi.dsi.fastutil.BidirectionalIterator bidirectional iterators}.
* Moreover, the iterator returned by When a specific {@link Comparator} is specified and stored in {@link
* #storedComparator}, we must check whether it is type-specific. If it is
* so, we can used directly, and we store it in {@link #actualComparator}. Otherwise,
* we generate on-the-fly an anonymous class that wraps the non-specific {@link Comparator}
* and makes it into a type-specific one.
*/
private void setActualComparator() {
#if #keyclass(Object)
actualComparator = storedComparator;
#else
/* If the provided comparator is already type-specific, we use it. Otherwise,
we use a wrapper anonymous class to fake that it is type-specific. */
if ( storedComparator == null || storedComparator instanceof KEY_COMPARATOR ) actualComparator = (KEY_COMPARATOR)storedComparator;
else actualComparator = new KEY_COMPARATOR KEY_SUPER_GENERIC() {
public int compare( KEY_GENERIC_TYPE k1, KEY_GENERIC_TYPE k2 ) {
return storedComparator.compare( KEY2OBJ( k1 ), KEY2OBJ( k2 ) );
}
public int compare( KEY_GENERIC_CLASS ok1, KEY_GENERIC_CLASS ok2 ) {
return storedComparator.compare( ok1, ok2 );
}
};
#endif
}
/** Creates a new empty tree map with the given comparator.
*
* @param c a (possibly type-specific) comparator.
*/
public AVL_TREE_MAP( final Comparator super KEY_GENERIC_CLASS> c ) {
this();
storedComparator = c;
setActualComparator();
}
/** Creates a new tree map copying a given map.
*
* @param m a {@link Map} to be copied into the new tree map.
*/
public AVL_TREE_MAP( final Map extends KEY_GENERIC_CLASS, ? extends VALUE_GENERIC_CLASS> m ) {
this();
putAll( m );
}
/** Creates a new tree map copying a given sorted map (and its {@link Comparator}).
*
* @param m a {@link SortedMap} to be copied into the new tree map.
*/
public AVL_TREE_MAP( final SortedMap This method uses the {@link #actualComparator} if it is non- We use the only "metadata", i.e., {@link Entry#info}, to store
* information about balance, predecessor status and successor status.
*
* Note that since the class is recursive, it can be
* considered equivalently a tree.
*/
private static final class Entry KEY_VALUE_GENERIC implements Cloneable, MAP.Entry KEY_VALUE_GENERIC {
/** If the bit in this mask is true, {@link #right} points to a successor. */
private final static int SUCC_MASK = 1 << 31;
/** If the bit in this mask is true, {@link #left} points to a predecessor. */
private final static int PRED_MASK = 1 << 30;
/** The bits in this mask hold the node balance info. You can get it just by casting to byte. */
private final static int BALANCE_MASK = 0xFF;
/** The key of this entry. */
KEY_GENERIC_TYPE key;
/** The value of this entry. */
VALUE_GENERIC_TYPE value;
/** The pointers to the left and right subtrees. */
Entry KEY_VALUE_GENERIC left, right;
/** This integers holds different information in different bits (see {@link #SUCC_MASK}, {@link #PRED_MASK} and {@link #BALANCE_MASK}). */
int info;
Entry() {}
/** Creates a new entry with the given key and value.
*
* @param k a key.
* @param v a value.
*/
Entry( final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE v ) {
this.key = k;
this.value = v;
info = SUCC_MASK | PRED_MASK;
}
/** Returns the left subtree.
*
* @return the left subtree ( This class can iterate in both directions on a threaded tree.
*/
private class TreeIterator {
/** The entry that will be returned by the next call to {@link java.util.ListIterator#previous()} (or This class can iterate in both directions on a threaded tree.
*/
private class EntryIterator extends TreeIterator implements ObjectListIterator This class can iterate in both directions on the keys of a threaded tree. We
* simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods (and possibly
* their type-specific counterparts) so that they return keys instead of entries.
*/
private final class KeyIterator extends TreeIterator implements KEY_LIST_ITERATOR KEY_GENERIC {
public KeyIterator() {}
public KeyIterator( final KEY_GENERIC_TYPE k ) { super( k ); }
public KEY_GENERIC_TYPE NEXT_KEY() { return nextEntry().key; }
public KEY_GENERIC_TYPE PREV_KEY() { return previousEntry().key; }
public void set( KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public void add( KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
#if !#keyclass(Object)
public KEY_GENERIC_CLASS next() { return KEY2OBJ( nextEntry().key ); }
public KEY_GENERIC_CLASS previous() { return KEY2OBJ( previousEntry().key ); }
public void set( KEY_CLASS ok ) { throw new UnsupportedOperationException(); }
public void add( KEY_CLASS ok ) { throw new UnsupportedOperationException(); }
#endif
};
/** A keyset implementation using a more direct implementation for iterators. */
private class KeySet extends ABSTRACT_SORTED_MAP KEY_VALUE_GENERIC.KeySet {
public KEY_BIDI_ITERATOR KEY_GENERIC iterator() { return new KeyIterator(); }
public KEY_BIDI_ITERATOR KEY_GENERIC iterator( final KEY_GENERIC_TYPE from ) { return new KeyIterator( from ); }
}
/** Returns a type-specific sorted set view of the keys contained in this map.
*
* In addition to the semantics of {@link java.util.Map#keySet()}, you can
* safely cast the set returned by this call to a type-specific sorted
* set interface.
*
* @return a type-specific sorted set view of the keys contained in this map.
*/
public SORTED_SET KEY_GENERIC keySet() {
if ( keys == null ) keys = new KeySet();
return keys;
}
/** An iterator on the whole range of values.
*
* This class can iterate in both directions on the values of a threaded tree. We
* simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods (and possibly
* their type-specific counterparts) so that they return values instead of entries.
*/
private final class ValueIterator extends TreeIterator implements VALUE_LIST_ITERATOR VALUE_GENERIC {
public VALUE_GENERIC_TYPE NEXT_VALUE() { return nextEntry().value; }
public VALUE_GENERIC_TYPE PREV_VALUE() { return previousEntry().value; }
public void set( VALUE_GENERIC_TYPE v ) { throw new UnsupportedOperationException(); }
public void add( VALUE_GENERIC_TYPE v ) { throw new UnsupportedOperationException(); }
#if #values(primitive)
public VALUE_GENERIC_CLASS next() { return VALUE2OBJ( nextEntry().value ); }
public VALUE_GENERIC_CLASS previous() { return VALUE2OBJ( previousEntry().value ); }
public void set( VALUE_CLASS ok ) { throw new UnsupportedOperationException(); }
public void add( VALUE_CLASS ok ) { throw new UnsupportedOperationException(); }
#endif
};
/** Returns a type-specific collection view of the values contained in this map.
*
* In addition to the semantics of {@link java.util.Map#values()}, you can
* safely cast the collection returned by this call to a type-specific collection
* interface.
*
* @return a type-specific collection view of the values contained in this map.
*/
public VALUE_COLLECTION VALUE_GENERIC values() {
if ( values == null ) values = new VALUE_ABSTRACT_COLLECTION VALUE_GENERIC() {
public VALUE_ITERATOR VALUE_GENERIC iterator() {
return new ValueIterator();
}
public boolean contains( final VALUE_TYPE k ) {
return containsValue( k );
}
public int size() {
return count;
}
public void clear() {
AVL_TREE_MAP.this.clear();
}
};
return values;
}
public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() {
return actualComparator;
}
public SORTED_MAP KEY_VALUE_GENERIC headMap( KEY_GENERIC_TYPE to ) {
return new Submap( KEY_NULL, true, to, false );
}
public SORTED_MAP KEY_VALUE_GENERIC tailMap( KEY_GENERIC_TYPE from ) {
return new Submap( from, false, KEY_NULL, true );
}
public SORTED_MAP KEY_VALUE_GENERIC subMap( KEY_GENERIC_TYPE from, KEY_GENERIC_TYPE to ) {
return new Submap( from, false, to, false );
}
/** A submap with given range.
*
* This class represents a submap. One has to specify the left/right
* limits (which can be set to -∞ or ∞). Since the submap is a
* view on the map, at a given moment it could happen that the limits of
* the range are not any longer in the main map. Thus, things such as
* {@link java.util.SortedMap#firstKey()} or {@link java.util.Collection#size()} must be always computed
* on-the-fly.
*/
private final class Submap extends ABSTRACT_SORTED_MAP KEY_VALUE_GENERIC implements java.io.Serializable {
private static final long serialVersionUID = -7046029254386353129L;
/** The start of the submap range, unless {@link #bottom} is true. */
KEY_GENERIC_TYPE from;
/** The end of the submap range, unless {@link #top} is true. */
KEY_GENERIC_TYPE to;
/** If true, the submap range starts from -∞. */
boolean bottom;
/** If true, the submap range goes to ∞. */
boolean top;
/** Cached set of entries. */
@SuppressWarnings("hiding")
protected transient volatile ObjectSortedSet This class inherits from {@link TreeIterator}, but overrides the methods that
* update the pointer after a {@link java.util.ListIterator#next()} or {@link java.util.ListIterator#previous()}. If we would
* move out of the range of the submap we just overwrite the next or previous
* entry with This class can iterate in both directions on a subrange of the
* keys of a threaded tree. We simply override the {@link
* java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods (and possibly their
* type-specific counterparts) so that they return keys instead of
* entries.
*/
private final class SubmapKeyIterator extends SubmapIterator implements KEY_LIST_ITERATOR KEY_GENERIC {
public SubmapKeyIterator() { super(); }
public SubmapKeyIterator( KEY_GENERIC_TYPE from ) { super( from ); }
public KEY_GENERIC_TYPE NEXT_KEY() { return nextEntry().key; }
public KEY_GENERIC_TYPE PREV_KEY() { return previousEntry().key; }
public void set( KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public void add( KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
#if !#keyclass(Object)
public KEY_GENERIC_CLASS next() { return KEY2OBJ( nextEntry().key ); }
public KEY_GENERIC_CLASS previous() { return KEY2OBJ( previousEntry().key ); }
public void set( KEY_CLASS ok ) { throw new UnsupportedOperationException(); }
public void add( KEY_CLASS ok ) { throw new UnsupportedOperationException(); }
#endif
};
/** An iterator on a subrange of values.
*
* This class can iterate in both directions on the values of a
* subrange of the keys of a threaded tree. We simply override the
* {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods (and possibly their
* type-specific counterparts) so that they return values instead of
* entries.
*/
private final class SubmapValueIterator extends SubmapIterator implements VALUE_LIST_ITERATOR VALUE_GENERIC {
public VALUE_GENERIC_TYPE NEXT_VALUE() { return nextEntry().value; }
public VALUE_GENERIC_TYPE PREV_VALUE() { return previousEntry().value; }
public void set( VALUE_GENERIC_TYPE v ) { throw new UnsupportedOperationException(); }
public void add( VALUE_GENERIC_TYPE v ) { throw new UnsupportedOperationException(); }
#if #values(primitive)
public VALUE_GENERIC_CLASS next() { return VALUE2OBJ( nextEntry().value ); }
public VALUE_GENERIC_CLASS previous() { return VALUE2OBJ( previousEntry().value ); }
public void set( VALUE_CLASS ok ) { throw new UnsupportedOperationException(); }
public void add( VALUE_CLASS ok ) { throw new UnsupportedOperationException(); }
#endif
};
}
/** Returns a deep copy of this tree map.
*
* This method performs a deep copy of this tree map; the data stored in the
* set, however, is not cloned. Note that this makes a difference only for object keys.
*
* @return a deep copy of this tree map.
*/
SUPPRESS_WARNINGS_KEY_VALUE_UNCHECKED
public AVL_TREE_MAP KEY_VALUE_GENERIC clone() {
AVL_TREE_MAP KEY_VALUE_GENERIC c;
try {
c = (AVL_TREE_MAP KEY_VALUE_GENERIC)super.clone();
}
catch(CloneNotSupportedException cantHappen) {
throw new InternalError();
}
c.keys = null;
c.values = null;
c.entries = null;
c.allocatePaths();
if ( count != 0 ) {
// Also this apparently unfathomable code is derived from GNU libavl.
Entry KEY_VALUE_GENERIC e, p, q, rp = new Entry KEY_VALUE_GENERIC(), rq = new Entry KEY_VALUE_GENERIC();
p = rp;
rp.left( tree );
q = rq;
rq.pred( null );
while( true ) {
if ( ! p.pred() ) {
e = p.left.clone();
e.pred( q.left );
e.succ( q );
q.left( e );
p = p.left;
q = q.left;
}
else {
while( p.succ() ) {
p = p.right;
if ( p == null ) {
q.right = null;
c.tree = rq.left;
c.firstEntry = c.tree;
while( c.firstEntry.left != null ) c.firstEntry = c.firstEntry.left;
c.lastEntry = c.tree;
while( c.lastEntry.right != null ) c.lastEntry = c.lastEntry.right;
return c;
}
q = q.right;
}
p = p.right;
q = q.right;
}
if ( ! p.succ() ) {
e = p.right.clone();
e.succ( q.right );
e.pred( q );
q.right( e );
}
}
}
return c;
}
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
int n = count;
EntryIterator i = new EntryIterator();
Entry KEY_VALUE_GENERIC e;
s.defaultWriteObject();
while(n-- != 0) {
e = i.nextEntry();
s.WRITE_KEY( e.key );
s.WRITE_VALUE( e.value );
}
}
/** Reads the given number of entries from the input stream, returning the corresponding tree.
*
* @param s the input stream.
* @param n the (positive) number of entries to read.
* @param pred the entry containing the key that preceeds the first key in the tree.
* @param succ the entry containing the key that follows the last key in the tree.
*/
SUPPRESS_WARNINGS_KEY_VALUE_UNCHECKED
private Entry KEY_VALUE_GENERIC readTree( final java.io.ObjectInputStream s, final int n, final Entry KEY_VALUE_GENERIC pred, final Entry KEY_VALUE_GENERIC succ ) throws java.io.IOException, ClassNotFoundException {
if ( n == 1 ) {
final Entry KEY_VALUE_GENERIC top = new Entry KEY_VALUE_GENERIC( KEY_GENERIC_CAST s.READ_KEY(), VALUE_GENERIC_CAST s.READ_VALUE() );
top.pred( pred );
top.succ( succ );
return top;
}
if ( n == 2 ) {
/* We handle separately this case so that recursion will
*always* be on nonempty subtrees. */
final Entry KEY_VALUE_GENERIC top = new Entry KEY_VALUE_GENERIC( KEY_GENERIC_CAST s.READ_KEY(), VALUE_GENERIC_CAST s.READ_VALUE() );
top.right( new Entry KEY_VALUE_GENERIC( KEY_GENERIC_CAST s.READ_KEY(), VALUE_GENERIC_CAST s.READ_VALUE() ) );
top.right.pred( top );
top.balance( 1 );
top.pred( pred );
top.right.succ( succ );
return top;
}
// The right subtree is the largest one.
final int rightN = n / 2, leftN = n - rightN - 1;
final Entry KEY_VALUE_GENERIC top = new Entry KEY_VALUE_GENERIC();
top.left( readTree( s, leftN, pred, top ) );
top.key = KEY_GENERIC_CAST s.READ_KEY();
top.value = VALUE_GENERIC_CAST s.READ_VALUE();
top.right( readTree( s, rightN, top, succ ) );
if ( n == ( n & -n ) ) top.balance( 1 ); // Quick test for determining whether n is a power of 2.
return top;
}
private void readObject( java.io.ObjectInputStream s ) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
/* The storedComparator is now correctly set, but we must restore
on-the-fly the actualComparator. */
setActualComparator();
allocatePaths();
if ( count != 0 ) {
tree = readTree( s, count, null, null );
Entry KEY_VALUE_GENERIC e;
e = tree;
while( e.left() != null ) e = e.left();
firstEntry = e;
e = tree;
while( e.right() != null ) e = e.right();
lastEntry = e;
}
if ( ASSERTS ) checkTree( tree );
}
#ifdef ASSERTS_CODE
private static KEY_VALUE_GENERIC int checkTree( Entry KEY_VALUE_GENERIC e ) {
if ( e == null ) return 0;
final int leftN = checkTree( e.left() ), rightN = checkTree( e.right() );
if ( leftN + e.balance() != rightN )
throw new AssertionError( "Mismatch between left tree size (" + leftN + "), right tree size (" + rightN + ") and balance (" + e.balance() + ")" );
return Math.max( leftN , rightN ) + 1;
}
#else
private static KEY_VALUE_GENERIC int checkTree( @SuppressWarnings("unused") Entry KEY_VALUE_GENERIC e ) { return 0; }
#endif
#ifdef TEST
private static long seed = System.currentTimeMillis();
private static java.util.Random r = new java.util.Random( seed );
private static KEY_TYPE genKey() {
#if #keyclass(Byte) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#else
return Integer.toBinaryString( r.nextInt() );
#endif
}
private static VALUE_TYPE genValue() {
#if #valueclass(Byte) || #valueclass(Short) || #valueclass(Character)
return (VALUE_TYPE)(r.nextInt());
#elif #values(primitive)
return r.NEXT_VALUE();
#elif !#valueclass(Reference) || #keyclass(Reference)
return Integer.toBinaryString( r.nextInt() );
#else
return new java.io.Serializable() {};
#endif
}
private static java.text.NumberFormat format = new java.text.DecimalFormat( "#,###.00" );
private static java.text.FieldPosition p = new java.text.FieldPosition( 0 );
private static String format( double d ) {
StringBuffer s = new StringBuffer();
return format.format( d, s, p ).toString();
}
private static void speedTest( int n, boolean comp ) {
int i, j;
AVL_TREE_MAP m;
java.util.TreeMap t;
KEY_TYPE k[] = new KEY_TYPE[n];
KEY_TYPE nk[] = new KEY_TYPE[n];
VALUE_TYPE v[] = new VALUE_TYPE[n];
long ms;
for( i = 0; i < n; i++ ) {
k[i] = genKey();
nk[i] = genKey();
v[i] = genValue();
}
double totPut = 0, totYes = 0, totNo = 0, totIterFor = 0, totIterBack = 0, totRemYes = 0, d, dd;
if ( comp ) { for( j = 0; j < 20; j++ ) {
t = new java.util.TreeMap();
/* We first add all pairs to t. */
for( i = 0; i < n; i++ ) t.put( KEY2OBJ( k[i] ), VALUE2OBJ( v[i] ) );
/* Then we remove the first half and put it back. */
for( i = 0; i < n/2; i++ ) t.remove( KEY2OBJ( k[i] ) );
ms = System.currentTimeMillis();
for( i = 0; i < n/2; i++ ) t.put( KEY2OBJ( k[i] ), VALUE2OBJ( v[i] ) );
d = System.currentTimeMillis() - ms;
/* Then we remove the other half and put it back again. */
ms = System.currentTimeMillis();
for( i = n/2; i < n; i++ ) t.remove( KEY2OBJ( k[i] ) );
dd = System.currentTimeMillis() - ms ;
ms = System.currentTimeMillis();
for( i = n/2; i < n; i++ ) t.put( KEY2OBJ( k[i] ), VALUE2OBJ( v[i] ) );
d += System.currentTimeMillis() - ms;
if ( j > 2 ) totPut += n/d;
System.out.print("Add: " + format( n/d ) +" K/s " );
/* Then we remove again the first half. */
ms = System.currentTimeMillis();
for( i = 0; i < n/2; i++ ) t.remove( KEY2OBJ( k[i] ) );
dd += System.currentTimeMillis() - ms ;
if ( j > 2 ) totRemYes += n/dd;
System.out.print("RemYes: " + format( n/dd ) +" K/s " );
/* And then we put it back. */
for( i = 0; i < n/2; i++ ) t.put( KEY2OBJ( k[i] ), VALUE2OBJ( v[i] ) );
/* We check for pairs in t. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) t.containsKey( KEY2OBJ( k[i] ) );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totYes += d;
System.out.print("Yes: " + format( d ) +" K/s " );
/* We check for pairs not in t. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) t.containsKey( KEY2OBJ( nk[i] ) );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totNo += d;
System.out.print("No: " + format( d ) +" K/s " );
/* We iterate on t. */
ms = System.currentTimeMillis();
for( Iterator it = t.entrySet().iterator(); it.hasNext(); it.next() );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totIterFor += d;
System.out.print("IterFor: " + format( d ) +" K/s " );
System.out.println();
}
System.out.println();
System.out.println( "java.util Put: " + format( totPut/(j-3) ) + " K/s RemYes: " + format( totRemYes/(j-3) ) + " K/s Yes: " + format( totYes/(j-3) ) + " K/s No: " + format( totNo/(j-3) )+ " K/s IterFor: " + format( totIterFor/(j-3) ) + " K/s" );
System.out.println();
t = null;
totPut = totYes = totNo = totIterFor = totIterBack = totRemYes = 0;
}
for( j = 0; j < 20; j++ ) {
m = new AVL_TREE_MAP();
/* We first add all pairs to m. */
for( i = 0; i < n; i++ ) m.put( k[i], v[i] );
/* Then we remove the first half and put it back. */
for( i = 0; i < n/2; i++ ) m.remove( k[i] );
ms = System.currentTimeMillis();
for( i = 0; i < n/2; i++ ) m.put( k[i], v[i] );
d = System.currentTimeMillis() - ms;
/* Then we remove the other half and put it back again. */
ms = System.currentTimeMillis();
for( i = n/2; i < n; i++ ) m.remove( k[i] );
dd = System.currentTimeMillis() - ms ;
ms = System.currentTimeMillis();
for( i = n/2; i < n; i++ ) m.put( k[i], v[i] );
d += System.currentTimeMillis() - ms;
if ( j > 2 ) totPut += n/d;
System.out.print("Add: " + format( n/d ) +" K/s " );
/* Then we remove again the first half. */
ms = System.currentTimeMillis();
for( i = 0; i < n/2; i++ ) m.remove( k[i] );
dd += System.currentTimeMillis() - ms ;
if ( j > 2 ) totRemYes += n/dd;
System.out.print("RemYes: " + format( n/dd ) +" K/s " );
/* And then we put it back. */
for( i = 0; i < n/2; i++ ) m.put( k[i], v[i] );
/* We check for pairs in m. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) m.containsKey( k[i] );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totYes += d;
System.out.print("Yes: " + format( d ) +" K/s " );
/* We check for pairs not in m. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) m.containsKey( nk[i] );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totNo += d;
System.out.print("No: " + format( d ) +" K/s " );
/* We iterate on m. */
java.util.ListIterator it = (java.util.ListIterator)m.entrySet().iterator();
ms = System.currentTimeMillis();
for( it = (java.util.ListIterator)m.entrySet().iterator(); it.hasNext(); it.next() );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totIterFor += d;
System.out.print("IterFor: " + format( d ) +" K/s " );
/* We iterate back on m. */
ms = System.currentTimeMillis();
for( ; it.hasPrevious(); it.previous() );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totIterBack += d;
System.out.print("IterBack: " + format( d ) +" K/s " );
System.out.println();
}
System.out.println();
System.out.println( "fastutil Put: " + format( totPut/(j-3) ) + " K/s RemYes: " + format( totRemYes/(j-3) ) + " K/s Yes: " + format( totYes/(j-3) ) + " K/s No: " + format( totNo/(j-3) ) + " K/s IterFor: " + format( totIterFor/(j-3) ) + " K/s IterBack: " + format( totIterBack/(j-3) ) + "K/s" );
System.out.println();
}
private static boolean valEquals(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
private static void fatal( String msg ) {
System.out.println( msg );
System.exit( 1 );
}
private static void ensure( boolean cond, String msg ) {
if ( cond ) return;
fatal( msg );
}
private static Object[] k, v, nk;
private static KEY_TYPE kt[];
private static KEY_TYPE nkt[];
private static VALUE_TYPE vt[];
private static AVL_TREE_MAP topMap;
protected static void testMaps( SORTED_MAP m, SortedMap t, int n, int level ) {
long ms;
boolean mThrowsIllegal, tThrowsIllegal, mThrowsNoElement, tThrowsNoElement;
Object rt = null, rm = null;
if ( level > 4 ) return;
/* Now we check that both maps agree on first/last keys. */
mThrowsNoElement = mThrowsIllegal = tThrowsNoElement = tThrowsIllegal = false;
try {
m.firstKey();
}
catch ( NoSuchElementException e ) { mThrowsNoElement = true; }
try {
t.firstKey();
}
catch ( NoSuchElementException e ) { tThrowsNoElement = true; }
ensure( mThrowsNoElement == tThrowsNoElement, "Error (" + level + ", " + seed + "): firstKey() divergence at start in NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
if ( ! mThrowsNoElement ) ensure( t.firstKey().equals( m.firstKey() ), "Error (" + level + ", " + seed + "): m and t differ at start on their first key (" + m.firstKey() + ", " + t.firstKey() +")" );
mThrowsNoElement = mThrowsIllegal = tThrowsNoElement = tThrowsIllegal = false;
try {
m.lastKey();
}
catch ( NoSuchElementException e ) { mThrowsNoElement = true; }
try {
t.lastKey();
}
catch ( NoSuchElementException e ) { tThrowsNoElement = true; }
ensure( mThrowsNoElement == tThrowsNoElement, "Error (" + level + ", " + seed + "): lastKey() divergence at start in NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
if ( ! mThrowsNoElement ) ensure( t.lastKey().equals( m.lastKey() ), "Error (" + level + ", " + seed + "): m and t differ at start on their last key (" + m.lastKey() + ", " + t.lastKey() +")");
/* Now we check that m and t are equal. */
if ( !m.equals( t ) || ! t.equals( m ) ) System.err.println("m: " + m + " t: " + t);
ensure( m.equals( t ), "Error (" + level + ", " + seed + "): ! m.equals( t ) at start" );
ensure( t.equals( m ), "Error (" + level + ", " + seed + "): ! t.equals( m ) at start" );
/* Now we check that m actually holds that data. */
for(Iterator i=t.entrySet().iterator(); i.hasNext(); ) {
java.util.Map.Entry e = (java.util.Map.Entry)i.next();
ensure( valEquals(e.getValue(), m.get(e.getKey())), "Error (" + level + ", " + seed + "): m and t differ on an entry ("+e+") after insertion (iterating on t)" );
}
/* Now we check that m actually holds that data, but iterating on m. */
for(Iterator i=m.entrySet().iterator(); i.hasNext(); ) {
Entry e = (Entry)i.next();
ensure( valEquals(e.getValue(), t.get(e.getKey())), "Error (" + level + ", " + seed + "): m and t differ on an entry ("+e+") after insertion (iterating on m)" );
}
/* Now we check that m actually holds the same keys. */
for(Iterator i=t.keySet().iterator(); i.hasNext(); ) {
Object o = i.next();
ensure( m.containsKey(o), "Error (" + level + ", " + seed + "): m and t differ on a key ("+o+") after insertion (iterating on t)" );
ensure( m.keySet().contains(o), "Error (" + level + ", " + seed + "): m and t differ on a key ("+o+", in keySet()) after insertion (iterating on t)" );
}
/* Now we check that m actually holds the same keys, but iterating on m. */
for(Iterator i=m.keySet().iterator(); i.hasNext(); ) {
Object o = i.next();
ensure( t.containsKey(o), "Error (" + level + ", " + seed + "): m and t differ on a key after insertion (iterating on m)" );
ensure( t.keySet().contains(o), "Error (" + level + ", " + seed + "): m and t differ on a key (in keySet()) after insertion (iterating on m)" );
}
/* Now we check that m actually hold the same values. */
for(Iterator i=t.values().iterator(); i.hasNext(); ) {
Object o = i.next();
ensure( m.containsValue(o), "Error (" + level + ", " + seed + "): m and t differ on a value after insertion (iterating on t)" );
ensure( m.values().contains(o), "Error (" + level + ", " + seed + "): m and t differ on a value (in values()) after insertion (iterating on t)" );
}
/* Now we check that m actually hold the same values, but iterating on m. */
for(Iterator i=m.values().iterator(); i.hasNext(); ) {
Object o = i.next();
ensure( t.containsValue(o), "Error (" + level + ", " + seed + "): m and t differ on a value after insertion (iterating on m)");
ensure( t.values().contains(o), "Error (" + level + ", " + seed + "): m and t differ on a value (in values()) after insertion (iterating on m)");
}
/* Now we check that inquiries about random data give the same answer in m and t. For
m we use the polymorphic method. */
for(int i=0; i The iterators provided by this class are type-specific {@link
* it.unimi.dsi.fastutil.BidirectionalIterator bidirectional iterators}.
* Moreover, the iterator returned by When a specific {@link Comparator} is specified and stored in {@link
* #storedComparator}, we must check whether it is type-specific. If it is
* so, we can used directly, and we store it in {@link #actualComparator}. Otherwise,
* we generate on-the-fly an anonymous class that wraps the non-specific {@link Comparator}
* and makes it into a type-specific one.
*/
private void setActualComparator() {
#if #keyclass(Object)
actualComparator = storedComparator;
#else
/* If the provided comparator is already type-specific, we use it. Otherwise,
we use a wrapper anonymous class to fake that it is type-specific. */
if ( storedComparator == null || storedComparator instanceof KEY_COMPARATOR ) actualComparator = (KEY_COMPARATOR)storedComparator;
else actualComparator = new KEY_COMPARATOR KEY_GENERIC() {
public int compare( KEY_GENERIC_TYPE k1, KEY_GENERIC_TYPE k2 ) {
return storedComparator.compare( KEY2OBJ( k1 ), KEY2OBJ( k2 ) );
}
public int compare( KEY_CLASS ok1, KEY_CLASS ok2 ) {
return storedComparator.compare( ok1, ok2 );
}
};
#endif
}
/** Creates a new empty tree set with the given comparator.
*
* @param c a {@link Comparator} (even better, a type-specific comparator).
*/
public AVL_TREE_SET( final Comparator super KEY_GENERIC_CLASS> c ) {
this();
storedComparator = c;
setActualComparator();
}
/** Creates a new tree set copying a given set.
*
* @param c a collection to be copied into the new tree set.
*/
public AVL_TREE_SET( final Collection extends KEY_GENERIC_CLASS> c ) {
this();
addAll( c );
}
/** Creates a new tree set copying a given sorted set (and its {@link Comparator}).
*
* @param s a {@link SortedSet} to be copied into the new tree set.
*/
public AVL_TREE_SET( final SortedSet This method uses the {@link #actualComparator} if it is non- We use the only "metadata", i.e., {@link Entry#info}, to store
* information about balance, predecessor status and successor status.
*
* Note that since the class is recursive, it can be
* considered equivalently a tree.
*/
private static final class Entry KEY_GENERIC implements Cloneable {
/** If the bit in this mask is true, {@link #right} points to a successor. */
private final static int SUCC_MASK = 1 << 31;
/** If the bit in this mask is true, {@link #left} points to a predecessor. */
private final static int PRED_MASK = 1 << 30;
/** The bits in this mask hold the node balance info. You can get it just by casting to byte. */
private final static int BALANCE_MASK = 0xFF;
/** The key of this entry. */
KEY_GENERIC_TYPE key;
/** The pointers to the left and right subtrees. */
Entry KEY_GENERIC left, right;
/** This integers holds different information in different bits (see {@link #SUCC_MASK}, {@link #PRED_MASK} and {@link #BALANCE_MASK}). */
int info;
Entry() {}
/** Creates a new entry with the given key.
*
* @param k a key.
*/
Entry( final KEY_GENERIC_TYPE k ) {
this.key = k;
info = SUCC_MASK | PRED_MASK;
}
/** Returns the left subtree.
*
* @return the left subtree ( This class can iterate in both directions on a threaded tree.
*/
private class SetIterator extends KEY_ABSTRACT_LIST_ITERATOR KEY_GENERIC {
/** The entry that will be returned by the next call to {@link java.util.ListIterator#previous()} (or This class represents a subset. One has to specify the left/right
* limits (which can be set to -∞ or ∞). Since the subset is a
* view on the set, at a given moment it could happen that the limits of
* the range are not any longer in the main set. Thus, things such as
* {@link java.util.SortedSet#first()} or {@link java.util.SortedSet#size()} must be always computed
* on-the-fly.
*/
private final class Subset extends ABSTRACT_SORTED_SET KEY_GENERIC implements java.io.Serializable, SORTED_SET KEY_GENERIC {
private static final long serialVersionUID = -7046029254386353129L;
/** The start of the subset range, unless {@link #bottom} is true. */
KEY_GENERIC_TYPE from;
/** The end of the subset range, unless {@link #top} is true. */
KEY_GENERIC_TYPE to;
/** If true, the subset range starts from -∞. */
boolean bottom;
/** If true, the subset range goes to ∞. */
boolean top;
/** Creates a new subset with given key range.
*
* @param from the start of the subset range.
* @param bottom if true, the first parameter is ignored and the range starts from -∞.
* @param to the end of the subset range.
* @param top if true, the third parameter is ignored and the range goes to ∞.
*/
public Subset( final KEY_GENERIC_TYPE from, final boolean bottom, final KEY_GENERIC_TYPE to, final boolean top ) {
if ( ! bottom && ! top && AVL_TREE_SET.this.compare( from, to ) > 0 ) throw new IllegalArgumentException( "Start element (" + from + ") is larger than end element (" + to + ")" );
this.from = from;
this.bottom = bottom;
this.to = to;
this.top = top;
}
public void clear() {
final SubsetIterator i = new SubsetIterator();
while( i.hasNext() ) {
i.next();
i.remove();
}
}
/** Checks whether a key is in the subset range.
* @param k a key.
* @return true if is the key is in the subset range.
*/
final boolean in( final KEY_GENERIC_TYPE k ) {
return ( bottom || AVL_TREE_SET.this.compare( k, from ) >= 0 ) &&
( top || AVL_TREE_SET.this.compare( k, to ) < 0 );
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
public boolean contains( final KEY_TYPE k ) {
return in( KEY_GENERIC_CAST k ) && AVL_TREE_SET.this.contains( k );
}
public boolean add( final KEY_GENERIC_TYPE k ) {
if ( ! in( k ) ) throw new IllegalArgumentException( "Element (" + k + ") out of range [" + ( bottom ? "-" : String.valueOf( from ) ) + ", " + ( top ? "-" : String.valueOf( to ) ) + ")" );
return AVL_TREE_SET.this.add( k );
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
public boolean remove( final KEY_TYPE k ) {
if ( ! in( KEY_GENERIC_CAST k ) ) return false;
return AVL_TREE_SET.this.remove( k );
}
public int size() {
final SubsetIterator i = new SubsetIterator();
int n = 0;
while( i.hasNext() ) {
n++;
i.next();
}
return n;
}
public boolean isEmpty() {
return ! new SubsetIterator().hasNext();
}
public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() {
return actualComparator;
}
public KEY_BIDI_ITERATOR KEY_GENERIC iterator() {
return new SubsetIterator();
}
public KEY_BIDI_ITERATOR KEY_GENERIC iterator( final KEY_GENERIC_TYPE from ) {
return new SubsetIterator( from );
}
public SORTED_SET KEY_GENERIC headSet( final KEY_GENERIC_TYPE to ) {
if ( top ) return new Subset( from, bottom, to, false );
return compare( to, this.to ) < 0 ? new Subset( from, bottom, to, false ) : this;
}
public SORTED_SET KEY_GENERIC tailSet( final KEY_GENERIC_TYPE from ) {
if ( bottom ) return new Subset( from, false, to, top );
return compare( from, this.from ) > 0 ? new Subset( from, false, to, top ) : this;
}
public SORTED_SET KEY_GENERIC subSet( KEY_GENERIC_TYPE from, KEY_GENERIC_TYPE to ) {
if ( top && bottom ) return new Subset( from, false, to, false );
if ( ! top ) to = compare( to, this.to ) < 0 ? to : this.to;
if ( ! bottom ) from = compare( from, this.from ) > 0 ? from : this.from;
if ( ! top && ! bottom && from == this.from && to == this.to ) return this;
return new Subset( from, false, to, false );
}
/** Locates the first entry.
*
* @return the first entry of this subset, or This class inherits from {@link SetIterator}, but overrides the methods that
* update the pointer after a {@link java.util.ListIterator#next()} or {@link java.util.ListIterator#previous()}. If we would
* move out of the range of the subset we just overwrite the next or previous
* entry with This method performs a deep copy of this tree set; the data stored in the
* set, however, is not cloned. Note that this makes a difference only for object keys.
*
* @return a deep copy of this tree set.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public Object clone() {
AVL_TREE_SET KEY_GENERIC c;
try {
c = (AVL_TREE_SET KEY_GENERIC)super.clone();
}
catch(CloneNotSupportedException cantHappen) {
throw new InternalError();
}
c.allocatePaths();
if ( count != 0 ) {
// Also this apparently unfathomable code is derived from GNU libavl.
Entry KEY_GENERIC e, p, q, rp = new Entry KEY_GENERIC(), rq = new Entry KEY_GENERIC();
p = rp;
rp.left( tree );
q = rq;
rq.pred( null );
while( true ) {
if ( ! p.pred() ) {
e = p.left.clone();
e.pred( q.left );
e.succ( q );
q.left( e );
p = p.left;
q = q.left;
}
else {
while( p.succ() ) {
p = p.right;
if ( p == null ) {
q.right = null;
c.tree = rq.left;
c.firstEntry = c.tree;
while( c.firstEntry.left != null ) c.firstEntry = c.firstEntry.left;
c.lastEntry = c.tree;
while( c.lastEntry.right != null ) c.lastEntry = c.lastEntry.right;
return c;
}
q = q.right;
}
p = p.right;
q = q.right;
}
if ( ! p.succ() ) {
e = p.right.clone();
e.succ( q.right );
e.pred( q );
q.right( e );
}
}
}
return c;
}
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
int n = count;
SetIterator i = new SetIterator();
s.defaultWriteObject();
while( n-- != 0 ) s.WRITE_KEY( i.NEXT_KEY() );
}
/** Reads the given number of entries from the input stream, returning the corresponding tree.
*
* @param s the input stream.
* @param n the (positive) number of entries to read.
* @param pred the entry containing the key that preceeds the first key in the tree.
* @param succ the entry containing the key that follows the last key in the tree.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
private Entry KEY_GENERIC readTree( final java.io.ObjectInputStream s, final int n, final Entry KEY_GENERIC pred, final Entry KEY_GENERIC succ ) throws java.io.IOException, ClassNotFoundException {
if ( n == 1 ) {
final Entry KEY_GENERIC top = new Entry KEY_GENERIC( KEY_GENERIC_CAST s.READ_KEY() );
top.pred( pred );
top.succ( succ );
return top;
}
if ( n == 2 ) {
/* We handle separately this case so that recursion will
*always* be on nonempty subtrees. */
final Entry KEY_GENERIC top = new Entry KEY_GENERIC( KEY_GENERIC_CAST s.READ_KEY() );
top.right( new Entry KEY_GENERIC( KEY_GENERIC_CAST s.READ_KEY() ) );
top.right.pred( top );
top.balance( 1 );
top.pred( pred );
top.right.succ( succ );
return top;
}
// The right subtree is the largest one.
final int rightN = n / 2, leftN = n - rightN - 1;
final Entry KEY_GENERIC top = new Entry KEY_GENERIC();
top.left( readTree( s, leftN, pred, top ) );
top.key = KEY_GENERIC_CAST s.READ_KEY();
top.right( readTree( s, rightN, top, succ ) );
if ( n == ( n & -n ) ) top.balance( 1 ); // Quick test for determining whether n is a power of 2.
return top;
}
private void readObject( java.io.ObjectInputStream s ) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
/* The storedComparator is now correctly set, but we must restore
on-the-fly the actualComparator. */
setActualComparator();
allocatePaths();
if ( count != 0 ) {
tree = readTree( s, count, null, null );
Entry KEY_GENERIC e;
e = tree;
while( e.left() != null ) e = e.left();
firstEntry = e;
e = tree;
while( e.right() != null ) e = e.right();
lastEntry = e;
}
if ( ASSERTS ) checkTree( tree );
}
#ifdef ASSERTS_CODE
private static KEY_GENERIC int checkTree( Entry KEY_GENERIC e ) {
if ( e == null ) return 0;
final int leftN = checkTree( e.left() ), rightN = checkTree( e.right() );
if ( leftN + e.balance() != rightN )
throw new AssertionError( "Mismatch between left tree size (" + leftN + "), right tree size (" + rightN + ") and balance (" + e.balance() + ")" );
return Math.max( leftN , rightN ) + 1;
}
#else
private static KEY_GENERIC int checkTree( @SuppressWarnings("unused") Entry KEY_GENERIC e ) { return 0; }
#endif
#ifdef TEST
private static long seed = System.currentTimeMillis();
private static java.util.Random r = new java.util.Random( seed );
private static KEY_TYPE genKey() {
#if #keyclass(Byte) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#else
return Integer.toBinaryString( r.nextInt() );
#endif
}
private static java.text.NumberFormat format = new java.text.DecimalFormat( "#,###.00" );
private static java.text.FieldPosition p = new java.text.FieldPosition( 0 );
private static String format( double d ) {
StringBuffer s = new StringBuffer();
return format.format( d, s, p ).toString();
}
private static void speedTest( int n, boolean comp ) {
int i, j;
AVL_TREE_SET m;
java.util.TreeSet t;
KEY_TYPE k[] = new KEY_TYPE[n];
KEY_TYPE nk[] = new KEY_TYPE[n];
long ms;
for( i = 0; i < n; i++ ) {
k[i] = genKey();
nk[i] = genKey();
}
double totAdd = 0, totYes = 0, totNo = 0, totIterFor = 0, totIterBack = 0, totRemYes = 0, d, dd;
if ( comp ) {
for( j = 0; j < 20; j++ ) {
t = new java.util.TreeSet();
/* We first add all pairs to t. */
for( i = 0; i < n; i++ ) t.add( KEY2OBJ( k[i] ) );
/* Then we remove the first half and put it back. */
for( i = 0; i < n/2; i++ ) t.remove( KEY2OBJ( k[i] ) );
ms = System.currentTimeMillis();
for( i = 0; i < n/2; i++ ) t.add( KEY2OBJ( k[i] ) );
d = System.currentTimeMillis() - ms;
/* Then we remove the other half and put it back again. */
ms = System.currentTimeMillis();
for( i = n/2; i < n; i++ ) t.remove( KEY2OBJ( k[i] ) );
dd = System.currentTimeMillis() - ms ;
ms = System.currentTimeMillis();
for( i = n/2; i < n; i++ ) t.add( KEY2OBJ( k[i] ) );
d += System.currentTimeMillis() - ms;
if ( j > 2 ) totAdd += n/d;
System.out.print("Add: " + format( n/d ) +" K/s " );
/* Then we remove again the first half. */
ms = System.currentTimeMillis();
for( i = 0; i < n/2; i++ ) t.remove( KEY2OBJ( k[i] ) );
dd += System.currentTimeMillis() - ms ;
if ( j > 2 ) totRemYes += n/dd;
System.out.print("RemYes: " + format( n/dd ) +" K/s " );
/* And then we put it back. */
for( i = 0; i < n/2; i++ ) t.add( KEY2OBJ( k[i] ) );
/* We check for pairs in t. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) t.contains( KEY2OBJ( k[i] ) );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totYes += d;
System.out.print("Yes: " + format( d ) +" K/s " );
/* We check for pairs not in t. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) t.contains( KEY2OBJ( nk[i] ) );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totNo += d;
System.out.print("No: " + format( d ) +" K/s " );
/* We iterate on t. */
ms = System.currentTimeMillis();
for( Iterator it = t.iterator(); it.hasNext(); it.next() );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totIterFor += d;
System.out.print("IterFor: " + format( d ) +" K/s " );
System.out.println();
}
System.out.println();
System.out.println( "java.util Add: " + format( totAdd/(j-3) ) + " K/s RemYes: " + format( totRemYes/(j-3) ) + " K/s Yes: " + format( totYes/(j-3) ) + " K/s No: " + format( totNo/(j-3) ) + " K/s IterFor: " + format( totIterFor/(j-3) ) + " K/s" );
System.out.println();
totAdd = totYes = totNo = totIterFor = totIterBack = totRemYes = 0;
}
for( j = 0; j < 20; j++ ) {
m = new AVL_TREE_SET();
/* We first add all pairs to m. */
for( i = 0; i < n; i++ ) m.add( k[i] );
/* Then we remove the first half and put it back. */
for( i = 0; i < n/2; i++ ) m.remove( k[i] );
ms = System.currentTimeMillis();
for( i = 0; i < n/2; i++ ) m.add( k[i] );
d = System.currentTimeMillis() - ms;
/* Then we remove the other half and put it back again. */
ms = System.currentTimeMillis();
for( i = n/2; i < n; i++ ) m.remove( k[i] );
dd = System.currentTimeMillis() - ms ;
ms = System.currentTimeMillis();
for( i = n/2; i < n; i++ ) m.add( k[i] );
d += System.currentTimeMillis() - ms;
if ( j > 2 ) totAdd += n/d;
System.out.print("Add: " + format( n/d ) +" K/s " );
/* Then we remove again the first half. */
ms = System.currentTimeMillis();
for( i = 0; i < n/2; i++ ) m.remove( k[i] );
dd += System.currentTimeMillis() - ms ;
if ( j > 2 ) totRemYes += n/dd;
System.out.print("RemYes: " + format( n/dd ) +" K/s " );
/* And then we put it back. */
for( i = 0; i < n/2; i++ ) m.add( k[i] );
/* We check for pairs in m. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) m.contains( k[i] );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totYes += d;
System.out.print("Yes: " + format( d ) +" K/s " );
/* We check for pairs not in m. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) m.contains( nk[i] );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totNo += d;
System.out.print("No: " + format( d ) +" K/s " );
/* We iterate on m. */
KEY_LIST_ITERATOR it = (KEY_LIST_ITERATOR)m.iterator();
ms = System.currentTimeMillis();
for( ; it.hasNext(); it.NEXT_KEY() );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totIterFor += d;
System.out.print("IterFor: " + format( d ) +" K/s " );
/* We iterate back on m. */
ms = System.currentTimeMillis();
for( ; it.hasPrevious(); it.PREV_KEY() );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totIterBack += d;
System.out.print("IterBack: " + format( d ) +" K/s " );
System.out.println();
}
System.out.println();
System.out.println( "fastutil Add: " + format( totAdd/(j-3) ) + " K/s RemYes: " + format( totRemYes/(j-3) ) + " K/s Yes: " + format( totYes/(j-3) ) + " K/s No: " + format( totNo/(j-3) ) + " K/s IterFor: " + format( totIterFor/(j-3) ) + " K/s IterBack: " + format( totIterBack/(j-3) ) + "K/s" );
System.out.println();
}
private static boolean valEquals(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
private static void fatal( String msg ) {
System.out.println( msg );
System.exit( 1 );
}
private static void ensure( boolean cond, String msg ) {
if ( cond ) return;
fatal( msg );
}
private static Object[] k, v, nk;
private static KEY_TYPE kt[];
private static KEY_TYPE nkt[];
private static AVL_TREE_SET topSet;
protected static void testSets( SORTED_SET m, SortedSet t, int n, int level ) {
long ms;
boolean mThrowsIllegal, tThrowsIllegal, mThrowsNoElement, tThrowsNoElement;
boolean rt = false, rm = false;
if ( level > 4 ) return;
/* Now we check that both sets agree on first/last keys. */
mThrowsNoElement = mThrowsIllegal = tThrowsNoElement = tThrowsIllegal = false;
try {
m.first();
}
catch ( NoSuchElementException e ) { mThrowsNoElement = true; }
try {
t.first();
}
catch ( NoSuchElementException e ) { tThrowsNoElement = true; }
ensure( mThrowsNoElement == tThrowsNoElement, "Error (" + level + ", " + seed + "): first() divergence at start in NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
if ( ! mThrowsNoElement ) ensure( t.first().equals( m.first() ), "Error (" + level + ", " + seed + "): m and t differ at start on their first key (" + m.first() + ", " + t.first() +")" );
mThrowsNoElement = mThrowsIllegal = tThrowsNoElement = tThrowsIllegal = false;
try {
m.last();
}
catch ( NoSuchElementException e ) { mThrowsNoElement = true; }
try {
t.last();
}
catch ( NoSuchElementException e ) { tThrowsNoElement = true; }
ensure( mThrowsNoElement == tThrowsNoElement, "Error (" + level + ", " + seed + "): last() divergence at start in NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
if ( ! mThrowsNoElement ) ensure( t.last().equals( m.last() ), "Error (" + level + ", " + seed + "): m and t differ at start on their last key (" + m.last() + ", " + t.last() +")");
/* Now we check that m and t are equal. */
if ( !m.equals( t ) || ! t.equals( m ) ) System.err.println("m: " + m + " t: " + t);
ensure( m.equals( t ), "Error (" + level + ", " + seed + "): ! m.equals( t ) at start" );
ensure( t.equals( m ), "Error (" + level + ", " + seed + "): ! t.equals( m ) at start" );
/* Now we check that m actually holds that data. */
for(Iterator i=t.iterator(); i.hasNext(); ) {
ensure( m.contains( i.next() ), "Error (" + level + ", " + seed + "): m and t differ on an entry after insertion (iterating on t)" );
}
/* Now we check that m actually holds that data, but iterating on m. */
for(Iterator i=m.iterator(); i.hasNext(); ) {
ensure( t.contains( i.next() ), "Error (" + level + ", " + seed + "): m and t differ on an entry after insertion (iterating on m)" );
}
/* Now we check that inquiries about random data give the same answer in m and t. For
m we use the polymorphic method. */
for(int i=0; i To create a type-specific bidirectional iterator, besides what is needed
* for an iterator you need both a method returning the previous element as
* primitive type and a method returning the previous element as an
* object. However, if you inherit from this class you need just one (anyone).
*
* This class implements also a trivial version of {@link #back(int)} that
* uses type-specific methods.
*/
public abstract class KEY_ABSTRACT_BIDI_ITERATOR KEY_GENERIC extends KEY_ABSTRACT_ITERATOR KEY_GENERIC implements KEY_BIDI_ITERATOR KEY_GENERIC {
protected KEY_ABSTRACT_BIDI_ITERATOR() {}
#if #keys(primitive)
/** Delegates to the corresponding generic method. */
public KEY_TYPE PREV_KEY() { return previous().KEY_VALUE(); }
/** Delegates to the corresponding type-specific method. */
public KEY_GENERIC_CLASS previous() { return KEY_CLASS.valueOf( PREV_KEY() ); }
#endif
/** This method just iterates the type-specific version of {@link #previous()} for
* at most This is a trivial iterator-based implementation. It is expected that
* implementations will override this method with a more optimized version.
*
* @param from the start index (inclusive).
* @param to the end index (exclusive).
*/
public void removeElements( final long from, final long to ) {
ensureIndex( to );
KEY_BIG_LIST_ITERATOR KEY_GENERIC i = listIterator( from );
long n = to - from;
if ( n < 0 ) throw new IllegalArgumentException( "Start index (" + from + ") is greater than end index (" + to + ")" );
while( n-- != 0 ) {
i.NEXT_KEY();
i.remove();
}
}
/** Adds elements to this type-specific big list one-by-one.
*
* This is a trivial iterator-based implementation. It is expected that
* implementations will override this method with a more optimized version.
*
* @param index the index at which to add elements.
* @param a the big array containing the elements.
* @param offset the offset of the first element to add.
* @param length the number of elements to add.
*/
public void addElements( long index, final KEY_GENERIC_TYPE a[][], long offset, long length ) {
ensureIndex( index );
BIG_ARRAYS.ensureOffsetLength( a, offset, length );
while( length-- != 0 ) add( index++, BIG_ARRAYS.get( a, offset++ ) );
}
public void addElements( final long index, final KEY_GENERIC_TYPE a[][] ) {
addElements( index, a, 0, BIG_ARRAYS.length( a ) );
}
/** Copies element of this type-specific big list into the given big array one-by-one.
*
* This is a trivial iterator-based implementation. It is expected that
* implementations will override this method with a more optimized version.
*
* @param from the start index (inclusive).
* @param a the destination big array.
* @param offset the offset into the destination big array where to store the first element copied.
* @param length the number of elements to be copied.
*/
public void getElements( final long from, final KEY_TYPE a[][], long offset, long length ) {
KEY_BIG_LIST_ITERATOR KEY_GENERIC i = listIterator( from );
BIG_ARRAYS.ensureOffsetLength( a, offset, length );
if ( from + length > size64() ) throw new IndexOutOfBoundsException( "End index (" + ( from + length ) + ") is greater than list size (" + size64() + ")" );
while( length-- != 0 ) BIG_ARRAYS.set( a, offset++, i.NEXT_KEY() );
}
@Deprecated
public int size() {
return (int)Math.min( Integer.MAX_VALUE, size64() );
}
#if ! #keyclass(Reference)
private boolean valEquals( final Object a, final Object b ) {
return a == null ? b == null : a.equals( b );
}
#endif
public boolean equals( final Object o ) {
if ( o == this ) return true;
if ( ! ( o instanceof BigList ) ) return false;
final BigList> l = (BigList>)o;
long s = size64();
if ( s != l.size64() ) return false;
#if #keys(primitive)
if ( l instanceof BIG_LIST ) {
final KEY_BIG_LIST_ITERATOR KEY_GENERIC i1 = listIterator(), i2 = ((BIG_LIST KEY_GENERIC)l).listIterator();
while( s-- != 0 ) if ( i1.NEXT_KEY() != i2.NEXT_KEY() ) return false;
return true;
}
#endif
final BigListIterator> i1 = listIterator(), i2 = l.listIterator();
#if #keyclass(Reference)
while( s-- != 0 ) if ( i1.next() != i2.next() ) return false;
#else
while( s-- != 0 ) if ( ! valEquals( i1.next(), i2.next() ) ) return false;
#endif
return true;
}
#if ! #keyclass(Reference)
/** Compares this big list to another object. If the
* argument is a {@link BigList}, this method performs a lexicographical comparison; otherwise,
* it throws a This implementation provides (deprecated) implementations of {@link ListIterator#previousIndex()} and {@link ListIterator#nextIndex()} that
* just invoke the corresponding {@link BigListIterator} methods.
*
* @see java.util.ListIterator
* @see it.unimi.dsi.fastutil.BigListIterator
*/
public abstract class KEY_ABSTRACT_BIG_LIST_ITERATOR KEY_GENERIC extends KEY_ABSTRACT_BIDI_ITERATOR KEY_GENERIC implements KEY_BIG_LIST_ITERATOR KEY_GENERIC {
protected KEY_ABSTRACT_BIG_LIST_ITERATOR() {}
#if #keys(primitive)
/** Delegates to the corresponding type-specific method. */
public void set( KEY_GENERIC_CLASS ok ) { set( ok.KEY_VALUE() ); }
/** Delegates to the corresponding type-specific method. */
public void add( KEY_GENERIC_CLASS ok ) { add( ok.KEY_VALUE() ); }
#endif
/** This method just throws an {@link UnsupportedOperationException}. */
public void set( KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
/** This method just throws an {@link UnsupportedOperationException}. */
public void add( KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
/** This method just iterates the type-specific version of {@link #next()} for at most
* In particular, this class provide {@link #iterator()}, To create a type-specific comparator you need both a method comparing
* primitive types and a method comparing objects. However, if you have the
* first one you can just inherit from this class and get for free the second
* one.
*
* @see java.util.Comparator
*/
public abstract class KEY_ABSTRACT_COMPARATOR KEY_GENERIC implements KEY_COMPARATOR KEY_GENERIC {
protected KEY_ABSTRACT_COMPARATOR() {}
public int compare( KEY_GENERIC_CLASS ok1, KEY_GENERIC_CLASS ok2 ) {
return compare( ok1.KEY_VALUE(), ok2.KEY_VALUE() );
}
public abstract int compare( KEY_TYPE k1, KEY_TYPE k2 );
}
fastutil-7.0.2/drv/AbstractFunction.drv 0000644 0000000 0000000 00000011164 12502261336 016756 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
/** An abstract class providing basic methods for functions implementing a type-specific interface.
*
* Optional operations just throw an {@link
* UnsupportedOperationException}. Generic versions of accessors delegate to
* the corresponding type-specific counterparts following the interface rules
* (they take care of returning This class handles directly a default return
* value (including {@linkplain #defaultReturnValue() methods to access
* it}). Instances of classes inheriting from this class have just to return
* Implementing subclasses have just to provide type-specific This method must check whether the provided key is in the map using This method must check whether the provided key is in the map using This method must check whether the provided key is in the map using To create a type-specific iterator you need both a method returning the
* next element as primitive type and a method returning the next element as an
* object. However, if you inherit from this class you need just one (anyone).
*
* This class implements also a trivial version of {@link #skip(int)} that uses
* type-specific methods; moreover, {@link #remove()} will throw an {@link
* UnsupportedOperationException}.
*
* @see java.util.Iterator
*/
public abstract class KEY_ABSTRACT_ITERATOR KEY_GENERIC implements KEY_ITERATOR KEY_GENERIC {
protected KEY_ABSTRACT_ITERATOR() {}
#if #keys(primitive)
/** Delegates to the corresponding generic method. */
public KEY_TYPE NEXT_KEY() { return next().KEY_VALUE(); }
/** Delegates to the corresponding type-specific method. */
public KEY_GENERIC_CLASS next() { return KEY_CLASS.valueOf( NEXT_KEY() ); }
#endif
/** This method just throws an {@link UnsupportedOperationException}. */
public void remove() { throw new UnsupportedOperationException(); }
/** This method just iterates the type-specific version of {@link #next()} for at most
* As an additional bonus, this class implements on top of the list operations a type-specific stack.
*/
public abstract class ABSTRACT_LIST KEY_GENERIC extends ABSTRACT_COLLECTION KEY_GENERIC implements LIST KEY_GENERIC, STACK KEY_GENERIC {
protected ABSTRACT_LIST() {}
/** Ensures that the given index is nonnegative and not greater than the list size.
*
* @param index an index.
* @throws IndexOutOfBoundsException if the given index is negative or greater than the list size.
*/
protected void ensureIndex( final int index ) {
if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" );
if ( index > size() ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than list size (" + ( size() ) + ")" );
}
/** Ensures that the given index is nonnegative and smaller than the list size.
*
* @param index an index.
* @throws IndexOutOfBoundsException if the given index is negative or not smaller than the list size.
*/
protected void ensureRestrictedIndex( final int index ) {
if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" );
if ( index >= size() ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + ( size() ) + ")" );
}
public void add( final int index, final KEY_GENERIC_TYPE k ) {
throw new UnsupportedOperationException();
}
public boolean add( final KEY_GENERIC_TYPE k ) {
add( size(), k );
return true;
}
public KEY_GENERIC_TYPE REMOVE_KEY( int i ) {
throw new UnsupportedOperationException();
}
public KEY_GENERIC_TYPE set( final int index, final KEY_GENERIC_TYPE k ) {
throw new UnsupportedOperationException();
}
public boolean addAll( int index, final Collection extends KEY_GENERIC_CLASS> c ) {
ensureIndex( index );
int n = c.size();
if ( n == 0 ) return false;
Iterator extends KEY_GENERIC_CLASS> i = c.iterator();
while( n-- != 0 ) add( index++, i.next() );
return true;
}
/** Delegates to a more generic method. */
public boolean addAll( final Collection extends KEY_GENERIC_CLASS> c ) {
return addAll( size(), c );
}
/** Delegates to the new covariantly stronger generic method. */
@Deprecated
public KEY_LIST_ITERATOR KEY_GENERIC KEY_LIST_ITERATOR_METHOD() {
return listIterator();
}
/** Delegates to the new covariantly stronger generic method. */
@Deprecated
public KEY_LIST_ITERATOR KEY_GENERIC KEY_LIST_ITERATOR_METHOD( final int index ) {
return listIterator( index );
}
public KEY_LIST_ITERATOR KEY_GENERIC iterator() {
return listIterator();
}
public KEY_LIST_ITERATOR KEY_GENERIC listIterator() {
return listIterator( 0 );
}
public KEY_LIST_ITERATOR KEY_GENERIC listIterator( final int index ) {
return new KEY_ABSTRACT_LIST_ITERATOR KEY_GENERIC() {
int pos = index, last = -1;
public boolean hasNext() { return pos < ABSTRACT_LIST.this.size(); }
public boolean hasPrevious() { return pos > 0; }
public KEY_GENERIC_TYPE NEXT_KEY() { if ( ! hasNext() ) throw new NoSuchElementException(); return ABSTRACT_LIST.this.GET_KEY( last = pos++ ); }
public KEY_GENERIC_TYPE PREV_KEY() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return ABSTRACT_LIST.this.GET_KEY( last = --pos ); }
public int nextIndex() { return pos; }
public int previousIndex() { return pos - 1; }
public void add( KEY_GENERIC_TYPE k ) {
if ( last == -1 ) throw new IllegalStateException();
ABSTRACT_LIST.this.add( pos++, k );
last = -1;
}
public void set( KEY_GENERIC_TYPE k ) {
if ( last == -1 ) throw new IllegalStateException();
ABSTRACT_LIST.this.set( last, k );
}
public void remove() {
if ( last == -1 ) throw new IllegalStateException();
ABSTRACT_LIST.this.REMOVE_KEY( last );
/* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */
if ( last < pos ) pos--;
last = -1;
}
};
}
public boolean contains( final KEY_TYPE k ) {
return indexOf( k ) >= 0;
}
public int indexOf( final KEY_TYPE k ) {
final KEY_LIST_ITERATOR KEY_GENERIC i = listIterator();
KEY_GENERIC_TYPE e;
while( i.hasNext() ) {
e = i.NEXT_KEY();
if ( KEY_EQUALS( k, e ) ) return i.previousIndex();
}
return -1;
}
public int lastIndexOf( final KEY_TYPE k ) {
KEY_LIST_ITERATOR KEY_GENERIC i = listIterator( size() );
KEY_GENERIC_TYPE e;
while( i.hasPrevious() ) {
e = i.PREV_KEY();
if ( KEY_EQUALS( k, e ) ) return i.nextIndex();
}
return -1;
}
public void size( final int size ) {
int i = size();
if ( size > i ) while( i++ < size ) add( KEY_NULL );
else while( i-- != size ) remove( i );
}
public LIST KEY_GENERIC subList( final int from, final int to ) {
ensureIndex( from );
ensureIndex( to );
if ( from > to ) throw new IndexOutOfBoundsException( "Start index (" + from + ") is greater than end index (" + to + ")" );
return new SUBLIST KEY_GENERIC( this, from, to );
}
/** Delegates to the new covariantly stronger generic method. */
@Deprecated
public LIST KEY_GENERIC SUBLIST_METHOD( final int from, final int to ) {
return subList( from, to );
}
/** Removes elements of this type-specific list one-by-one.
*
* This is a trivial iterator-based implementation. It is expected that
* implementations will override this method with a more optimized version.
*
*
* @param from the start index (inclusive).
* @param to the end index (exclusive).
*/
public void removeElements( final int from, final int to ) {
ensureIndex( to );
KEY_LIST_ITERATOR KEY_GENERIC i = listIterator( from );
int n = to - from;
if ( n < 0 ) throw new IllegalArgumentException( "Start index (" + from + ") is greater than end index (" + to + ")" );
while( n-- != 0 ) {
i.NEXT_KEY();
i.remove();
}
}
/** Adds elements to this type-specific list one-by-one.
*
* This is a trivial iterator-based implementation. It is expected that
* implementations will override this method with a more optimized version.
*
* @param index the index at which to add elements.
* @param a the array containing the elements.
* @param offset the offset of the first element to add.
* @param length the number of elements to add.
*/
public void addElements( int index, final KEY_GENERIC_TYPE a[], int offset, int length ) {
ensureIndex( index );
if ( offset < 0 ) throw new ArrayIndexOutOfBoundsException( "Offset (" + offset + ") is negative" );
if ( offset + length > a.length ) throw new ArrayIndexOutOfBoundsException( "End index (" + ( offset + length ) + ") is greater than array length (" + a.length + ")" );
while( length-- != 0 ) add( index++, a[ offset++ ] );
}
public void addElements( final int index, final KEY_GENERIC_TYPE a[] ) {
addElements( index, a, 0, a.length );
}
/** Copies element of this type-specific list into the given array one-by-one.
*
* This is a trivial iterator-based implementation. It is expected that
* implementations will override this method with a more optimized version.
*
* @param from the start index (inclusive).
* @param a the destination array.
* @param offset the offset into the destination array where to store the first element copied.
* @param length the number of elements to be copied.
*/
public void getElements( final int from, final KEY_TYPE a[], int offset, int length ) {
KEY_LIST_ITERATOR KEY_GENERIC i = listIterator( from );
if ( offset < 0 ) throw new ArrayIndexOutOfBoundsException( "Offset (" + offset + ") is negative" );
if ( offset + length > a.length ) throw new ArrayIndexOutOfBoundsException( "End index (" + ( offset + length ) + ") is greater than array length (" + a.length + ")" );
if ( from + length > size() ) throw new IndexOutOfBoundsException( "End index (" + ( from + length ) + ") is greater than list size (" + size() + ")" );
while( length-- != 0 ) a[ offset++ ] = i.NEXT_KEY();
}
#if ! #keyclass(Reference)
private boolean valEquals( final Object a, final Object b ) {
return a == null ? b == null : a.equals( b );
}
#endif
public boolean equals( final Object o ) {
if ( o == this ) return true;
if ( ! ( o instanceof List ) ) return false;
final List> l = (List>)o;
int s = size();
if ( s != l.size() ) return false;
#if #keys(primitive)
if ( l instanceof LIST ) {
final KEY_LIST_ITERATOR KEY_GENERIC i1 = listIterator(), i2 = ((LIST KEY_GENERIC)l).listIterator();
while( s-- != 0 ) if ( i1.NEXT_KEY() != i2.NEXT_KEY() ) return false;
return true;
}
#endif
final ListIterator> i1 = listIterator(), i2 = l.listIterator();
#if #keyclass(Reference)
while( s-- != 0 ) if ( i1.next() != i2.next() ) return false;
#else
while( s-- != 0 ) if ( ! valEquals( i1.next(), i2.next() ) ) return false;
#endif
return true;
}
#if ! #keyclass(Reference)
/** Compares this list to another object. If the
* argument is a {@link java.util.List}, this method performs a lexicographical comparison; otherwise,
* it throws a This class provides trivial type-specific implementations of {@link
* java.util.ListIterator#set(Object) set()} and {@link java.util.ListIterator#add(Object) add()} which
* throw an {@link UnsupportedOperationException}. For primitive types, it also
* provides a trivial implementation of {@link java.util.ListIterator#set(Object) set()} and {@link
* java.util.ListIterator#add(Object) add()} that just invokes the type-specific one.
*
*
* @see java.util.ListIterator
*/
public abstract class KEY_ABSTRACT_LIST_ITERATOR KEY_GENERIC extends KEY_ABSTRACT_BIDI_ITERATOR KEY_GENERIC implements KEY_LIST_ITERATOR KEY_GENERIC {
protected KEY_ABSTRACT_LIST_ITERATOR() {}
#if #keys(primitive)
/** Delegates to the corresponding type-specific method. */
public void set( KEY_GENERIC_CLASS ok ) { set( ok.KEY_VALUE() ); }
/** Delegates to the corresponding type-specific method. */
public void add( KEY_GENERIC_CLASS ok ) { add( ok.KEY_VALUE() ); }
#endif
/** This method just throws an {@link UnsupportedOperationException}. */
public void set( KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
/** This method just throws an {@link UnsupportedOperationException}. */
public void add( KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
}
fastutil-7.0.2/drv/AbstractMap.drv 0000644 0000000 0000000 00000022207 12502302212 015673 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import VALUE_PACKAGE.VALUE_COLLECTION;
import VALUE_PACKAGE.VALUE_ABSTRACT_COLLECTION;
import VALUE_PACKAGE.VALUE_ITERATOR;
import VALUE_PACKAGE.VALUE_ABSTRACT_ITERATOR;
import it.unimi.dsi.fastutil.objects.ObjectSet;
#if #keys(primitive) && #values(primitive)
import it.unimi.dsi.fastutil.objects.ObjectIterator;
#endif
import java.util.Iterator;
import java.util.Map;
/** An abstract class providing basic methods for maps implementing a type-specific interface.
*
* Optional operations just throw an {@link
* UnsupportedOperationException}. Generic versions of accessors delegate to
* the corresponding type-specific counterparts following the interface rules
* (they take care of returning As a further help, this class provides a {@link BasicEntry BasicEntry} inner class
* that implements a type-specific version of {@link java.util.Map.Entry}; it
* is particularly useful for those classes that do not implement their own
* entries (e.g., most immutable maps).
*/
public abstract class ABSTRACT_MAP KEY_VALUE_GENERIC extends ABSTRACT_FUNCTION KEY_VALUE_GENERIC implements MAP KEY_VALUE_GENERIC, java.io.Serializable {
private static final long serialVersionUID = -4940583368468432370L;
protected ABSTRACT_MAP() {}
#if #values(primitive)
public boolean containsValue( Object ov ) {
return containsValue( VALUE_OBJ2TYPE( ov ) );
}
#endif
/** Checks whether the given value is contained in {@link #values()}. */
public boolean containsValue( VALUE_TYPE v ) {
return values().contains( v );
}
/** Checks whether the given value is contained in {@link #keySet()}. */
public boolean containsKey( KEY_TYPE k ) {
return keySet().contains( k );
}
/** Puts all pairs in the given map.
* If the map implements the interface of this map,
* it uses the faster iterators.
*
* @param m a map.
*/
#if #keys(primitive) ^ #values(primitive)
@SuppressWarnings("unchecked")
#endif
public void putAll(Map extends KEY_GENERIC_CLASS,? extends VALUE_GENERIC_CLASS> m) {
int n = m.size();
final Iterator extends Map.Entry extends KEY_GENERIC_CLASS,? extends VALUE_GENERIC_CLASS>> i = m.entrySet().iterator();
if (m instanceof MAP) {
MAP.Entry KEY_VALUE_EXTENDS_GENERIC e;
while(n-- != 0) {
e = (MAP.Entry KEY_VALUE_EXTENDS_GENERIC)i.next();
put(e.ENTRY_GET_KEY(), e.ENTRY_GET_VALUE());
}
}
else {
Map.Entry extends KEY_GENERIC_CLASS,? extends VALUE_GENERIC_CLASS> e;
while(n-- != 0) {
e = i.next();
put(e.getKey(), e.getValue());
}
}
}
public boolean isEmpty() {
return size() == 0;
}
/** This class provides a basic but complete type-specific entry class for all those maps implementations
* that do not have entries on their own (e.g., most immutable maps).
*
* This class does not implement {@link java.util.Map.Entry#setValue(Object) setValue()}, as the modification
* would not be reflected in the base map.
*/
public static class BasicEntry KEY_VALUE_GENERIC implements MAP.Entry KEY_VALUE_GENERIC {
protected KEY_GENERIC_TYPE key;
protected VALUE_GENERIC_TYPE value;
public BasicEntry( final KEY_GENERIC_CLASS key, final VALUE_GENERIC_CLASS value ) {
this.key = KEY_CLASS2TYPE(key);
this.value = VALUE_CLASS2TYPE(value);
}
#if #keys(primitive) || #values(primitive)
public BasicEntry( final KEY_GENERIC_TYPE key, final VALUE_GENERIC_TYPE value ) {
this.key = key;
this.value = value;
}
#endif
public KEY_GENERIC_CLASS getKey() {
return KEY2OBJ(key);
}
#if #keys(primitive)
public KEY_TYPE ENTRY_GET_KEY() {
return key;
}
#endif
public VALUE_GENERIC_CLASS getValue() {
return VALUE2OBJ(value);
}
#if #values(primitive)
public VALUE_TYPE ENTRY_GET_VALUE() {
return value;
}
#endif
public VALUE_GENERIC_TYPE setValue( final VALUE_GENERIC_TYPE value ) {
throw new UnsupportedOperationException();
}
#if #values(primitive)
public VALUE_GENERIC_CLASS setValue( final VALUE_GENERIC_CLASS value ) {
return VALUE_CLASS.valueOf(setValue(value.VALUE_VALUE()));
}
#endif
public boolean equals( final Object o ) {
if (!(o instanceof Map.Entry)) return false;
Map.Entry,?> e = (Map.Entry,?>)o;
return KEY_EQUALS( key, KEY_OBJ2TYPE( e.getKey() ) ) && VALUE_EQUALS( value, VALUE_OBJ2TYPE( e.getValue() ) );
}
public int hashCode() {
return KEY2JAVAHASH(key) ^ VALUE2JAVAHASH(value);
}
public String toString() {
return key + "->" + value;
}
}
/** Returns a type-specific-set view of the keys of this map.
*
* The view is backed by the set returned by {@link #entrySet()}. Note that
* no attempt is made at caching the result of this method, as this would
* require adding some attributes that lightweight implementations would
* not need. Subclasses may easily override this policy by calling
* this method and caching the result, but implementors are encouraged to
* write more efficient ad-hoc implementations.
*
* @return a set view of the keys of this map; it may be safely cast to a type-specific interface.
*/
public SET KEY_GENERIC keySet() {
return new ABSTRACT_SET KEY_GENERIC() {
public boolean contains( final KEY_TYPE k ) { return containsKey( k ); }
public int size() { return ABSTRACT_MAP.this.size(); }
public void clear() { ABSTRACT_MAP.this.clear(); }
public KEY_ITERATOR KEY_GENERIC iterator() {
return new KEY_ABSTRACT_ITERATOR KEY_GENERIC() {
final ObjectIterator The view is backed by the set returned by {@link #entrySet()}. Note that
* no attempt is made at caching the result of this method, as this would
* require adding some attributes that lightweight implementations would
* not need. Subclasses may easily override this policy by calling
* this method and caching the result, but implementors are encouraged to
* write more efficient ad-hoc implementations.
*
* @return a set view of the values of this map; it may be safely cast to a type-specific interface.
*/
public VALUE_COLLECTION VALUE_GENERIC values() {
return new VALUE_ABSTRACT_COLLECTION VALUE_GENERIC() {
public boolean contains( final VALUE_TYPE k ) { return containsValue( k ); }
public int size() { return ABSTRACT_MAP.this.size(); }
public void clear() { ABSTRACT_MAP.this.clear(); }
public VALUE_ITERATOR VALUE_GENERIC iterator() {
return new VALUE_ABSTRACT_ITERATOR VALUE_GENERIC() {
final ObjectIterator The view is backed by the sorted set returned by {@link #entrySet()}. Note that
* no attempt is made at caching the result of this method, as this would
* require adding some attributes that lightweight implementations would
* not need. Subclasses may easily override this policy by calling
* this method and caching the result, but implementors are encouraged to
* write more efficient ad-hoc implementations.
*
* @return a sorted set view of the keys of this map; it may be safely cast to a type-specific interface.
*/
public SORTED_SET KEY_GENERIC keySet() {
return new KeySet();
}
/** A wrapper exhibiting the keys of a map. */
protected class KeySet extends ABSTRACT_SORTED_SET KEY_GENERIC {
public boolean contains( final KEY_TYPE k ) { return containsKey( k ); }
public int size() { return ABSTRACT_SORTED_MAP.this.size(); }
public void clear() { ABSTRACT_SORTED_MAP.this.clear(); }
public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() { return ABSTRACT_SORTED_MAP.this.comparator(); }
public KEY_GENERIC_TYPE FIRST() { return FIRST_KEY(); }
public KEY_GENERIC_TYPE LAST() { return LAST_KEY(); }
public SORTED_SET KEY_GENERIC headSet( final KEY_GENERIC_TYPE to ) { return headMap( to ).keySet(); }
public SORTED_SET KEY_GENERIC tailSet( final KEY_GENERIC_TYPE from ) { return tailMap( from ).keySet(); }
public SORTED_SET KEY_GENERIC subSet( final KEY_GENERIC_TYPE from, final KEY_GENERIC_TYPE to ) { return subMap( from, to ).keySet(); }
public KEY_BIDI_ITERATOR KEY_GENERIC iterator( final KEY_GENERIC_TYPE from ) { return new KeySetIterator KEY_VALUE_GENERIC( entrySet().iterator( new BasicEntry KEY_VALUE_GENERIC( from, VALUE_NULL ) ) ); }
public KEY_BIDI_ITERATOR KEY_GENERIC iterator() { return new KeySetIterator KEY_VALUE_GENERIC( entrySet().iterator() ); }
}
/** A wrapper exhibiting a map iterator as an iterator on keys.
*
* To provide an iterator on keys, just create an instance of this
* class using the corresponding iterator on entries.
*/
protected static class KeySetIterator KEY_VALUE_GENERIC extends KEY_ABSTRACT_BIDI_ITERATOR KEY_GENERIC {
protected final ObjectBidirectionalIterator The view is backed by the sorted set returned by {@link #entrySet()}. Note that
* no attempt is made at caching the result of this method, as this would
* require adding some attributes that lightweight implementations would
* not need. Subclasses may easily override this policy by calling
* this method and caching the result, but implementors are encouraged to
* write more efficient ad-hoc implementations.
*
* @return a type-specific collection view of the values contained in this map.
*/
public VALUE_COLLECTION VALUE_GENERIC values() {
return new ValuesCollection();
}
/** A wrapper exhibiting the values of a map. */
protected class ValuesCollection extends VALUE_ABSTRACT_COLLECTION VALUE_GENERIC {
public VALUE_ITERATOR VALUE_GENERIC iterator() { return new ValuesIterator KEY_VALUE_GENERIC( entrySet().iterator() ); }
public boolean contains( final VALUE_TYPE k ) { return containsValue( k ); }
public int size() { return ABSTRACT_SORTED_MAP.this.size(); }
public void clear() { ABSTRACT_SORTED_MAP.this.clear(); }
}
/** A wrapper exhibiting a map iterator as an iterator on values.
*
* To provide an iterator on values, just create an instance of this
* class using the corresponding iterator on entries.
*/
protected static class ValuesIterator KEY_VALUE_GENERIC extends VALUE_ABSTRACT_ITERATOR VALUE_GENERIC {
protected final ObjectBidirectionalIterator To create a type-specific stack, you need both object methods and
* primitive-type methods. However, if you inherit from this class you need
* just one (anyone).
*/
public abstract class ABSTRACT_STACK KEY_GENERIC extends AbstractStack Instances of this class represent a FIFO queue using a backing
* array in a circular way. The array is enlarged and shrunk as needed. You can use the {@link #trim()} method
* to reduce its memory usage, if necessary.
*
* This class provides additional methods that implement a deque (double-ended queue).
*/
public class ARRAY_FIFO_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KEY_GENERIC implements Serializable {
private static final long serialVersionUID = 0L;
/** The standard initial capacity of a queue. */
public final static int INITIAL_CAPACITY = 4;
/** The backing array. */
protected transient KEY_GENERIC_TYPE array[];
/** The current (cached) length of {@link #array}. */
protected transient int length;
/** The start position in {@link #array}. It is always strictly smaller than {@link #length}.*/
protected transient int start;
/** The end position in {@link #array}. It is always strictly smaller than {@link #length}.
* Might be actually smaller than {@link #start} because {@link #array} is used cyclically. */
protected transient int end;
/** Creates a new empty queue with given capacity.
*
* @param capacity the initial capacity of this queue.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public ARRAY_FIFO_QUEUE( final int capacity ) {
if ( capacity < 0 ) throw new IllegalArgumentException( "Initial capacity (" + capacity + ") is negative" );
array = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ Math.max( 1, capacity ) ]; // Never build a queue with zero-sized backing array.
length = array.length;
}
/** Creates a new empty queue with standard {@linkplain #INITIAL_CAPACITY initial capacity}.
*/
public ARRAY_FIFO_QUEUE() {
this( INITIAL_CAPACITY );
}
/** Returns This class stores immutably a list of arrays in a single large array
* using front coding (of course, the compression will be reasonable only if
* the list is sorted lexicographically—see below). It implements an
* immutable type-specific list that returns the i-th array when
* calling {@link #get(int) get(i)}. The returned array may be
* freely modified.
*
* Front coding is based on the idea that if the i-th and the
* (i+1)-th array have a common prefix, we might store the length
* of the common prefix, and then the rest of the second array.
*
* This approach, of course, requires that once in a while an array is
* stored entirely. The ratio of a front-coded list defines how
* often this happens (once every {@link #ratio()} arrays). A higher ratio
* means more compression, but means also a longer access time, as more arrays
* have to be probed to build the result. Note that we must build an array
* every time {@link #get(int)} is called, but this class provides also methods
* that extract one of the stored arrays in a given array, reducing garbage
* collection. See the documentation of the family of By setting the ratio to 1 we actually disable front coding: however, we
* still have a data structure storing large list of arrays with a reduced
* overhead (just one integer per array, plus the space required for lengths).
*
* Note that the typical usage of front-coded lists is under the form of
* serialized objects; usually, the data that has to be compacted is processed
* offline, and the resulting structure is stored permanently. Since the
* pointer array is not stored, the serialized format is very small.
*
* All arrays are stored in a {@linkplain it.unimi.dsi.fastutil.BigArrays big array}. A separate array of pointers
* indexes arrays whose position is a multiple of the ratio: thus, a higher ratio
* means also less pointers.
*
* More in detail, an array whose position is a multiple of the ratio is
* stored as the array length, followed by the elements of the array. The array
* length is coded by a simple variable-length list of k-1 bit
* blocks, where k is the number of bits of the underlying primitive
* type. All other arrays are stored as follows: let This private version of {@link #arrayLength(int)} does not check its argument.
*
* @param index an index.
* @return the length of the Instances of this class are based on a single array. This implementation
* is extremely inefficient, but it is difficult to beat when the size of the
* queue is very small. The array is enlarged as needed, but it is never
* shrunk. Use the {@link #trim()} method to reduce its size, if necessary.
*
* Either comparator may be This constructor uses as secondary comparator the opposite order of This constructor uses as secondary comparator the opposite of the natural order.
*
* @param refArray the reference array.
* @param capacity the initial capacity of this queue.
*/
public ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity ) {
this( refArray, capacity, null );
}
/** Creates a new empty queue with capacity equal to the length of the reference array.
*
* @param refArray the reference array.
* @param c the primary comparator used in this queue, or This constructor uses as secondary comparator the opposite order of This constructor uses as secondary comparator the opposite of the natural order.
*
* @param refArray the reference array.
*/
public ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray ) {
this( refArray, refArray.length, null );
}
/** Wraps a given array in a queue using the given comparators.
*
* The queue returned by this method will be backed by the given array.
*
* @param refArray the reference array.
* @param a an array of indices into The queue returned by this method will be backed by the given array.
*
* @param refArray the reference array.
* @param a an array of indices into The queue returned by this method will be backed by the given array.
*
* @param refArray the reference array.
* @param a an array of indices into The queue returned by this method will be backed by the given array.
*
* @param refArray the reference array.
* @param a an array of indices into The queue returned by this method will be backed by the given array.
*
* @param refArray the reference array.
* @param a an array of indices into The queue returned by this method will be backed by the given array.
*
* @param refArray the reference array.
* @param a an array of indices into Instances of this class use as reference list a reference array,
* which must be provided to each constructor, and represent a priority queue
* using a backing array of integer indices—all operations are performed
* directly on the array. The array is enlarged as needed, but it is never
* shrunk. Use the {@link #trim()} method to reduce its size, if necessary.
*
* This implementation is extremely inefficient, but it is difficult to beat
* when the size of the queue is very small. Moreover, it allows to enqueue several
* time the same index, without limitations.
*/
public class ARRAY_INDIRECT_PRIORITY_QUEUE KEY_GENERIC extends AbstractIndirectPriorityQueue The queue returned by this method will be backed by the given array.
*
* @param refArray the reference array.
* @param a an array of indices into The queue returned by this method will be backed by the given array.
*
* @param refArray the reference array.
* @param a an array of indices into The queue returned by this method will be backed by the given array.
*
* @param refArray the reference array.
* @param a an array of indices into The queue returned by this method will be backed by the given array.
*
* @param refArray the reference array.
* @param a an array of indices into Note that for efficiency reasons this method will not throw an exception
* when Note that for efficiency reasons this method will not throw an exception
* when This class implements a lightweight, fast, open, optimized,
* reuse-oriented version of array-based lists. Instances of this class
* represent a list with an array that is enlarged as needed when new entries
* are created (by doubling its current length), but is
* never made smaller (even on a {@link #clear()}). A family of
* {@linkplain #trim() trimming methods} lets you control the size of the
* backing array; this is particularly useful if you reuse instances of this class.
* Range checks are equivalent to those of {@link java.util}'s classes, but
* they are delayed as much as possible. The backing array is exposed by the
* {@link #elements()} method.
*
* This class implements the bulk methods This class implements a lightweight, fast, open, optimized,
* reuse-oriented version of array-based lists. Instances of this class
* represent a list with an array that is enlarged as needed when new entries
* are created (by doubling the current length), but is
* never made smaller (even on a {@link #clear()}). A family of
* {@linkplain #trim() trimming methods} lets you control the size of the
* backing array; this is particularly useful if you reuse instances of this class.
* Range checks are equivalent to those of {@link java.util}'s classes, but
* they are delayed as much as possible.
*
* The backing array is exposed by the {@link #elements()} method. If an instance
* of this class was created {@linkplain #wrap(Object[],int) by wrapping},
* backing-array reallocations will be performed using reflection, so that
* {@link #elements()} can return an array of the same type of the original array; the comments
* about efficiency made in {@link it.unimi.dsi.fastutil.objects.ObjectArrays} apply here.
*
* This class implements the bulk methods This constructor is only meant to be used by the wrapping methods.
*
* @param a the array that will be used to back this array list.
*/
@SuppressWarnings("unused")
protected ARRAY_LIST( final KEY_GENERIC_TYPE a[], boolean dummy ) {
this.a = a;
#if ! #keys(primitive)
this.wrapped = true;
#endif
}
/** Creates a new array list with given capacity.
*
* @param capacity the initial capacity of the array list (may be 0).
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public ARRAY_LIST( final int capacity ) {
if ( capacity < 0 ) throw new IllegalArgumentException( "Initial capacity (" + capacity + ") is negative" );
a = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ capacity ];
#if ! #keys(primitive)
wrapped = false;
#endif
}
/** Creates a new array list with {@link #DEFAULT_INITIAL_CAPACITY} capacity.
*/
public ARRAY_LIST() {
this( DEFAULT_INITIAL_CAPACITY );
}
/** Creates a new array list and fills it with a given collection.
*
* @param c a collection that will be used to fill the array list.
*/
public ARRAY_LIST( final Collection extends KEY_GENERIC_CLASS> c ) {
this( c.size() );
#if #keys(primitive)
size = ITERATORS.unwrap( ITERATORS.AS_KEY_ITERATOR( c.iterator() ), a );
#else
size = ITERATORS.unwrap( c.iterator(), a );
#endif
}
/** Creates a new array list and fills it with a given type-specific collection.
*
* @param c a type-specific collection that will be used to fill the array list.
*/
public ARRAY_LIST( final COLLECTION KEY_EXTENDS_GENERIC c ) {
this( c.size() );
size = ITERATORS.unwrap( c.iterator(), a );
}
/** Creates a new array list and fills it with a given type-specific list.
*
* @param l a type-specific list that will be used to fill the array list.
*/
public ARRAY_LIST( final LIST KEY_EXTENDS_GENERIC l ) {
this( l.size() );
l.getElements( 0, a, 0, size = l.size() );
}
/** Creates a new array list and fills it with the elements of a given array.
*
* @param a an array whose elements will be used to fill the array list.
*/
public ARRAY_LIST( final KEY_GENERIC_TYPE a[] ) {
this( a, 0, a.length );
}
/** Creates a new array list and fills it with the elements of a given array.
*
* @param a an array whose elements will be used to fill the array list.
* @param offset the first element to use.
* @param length the number of elements to use.
*/
public ARRAY_LIST( final KEY_GENERIC_TYPE a[], final int offset, final int length ) {
this( length );
System.arraycopy( a, offset, this.a, 0, length );
size = length;
}
/** Creates a new array list and fills it with the elements returned by an iterator..
*
* @param i an iterator whose returned elements will fill the array list.
*/
public ARRAY_LIST( final Iterator extends KEY_GENERIC_CLASS> i ) {
this();
while( i.hasNext() ) this.add( i.next() );
}
/** Creates a new array list and fills it with the elements returned by a type-specific iterator..
*
* @param i a type-specific iterator whose returned elements will fill the array list.
*/
public ARRAY_LIST( final KEY_ITERATOR KEY_EXTENDS_GENERIC i ) {
this();
while( i.hasNext() ) this.add( i.NEXT_KEY() );
}
#if #keys(primitive)
/** Returns the backing array of this list.
*
* @return the backing array.
*/
public KEY_GENERIC_TYPE[] elements() {
return a;
}
#else
/** Returns the backing array of this list.
*
* If this array list was created by wrapping a given array, it is guaranteed
* that the type of the returned array will be the same. Otherwise, the returned
* array will be of type {@link Object Object[]} (in spite of the declared return type).
*
* Warning: This behaviour may cause (unfathomable)
* run-time errors if a method expects an array
* actually of type This method is useful when reusing lists. {@linkplain #clear() Clearing a
* list} leaves the array length untouched. If you are reusing a list
* many times, you can call this method with a typical
* size to avoid keeping around a very large array just
* because of a few large transient lists.
*
* @param n the threshold for the trimming.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public void trim( final int n ) {
// TODO: use Arrays.trim() and preserve type only if necessary
if ( n >= a.length || size == a.length ) return;
final KEY_GENERIC_TYPE t[] = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ Math.max( n, size ) ];
System.arraycopy( a, 0, t, 0, size );
a = t;
if ( ASSERTS ) assert size <= a.length;
}
/** Copies element of this type-specific list into the given array using optimized system calls.
*
* @param from the start index (inclusive).
* @param a the destination array.
* @param offset the offset into the destination array where to store the first element copied.
* @param length the number of elements to be copied.
*/
public void getElements( final int from, final KEY_TYPE[] a, final int offset, final int length ) {
ARRAYS.ensureOffsetLength( a, offset, length );
System.arraycopy( this.a, from, a, offset, length );
}
/** Removes elements of this type-specific list using optimized system calls.
*
* @param from the start index (inclusive).
* @param to the end index (exclusive).
*/
public void removeElements( final int from, final int to ) {
it.unimi.dsi.fastutil.Arrays.ensureFromTo( size, from, to );
System.arraycopy( a, to, a, from, size - to );
size -= ( to - from );
#if #keys(reference)
int i = to - from;
while( i-- != 0 ) a[ size + i ] = null;
#endif
}
/** Adds elements to this type-specific list using optimized system calls.
*
* @param index the index at which to add elements.
* @param a the array containing the elements.
* @param offset the offset of the first element to add.
* @param length the number of elements to add.
*/
public void addElements( final int index, final KEY_GENERIC_TYPE a[], final int offset, final int length ) {
ensureIndex( index );
ARRAYS.ensureOffsetLength( a, offset, length );
grow( size + length );
System.arraycopy( this.a, index, this.a, index + length, size - index );
System.arraycopy( a, offset, this.a, index, length );
size += length;
}
#if #keys(primitive)
public KEY_TYPE[] TO_KEY_ARRAY( KEY_TYPE a[] ) {
if ( a == null || a.length < size ) a = new KEY_TYPE[ size ];
System.arraycopy( this.a, 0, a, 0, size );
return a;
}
public boolean addAll( int index, final COLLECTION c ) {
ensureIndex( index );
int n = c.size();
if ( n == 0 ) return false;
grow( size + n );
if ( index != size ) System.arraycopy( a, index, a, index + n, size - index );
final KEY_ITERATOR i = c.iterator();
size += n;
while( n-- != 0 ) a[ index++ ] = i.NEXT_KEY();
if ( ASSERTS ) assert size <= a.length;
return true;
}
public boolean addAll( final int index, final LIST l ) {
ensureIndex( index );
final int n = l.size();
if ( n == 0 ) return false;
grow( size + n );
if ( index != size ) System.arraycopy( a, index, a, index + n, size - index );
l.getElements( 0, a, index, n );
size += n;
if ( ASSERTS ) assert size <= a.length;
return true;
}
#endif
public KEY_LIST_ITERATOR KEY_GENERIC listIterator( final int index ) {
ensureIndex( index );
return new KEY_ABSTRACT_LIST_ITERATOR KEY_GENERIC() {
int pos = index, last = -1;
public boolean hasNext() { return pos < size; }
public boolean hasPrevious() { return pos > 0; }
public KEY_GENERIC_TYPE NEXT_KEY() { if ( ! hasNext() ) throw new NoSuchElementException(); return a[ last = pos++ ]; }
public KEY_GENERIC_TYPE PREV_KEY() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return a[ last = --pos ]; }
public int nextIndex() { return pos; }
public int previousIndex() { return pos - 1; }
public void add( KEY_GENERIC_TYPE k ) {
if ( last == -1 ) throw new IllegalStateException();
ARRAY_LIST.this.add( pos++, k );
last = -1;
}
public void set( KEY_GENERIC_TYPE k ) {
if ( last == -1 ) throw new IllegalStateException();
ARRAY_LIST.this.set( last, k );
}
public void remove() {
if ( last == -1 ) throw new IllegalStateException();
ARRAY_LIST.this.REMOVE_KEY( last );
/* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */
if ( last < pos ) pos--;
last = -1;
}
};
}
public ARRAY_LIST KEY_GENERIC clone() {
ARRAY_LIST KEY_GENERIC c = new ARRAY_LIST KEY_GENERIC( size );
System.arraycopy( a, 0, c.a, 0, size );
c.size = size;
return c;
}
#if #keyclass(Object)
private boolean valEquals( final K a, final K b ) {
return a == null ? b == null : a.equals( b );
}
#endif
/** Compares this type-specific array list to another one.
*
* This method exists only for sake of efficiency. The implementation
* inherited from the abstract implementation would already work.
*
* @param l a type-specific array list.
* @return true if the argument contains the same elements of this type-specific array list.
*/
public boolean equals( final ARRAY_LIST KEY_GENERIC l ) {
if ( l == this ) return true;
int s = size();
if ( s != l.size() ) return false;
final KEY_GENERIC_TYPE[] a1 = a;
final KEY_GENERIC_TYPE[] a2 = l.a;
#if #keyclass(Object)
while( s-- != 0 ) if ( ! valEquals( a1[ s ], a2[ s ] ) ) return false;
#else
while( s-- != 0 ) if ( a1[ s ] != a2[ s ] ) return false;
#endif
return true;
}
#if ! #keyclass(Reference)
/** Compares this array list to another array list.
*
* This method exists only for sake of efficiency. The implementation
* inherited from the abstract implementation would already work.
*
* @param l an array list.
* @return a negative integer,
* zero, or a positive integer as this list is lexicographically less than, equal
* to, or greater than the argument.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public int compareTo( final ARRAY_LIST KEY_EXTENDS_GENERIC l ) {
final int s1 = size(), s2 = l.size();
final KEY_GENERIC_TYPE a1[] = a, a2[] = l.a;
KEY_GENERIC_TYPE e1, e2;
int r, i;
for( i = 0; i < s1 && i < s2; i++ ) {
e1 = a1[ i ];
e2 = a2[ i ];
if ( ( r = KEY_CMP( e1, e2 ) ) != 0 ) return r;
}
return i < s2 ? -1 : ( i < s1 ? 1 : 0 );
}
#endif
private void writeObject( java.io.ObjectOutputStream s ) throws java.io.IOException {
s.defaultWriteObject();
for( int i = 0; i < size; i++ ) s.WRITE_KEY( a[ i ] );
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
private void readObject( java.io.ObjectInputStream s ) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
a = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ size ];
for( int i = 0; i < size; i++ ) a[ i ] = KEY_GENERIC_CAST s.READ_KEY();
}
#ifdef TEST
private static long seed = System.currentTimeMillis();
private static java.util.Random r = new java.util.Random( seed );
private static KEY_TYPE genKey() {
#if #keyclass(Byte) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#elif #keyclass(Object)
return Integer.toBinaryString( r.nextInt() );
#else
return new java.io.Serializable() {};
#endif
}
private static java.text.NumberFormat format = new java.text.DecimalFormat( "#,###.00" );
private static java.text.FieldPosition p = new java.text.FieldPosition( 0 );
private static String format( double d ) {
StringBuffer s = new StringBuffer();
return format.format( d, s, p ).toString();
}
private static void speedTest( int n, boolean comp ) {
System.out.println( "There are presently no speed tests for this class." );
}
private static void fatal( String msg ) {
System.out.println( msg );
System.exit( 1 );
}
private static void ensure( boolean cond, String msg ) {
if ( cond ) return;
fatal( msg );
}
private static Object[] k, v, nk;
private static KEY_TYPE kt[];
private static KEY_TYPE nkt[];
private static ARRAY_LIST topList;
protected static void testLists( LIST m, java.util.List t, int n, int level ) {
long ms;
Exception mThrowsIllegal, tThrowsIllegal, mThrowsOutOfBounds, tThrowsOutOfBounds;
Object rt = null;
KEY_TYPE rm = KEY_NULL;
if ( level > 4 ) return;
/* Now we check that both sets agree on random keys. For m we use the polymorphic method. */
for( int i = 0; i < n; i++ ) {
int p = r.nextInt() % ( n * 2 );
KEY_TYPE T = genKey();
mThrowsOutOfBounds = tThrowsOutOfBounds = null;
try {
m.set( p, T );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
try {
t.set( p, KEY2OBJ( T ) );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + level + ", " + seed + "): set() divergence at start in IndexOutOfBoundsException for index " + p + " (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
if ( mThrowsOutOfBounds == null ) ensure( t.get( p ).equals( KEY2OBJ( m.GET_KEY( p ) ) ), "Error (" + level + ", " + seed + "): m and t differ after set() on position " + p + " (" + m.GET_KEY( p ) + ", " + t.get( p ) + ")" );
p = r.nextInt() % ( n * 2 );
mThrowsOutOfBounds = tThrowsOutOfBounds = null;
try {
m.GET_KEY( p );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
try {
t.get( p );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + level + ", " + seed + "): get() divergence at start in IndexOutOfBoundsException for index " + p + " (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
if ( mThrowsOutOfBounds == null ) ensure( t.get( p ).equals( KEY2OBJ( m.GET_KEY( p ) ) ), "Error (" + level + ", " + seed + "): m and t differ aftre get() on position " + p + " (" + m.GET_KEY( p ) + ", " + t.get( p ) + ")" );
}
/* Now we check that both sets agree on random keys. For m we use the standard method. */
for( int i = 0; i < n; i++ ) {
int p = r.nextInt() % ( n * 2 );
mThrowsOutOfBounds = tThrowsOutOfBounds = null;
try {
m.get( p );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
try {
t.get( p );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + level + ", " + seed + "): get() divergence at start in IndexOutOfBoundsException for index " + p + " (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
if ( mThrowsOutOfBounds == null ) ensure( t.get( p ).equals( m.get( p ) ), "Error (" + level + ", " + seed + "): m and t differ at start on position " + p + " (" + m.get( p ) + ", " + t.get( p ) + ")" );
}
/* Now we check that m and t are equal. */
if ( !m.equals( t ) || ! t.equals( m ) ) System.err.println("m: " + m + " t: " + t);
ensure( m.equals( t ), "Error (" + level + ", " + seed + "): ! m.equals( t ) at start" );
ensure( t.equals( m ), "Error (" + level + ", " + seed + "): ! t.equals( m ) at start" );
/* Now we check that m actually holds that data. */
for(Iterator i=t.iterator(); i.hasNext(); ) {
ensure( m.contains( i.next() ), "Error (" + level + ", " + seed + "): m and t differ on an entry after insertion (iterating on t)" );
}
/* Now we check that m actually holds that data, but iterating on m. */
for(Iterator i=m.listIterator(); i.hasNext(); ) {
ensure( t.contains( i.next() ), "Error (" + level + ", " + seed + "): m and t differ on an entry after insertion (iterating on m)" );
}
/* Now we check that inquiries about random data give the same answer in m and t. For
m we use the polymorphic method. */
for(int i=0; i The main purpose of this
* implementation is that of wrapping cleanly the brute-force approach to the storage of a very
* small number of pairs: just put them into two parallel arrays and scan linearly to find an item.
*/
public class ARRAY_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENERIC implements java.io.Serializable, Cloneable {
private static final long serialVersionUID = 1L;
/** The keys (valid up to {@link #size}, excluded). */
private transient KEY_TYPE[] key;
/** The values (parallel to {@link #key}). */
private transient VALUE_TYPE[] value;
/** The number of valid entries in {@link #key} and {@link #value}. */
private int size;
/** Creates a new empty array map with given key and value backing arrays. The resulting map will have as many entries as the given arrays.
*
* It is responsibility of the caller that the elements of It is responsibility of the caller that the first This method performs a deep copy of this hash map; the data stored in the
* map, however, is not cloned. Note that this makes a difference only for object keys.
*
* @return a deep copy of this map.
*/
SUPPRESS_WARNINGS_KEY_VALUE_UNCHECKED
public ARRAY_MAP KEY_VALUE_GENERIC clone() {
ARRAY_MAP KEY_VALUE_GENERIC c;
try {
c = (ARRAY_MAP KEY_VALUE_GENERIC)super.clone();
}
catch(CloneNotSupportedException cantHappen) {
throw new InternalError();
}
c.key = key.clone();
c.value = value.clone();
return c;
}
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
s.defaultWriteObject();
for( int i = 0; i < size; i++ ) {
s.WRITE_KEY( key[ i ] );
s.WRITE_VALUE( value[ i ] );
}
}
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
key = new KEY_TYPE[ size ];
value = new VALUE_TYPE[ size ];
for( int i = 0; i < size; i++ ) {
key[ i ] = s.READ_KEY();
value[ i ] = s.READ_VALUE();
}
}
}
fastutil-7.0.2/drv/ArrayPriorityQueue.drv 0000644 0000000 0000000 00000014256 12502261336 017337 0 ustar root wheel /*
* Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
#if #keyclass(Object)
import java.util.Arrays;
import java.util.Comparator;
import it.unimi.dsi.fastutil.AbstractPriorityQueue;
#endif
import java.util.NoSuchElementException;
/** A type-specific array-based priority queue.
*
* Instances of this class represent a priority queue using a backing
* array—all operations are performed directly on the array. The array is
* enlarged as needed, but it is never shrunk. Use the {@link #trim()} method
* to reduce its size, if necessary.
*
* This implementation is extremely inefficient, but it is difficult to beat
* when the size of the queue is very small.
*/
public class ARRAY_PRIORITY_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KEY_GENERIC {
/** The backing array. */
SUPPRESS_WARNINGS_KEY_UNCHECKED
protected KEY_GENERIC_TYPE array[] = KEY_GENERIC_ARRAY_CAST ARRAYS.EMPTY_ARRAY;
/** The number of elements in this queue. */
protected int size;
/** The type-specific comparator used in this queue. */
protected KEY_COMPARATOR KEY_SUPER_GENERIC c;
/** The first index, cached, if {@link #firstIndexValid} is true. */
protected int firstIndex;
/** Whether {@link #firstIndex} contains a valid value. */
protected boolean firstIndexValid;
/** Creates a new empty queue with a given capacity and comparator.
*
* @param capacity the initial capacity of this queue.
* @param c the comparator used in this queue, or The queue returned by this method will be backed by the given array.
*
* @param a an array.
* @param size the number of elements to be included in the queue.
* @param c the comparator used in this queue, or The queue returned by this method will be backed by the given array.
*
* @param a an array.
* @param c the comparator used in this queue, or The queue returned by this method will be backed by the given array.
*
* @param a an array.
* @param size the number of elements to be included in the queue.
*/
public ARRAY_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] a, int size ) {
this( a, size, null );
}
/** Wraps a given array in a queue using the natural order.
*
* The queue returned by this method will be backed by the given array.
*
* @param a an array.
*/
public ARRAY_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] a ) {
this( a, a.length );
}
/** Returns the index of the smallest element. */
SUPPRESS_WARNINGS_KEY_UNCHECKED
private int findFirst() {
if ( firstIndexValid ) return this.firstIndex;
firstIndexValid = true;
int i = size;
int firstIndex = --i;
KEY_GENERIC_TYPE first = array[ firstIndex ];
if ( c == null ) { while( i-- != 0 ) if ( KEY_LESS( array[ i ], first ) ) first = array[ firstIndex = i ]; }
else while( i-- != 0 ) { if ( c.compare( array[ i ], first ) < 0 ) first = array[ firstIndex = i ]; }
return this.firstIndex = firstIndex;
}
private void ensureNonEmpty() {
if ( size == 0 ) throw new NoSuchElementException();
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
public void enqueue( KEY_GENERIC_TYPE x ) {
if ( size == array.length ) array = ARRAYS.grow( array, size + 1 );
if ( firstIndexValid ) {
if ( c == null ) { if ( KEY_LESS( x, array[ firstIndex ] ) ) firstIndex = size; }
else if ( c.compare( x, array[ firstIndex ] ) < 0 ) firstIndex = size;
}
else firstIndexValid = false;
array[ size++ ] = x;
}
public KEY_GENERIC_TYPE DEQUEUE() {
ensureNonEmpty();
final int first = findFirst();
final KEY_GENERIC_TYPE result = array[ first ];
System.arraycopy( array, first + 1, array, first, --size - first );
#if #keyclass(Object)
array[ size ] = null;
#endif
firstIndexValid = false;
return result;
}
public KEY_GENERIC_TYPE FIRST() {
ensureNonEmpty();
return array[ findFirst() ];
}
public void changed() {
ensureNonEmpty();
firstIndexValid = false;
}
public int size() { return size; }
public void clear() {
#if #keyclass(Object)
Arrays.fill( array, 0, size, null );
#endif
size = 0;
firstIndexValid = false;
}
/** Trims the underlying array so that it has exactly {@link #size()} elements.
*/
public void trim() {
array = ARRAYS.trim( array, size );
}
public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() { return c; }
}
fastutil-7.0.2/drv/ArraySet.drv 0000644 0000000 0000000 00000011727 12502266705 015251 0 ustar root wheel /*
* Copyright (C) 2007-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import java.util.Collection;
/** A simple, brute-force implementation of a set based on a backing array.
*
* The main purpose of this
* implementation is that of wrapping cleanly the brute-force approach to the storage of a very
* small number of items: just put them into an array and scan linearly to find an item.
*/
public class ARRAY_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implements java.io.Serializable, Cloneable {
private static final long serialVersionUID = 1L;
/** The backing array (valid up to {@link #size}, excluded). */
private transient KEY_TYPE[] a;
/** The number of valid entries in {@link #a}. */
private int size;
/** Creates a new array set using the given backing array. The resulting set will have as many elements as the array.
*
* It is responsibility of the caller that the elements of It is responsibility of the caller that the first This method performs a deep copy of this hash set; the data stored in the
* set, however, is not cloned. Note that this makes a difference only for object keys.
*
* @return a deep copy of this set.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public ARRAY_SET KEY_GENERIC clone() {
ARRAY_SET KEY_GENERIC c;
try {
c = (ARRAY_SET KEY_GENERIC)super.clone();
}
catch(CloneNotSupportedException cantHappen) {
throw new InternalError();
}
c.a = a.clone();
return c;
}
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
s.defaultWriteObject();
for( int i = 0; i < size; i++ ) s.WRITE_KEY( a[ i ] );
}
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
a = new KEY_TYPE[ size ];
for( int i = 0; i < size; i++ ) a[ i ] = s.READ_KEY();
}
}
fastutil-7.0.2/drv/Arrays.drv 0000644 0000000 0000000 00000335077 12502623266 014766 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*
*
* For the sorting and binary search code:
*
* Copyright (C) 1999 CERN - European Organization for Nuclear Research.
*
* Permission to use, copy, modify, distribute and sell this software and
* its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation. CERN makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without expressed or implied warranty.
*/
package PACKAGE;
import it.unimi.dsi.fastutil.Arrays;
import it.unimi.dsi.fastutil.Hash;
import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
#if ! #keyclass(Integer)
import it.unimi.dsi.fastutil.ints.IntArrays;
#endif
#if #keys(primitive)
#if ! #keyclass(Boolean)
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
#endif
/** A class providing static methods and objects that do useful things with type-specific arrays.
*
* In particular, the Note that {@link it.unimi.dsi.fastutil.io.BinIO} and {@link it.unimi.dsi.fastutil.io.TextIO}
* contain several methods make it possible to load and save arrays of primitive types as sequences
* of elements in {@link java.io.DataInput} format (i.e., not as objects) or as sequences of lines of text.
*
* There are several sorting methods available. The main theme is that of letting you choose
* the sorting algorithm you prefer (i.e., trading stability of mergesort for no memory allocation in quicksort).
* Several algorithms provide a parallel version, that will use the {@linkplain Runtime#availableProcessors() number of cores available}.
* Some algorithms also provide an explicit indirect sorting facility, which makes it possible
* to sort an array using the values in another array as comparator.
*
* All comparison-based algorithm have an implementation based on a type-specific comparator.
*
* As a general rule, sequential radix sort is significantly faster than quicksort or mergesort, in particular
* on random-looking data. In
* the parallel case, up to a few cores parallel radix sort is still the fastest, but at some point quicksort
* exploits parallelism better.
*
* If you are fine with not knowing exactly which algorithm will be run (in particular, not knowing exactly whether a support array will be allocated),
* the dual-pivot parallel sorts in {@link java.util.Arrays}
* are about 50% faster than the classical single-pivot implementation used here.
*
* In any case, if sorting time is important I suggest that you benchmark your sorting load
* with your data distribution and on your architecture.
*
* @see java.util.Arrays
*/
public class ARRAYS {
#else
import java.util.Comparator;
/** A class providing static methods and objects that do useful things with type-specific arrays.
*
* In particular, the Warning: creating arrays
* using {@linkplain java.lang.reflect.Array#newInstance(Class,int) reflection}, as it
* happens in {@link #ensureCapacity(Object[],int,int)} and {@link #grow(Object[],int,int)},
* is significantly slower than using There are several sorting methods available. The main theme is that of letting you choose
* the sorting algorithm you prefer (i.e., trading stability of mergesort for no memory allocation in quicksort).
* Several algorithms provide a parallel version, that will use the {@linkplain Runtime#availableProcessors() number of cores available}.
*
* All comparison-based algorithm have an implementation based on a type-specific comparator.
*
* If you are fine with not knowing exactly which algorithm will be run (in particular, not knowing exactly whether a support array will be allocated),
* the dual-pivot parallel sorts in {@link java.util.Arrays}
* are about 50% faster than the classical single-pivot implementation used here.
*
* In any case, if sorting time is important I suggest that you benchmark your sorting load
* with your data distribution and on your architecture.
*
* @see java.util.Arrays
*/
public class ARRAYS {
#endif
private ARRAYS() {}
/** A static, final, empty array. */
public final static KEY_TYPE[] EMPTY_ARRAY = {};
#if #keyclass(Object)
/** Creates a new array using a the given one as prototype.
*
* This method returns a new array of the given length whose element
* are of the same class as of those of If you cannot foresee whether this array will need again to be
* enlarged, you should probably use If you want complete control on the array growth, you
* should probably use If you want complete control on the array growth, you
* should probably use This method may be used whenever an array range check is needed.
*
* @param a an array.
* @param from a start index (inclusive).
* @param to an end index (exclusive).
* @throws IllegalArgumentException if This method may be used whenever an array range check is needed.
*
* @param a an array.
* @param offset a start index.
* @param length a length (the number of elements in the range).
* @throws IllegalArgumentException if The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* Note that this implementation does not allocate any object, contrarily to the implementation
* used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs.
*
* @param x the array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
* @param comp the comparator to determine the sorting order.
*
*/
public static KEY_GENERIC void quickSort( final KEY_GENERIC_TYPE[] x, final int from, final int to, final KEY_COMPARATOR KEY_GENERIC comp ) {
final int len = to - from;
// Selection sort on smallest arrays
if ( len < QUICKSORT_NO_REC ) {
selectionSort( x, from, to, comp );
return;
}
// Choose a partition element, v
int m = from + len / 2;
int l = from;
int n = to - 1;
if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9
int s = len / 8;
l = med3( x, l, l + s, l + 2 * s, comp );
m = med3( x, m - s, m, m + s, comp );
n = med3( x, n - 2 * s, n - s, n, comp );
}
m = med3( x, l, m, n, comp ); // Mid-size, med of 3
final KEY_GENERIC_TYPE v = x[ m ];
// Establish Invariant: v* ( The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* Note that this implementation does not allocate any object, contrarily to the implementation
* used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs.
*
* @param x the array to be sorted.
* @param comp the comparator to determine the sorting order.
*
*/
public static KEY_GENERIC void quickSort( final KEY_GENERIC_TYPE[] x, final KEY_COMPARATOR KEY_GENERIC comp ) {
quickSort( x, 0, x.length, comp );
}
protected static class ForkJoinQuickSortComp KEY_GENERIC extends RecursiveAction {
private static final long serialVersionUID = 1L;
private final int from;
private final int to;
private final KEY_GENERIC_TYPE[] x;
private final KEY_COMPARATOR KEY_GENERIC comp;
public ForkJoinQuickSortComp( final KEY_GENERIC_TYPE[] x , final int from , final int to, final KEY_COMPARATOR KEY_GENERIC comp ) {
this.from = from;
this.to = to;
this.x = x;
this.comp = comp;
}
@Override
protected void compute() {
final KEY_GENERIC_TYPE[] x = this.x;
final int len = to - from;
if ( len < PARALLEL_QUICKSORT_NO_FORK ) {
quickSort( x, from, to, comp );
return;
}
// Choose a partition element, v
int m = from + len / 2;
int l = from;
int n = to - 1;
int s = len / 8;
l = med3( x, l, l + s, l + 2 * s );
m = med3( x, m - s, m, m + s );
n = med3( x, n - 2 * s, n - s, n );
m = med3( x, l, m, n );
final KEY_GENERIC_TYPE v = x[ m ];
// Establish Invariant: v* ( The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* This implementation uses a {@link ForkJoinPool} executor service with
* {@link Runtime#availableProcessors()} parallel threads.
*
* @param x the array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
* @param comp the comparator to determine the sorting order.
*/
public static KEY_GENERIC void parallelQuickSort( final KEY_GENERIC_TYPE[] x, final int from, final int to, final KEY_COMPARATOR KEY_GENERIC comp ) {
final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() );
pool.invoke( new ForkJoinQuickSortComp KEY_GENERIC( x, from, to, comp ) );
pool.shutdown();
}
/** Sorts an array according to the order induced by the specified
* comparator using a parallel quicksort.
*
* The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* This implementation uses a {@link ForkJoinPool} executor service with
* {@link Runtime#availableProcessors()} parallel threads.
*
* @param x the array to be sorted.
* @param comp the comparator to determine the sorting order.
*/
public static KEY_GENERIC void parallelQuickSort( final KEY_GENERIC_TYPE[] x, final KEY_COMPARATOR KEY_GENERIC comp ) {
parallelQuickSort( x, 0, x.length, comp );
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
private static KEY_GENERIC int med3( final KEY_GENERIC_TYPE x[], final int a, final int b, final int c ) {
final int ab = KEY_CMP( x[ a ], x[ b ] );
final int ac = KEY_CMP( x[ a ], x[ c ] );
final int bc = KEY_CMP( x[ b ], x[ c ] );
return ( ab < 0 ?
( bc < 0 ? b : ac < 0 ? c : a ) :
( bc > 0 ? b : ac > 0 ? c : a ) );
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
private static KEY_GENERIC void selectionSort( final KEY_GENERIC_TYPE[] a, final int from, final int to ) {
for( int i = from; i < to - 1; i++ ) {
int m = i;
for( int j = i + 1; j < to; j++ ) if ( KEY_LESS( a[ j ], a[ m ] ) ) m = j;
if ( m != i ) {
final KEY_GENERIC_TYPE u = a[ i ];
a[ i ] = a[ m ];
a[ m ] = u;
}
}
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
private static KEY_GENERIC void insertionSort( final KEY_GENERIC_TYPE[] a, final int from, final int to ) {
for ( int i = from; ++i < to; ) {
KEY_GENERIC_TYPE t = a[ i ];
int j = i;
for ( KEY_GENERIC_TYPE u = a[ j - 1 ]; KEY_LESS( t, u ); u = a[ --j - 1 ] ) {
a[ j ] = u;
if ( from == j - 1 ) {
--j;
break;
}
}
a[ j ] = t;
}
}
/** Sorts the specified range of elements according to the natural ascending order using quicksort.
*
* The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* Note that this implementation does not allocate any object, contrarily to the implementation
* used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs.
*
* @param x the array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static KEY_GENERIC void quickSort( final KEY_GENERIC_TYPE[] x, final int from, final int to ) {
final int len = to - from;
// Selection sort on smallest arrays
if ( len < QUICKSORT_NO_REC ) {
selectionSort( x, from, to );
return;
}
// Choose a partition element, v
int m = from + len / 2;
int l = from;
int n = to - 1;
if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9
int s = len / 8;
l = med3( x, l, l + s, l + 2 * s );
m = med3( x, m - s, m, m + s );
n = med3( x, n - 2 * s, n - s, n );
}
m = med3( x, l, m, n ); // Mid-size, med of 3
final KEY_GENERIC_TYPE v = x[ m ];
// Establish Invariant: v* ( The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* Note that this implementation does not allocate any object, contrarily to the implementation
* used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs.
*
* @param x the array to be sorted.
*
*/
public static KEY_GENERIC void quickSort( final KEY_GENERIC_TYPE[] x ) {
quickSort( x, 0, x.length );
}
protected static class ForkJoinQuickSort KEY_GENERIC extends RecursiveAction {
private static final long serialVersionUID = 1L;
private final int from;
private final int to;
private final KEY_GENERIC_TYPE[] x;
public ForkJoinQuickSort( final KEY_GENERIC_TYPE[] x , final int from , final int to ) {
this.from = from;
this.to = to;
this.x = x;
}
@Override
SUPPRESS_WARNINGS_KEY_UNCHECKED
protected void compute() {
final KEY_GENERIC_TYPE[] x = this.x;
final int len = to - from;
if ( len < PARALLEL_QUICKSORT_NO_FORK ) {
quickSort( x, from, to );
return;
}
// Choose a partition element, v
int m = from + len / 2;
int l = from;
int n = to - 1;
int s = len / 8;
l = med3( x, l, l + s, l + 2 * s );
m = med3( x, m - s, m, m + s );
n = med3( x, n - 2 * s, n - s, n );
m = med3( x, l, m, n );
final KEY_GENERIC_TYPE v = x[ m ];
// Establish Invariant: v* ( The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* This implementation uses a {@link ForkJoinPool} executor service with
* {@link Runtime#availableProcessors()} parallel threads.
*
* @param x the array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
public static KEY_GENERIC void parallelQuickSort( final KEY_GENERIC_TYPE[] x, final int from, final int to ) {
final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() );
pool.invoke( new ForkJoinQuickSort KEY_GENERIC( x, from, to ) );
pool.shutdown();
}
/** Sorts an array according to the natural ascending order using a parallel quicksort.
*
* The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* This implementation uses a {@link ForkJoinPool} executor service with
* {@link Runtime#availableProcessors()} parallel threads.
*
* @param x the array to be sorted.
*
*/
public static KEY_GENERIC void parallelQuickSort( final KEY_GENERIC_TYPE[] x ) {
parallelQuickSort( x, 0, x.length );
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
private static KEY_GENERIC int med3Indirect( final int perm[], final KEY_GENERIC_TYPE x[], final int a, final int b, final int c ) {
final KEY_GENERIC_TYPE aa = x[ perm[ a ] ];
final KEY_GENERIC_TYPE bb = x[ perm[ b ] ];
final KEY_GENERIC_TYPE cc = x[ perm[ c ] ];
final int ab = KEY_CMP( aa, bb );
final int ac = KEY_CMP( aa, cc );
final int bc = KEY_CMP( bb, cc );
return ( ab < 0 ?
( bc < 0 ? b : ac < 0 ? c : a ) :
( bc > 0 ? b : ac > 0 ? c : a ) );
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
private static KEY_GENERIC void insertionSortIndirect( final int[] perm, final KEY_GENERIC_TYPE[] a, final int from, final int to ) {
for ( int i = from; ++i < to; ) {
int t = perm[ i ];
int j = i;
for ( int u = perm[ j - 1 ]; KEY_LESS( a[ t ], a[ u ] ); u = perm[ --j - 1 ] ) {
perm[ j ] = u;
if ( from == j - 1 ) {
--j;
break;
}
}
perm[ j ] = t;
}
}
/** Sorts the specified range of elements according to the natural ascending order using indirect quicksort.
*
* The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* This method implement an indirect sort. The elements of Note that this implementation does not allocate any object, contrarily to the implementation
* used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs.
*
* @param perm a permutation array indexing {@code x}.
* @param x the array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static KEY_GENERIC void quickSortIndirect( final int[] perm, final KEY_GENERIC_TYPE[] x, final int from, final int to ) {
final int len = to - from;
// Selection sort on smallest arrays
if ( len < QUICKSORT_NO_REC ) {
insertionSortIndirect( perm, x, from, to );
return;
}
// Choose a partition element, v
int m = from + len / 2;
int l = from;
int n = to - 1;
if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9
int s = len / 8;
l = med3Indirect( perm, x, l, l + s, l + 2 * s );
m = med3Indirect( perm, x, m - s, m, m + s );
n = med3Indirect( perm, x, n - 2 * s, n - s, n );
}
m = med3Indirect( perm, x, l, m, n ); // Mid-size, med of 3
final KEY_GENERIC_TYPE v = x[ perm[ m ] ];
// Establish Invariant: v* ( The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* This method implement an indirect sort. The elements of Note that this implementation does not allocate any object, contrarily to the implementation
* used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs.
*
* @param perm a permutation array indexing {@code x}.
* @param x the array to be sorted.
*/
public static KEY_GENERIC void quickSortIndirect( final int perm[], final KEY_GENERIC_TYPE[] x ) {
quickSortIndirect( perm, x, 0, x.length );
}
protected static class ForkJoinQuickSortIndirect KEY_GENERIC extends RecursiveAction {
private static final long serialVersionUID = 1L;
private final int from;
private final int to;
private final int[] perm;
private final KEY_GENERIC_TYPE[] x;
public ForkJoinQuickSortIndirect( final int perm[], final KEY_GENERIC_TYPE[] x , final int from , final int to ) {
this.from = from;
this.to = to;
this.x = x;
this.perm = perm;
}
@Override
SUPPRESS_WARNINGS_KEY_UNCHECKED
protected void compute() {
final KEY_GENERIC_TYPE[] x = this.x;
final int len = to - from;
if ( len < PARALLEL_QUICKSORT_NO_FORK ) {
quickSortIndirect( perm, x, from, to );
return;
}
// Choose a partition element, v
int m = from + len / 2;
int l = from;
int n = to - 1;
int s = len / 8;
l = med3Indirect( perm, x, l, l + s, l + 2 * s );
m = med3Indirect( perm, x, m - s, m, m + s );
n = med3Indirect( perm, x, n - 2 * s, n - s, n );
m = med3Indirect( perm, x, l, m, n );
final KEY_GENERIC_TYPE v = x[ perm[ m ] ];
// Establish Invariant: v* ( The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* This method implement an indirect sort. The elements of This implementation uses a {@link ForkJoinPool} executor service with
* {@link Runtime#availableProcessors()} parallel threads.
*
* @param perm a permutation array indexing {@code x}.
* @param x the array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
public static KEY_GENERIC void parallelQuickSortIndirect( final int[] perm, final KEY_GENERIC_TYPE[] x, final int from, final int to ) {
final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() );
pool.invoke( new ForkJoinQuickSortIndirect KEY_GENERIC( perm, x, from, to ) );
pool.shutdown();
}
/** Sorts an array according to the natural ascending order using a parallel indirect quicksort.
*
* The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* This method implement an indirect sort. The elements of This implementation uses a {@link ForkJoinPool} executor service with
* {@link Runtime#availableProcessors()} parallel threads.
*
* @param perm a permutation array indexing {@code x}.
* @param x the array to be sorted.
*
*/
public static KEY_GENERIC void parallelQuickSortIndirect( final int perm[], final KEY_GENERIC_TYPE[] x ) {
parallelQuickSortIndirect( perm, x, 0, x.length );
}
/** Stabilizes a permutation.
*
* This method can be used to stabilize the permutation generated by an indirect sorting, assuming that
* initially the permutation array was in ascending order (e.g., the identity, as usually happens). This method
* scans the permutation, and for each non-singleton block of elements with the same associated values in {@code x},
* permutes them in ascending order. The resulting permutation corresponds to a stable sort.
*
* Usually combining an unstable indirect sort and this method is more efficient than using a stable sort,
* as most stable sort algorithms require a support array.
*
* More precisely, assuming that This method can be used to stabilize the permutation generated by an indirect sorting, assuming that
* initially the permutation array was in ascending order (e.g., the identity, as usually happens). This method
* scans the permutation, and for each non-singleton block of elements with the same associated values in {@code x},
* permutes them in ascending order. The resulting permutation corresponds to a stable sort.
*
* Usually combining an unstable indirect sort and this method is more efficient than using a stable sort,
* as most stable sort algorithms require a support array.
*
* More precisely, assuming that The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* This method implements a lexicographical sorting of the arguments. Pairs of
* elements in the same position in the two provided arrays will be considered a single key, and
* permuted accordingly. In the end, either The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* This method implements a lexicographical sorting of the arguments. Pairs of
* elements in the same position in the two provided arrays will be considered a single key, and
* permuted accordingly. In the end, either The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* This method implements a lexicographical sorting of the arguments. Pairs of
* elements in the same position in the two provided arrays will be considered a single key, and
* permuted accordingly. In the end, either This implementation uses a {@link ForkJoinPool} executor service with
* {@link Runtime#availableProcessors()} parallel threads.
*
* @param x the first array to be sorted.
* @param y the second array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
public static KEY_GENERIC void parallelQuickSort( final KEY_GENERIC_TYPE[] x, final KEY_GENERIC_TYPE[] y, final int from, final int to ) {
final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() );
pool.invoke( new ForkJoinQuickSort2 KEY_GENERIC( x, y, from, to ) );
pool.shutdown();
}
/** Sorts two arrays according to the natural lexicographical
* ascending order using a parallel quicksort.
*
* The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* This method implements a lexicographical sorting of the arguments. Pairs of
* elements in the same position in the two provided arrays will be considered a single key, and
* permuted accordingly. In the end, either This implementation uses a {@link ForkJoinPool} executor service with
* {@link Runtime#availableProcessors()} parallel threads.
*
* @param x the first array to be sorted.
* @param y the second array to be sorted.
*/
public static KEY_GENERIC void parallelQuickSort( final KEY_GENERIC_TYPE[] x, final KEY_GENERIC_TYPE[] y ) {
ensureSameLength( x, y );
parallelQuickSort( x, y, 0, x.length );
}
/** Sorts the specified range of elements according to the natural ascending order using mergesort, using a given pre-filled support array.
*
* This sort is guaranteed to be stable: equal elements will not be reordered as a result
* of the sort. Moreover, no support arrays will be allocated.
* @param a the array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
* @param supp a support array containing at least This sort is guaranteed to be stable: equal elements will not be reordered as a result
* of the sort. An array as large as This sort is guaranteed to be stable: equal elements will not be reordered as a result
* of the sort. An array as large as This sort is guaranteed to be stable: equal elements will not be reordered as a result
* of the sort. Moreover, no support arrays will be allocated.
* @param a the array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
* @param comp the comparator to determine the sorting order.
* @param supp a support array containing at least This sort is guaranteed to be stable: equal elements will not be reordered as a result
* of the sort. An array as large as This sort is guaranteed to be stable: equal elements will not be reordered as a result
* of the sort. An array as large as The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This implementation is significantly faster than quicksort
* already at small sizes (say, more than 10000 elements), but it can only
* sort in ascending order.
*
* @param a the array to be sorted.
*/
public static void radixSort( final KEY_TYPE[] a ) {
radixSort( a, 0, a.length );
}
/** Sorts the specified range of an array using radix sort.
*
* The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This implementation is significantly faster than quicksort
* already at small sizes (say, more than 10000 elements), but it can only
* sort in ascending order.
*
* @param a the array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
public static void radixSort( final KEY_TYPE[] a, final int from, final int to ) {
if ( to - from < RADIXSORT_NO_REC ) {
quickSort( a, from, to );
return;
}
final int maxLevel = DIGITS_PER_ELEMENT - 1;
final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( DIGITS_PER_ELEMENT - 1 ) + 1;
final int[] offsetStack = new int[ stackSize ];
int offsetPos = 0;
final int[] lengthStack = new int[ stackSize ];
int lengthPos = 0;
final int[] levelStack = new int[ stackSize ];
int levelPos = 0;
offsetStack[ offsetPos++ ] = from;
lengthStack[ lengthPos++ ] = to - from;
levelStack[ levelPos++ ] = 0;
final int[] count = new int[ 1 << DIGIT_BITS ];
final int[] pos = new int[ 1 << DIGIT_BITS ];
while( offsetPos > 0 ) {
final int first = offsetStack[ --offsetPos ];
final int length = lengthStack[ --lengthPos ];
final int level = levelStack[ --levelPos ];
#if #keyclass(Character)
final int signMask = 0;
#else
final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif
final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key
// Count keys.
for( int i = first + length; i-- != first; ) count[ INT( KEY2LEXINT( a[ i ] ) >>> shift & DIGIT_MASK ^ signMask ) ]++;
// Compute cumulative distribution
int lastUsed = -1;
for ( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) {
if ( count[ i ] != 0 ) lastUsed = i;
pos[ i ] = ( p += count[ i ] );
}
final int end = first + length - count[ lastUsed ];
// i moves through the start of each block
for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) {
KEY_TYPE t = a[ i ];
c = INT( KEY2LEXINT( t ) >>> shift & DIGIT_MASK ^ signMask );
if ( i < end ) { // When all slots are OK, the last slot is necessarily OK.
while ( ( d = --pos[ c ] ) > i ) {
final KEY_TYPE z = t;
t = a[ d ];
a[ d ] = z;
c = INT( KEY2LEXINT( t ) >>> shift & DIGIT_MASK ^ signMask );
}
a[ i ] = t;
}
if ( level < maxLevel && count[ c ] > 1 ) {
if ( count[ c ] < RADIXSORT_NO_REC ) quickSort( a, i, i + count[ c ] );
else {
offsetStack[ offsetPos++ ] = i;
lengthStack[ lengthPos++ ] = count[ c ];
levelStack[ levelPos++ ] = level + 1;
}
}
}
}
}
protected final static class Segment {
protected final int offset, length, level;
protected Segment( final int offset, final int length, final int level ) {
this.offset = offset;
this.length = length;
this.level = level;
}
@Override
public String toString() {
return "Segment [offset=" + offset + ", length=" + length + ", level=" + level + "]";
}
}
protected final static Segment POISON_PILL = new Segment( -1, -1, -1 );
/** Sorts the specified range of an array using parallel radix sort.
*
* The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This implementation uses a pool of {@link Runtime#availableProcessors()} threads.
*
* @param a the array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
public static void parallelRadixSort( final KEY_TYPE[] a, final int from, final int to ) {
if ( to - from < PARALLEL_RADIXSORT_NO_FORK ) {
quickSort( a, from, to );
return;
}
final int maxLevel = DIGITS_PER_ELEMENT - 1;
final LinkedBlockingQueue The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This implementation uses a pool of {@link Runtime#availableProcessors()} threads.
*
* @param a the array to be sorted.
*/
public static void parallelRadixSort( final KEY_TYPE[] a ) {
parallelRadixSort( a, 0, a.length );
}
/** Sorts the specified array using indirect radix sort.
*
* The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This method implement an indirect sort. The elements of This implementation will allocate, in the stable case, a support array as large as The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This method implement an indirect sort. The elements of This implementation will allocate, in the stable case, a support array as large as The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This method implement an indirect sort. The elements of This implementation uses a pool of {@link Runtime#availableProcessors()} threads.
*
* @param perm a permutation array indexing The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This method implement an indirect sort. The elements of This implementation uses a pool of {@link Runtime#availableProcessors()} threads.
*
* @param perm a permutation array indexing The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This method implements a lexicographical sorting of the arguments. Pairs of elements
* in the same position in the two provided arrays will be considered a single key, and permuted
* accordingly. In the end, either The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This method implements a lexicographical sorting of the arguments. Pairs of elements
* in the same position in the two provided arrays will be considered a single key, and permuted
* accordingly. In the end, either The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This method implements a lexicographical sorting of the arguments. Pairs of elements
* in the same position in the two provided arrays will be considered a single key, and permuted
* accordingly. In the end, either This implementation uses a pool of {@link Runtime#availableProcessors()} threads.
*
* @param a the first array to be sorted.
* @param b the second array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
public static void parallelRadixSort( final KEY_TYPE[] a, final KEY_TYPE[] b, final int from, final int to ) {
if ( to - from < PARALLEL_RADIXSORT_NO_FORK ) {
quickSort( a, b, from, to );
return;
}
final int layers = 2;
if ( a.length != b.length ) throw new IllegalArgumentException( "Array size mismatch." );
final int maxLevel = DIGITS_PER_ELEMENT * layers - 1;
final LinkedBlockingQueue The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This method implements a lexicographical sorting of the arguments. Pairs of elements
* in the same position in the two provided arrays will be considered a single key, and permuted
* accordingly. In the end, either This implementation uses a pool of {@link Runtime#availableProcessors()} threads.
*
* @param a the first array to be sorted.
* @param b the second array to be sorted.
*/
public static void parallelRadixSort( final KEY_TYPE[] a, final KEY_TYPE[] b ) {
ensureSameLength( a, b );
parallelRadixSort( a, b, 0, a.length );
}
private static KEY_GENERIC void insertionSortIndirect( final int[] perm, final KEY_TYPE[] a, final KEY_TYPE[] b, final int from, final int to ) {
for ( int i = from; ++i < to; ) {
int t = perm[ i ];
int j = i;
for ( int u = perm[ j - 1 ]; KEY_LESS( a[ t ], a[ u ] ) || KEY_CMP_EQ( a[ t ], a[ u ] ) && KEY_LESS( b[ t ], b[ u ] ); u = perm[ --j - 1 ] ) {
perm[ j ] = u;
if ( from == j - 1 ) {
--j;
break;
}
}
perm[ j ] = t;
}
}
/** Sorts the specified pair of arrays lexicographically using indirect radix sort.
*
* The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This method implement an indirect sort. The elements of This implementation will allocate, in the stable case, a further support array as large as The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This method implement an indirect sort. The elements of This implementation will allocate, in the stable case, a further support array as large as The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This method implements a lexicographical sorting of the provided arrays. Tuples of elements
* in the same position will be considered a single key, and permuted
* accordingly.
*
* @param a an array containing arrays of equal length to be sorted lexicographically in parallel.
*/
public static void radixSort( final KEY_TYPE[][] a ) {
radixSort( a, 0, a[ 0 ].length );
}
/** Sorts the specified array of arrays lexicographically using radix sort.
*
* The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993).
*
* This method implements a lexicographical sorting of the provided arrays. Tuples of elements
* in the same position will be considered a single key, and permuted
* accordingly.
*
* @param a an array containing arrays of equal length to be sorted lexicographically in parallel.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
public static void radixSort( final KEY_TYPE[][] a, final int from, final int to ) {
if ( to - from < RADIXSORT_NO_REC ) {
selectionSort( a, from, to, 0 );
return;
}
final int layers = a.length;
final int maxLevel = DIGITS_PER_ELEMENT * layers - 1;
for( int p = layers, l = a[ 0 ].length; p-- != 0; ) if ( a[ p ].length != l ) throw new IllegalArgumentException( "The array of index " + p + " has not the same length of the array of index 0." );
final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( layers * DIGITS_PER_ELEMENT - 1 ) + 1;
final int[] offsetStack = new int[ stackSize ];
int offsetPos = 0;
final int[] lengthStack = new int[ stackSize ];
int lengthPos = 0;
final int[] levelStack = new int[ stackSize ];
int levelPos = 0;
offsetStack[ offsetPos++ ] = from;
lengthStack[ lengthPos++ ] = to - from;
levelStack[ levelPos++ ] = 0;
final int[] count = new int[ 1 << DIGIT_BITS ];
final int[] pos = new int[ 1 << DIGIT_BITS ];
final KEY_TYPE[] t = new KEY_TYPE[ layers ];
while( offsetPos > 0 ) {
final int first = offsetStack[ --offsetPos ];
final int length = lengthStack[ --lengthPos ];
final int level = levelStack[ --levelPos ];
#if #keyclass(Character)
final int signMask = 0;
#else
final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif
final KEY_TYPE[] k = a[ level / DIGITS_PER_ELEMENT ]; // This is the key array
final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key
// Count keys.
for( int i = first + length; i-- != first; ) count[ INT( KEY2LEXINT( k[ i ] ) >>> shift & DIGIT_MASK ^ signMask ) ]++;
// Compute cumulative distribution
int lastUsed = -1;
for ( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) {
if ( count[ i ] != 0 ) lastUsed = i;
pos[ i ] = ( p += count[ i ] );
}
final int end = first + length - count[ lastUsed ];
// i moves through the start of each block
for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) {
for( int p = layers; p-- != 0; ) t[ p ] = a[ p ][ i ];
c = INT( KEY2LEXINT( k[ i ] ) >>> shift & DIGIT_MASK ^ signMask );
if ( i < end ) { // When all slots are OK, the last slot is necessarily OK.
while( ( d = --pos[ c ] ) > i ) {
c = INT( KEY2LEXINT( k[ d ] ) >>> shift & DIGIT_MASK ^ signMask );
for( int p = layers; p-- != 0; ) {
final KEY_TYPE u = t[ p ];
t[ p ] = a[ p ][ d ];
a[ p ][ d ] = u;
}
}
for( int p = layers; p-- != 0; ) a[ p ][ i ] = t[ p ];
}
if ( level < maxLevel && count[ c ] > 1 ) {
if ( count[ c ] < RADIXSORT_NO_REC ) selectionSort( a, i, i + count[ c ], level + 1 );
else {
offsetStack[ offsetPos++ ] = i;
lengthStack[ lengthPos++ ] = count[ c ];
levelStack[ levelPos++ ] = level + 1;
}
}
}
}
}
#endif
#endif
/** Shuffles the specified array fragment using the specified pseudorandom number generator.
*
* @param a the array to be shuffled.
* @param from the index of the first element (inclusive) to be shuffled.
* @param to the index of the last element (exclusive) to be shuffled.
* @param random a pseudorandom number generator (please use a XorShift* generator).
* @return This hash strategy may be used in custom hash collections whenever keys are
* arrays, and they must be considered equal by content. This strategy
* will handle The effect of this call is exactly the same as that of
* calling {@link #previous()} for This class implements a lightweight, fast, open, optimized,
* reuse-oriented version of big-array-based big lists. Instances of this class
* represent a big list with a big array that is enlarged as needed when new entries
* are created (by doubling the current length), but is
* never made smaller (even on a {@link #clear()}). A family of
* {@linkplain #trim() trimming methods} lets you control the size of the
* backing big array; this is particularly useful if you reuse instances of this class.
* Range checks are equivalent to those of {@link java.util}'s classes, but
* they are delayed as much as possible. The backing big array is exposed by the
* {@link #elements()} method.
*
* This class implements the bulk methods This class implements a lightweight, fast, open, optimized,
* reuse-oriented version of big-array-based big lists. Instances of this class
* represent a big list with a big array that is enlarged as needed when new entries
* are created (by doubling the current length), but is
* never made smaller (even on a {@link #clear()}). A family of
* {@linkplain #trim() trimming methods} lets you control the size of the
* backing big array; this is particularly useful if you reuse instances of this class.
* Range checks are equivalent to those of {@link java.util}'s classes, but
* they are delayed as much as possible.
*
* The backing big array is exposed by the {@link #elements()} method. If an instance
* of this class was created {@linkplain #wrap(Object[][],long) by wrapping},
* backing-array reallocations will be performed using reflection, so that
* {@link #elements()} can return a big array of the same type of the original big array; the comments
* about efficiency made in {@link it.unimi.dsi.fastutil.objects.ObjectArrays} apply here.
*
* This class implements the bulk methods This constructor is only meant to be used by the wrapping methods.
*
* @param a the big array that will be used to back this big-array big list.
*/
@SuppressWarnings("unused")
protected BIG_ARRAY_BIG_LIST( final KEY_GENERIC_TYPE a[][], boolean dummy ) {
this.a = a;
#if ! #keys(primitive)
this.wrapped = true;
#endif
}
/** Creates a new big-array big list with given capacity.
*
* @param capacity the initial capacity of the array list (may be 0).
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public BIG_ARRAY_BIG_LIST( final long capacity ) {
if ( capacity < 0 ) throw new IllegalArgumentException( "Initial capacity (" + capacity + ") is negative" );
a = KEY_GENERIC_BIG_ARRAY_CAST BIG_ARRAYS.newBigArray( capacity );
#if ! #keys(primitive)
wrapped = false;
#endif
}
/** Creates a new big-array big list with {@link #DEFAULT_INITIAL_CAPACITY} capacity.
*/
public BIG_ARRAY_BIG_LIST() {
this( DEFAULT_INITIAL_CAPACITY );
}
/** Creates a new big-array big list and fills it with a given type-specific collection.
*
* @param c a type-specific collection that will be used to fill the array list.
*/
public BIG_ARRAY_BIG_LIST( final COLLECTION KEY_EXTENDS_GENERIC c ) {
this( c.size() );
for( KEY_ITERATOR KEY_EXTENDS_GENERIC i = c.iterator(); i.hasNext(); ) add( i.NEXT_KEY() );
}
/** Creates a new big-array big list and fills it with a given type-specific list.
*
* @param l a type-specific list that will be used to fill the array list.
*/
public BIG_ARRAY_BIG_LIST( final BIG_LIST KEY_EXTENDS_GENERIC l ) {
this( l.size64() );
l.getElements( 0, a, 0, size = l.size64() );
}
/** Creates a new big-array big list and fills it with the elements of a given big array.
*
* Note that this constructor makes it easy to build big lists from literal arrays
* declared as Note that this constructor makes it easy to build big lists from literal arrays
* declared as If this big-array big list was created by wrapping a given big array, it is guaranteed
* that the type of the returned big array will be the same. Otherwise, the returned
* big array will be an big array of objects.
*
* @return the backing big array.
*/
public KEY_GENERIC_TYPE[][] elements() {
return a;
}
#endif
/** Wraps a given big array into a big-array list of given size.
*
* @param a a big array to wrap.
* @param length the length of the resulting big-array list.
* @return a new big-array list of the given size, wrapping the given big array.
*/
public static KEY_GENERIC BIG_ARRAY_BIG_LIST KEY_GENERIC wrap( final KEY_GENERIC_TYPE a[][], final long length ) {
if ( length > BIG_ARRAYS.length( a ) ) throw new IllegalArgumentException( "The specified length (" + length + ") is greater than the array size (" + BIG_ARRAYS.length( a ) + ")" );
final BIG_ARRAY_BIG_LIST KEY_GENERIC l = new BIG_ARRAY_BIG_LIST KEY_GENERIC( a, false );
l.size = length;
return l;
}
/** Wraps a given big array into a big-array big list.
*
* @param a a big array to wrap.
* @return a new big-array big list wrapping the given array.
*/
public static KEY_GENERIC BIG_ARRAY_BIG_LIST KEY_GENERIC wrap( final KEY_GENERIC_TYPE a[][] ) {
return wrap( a, BIG_ARRAYS.length( a ) );
}
/** Ensures that this big-array big list can contain the given number of entries without resizing.
*
* @param capacity the new minimum capacity for this big-array big list.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public void ensureCapacity( final long capacity ) {
#if #keys(primitive)
a = BIG_ARRAYS.ensureCapacity( a, capacity, size );
#else
if ( wrapped ) a = BIG_ARRAYS.ensureCapacity( a, capacity, size );
else {
if ( capacity > BIG_ARRAYS.length( a ) ) {
final Object t[][] = BIG_ARRAYS.newBigArray( capacity );
BIG_ARRAYS.copy( a, 0, t, 0, size );
a = (KEY_GENERIC_TYPE[][])t;
}
}
#endif
if ( ASSERTS ) assert size <= BIG_ARRAYS.length( a );
}
/** Grows this big-array big list, ensuring that it can contain the given number of entries without resizing,
* and in case enlarging it at least by a factor of two.
*
* @param capacity the new minimum capacity for this big-array big list.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
private void grow( final long capacity ) {
#if #keys(primitive)
a = BIG_ARRAYS.grow( a, capacity, size );
#else
if ( wrapped ) a = BIG_ARRAYS.grow( a, capacity, size );
else {
if ( capacity > BIG_ARRAYS.length( a ) ) {
final int newLength = (int)Math.max( Math.min( 2 * BIG_ARRAYS.length( a ), it.unimi.dsi.fastutil.Arrays.MAX_ARRAY_SIZE ), capacity );
final Object t[][] = BIG_ARRAYS.newBigArray( newLength );
BIG_ARRAYS.copy( a, 0, t, 0, size );
a = (KEY_GENERIC_TYPE[][])t;
}
}
#endif
if ( ASSERTS ) assert size <= BIG_ARRAYS.length( a );
}
public void add( final long index, final KEY_GENERIC_TYPE k ) {
ensureIndex( index );
grow( size + 1 );
if ( index != size ) BIG_ARRAYS.copy( a, index, a, index + 1, size - index );
BIG_ARRAYS.set( a, index, k );
size++;
if ( ASSERTS ) assert size <= BIG_ARRAYS.length( a );
}
public boolean add( final KEY_GENERIC_TYPE k ) {
grow( size + 1 );
BIG_ARRAYS.set( a, size++, k );
if ( ASSERTS ) assert size <= BIG_ARRAYS.length( a );
return true;
}
public KEY_GENERIC_TYPE GET_KEY( final long index ) {
if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" );
return BIG_ARRAYS.get( a, index );
}
public long indexOf( final KEY_TYPE k ) {
for( long i = 0; i < size; i++ ) if ( KEY_EQUALS( k, BIG_ARRAYS.get( a, i ) ) ) return i;
return -1;
}
public long lastIndexOf( final KEY_TYPE k ) {
for( long i = size; i-- != 0; ) if ( KEY_EQUALS( k, BIG_ARRAYS.get( a, i ) ) ) return i;
return -1;
}
public KEY_GENERIC_TYPE REMOVE_KEY( final long index ) {
if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" );
final KEY_GENERIC_TYPE old = BIG_ARRAYS.get( a, index );
size--;
if ( index != size ) BIG_ARRAYS.copy( a, index + 1, a, index, size - index );
#if #keys(reference)
BIG_ARRAYS.set( a, size, null );
#endif
if ( ASSERTS ) assert size <= BIG_ARRAYS.length( a );
return old;
}
public boolean rem( final KEY_TYPE k ) {
final long index = indexOf( k );
if ( index == -1 ) return false;
REMOVE_KEY( index );
if ( ASSERTS ) assert size <= BIG_ARRAYS.length( a );
return true;
}
#if #keys(reference)
public boolean remove( final Object o ) {
return rem( o );
}
#endif
public KEY_GENERIC_TYPE set( final long index, final KEY_GENERIC_TYPE k ) {
if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" );
KEY_GENERIC_TYPE old = BIG_ARRAYS.get( a, index );
BIG_ARRAYS.set( a, index, k );
return old;
}
public void clear() {
#if #keys(reference)
BIG_ARRAYS.fill( a, 0, size, null );
#endif
size = 0;
if ( ASSERTS ) assert size <= BIG_ARRAYS.length( a );
}
public long size64() {
return size;
}
public void size( final long size ) {
if ( size > BIG_ARRAYS.length( a ) ) ensureCapacity( size );
if ( size > this.size ) BIG_ARRAYS.fill( a, this.size, size, KEY_NULL );
#if #keys(reference)
else BIG_ARRAYS.fill( a, size, this.size, KEY_NULL );
#endif
this.size = size;
}
public boolean isEmpty() {
return size == 0;
}
/** Trims this big-array big list so that the capacity is equal to the size.
*
* @see java.util.ArrayList#trimToSize()
*/
public void trim() {
trim( 0 );
}
/** Trims the backing big array if it is too large.
*
* If the current big array length is smaller than or equal to
* This method is useful when reusing big lists. {@linkplain #clear() Clearing a
* big list} leaves the big-array length untouched. If you are reusing a big list
* many times, you can call this method with a typical
* size to avoid keeping around a very large big array just
* because of a few large transient big lists.
*
* @param n the threshold for the trimming.
*/
public void trim( final long n ) {
final long arrayLength = BIG_ARRAYS.length( a );
if ( n >= arrayLength || size == arrayLength ) return;
a = BIG_ARRAYS.trim( a, Math.max( n, size ) );
if ( ASSERTS ) assert size <= BIG_ARRAYS.length( a );
}
/** Copies element of this type-specific list into the given big array using optimized system calls.
*
* @param from the start index (inclusive).
* @param a the destination big array.
* @param offset the offset into the destination array where to store the first element copied.
* @param length the number of elements to be copied.
*/
public void getElements( final int from, final KEY_TYPE[][] a, final long offset, final long length ) {
BIG_ARRAYS.copy( this.a, from, a, offset, length );
}
/** Removes elements of this type-specific list using optimized system calls.
*
* @param from the start index (inclusive).
* @param to the end index (exclusive).
*/
public void removeElements( final int from, final int to ) {
BigArrays.ensureFromTo( size, from, to );
BIG_ARRAYS.copy( a, to, a, from, size - to );
size -= ( to - from );
#if #keys(reference)
BIG_ARRAYS.fill( a, size, size + to - from, null );
#endif
}
/** Adds elements to this type-specific list using optimized system calls.
*
* @param index the index at which to add elements.
* @param a the big array containing the elements.
* @param offset the offset of the first element to add.
* @param length the number of elements to add.
*/
public void addElements( final int index, final KEY_GENERIC_TYPE a[][], final long offset, final long length ) {
ensureIndex( index );
BIG_ARRAYS.ensureOffsetLength( a, offset, length );
grow( size + length );
BIG_ARRAYS.copy( this.a, index, this.a, index + length, size - index );
BIG_ARRAYS.copy( a, offset, this.a, index, length );
size += length;
}
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator( final int index ) {
ensureIndex( index );
return new KEY_ABSTRACT_BIG_LIST_ITERATOR KEY_GENERIC() {
int pos = index, last = -1;
public boolean hasNext() { return pos < size; }
public boolean hasPrevious() { return pos > 0; }
public KEY_GENERIC_TYPE NEXT_KEY() { if ( ! hasNext() ) throw new NoSuchElementException(); return BIG_ARRAYS.get( a, last = pos++ ); }
public KEY_GENERIC_TYPE PREV_KEY() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return BIG_ARRAYS.get( a, last = --pos ); }
public long nextIndex() { return pos; }
public long previousIndex() { return pos - 1; }
public void add( KEY_GENERIC_TYPE k ) {
if ( last == -1 ) throw new IllegalStateException();
BIG_ARRAY_BIG_LIST.this.add( pos++, k );
last = -1;
}
public void set( KEY_GENERIC_TYPE k ) {
if ( last == -1 ) throw new IllegalStateException();
BIG_ARRAY_BIG_LIST.this.set( last, k );
}
public void remove() {
if ( last == -1 ) throw new IllegalStateException();
BIG_ARRAY_BIG_LIST.this.REMOVE_KEY( last );
/* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */
if ( last < pos ) pos--;
last = -1;
}
};
}
public BIG_ARRAY_BIG_LIST KEY_GENERIC clone() {
BIG_ARRAY_BIG_LIST KEY_GENERIC c = new BIG_ARRAY_BIG_LIST KEY_GENERIC( size );
BIG_ARRAYS.copy( a, 0, c.a, 0, size );
c.size = size;
return c;
}
#if #keyclass(Object)
private boolean valEquals( final K a, final K b ) {
return a == null ? b == null : a.equals( b );
}
#endif
/** Compares this type-specific big-array list to another one.
*
* This method exists only for sake of efficiency. The implementation
* inherited from the abstract implementation would already work.
*
* @param l a type-specific big-array list.
* @return true if the argument contains the same elements of this type-specific big-array list.
*/
public boolean equals( final BIG_ARRAY_BIG_LIST KEY_GENERIC l ) {
if ( l == this ) return true;
long s = size64();
if ( s != l.size64() ) return false;
final KEY_GENERIC_TYPE[][] a1 = a;
final KEY_GENERIC_TYPE[][] a2 = l.a;
#if #keyclass(Object)
while( s-- != 0 ) if ( ! valEquals( BIG_ARRAYS.get( a1, s ), BIG_ARRAYS.get( a2, s ) ) ) return false;
#else
while( s-- != 0 ) if ( BIG_ARRAYS.get( a1, s ) != BIG_ARRAYS.get( a2, s ) ) return false;
#endif
return true;
}
#if ! #keyclass(Reference)
/** Compares this big list to another big list.
*
* This method exists only for sake of efficiency. The implementation
* inherited from the abstract implementation would already work.
*
* @param l a big list.
* @return a negative integer,
* zero, or a positive integer as this big list is lexicographically less than, equal
* to, or greater than the argument.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public int compareTo( final BIG_ARRAY_BIG_LIST KEY_EXTENDS_GENERIC l ) {
final long s1 = size64(), s2 = l.size64();
final KEY_GENERIC_TYPE a1[][] = a, a2[][] = l.a;
KEY_GENERIC_TYPE e1, e2;
int r, i;
for( i = 0; i < s1 && i < s2; i++ ) {
e1 = BIG_ARRAYS.get( a1, i );
e2 = BIG_ARRAYS.get( a2, i );
if ( ( r = KEY_CMP( e1, e2 ) ) != 0 ) return r;
}
return i < s2 ? -1 : ( i < s1 ? 1 : 0 );
}
#endif
private void writeObject( java.io.ObjectOutputStream s ) throws java.io.IOException {
s.defaultWriteObject();
for( int i = 0; i < size; i++ ) s.WRITE_KEY( BIG_ARRAYS.get( a, i ) );
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
private void readObject( java.io.ObjectInputStream s ) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
a = KEY_GENERIC_BIG_ARRAY_CAST BIG_ARRAYS.newBigArray( size );
for( int i = 0; i < size; i++ ) BIG_ARRAYS.set( a, i, KEY_GENERIC_CAST s.READ_KEY() );
}
#ifdef TEST
private static long seed = System.currentTimeMillis();
private static java.util.Random r = new java.util.Random( seed );
private static KEY_TYPE genKey() {
#if #keyclass(Byte) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#elif #keyclass(Object)
return Integer.toBinaryString( r.nextInt() );
#else
return new java.io.Serializable() {};
#endif
}
private static java.text.NumberFormat format = new java.text.DecimalFormat( "#,###.00" );
private static java.text.FieldPosition p = new java.text.FieldPosition( 0 );
private static String format( double d ) {
StringBuffer s = new StringBuffer();
return format.format( d, s, p ).toString();
}
private static void speedTest( int n, boolean comp ) {
System.out.println( "There are presently no speed tests for this class." );
}
private static void fatal( String msg ) {
System.out.println( msg );
System.exit( 1 );
}
private static void ensure( boolean cond, String msg ) {
if ( cond ) return;
fatal( msg );
}
private static Object[] k, v, nk;
private static KEY_TYPE kt[];
private static KEY_TYPE nkt[];
private static BIG_ARRAY_BIG_LIST topList;
protected static void testLists( BIG_LIST m, BIG_LIST t, int n, int level ) {
long ms;
Exception mThrowsIllegal, tThrowsIllegal, mThrowsOutOfBounds, tThrowsOutOfBounds;
Object rt = null;
KEY_TYPE rm = KEY_NULL;
if ( level > 4 ) return;
/* Now we check that both sets agree on random keys. For m we use the polymorphic method. */
for( int i = 0; i < n; i++ ) {
int p = r.nextInt() % ( n * 2 );
KEY_TYPE T = genKey();
mThrowsOutOfBounds = tThrowsOutOfBounds = null;
try {
m.set( p, T );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
try {
t.set( p, KEY2OBJ( T ) );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + level + ", " + seed + "): set() divergence at start in IndexOutOfBoundsException for index " + p + " (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
if ( mThrowsOutOfBounds == null ) ensure( t.get( p ).equals( KEY2OBJ( m.GET_KEY( p ) ) ), "Error (" + level + ", " + seed + "): m and t differ after set() on position " + p + " (" + m.GET_KEY( p ) + ", " + t.get( p ) + ")" );
p = r.nextInt() % ( n * 2 );
mThrowsOutOfBounds = tThrowsOutOfBounds = null;
try {
m.GET_KEY( p );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
try {
t.get( p );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + level + ", " + seed + "): get() divergence at start in IndexOutOfBoundsException for index " + p + " (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
if ( mThrowsOutOfBounds == null ) ensure( t.get( p ).equals( KEY2OBJ( m.GET_KEY( p ) ) ), "Error (" + level + ", " + seed + "): m and t differ aftre get() on position " + p + " (" + m.GET_KEY( p ) + ", " + t.get( p ) + ")" );
}
/* Now we check that both sets agree on random keys. For m we use the standard method. */
for( int i = 0; i < n; i++ ) {
int p = r.nextInt() % ( n * 2 );
mThrowsOutOfBounds = tThrowsOutOfBounds = null;
try {
m.get( p );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
try {
t.get( p );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + level + ", " + seed + "): get() divergence at start in IndexOutOfBoundsException for index " + p + " (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
if ( mThrowsOutOfBounds == null ) ensure( t.get( p ).equals( m.get( p ) ), "Error (" + level + ", " + seed + "): m and t differ at start on position " + p + " (" + m.get( p ) + ", " + t.get( p ) + ")" );
}
/* Now we check that m and t are equal. */
if ( !m.equals( t ) || ! t.equals( m ) ) System.err.println("m: " + m + " t: " + t);
ensure( m.equals( t ), "Error (" + level + ", " + seed + "): ! m.equals( t ) at start" );
ensure( t.equals( m ), "Error (" + level + ", " + seed + "): ! t.equals( m ) at start" );
/* Now we check that m actually holds that data. */
for(Iterator i=t.iterator(); i.hasNext(); ) {
ensure( m.contains( i.next() ), "Error (" + level + ", " + seed + "): m and t differ on an entry after insertion (iterating on t)" );
}
/* Now we check that m actually holds that data, but iterating on m. */
for(Iterator i=m.listIterator(); i.hasNext(); ) {
ensure( t.contains( i.next() ), "Error (" + level + ", " + seed + "): m and t differ on an entry after insertion (iterating on m)" );
}
/* Now we check that inquiries about random data give the same answer in m and t. For
m we use the polymorphic method. */
for(int i=0; i In particular, the Note that {@link it.unimi.dsi.fastutil.io.BinIO} and {@link it.unimi.dsi.fastutil.io.TextIO}
* contain several methods that make it possible to load and save big arrays of primitive types as sequences
* of elements in {@link java.io.DataInput} format (i.e., not as objects) or as sequences of lines of text.
*
* @see BigArrays
*/
public class BIG_ARRAYS {
#else
import java.util.Comparator;
/** A class providing static methods and objects that do useful things with {@linkplain BigArrays big arrays}.
*
* In particular, the Note that {@link it.unimi.dsi.fastutil.io.BinIO} and {@link it.unimi.dsi.fastutil.io.TextIO}
* contain several methods make it possible to load and save big arrays of primitive types as sequences
* of elements in {@link java.io.DataInput} format (i.e., not as objects) or as sequences of lines of text.
*
* Warning: creating arrays
* using {@linkplain java.lang.reflect.Array#newInstance(Class,int) reflection}, as it
* happens in {@link #ensureCapacity(Object[][],long,long)} and {@link #grow(Object[][],long,long)},
* is significantly slower than using This method returns a new big array of the given length whose element
* are of the same class as of those of This method returns a new big array whose segments
* are of class Note that the returned big array might contain as a segment the original array.
*
* @param array an array.
* @return a new big array with the same length and content of Note that the returned big array might contain as a segment the original array.
*
* @param array an array.
* @return a new big array with the same length and content of If you cannot foresee whether this big array will need again to be
* enlarged, you should probably use Warning: the returned array might use part of the segments of the original
* array, which must be considered read-only after calling this method.
*
* @param array a big array.
* @param length the new minimum length for this big array.
* @return This method returns a new big array of the given length whose element
* are of the same class as of those of Warning: the returned array might use part of the segments of the original
* array, which must be considered read-only after calling this method.
*
* @param array a big array.
* @param length the new minimum length for this big array.
* @param preserve the number of elements of the big array that must be preserved in case a new allocation is necessary.
* @return Warning: the returned array might use part of the segments of the original
* array, which must be considered read-only after calling this method.
*
* @param array a big array.
* @param length the new minimum length for this big array.
* @param preserve the number of elements of the big array that must be preserved in case a new allocation is necessary.
* @return If you want complete control on the big array growth, you
* should probably use Warning: the returned array might use part of the segments of the original
* array, which must be considered read-only after calling this method.
*
* @param array a big array.
* @param length the new minimum length for this big array.
* @return If you want complete control on the big array growth, you
* should probably use Warning: the returned array might use part of the segments of the original
* array, which must be considered read-only after calling this method.
*
* @param array a big array.
* @param length the new minimum length for this big array.
* @param preserve the number of elements of the big array that must be preserved in case a new allocation is necessary.
* @return Warning: the returned array might use part of the segments of the original
* array, which must be considered read-only after calling this method.
*
* @param array a big array.
* @param length the new maximum length for the big array.
* @return Warning: the returned array might use part of the segments of the original
* array, which must be considered read-only after calling this method.
*
* @param array a big array.
* @param length the new maximum length for the big array.
* @return Warning: the returned array might use part of the segments of the original
* array, which must be considered read-only after calling this method.
*
* @param array a big array.
* @param length the new length for the big array.
* @return This method uses a backward loop. It is significantly faster than the corresponding
* method in {@link java.util.Arrays}.
*
* @param array a big array.
* @param value the new value for all elements of the big array.
*/
public static KEY_GENERIC void fill( final KEY_GENERIC_TYPE[][] array, final KEY_GENERIC_TYPE value ) {
for( int i = array.length; i-- != 0; ) Arrays.fill( array[ i ], value );
}
/** Fills a portion of the given big array with the given value.
*
* If possible (i.e., This method uses a backward loop. It is significantly faster than the corresponding
* method in {@link java.util.Arrays}.
*
* @param a1 a big array.
* @param a2 another big array.
* @return true if the two big arrays are of the same length, and their elements are equal.
*/
public static KEY_GENERIC boolean equals( final KEY_GENERIC_TYPE[][] a1, final KEY_GENERIC_TYPE a2[][] ) {
if ( length( a1 ) != length( a2 ) ) return false;
int i = a1.length, j;
KEY_GENERIC_TYPE[] t, u;
while( i-- != 0 ) {
t = a1[ i ];
u = a2[ i ];
j = t.length;
while( j-- != 0 ) if (! KEY_EQUALS( t[ j ], u[ j ] ) ) return false;
}
return true;
}
/* Returns a string representation of the contents of the specified big array.
*
* The string representation consists of a list of the big array's elements, enclosed in square brackets ("[]"). Adjacent elements are separated by the characters ", " (a comma followed by a space). Returns "null" if This method may be used whenever a big array range check is needed.
*
* @param a a big array.
* @param from a start index (inclusive).
* @param to an end index (inclusive).
* @throws IllegalArgumentException if This method may be used whenever a big array range check is needed.
*
* @param a a big array.
* @param offset a start index.
* @param length a length (the number of elements in the range).
* @throws IllegalArgumentException if This hash strategy may be used in custom hash collections whenever keys are
* big arrays, and they must be considered equal by content. This strategy
* will handle The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* @param x the big array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
* @param comp the comparator to determine the sorting order.
*/
public static KEY_GENERIC void quickSort( final KEY_GENERIC_TYPE[][] x, final long from, final long to, final KEY_COMPARATOR KEY_GENERIC comp ) {
final long len = to - from;
// Selection sort on smallest arrays
if ( len < SMALL ) {
selectionSort( x, from, to, comp );
return;
}
// Choose a partition element, v
long m = from + len / 2; // Small arrays, middle element
if ( len > SMALL ) {
long l = from;
long n = to - 1;
if ( len > MEDIUM ) { // Big arrays, pseudomedian of 9
long s = len / 8;
l = med3( x, l, l + s, l + 2 * s, comp );
m = med3( x, m - s, m, m + s, comp );
n = med3( x, n - 2 * s, n - s, n, comp );
}
m = med3( x, l, m, n, comp ); // Mid-size, med of 3
}
final KEY_GENERIC_TYPE v = get( x, m );
// Establish Invariant: v* ( The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* @param x the big array to be sorted.
* @param comp the comparator to determine the sorting order.
*
*/
public static KEY_GENERIC void quickSort( final KEY_GENERIC_TYPE[][] x, final KEY_COMPARATOR KEY_GENERIC comp ) {
quickSort( x, 0, BIG_ARRAYS.length( x ), comp );
}
/** Sorts the specified range of elements according to the natural ascending order using quicksort.
*
* The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* @param x the big array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static KEY_GENERIC void quickSort( final KEY_GENERIC_TYPE[][] x, final long from, final long to ) {
final long len = to - from;
// Selection sort on smallest arrays
if ( len < SMALL ) {
selectionSort( x, from, to );
return;
}
// Choose a partition element, v
long m = from + len / 2; // Small arrays, middle element
if ( len > SMALL ) {
long l = from;
long n = to - 1;
if ( len > MEDIUM ) { // Big arrays, pseudomedian of 9
long s = len / 8;
l = med3( x, l, l + s, l + 2 * s );
m = med3( x, m - s, m, m + s );
n = med3( x, n - 2 * s, n - s, n );
}
m = med3( x, l, m, n ); // Mid-size, med of 3
}
final KEY_GENERIC_TYPE v = get( x, m );
// Establish Invariant: v* ( The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
* McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages
* 1249−1265, 1993.
*
* @param x the big array to be sorted.
*/
public static KEY_GENERIC void quickSort( final KEY_GENERIC_TYPE[][] x ) {
quickSort( x, 0, BIG_ARRAYS.length( x ) );
}
#if ! #keyclass(Boolean)
/**
* Searches a range of the specified big array for the specified value using
* the binary search algorithm. The range must be sorted prior to making this call.
* If it is not sorted, the results are undefined. If the range contains multiple elements with
* the specified value, there is no guarantee which one will be found.
*
* @param a the big array to be searched.
* @param from the index of the first element (inclusive) to be searched.
* @param to the index of the last element (exclusive) to be searched.
* @param key the value to be searched for.
* @return index of the search key, if it is contained in the big array;
* otherwise, (-(insertion point) - 1). The insertion
* point is defined as the the point at which the value would
* be inserted into the big array: the index of the first
* element greater than the key, or the length of the big array, if all
* elements in the big array are less than the specified key. Note
* that this guarantees that the return value will be >= 0 if
* and only if the key is found.
* @see java.util.Arrays
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static KEY_GENERIC long binarySearch( final KEY_GENERIC_TYPE[][] a, long from, long to, final KEY_GENERIC_TYPE key ) {
KEY_GENERIC_TYPE midVal;
to--;
while (from <= to) {
final long mid = (from + to) >>> 1;
midVal = get( a, mid );
#if #keys(primitive)
if (midVal < key) from = mid + 1;
else if (midVal > key) to = mid - 1;
else return mid;
#else
final int cmp = ((Comparable KEY_SUPER_GENERIC)midVal).compareTo( key );
if ( cmp < 0 ) from = mid + 1;
else if (cmp > 0) to = mid - 1;
else return mid;
#endif
}
return -( from + 1 );
}
/**
* Searches a big array for the specified value using
* the binary search algorithm. The range must be sorted prior to making this call.
* If it is not sorted, the results are undefined. If the range contains multiple elements with
* the specified value, there is no guarantee which one will be found.
*
* @param a the big array to be searched.
* @param key the value to be searched for.
* @return index of the search key, if it is contained in the big array;
* otherwise, (-(insertion point) - 1). The insertion
* point is defined as the the point at which the value would
* be inserted into the big array: the index of the first
* element greater than the key, or the length of the big array, if all
* elements in the big array are less than the specified key. Note
* that this guarantees that the return value will be >= 0 if
* and only if the key is found.
* @see java.util.Arrays
*/
public static KEY_GENERIC long binarySearch( final KEY_GENERIC_TYPE[][] a, final KEY_TYPE key ) {
return binarySearch( a, 0, BIG_ARRAYS.length( a ), key );
}
/**
* Searches a range of the specified big array for the specified value using
* the binary search algorithm and a specified comparator. The range must be sorted following the comparator prior to making this call.
* If it is not sorted, the results are undefined. If the range contains multiple elements with
* the specified value, there is no guarantee which one will be found.
*
* @param a the big array to be searched.
* @param from the index of the first element (inclusive) to be searched.
* @param to the index of the last element (exclusive) to be searched.
* @param key the value to be searched for.
* @param c a comparator.
* @return index of the search key, if it is contained in the big array;
* otherwise, (-(insertion point) - 1). The insertion
* point is defined as the the point at which the value would
* be inserted into the big array: the index of the first
* element greater than the key, or the length of the big array, if all
* elements in the big array are less than the specified key. Note
* that this guarantees that the return value will be >= 0 if
* and only if the key is found.
* @see java.util.Arrays
*/
public static KEY_GENERIC long binarySearch( final KEY_GENERIC_TYPE[][] a, long from, long to, final KEY_GENERIC_TYPE key, final KEY_COMPARATOR KEY_GENERIC c ) {
KEY_GENERIC_TYPE midVal;
to--;
while (from <= to) {
final long mid = (from + to) >>> 1;
midVal = get( a, mid );
final int cmp = c.compare( midVal, key );
if ( cmp < 0 ) from = mid + 1;
else if (cmp > 0) to = mid - 1;
else return mid; // key found
}
return -( from + 1 );
}
/**
* Searches a big array for the specified value using
* the binary search algorithm and a specified comparator. The range must be sorted following the comparator prior to making this call.
* If it is not sorted, the results are undefined. If the range contains multiple elements with
* the specified value, there is no guarantee which one will be found.
*
* @param a the big array to be searched.
* @param key the value to be searched for.
* @param c a comparator.
* @return index of the search key, if it is contained in the big array;
* otherwise, (-(insertion point) - 1). The insertion
* point is defined as the the point at which the value would
* be inserted into the big array: the index of the first
* element greater than the key, or the length of the big array, if all
* elements in the big array are less than the specified key. Note
* that this guarantees that the return value will be >= 0 if
* and only if the key is found.
* @see java.util.Arrays
*/
public static KEY_GENERIC long binarySearch( final KEY_GENERIC_TYPE[][] a, final KEY_GENERIC_TYPE key, final KEY_COMPARATOR KEY_GENERIC c ) {
return binarySearch( a, 0, BIG_ARRAYS.length( a ), key, c );
}
#if #keys(primitive)
/** The size of a digit used during radix sort (must be a power of 2). */
private static final int DIGIT_BITS = 8;
/** The mask to extract a digit of {@link #DIGIT_BITS} bits. */
private static final int DIGIT_MASK = ( 1 << DIGIT_BITS ) - 1;
/** The number of digits per element. */
private static final int DIGITS_PER_ELEMENT = KEY_CLASS.SIZE / DIGIT_BITS;
/** This method fixes negative numbers so that the combination exponent/significand is lexicographically sorted. */
#if #keyclass(Double)
private static final long fixDouble( final double d ) {
final long l = Double.doubleToRawLongBits( d );
return l >= 0 ? l : l ^ 0x7FFFFFFFFFFFFFFFL;
}
#elif #keyclass(Float)
private static final long fixFloat( final float f ) {
final long i = Float.floatToRawIntBits( f );
return i >= 0 ? i : i ^ 0x7FFFFFFF;
}
#endif
/** Sorts the specified big array using radix sort.
*
* The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993),
* and further improved using the digit-oracle idea described by
* Juha Kärkkäinen and Tommi Rantala in “Engineering radix sort for strings”,
* String Processing and Information Retrieval, 15th International Symposium, volume 5280 of
* Lecture Notes in Computer Science, pages 3−14, Springer (2008).
*
* This implementation is significantly faster than quicksort
* already at small sizes (say, more than 10000 elements), but it can only
* sort in ascending order.
* It will allocate a support array of bytes with the same number of elements as the array to be sorted.
*
* @param a the big array to be sorted.
*/
public static void radixSort( final KEY_TYPE[][] a ) {
radixSort( a, 0, BIG_ARRAYS.length( a ) );
}
/** Sorts the specified big array using radix sort.
*
* The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993),
* and further improved using the digit-oracle idea described by
* Juha Kärkkäinen and Tommi Rantala in “Engineering radix sort for strings”,
* String Processing and Information Retrieval, 15th International Symposium, volume 5280 of
* Lecture Notes in Computer Science, pages 3−14, Springer (2008).
*
* This implementation is significantly faster than quicksort
* already at small sizes (say, more than 10000 elements), but it can only
* sort in ascending order.
* It will allocate a support array of bytes with the same number of elements as the array to be sorted.
*
* @param a the big array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
public static void radixSort( final KEY_TYPE[][] a, final long from, final long to ) {
final int maxLevel = DIGITS_PER_ELEMENT - 1;
final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( DIGITS_PER_ELEMENT - 1 ) + 1;
final long[] offsetStack = new long[ stackSize ];
int offsetPos = 0;
final long[] lengthStack = new long[ stackSize ];
int lengthPos = 0;
final int[] levelStack = new int[ stackSize ];
int levelPos = 0;
offsetStack[ offsetPos++ ] = from;
lengthStack[ lengthPos++ ] = to - from;
levelStack[ levelPos++ ] = 0;
final long[] count = new long[ 1 << DIGIT_BITS ];
final long[] pos = new long[ 1 << DIGIT_BITS ];
final byte[][] digit = ByteBigArrays.newBigArray( to - from );
while( offsetPos > 0 ) {
final long first = offsetStack[ --offsetPos ];
final long length = lengthStack[ --lengthPos ];
final int level = levelStack[ --levelPos ];
#if #keyclass(Character)
final int signMask = 0;
#else
final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif
if ( length < MEDIUM ) {
selectionSort( a, first, first + length );
continue;
}
final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key
// Count keys.
for( long i = length; i-- != 0; ) ByteBigArrays.set( digit, i, (byte)( ( ( KEY2LEXINT( BIG_ARRAYS.get( a, first + i ) ) >>> shift ) & DIGIT_MASK ) ^ signMask ));
for( long i = length; i-- != 0; ) count[ ByteBigArrays.get( digit, i ) & 0xFF ]++;
// Compute cumulative distribution and push non-singleton keys on stack.
int lastUsed = -1;
long p = 0;
for( int i = 0; i < 1 << DIGIT_BITS; i++ ) {
if ( count[ i ] != 0 ) {
lastUsed = i;
if ( level < maxLevel && count[ i ] > 1 ){
//System.err.println( " Pushing " + new StackEntry( first + pos[ i - 1 ], first + pos[ i ], level + 1 ) );
offsetStack[ offsetPos++ ] = p + first;
lengthStack[ lengthPos++ ] = count[ i ];
levelStack[ levelPos++ ] = level + 1;
}
}
pos[ i ] = ( p += count[ i ] );
}
// When all slots are OK, the last slot is necessarily OK.
final long end = length - count[ lastUsed ];
count[ lastUsed ] = 0;
// i moves through the start of each block
int c = -1;
for( long i = 0, d; i < end; i += count[ c ], count[ c ] = 0 ) {
KEY_TYPE t = BIG_ARRAYS.get( a, i +first );
c = ByteBigArrays.get( digit, i ) & 0xFF;
while( ( d = --pos[ c ] ) > i ) {
final KEY_TYPE z = t;
final int zz = c;
t = BIG_ARRAYS.get( a, d + first );
c = ByteBigArrays.get( digit, d ) & 0xFF;
BIG_ARRAYS.set( a, d + first, z );
ByteBigArrays.set( digit, d, (byte)zz );
}
BIG_ARRAYS.set( a, i + first, t );
}
}
}
private static void selectionSort( final KEY_TYPE[][] a, final KEY_TYPE[][] b, final long from, final long to ) {
for( long i = from; i < to - 1; i++ ) {
long m = i;
for( long j = i + 1; j < to; j++ )
if ( KEY_LESS( BIG_ARRAYS.get( a, j ), BIG_ARRAYS.get( a, m ) ) || KEY_CMP_EQ( BIG_ARRAYS.get( a, j ), BIG_ARRAYS.get( a, m ) ) && KEY_LESS( BIG_ARRAYS.get( b, j ), BIG_ARRAYS.get( b, m ) ) ) m = j;
if ( m != i ) {
KEY_TYPE t = BIG_ARRAYS.get( a, i );
BIG_ARRAYS.set( a, i, BIG_ARRAYS.get( a, m ) );
BIG_ARRAYS.set( a, m, t );
t = BIG_ARRAYS.get( b, i );
BIG_ARRAYS.set( b, i, BIG_ARRAYS.get( b, m ) );
BIG_ARRAYS.set( b, m, t );
}
}
}
/** Sorts the specified pair of big arrays lexicographically using radix sort.
* The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993),
* and further improved using the digit-oracle idea described by
* Juha Kärkkäinen and Tommi Rantala in “Engineering radix sort for strings”,
* String Processing and Information Retrieval, 15th International Symposium, volume 5280 of
* Lecture Notes in Computer Science, pages 3−14, Springer (2008).
*
* This method implements a lexicographical sorting of the arguments. Pairs of elements
* in the same position in the two provided arrays will be considered a single key, and permuted
* accordingly. In the end, either This implementation is significantly faster than quicksort
* already at small sizes (say, more than 10000 elements), but it can only
* sort in ascending order. It will allocate a support array of bytes with the same number of elements as the arrays to be sorted.
*
* @param a the first big array to be sorted.
* @param b the second big array to be sorted.
*/
public static void radixSort( final KEY_TYPE[][] a, final KEY_TYPE[][] b ) {
radixSort( a, b, 0, BIG_ARRAYS.length( a ) );
}
/** Sorts the specified pair of big arrays lexicographically using radix sort.
*
* The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
* McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993),
* and further improved using the digit-oracle idea described by
* Juha Kärkkäinen and Tommi Rantala in “Engineering radix sort for strings”,
* String Processing and Information Retrieval, 15th International Symposium, volume 5280 of
* Lecture Notes in Computer Science, pages 3−14, Springer (2008).
*
* This method implements a lexicographical sorting of the arguments. Pairs of elements
* in the same position in the two provided arrays will be considered a single key, and permuted
* accordingly. In the end, either This implementation is significantly faster than quicksort
* already at small sizes (say, more than 10000 elements), but it can only
* sort in ascending order. It will allocate a support array of bytes with the same number of elements as the arrays to be sorted.
*
* @param a the first big array to be sorted.
* @param b the second big array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
public static void radixSort( final KEY_TYPE[][] a, final KEY_TYPE[][] b, final long from, final long to ) {
final int layers = 2;
if ( BIG_ARRAYS.length( a ) != BIG_ARRAYS.length( b ) ) throw new IllegalArgumentException( "Array size mismatch." );
final int maxLevel = DIGITS_PER_ELEMENT * layers - 1;
final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( layers * DIGITS_PER_ELEMENT - 1 ) + 1;
final long[] offsetStack = new long[ stackSize ];
int offsetPos = 0;
final long[] lengthStack = new long[ stackSize ];
int lengthPos = 0;
final int[] levelStack = new int[ stackSize ];
int levelPos = 0;
offsetStack[ offsetPos++ ] = from;
lengthStack[ lengthPos++ ] = to - from;
levelStack[ levelPos++ ] = 0;
final long[] count = new long[ 1 << DIGIT_BITS ];
final long[] pos = new long[ 1 << DIGIT_BITS ];
final byte[][] digit = ByteBigArrays.newBigArray( to - from );
while( offsetPos > 0 ) {
final long first = offsetStack[ --offsetPos ];
final long length = lengthStack[ --lengthPos ];
final int level = levelStack[ --levelPos ];
#if #keyclass(Character)
final int signMask = 0;
#else
final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif
if ( length < MEDIUM ) {
selectionSort( a, b, first, first + length );
continue;
}
final KEY_TYPE[][] k = level < DIGITS_PER_ELEMENT ? a : b; // This is the key array
final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key
// Count keys.
for( long i = length; i-- != 0; ) ByteBigArrays.set( digit, i, (byte)( ( ( KEY2LEXINT( BIG_ARRAYS.get( k, first + i ) ) >>> shift ) & DIGIT_MASK ) ^ signMask ) );
for( long i = length; i-- != 0; ) count[ ByteBigArrays.get( digit, i ) & 0xFF ]++;
// Compute cumulative distribution and push non-singleton keys on stack.
int lastUsed = -1;
long p = 0;
for( int i = 0; i < 1 << DIGIT_BITS; i++ ) {
if ( count[ i ] != 0 ) {
lastUsed = i;
if ( level < maxLevel && count[ i ] > 1 ){
offsetStack[ offsetPos++ ] = p + first;
lengthStack[ lengthPos++ ] = count[ i ];
levelStack[ levelPos++ ] = level + 1;
}
}
pos[ i ] = ( p += count[ i ] );
}
// When all slots are OK, the last slot is necessarily OK.
final long end = length - count[ lastUsed ];
count[ lastUsed ] = 0;
// i moves through the start of each block
int c = -1;
for( long i = 0, d; i < end; i += count[ c ], count[ c ] = 0 ) {
KEY_TYPE t = BIG_ARRAYS.get( a, i + first );
KEY_TYPE u = BIG_ARRAYS.get( b, i + first );
c = ByteBigArrays.get( digit, i ) & 0xFF;
while( ( d = --pos[ c ] ) > i ) {
KEY_TYPE z = t;
final int zz = c;
t = BIG_ARRAYS.get( a, d + first );
BIG_ARRAYS.set( a, d + first, z );
z = u;
u = BIG_ARRAYS.get( b, d + first );
BIG_ARRAYS.set( b, d + first, z );
c = ByteBigArrays.get( digit, d ) & 0xFF;
ByteBigArrays.set( digit, d, (byte)zz );
}
BIG_ARRAYS.set( a, i + first, t );
BIG_ARRAYS.set( b, i + first, u );
}
}
}
#endif
#endif
/** Shuffles the specified big array fragment using the specified pseudorandom number generator.
*
* @param a the big array to be shuffled.
* @param from the index of the first element (inclusive) to be shuffled.
* @param to the index of the last element (exclusive) to be shuffled.
* @param random a pseudorandom number generator (please use a XorShift* generator).
* @return Additionally, this interface strengthens {@link #iterator()}, {@link #listIterator()},
* {@link #listIterator(long)} and {@link #subList(long,long)}.
*
* Besides polymorphic methods, this interfaces specifies methods to copy into an array or remove contiguous
* sublists. Although the abstract implementation of this interface provides simple, one-by-one implementations
* of these methods, it is expected that concrete implementation override them with optimized versions.
*
* @see List
*/
public interface BIG_LIST KEY_GENERIC extends BigList Additionally, this interface strengthens {@link #iterator()}, {@link #listIterator()},
* {@link #listIterator(long)} and {@link #subList(long,long)}.
*
* Besides polymorphic methods, this interfaces specifies methods to copy into an array or remove contiguous
* sublists. Although the abstract implementation of this interface provides simple, one-by-one implementations
* of these methods, it is expected that concrete implementation override them with optimized versions.
*
* @see List
*/
public interface BIG_LIST KEY_GENERIC extends BigList Note that this specification strengthens the one given in {@link BigList#subList(long,long)}.
*
* @see BigList#subList(long,long)
*/
BIG_LIST KEY_GENERIC subList( long from, long to );
/** Copies (hopefully quickly) elements of this type-specific big list into the given big array.
*
* @param from the start index (inclusive).
* @param a the destination big array.
* @param offset the offset into the destination big array where to store the first element copied.
* @param length the number of elements to be copied.
*/
void getElements( long from, KEY_TYPE a[][], long offset, long length );
/** Removes (hopefully quickly) elements of this type-specific big list.
*
* @param from the start index (inclusive).
* @param to the end index (exclusive).
*/
void removeElements( long from, long to );
/** Add (hopefully quickly) elements to this type-specific big list.
*
* @param index the index at which to add elements.
* @param a the big array containing the elements.
*/
void addElements( long index, KEY_GENERIC_TYPE a[][] );
/** Add (hopefully quickly) elements to this type-specific big list.
*
* @param index the index at which to add elements.
* @param a the big array containing the elements.
* @param offset the offset of the first element to add.
* @param length the number of elements to add.
*/
void addElements( long index, KEY_GENERIC_TYPE a[][], long offset, long length );
#if #keys(primitive)
/**
* @see List#add(int,Object)
*/
void add( long index, KEY_TYPE key );
/**
* @see List#addAll(int,java.util.Collection)
*/
boolean addAll( long index, COLLECTION c );
/**
* @see List#addAll(int,java.util.Collection)
*/
boolean addAll( long index, BIG_LIST c );
/**
* @see List#addAll(int,java.util.Collection)
*/
boolean addAll( BIG_LIST c );
/**
* @see BigList#get(long)
*/
KEY_TYPE GET_KEY( long index );
/**
* @see BigList#indexOf(Object)
*/
long indexOf( KEY_TYPE k );
/**
* @see BigList#lastIndexOf(Object)
*/
long lastIndexOf( KEY_TYPE k );
/**
* @see BigList#remove(long)
*/
KEY_TYPE REMOVE_KEY( long index );
/**
* @see BigList#set(long,Object)
*/
KEY_TYPE set( long index, KEY_TYPE k );
#endif
} fastutil-7.0.2/drv/BigListIterator.drv 0000644 0000000 0000000 00000002111 12502261336 016544 0 ustar root wheel /*
* Copyright (C) 2010-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import it.unimi.dsi.fastutil.BigListIterator;
/** A type-specific {@link BigListIterator}.
*
* This interface adds a skipping method that take longs.
*
* @see BigListIterator
*/
public interface KEY_BIG_LIST_ITERATOR KEY_GENERIC extends KEY_BIDI_ITERATOR KEY_GENERIC, BigListIterator This class may be useful to implement your own in case you subclass
* a type-specific iterator.
*/
public static class EmptyBigListIterator KEY_GENERIC extends KEY_ABSTRACT_BIG_LIST_ITERATOR KEY_GENERIC implements java.io.Serializable, Cloneable {
private static final long serialVersionUID = -7046029254386353129L;
protected EmptyBigListIterator() {}
public boolean hasNext() { return false; }
public boolean hasPrevious() { return false; }
public KEY_GENERIC_TYPE NEXT_KEY() { throw new NoSuchElementException(); }
public KEY_GENERIC_TYPE PREV_KEY() { throw new NoSuchElementException(); }
public long nextIndex() { return 0; }
public long previousIndex() { return -1; }
public long skip( long n ) { return 0; };
public long back( long n ) { return 0; };
public Object clone() { return EMPTY_BIG_LIST_ITERATOR; }
private Object readResolve() { return EMPTY_BIG_LIST_ITERATOR; }
}
/** An empty iterator (immutable). It is serializable and cloneable.
*
* The class of this objects represent an abstract empty iterator
* that can iterate as a type-specific (list) iterator.
*/
SUPPRESS_WARNINGS_KEY_RAWTYPES
public final static EmptyBigListIterator EMPTY_BIG_LIST_ITERATOR = new EmptyBigListIterator();
/** An iterator returning a single element. */
private static class SingletonBigListIterator KEY_GENERIC extends KEY_ABSTRACT_BIG_LIST_ITERATOR KEY_GENERIC {
private final KEY_GENERIC_TYPE element;
private int curr;
public SingletonBigListIterator( final KEY_GENERIC_TYPE element ) {
this.element = element;
}
public boolean hasNext() { return curr == 0; }
public boolean hasPrevious() { return curr == 1; }
public KEY_GENERIC_TYPE NEXT_KEY() {
if ( ! hasNext() ) throw new NoSuchElementException();
curr = 1;
return element;
}
public KEY_GENERIC_TYPE PREV_KEY() {
if ( ! hasPrevious() ) throw new NoSuchElementException();
curr = 0;
return element;
}
public long nextIndex() {
return curr;
}
public long previousIndex() {
return curr - 1;
}
}
/** Returns an iterator that iterates just over the given element.
*
* @param element the only element to be returned by a type-specific list iterator.
* @return an iterator that iterates just over This class may be useful to implement your own in case you subclass
* a type-specific list.
*/
public static class EmptyBigList KEY_GENERIC extends COLLECTIONS.EmptyCollection KEY_GENERIC implements BIG_LIST KEY_GENERIC, java.io.Serializable, Cloneable {
private static final long serialVersionUID = -7046029254386353129L;
protected EmptyBigList() {}
public void add( final long index, final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public boolean add( final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_TYPE REMOVE_KEY( long i ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_TYPE set( final long index, final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public long indexOf( KEY_TYPE k ) { return -1; }
public long lastIndexOf( KEY_TYPE k ) { return -1; }
public boolean addAll( Collection extends KEY_GENERIC_CLASS> c ) { throw new UnsupportedOperationException(); }
public boolean addAll( long i, Collection extends KEY_GENERIC_CLASS> c ) { throw new UnsupportedOperationException(); }
public boolean removeAll( Collection> c ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_CLASS get( long i ) { throw new IndexOutOfBoundsException(); }
#if #keys(primitive)
public boolean addAll( COLLECTION c ) { throw new UnsupportedOperationException(); }
public boolean addAll( BIG_LIST c ) { throw new UnsupportedOperationException(); }
public boolean addAll( long i, COLLECTION c ) { throw new UnsupportedOperationException(); }
public boolean addAll( long i, BIG_LIST c ) { throw new UnsupportedOperationException(); }
public void add( final long index, final KEY_GENERIC_CLASS k ) { throw new UnsupportedOperationException(); }
public boolean add( final KEY_GENERIC_CLASS k ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_CLASS set( final long index, final KEY_GENERIC_CLASS k ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_TYPE GET_KEY( long i ) { throw new IndexOutOfBoundsException(); }
public KEY_GENERIC_CLASS remove( long k ) { throw new UnsupportedOperationException(); }
public long indexOf( Object k ) { return -1; }
public long lastIndexOf( Object k ) { return -1; }
#else
public boolean remove( Object k ) { throw new UnsupportedOperationException(); }
#endif
SUPPRESS_WARNINGS_KEY_UNCHECKED
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator() { return BIG_LIST_ITERATORS.EMPTY_BIG_LIST_ITERATOR; }
SUPPRESS_WARNINGS_KEY_UNCHECKED
public KEY_BIG_LIST_ITERATOR KEY_GENERIC iterator() { return BIG_LIST_ITERATORS.EMPTY_BIG_LIST_ITERATOR; }
SUPPRESS_WARNINGS_KEY_UNCHECKED
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator( long i ) { if ( i == 0 ) return BIG_LIST_ITERATORS.EMPTY_BIG_LIST_ITERATOR; throw new IndexOutOfBoundsException( String.valueOf( i ) ); }
public BIG_LIST KEY_GENERIC subList( long from, long to ) { if ( from == 0 && to == 0 ) return this; throw new IndexOutOfBoundsException(); }
public void getElements( long from, KEY_TYPE[][] a, long offset, long length ) { BIG_ARRAYS.ensureOffsetLength( a, offset, length ); if ( from != 0 ) throw new IndexOutOfBoundsException(); }
public void removeElements( long from, long to ) { throw new UnsupportedOperationException(); }
public void addElements( long index, final KEY_GENERIC_TYPE a[][], long offset, long length ) { throw new UnsupportedOperationException(); }
public void addElements( long index, final KEY_GENERIC_TYPE a[][] ) { throw new UnsupportedOperationException(); }
public void size( long s ) { throw new UnsupportedOperationException(); }
public long size64() { return 0; }
public int compareTo( final BigList extends KEY_GENERIC_CLASS> o ) {
if ( o == this ) return 0;
return ((BigList>)o).isEmpty() ? 0 : -1;
}
private Object readResolve() { return EMPTY_BIG_LIST; }
public Object clone() { return EMPTY_BIG_LIST; }
}
/** An empty big list (immutable). It is serializable and cloneable.
*
* The class of this objects represent an abstract empty list
* that is a sublist of any type of list. Thus, {@link #EMPTY_BIG_LIST}
* may be assigned to a variable of any (sorted) type-specific list.
*/
SUPPRESS_WARNINGS_KEY_RAWTYPES
public static final EmptyBigList EMPTY_BIG_LIST = new EmptyBigList();
/** An immutable class representing a type-specific singleton big list.
*
* This class may be useful to implement your own in case you subclass
* a type-specific big list.
*/
public static class Singleton KEY_GENERIC extends ABSTRACT_BIG_LIST KEY_GENERIC implements java.io.Serializable, Cloneable {
private static final long serialVersionUID = -7046029254386353129L;
private final KEY_GENERIC_TYPE element;
private Singleton( final KEY_GENERIC_TYPE element ) {
this.element = element;
}
public KEY_GENERIC_TYPE GET_KEY( final long i ) { if ( i == 0 ) return element; throw new IndexOutOfBoundsException(); }
public KEY_GENERIC_TYPE REMOVE_KEY( final long i ) { throw new UnsupportedOperationException(); }
public boolean contains( final KEY_TYPE k ) { return KEY_EQUALS( k, element ); }
public boolean addAll( final Collection extends KEY_GENERIC_CLASS> c ) { throw new UnsupportedOperationException(); }
public boolean addAll( final long i, final Collection extends KEY_GENERIC_CLASS> c ) { throw new UnsupportedOperationException(); }
public boolean removeAll( final Collection> c ) { throw new UnsupportedOperationException(); }
public boolean retainAll( final Collection> c ) { throw new UnsupportedOperationException(); }
/* Slightly optimized w.r.t. the one in ABSTRACT_SET. */
public KEY_TYPE[] TO_KEY_ARRAY() {
KEY_TYPE a[] = new KEY_TYPE[ 1 ];
a[ 0 ] = element;
return a;
}
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator() { return BIG_LIST_ITERATORS.singleton( element ); }
public KEY_BIG_LIST_ITERATOR KEY_GENERIC iterator() { return listIterator(); }
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator( long i ) {
if ( i > 1 || i < 0 ) throw new IndexOutOfBoundsException();
KEY_BIG_LIST_ITERATOR KEY_GENERIC l = listIterator();
if ( i == 1 ) l.next();
return l;
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
public BIG_LIST KEY_GENERIC subList( final long from, final long to ) {
ensureIndex( from );
ensureIndex( to );
if ( from > to ) throw new IndexOutOfBoundsException( "Start index (" + from + ") is greater than end index (" + to + ")" );
if ( from != 0 || to != 1 ) return EMPTY_BIG_LIST;
return this;
}
@Deprecated
public int size() { return 1; }
public long size64() { return 1; }
public void size( final long size ) { throw new UnsupportedOperationException(); }
public void clear() { throw new UnsupportedOperationException(); }
public Object clone() { return this; }
#if #keys(primitive)
public boolean rem( final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public boolean addAll( final COLLECTION c ) { throw new UnsupportedOperationException(); }
public boolean addAll( final long i, final COLLECTION c ) { throw new UnsupportedOperationException(); }
#else
public boolean remove( Object k ) { throw new UnsupportedOperationException(); }
#endif
}
/** Returns a type-specific immutable big list containing only the specified element. The returned big list is serializable and cloneable.
*
* @param element the only element of the returned big list.
* @return a type-specific immutable big list containing just This class fills some gaps in the Java API. First of all, you have two
* buffered, easy-to-use methods to {@linkplain #storeObject(Object,CharSequence) store an object to a file}
* or {@linkplain #loadObject(CharSequence) load an object from a file},
* and two
* buffered, easy-to-use methods to {@linkplain #storeObject(Object,OutputStream) store an object to an output stream}
* or to {@linkplain #loadObject(InputStream) load an object from an input stream}.
*
* Second, a natural operation on sequences of primitive elements is to load or
* store them in binary form using the {@link DataInput} conventions. This
* method is much more flexible than storing arrays as objects, as it allows
* for partial load, partial store, and makes it easy to read the
* resulting files from other languages.
*
* For each primitive type, this class provides methods that read elements
* from a {@link DataInput} or from a filename into an array. Analogously, there are
* methods that store the content of an array (fragment) or the elements
* returned by an iterator to a {@link DataOutput} or to a given filename. Files
* are buffered using {@link FastBufferedInputStream} and {@link FastBufferedOutputStream}.
*
* Since bytes can be read from or written to any stream, additional methods
* makes it possible to {@linkplain #loadBytes(InputStream,byte[]) load bytes from} and
* {@linkplain #storeBytes(byte[],OutputStream) store bytes to} a stream. Such methods
* use the bulk-read methods of {@link InputStream} and {@link OutputStream}, but they
* also include a workaround for bug #6478546.
*
* Finally, there are useful wrapper methods that {@linkplain #asIntIterator(CharSequence)
* exhibit a file as a type-specific iterator}.
*
* @since 4.4
*/
public class BinIO {
private BinIO() {}
/** Stores an object in a file given by a {@link File} object.
*
* @param o an object.
* @param file a file.
* @see #loadObject(File)
*/
public static void storeObject( final Object o, final File file ) throws IOException {
final ObjectOutputStream oos = new ObjectOutputStream( new FastBufferedOutputStream( new FileOutputStream( file ) ) );
oos.writeObject( o );
oos.close();
}
/** Stores an object in a file given by a pathname.
*
* @param o an object.
* @param filename a filename.
* @see #loadObject(CharSequence)
*/
public static void storeObject( final Object o, final CharSequence filename ) throws IOException {
storeObject( o, new File( filename.toString() ) );
}
/** Loads an object from a file given by a {@link File} object.
*
* @param file a file.
* @return the object stored under the given file.
* @see #storeObject(Object, File)
*/
public static Object loadObject( final File file ) throws IOException, ClassNotFoundException {
final ObjectInputStream ois = new ObjectInputStream( new FastBufferedInputStream( new FileInputStream( file ) ) );
final Object result = ois.readObject();
ois.close();
return result;
}
/** Loads an object from a file given by a pathname.
*
* @param filename a filename.
* @return the object stored under the given filename.
* @see #storeObject(Object, CharSequence)
*/
public static Object loadObject( final CharSequence filename ) throws IOException, ClassNotFoundException {
return loadObject( new File( filename.toString() ) );
}
/** Stores an object in a given output stream.
*
* This methods buffers Warning: this method buffers the input stream. As a consequence,
* subsequent reads from the same stream may not give the desired results, as bytes
* may have been read by the internal buffer, but not used by Note that this method is going to be significantly faster than {@link #loadBytes(DataInput,byte[],int,int)}
* as it uses {@link InputStream}'s bulk-read methods.
*
* @param inputStream an input stream.
* @param array an array which will be filled with data from Note that this method is going to be significantly faster than {@link #loadBytes(DataInput,byte[])}
* as it uses {@link InputStream}'s bulk-read methods.
*
* @param inputStream an input stream.
* @param array an array which will be filled with data from Note that this method is going to be significantly faster than {@link #storeBytes(byte[],int,int,DataOutput)}
* as it uses {@link OutputStream}'s bulk-read methods.
*
* @param array an array whose elements will be written to Note that this method is going to be significantly faster than {@link #storeBytes(byte[],DataOutput)}
* as it uses {@link OutputStream}'s bulk-read methods.
*
* @param array an array whose elements will be written to Note that this method is going to be significantly faster than {@link #loadBytes(DataInput,byte[][],long,long)}
* as it uses {@link InputStream}'s bulk-read methods.
*
* @param inputStream an input stream.
* @param array a big array which will be filled with data from Note that this method is going to be significantly faster than {@link #loadBytes(DataInput,byte[][])}
* as it uses {@link InputStream}'s bulk-read methods.
*
* @param inputStream an input stream.
* @param array a big array which will be filled with data from Note that this method is going to be significantly faster than {@link #storeBytes(byte[][],long,long,DataOutput)}
* as it uses {@link OutputStream}'s bulk-read methods.
*
* @param array a big array whose elements will be written to Note that this method is going to be significantly faster than {@link #storeBytes(byte[][],DataOutput)}
* as it uses {@link OutputStream}'s bulk-read methods.
*
* @param array a big array whose elements will be written to Note that the length of the returned array will be computed
* dividing the specified file size by the number of bytes used to
* represent each element.
*
* @param file a file.
* @return an array filled with the content of the specified file.
*/
public static KEY_TYPE[] LOAD_KEYS( final File file ) throws IOException {
final FileInputStream fis = new FileInputStream( file );
#if #keyclass(Boolean)
final long length = fis.getChannel().size();
#else
final long length = fis.getChannel().size() / ( KEY_CLASS.SIZE / 8 );
#endif
if ( length > Integer.MAX_VALUE ) {
fis.close();
throw new IllegalArgumentException( "File too long: " + fis.getChannel().size()+ " bytes (" + length + " elements)" );
}
final KEY_TYPE[] array = new KEY_TYPE[ (int)length ];
#if #keyclass(Byte)
if ( read( fis, array, 0, (int)length ) < length ) throw new EOFException();
fis.close();
#else
final DataInputStream dis = new DataInputStream( new FastBufferedInputStream( fis ) );
for( int i = 0; i < length; i++ ) array[ i ] = dis.READ_KEY();
dis.close();
#endif
return array;
}
/** Loads elements from a file given by a filename, storing them in a new array.
*
* Note that the length of the returned array will be computed
* dividing the specified file size by the number of bytes used to
* represent each element.
*
* @param filename a filename.
* @return an array filled with the content of the specified file.
*/
public static KEY_TYPE[] LOAD_KEYS( final CharSequence filename ) throws IOException {
return LOAD_KEYS( new File( filename.toString() ) );
}
/** Stores an array fragment to a given data output.
*
* @param array an array whose elements will be written to Note that the length of the returned big array will be computed
* dividing the specified file size by the number of bytes used to
* represent each element.
*
* @param file a file.
* @return a big array filled with the content of the specified file.
*/
public static KEY_TYPE[][] LOAD_KEYS_BIG( final File file ) throws IOException {
final FileInputStream fis = new FileInputStream( file );
#if #keyclass(Boolean)
final long length = fis.getChannel().size();
#else
final long length = fis.getChannel().size() / ( KEY_CLASS.SIZE / 8 );
#endif
final KEY_TYPE[][] array = BIG_ARRAYS.newBigArray( length );
#if #keyclass(Byte)
if ( read( fis, array, 0, length ) < length ) throw new EOFException();
fis.close();
#else
final DataInputStream dis = new DataInputStream( new FastBufferedInputStream( fis ) );
for( int i = 0; i < array.length; i++ ) {
final KEY_TYPE[] t = array[ i ];
final int l = t.length;
for( int d = 0; d < l; d++ ) t[ d ] = dis.READ_KEY();
}
dis.close();
#endif
return array;
}
/** Loads elements from a file given by a filename, storing them in a new big array.
*
* Note that the length of the returned big array will be computed
* dividing the specified file size by the number of bytes used to
* represent each element.
*
* @param filename a filename.
* @return a big array filled with the content of the specified file.
*/
public static KEY_TYPE[][] LOAD_KEYS_BIG( final CharSequence filename ) throws IOException {
return LOAD_KEYS_BIG( new File( filename.toString() ) );
}
/** Stores an array fragment to a given data output.
*
* @param array an array whose elements will be written to Additionally, this class defines strengthens (again) {@link #iterator()} and defines
* a slightly different semantics for {@link #toArray(Object[])}.
*
* @see Collection
*/
public interface COLLECTION KEY_GENERIC extends Collection Note that this specification strengthens the one given in
* {@link java.lang.Iterable#iterator()}, which was already
* strengthened in the corresponding type-specific class,
* but was weakened by the fact that this interface extends {@link Collection}.
*
* @return a type-specific iterator on the elements of this collection.
*/
KEY_ITERATOR KEY_GENERIC iterator();
/** Returns a type-specific iterator on this elements of this collection.
*
* @see #iterator()
* @deprecated As of Warning: Note that, contrarily to {@link Collection#toArray(Object[])}, this
* methods just writes all elements of this collection: no special
* value will be added after the last one.
*
* @param a if this array is big enough, it will be used to store this collection.
* @return a primitive type array containing the items of this collection.
* @see Collection#toArray(Object[])
*/
Note that, contrarily to {@link Collection#toArray(Object[])}, this
* methods just writes all elements of this collection: no special
* value will be added after the last one.
*
* @param a if this array is big enough, it will be used to store this collection.
* @return a primitive type array containing the items of this collection.
* @see Collection#toArray(Object[])
*/
KEY_TYPE[] TO_KEY_ARRAY( KEY_TYPE a[] );
/** Returns a primitive type array containing the items of this collection.
*
* Note that, contrarily to {@link Collection#toArray(Object[])}, this
* methods just writes all elements of this collection: no special
* value will be added after the last one.
*
* @param a if this array is big enough, it will be used to store this collection.
* @return a primitive type array containing the items of this collection.
* @see Collection#toArray(Object[])
*/
KEY_TYPE[] toArray( KEY_TYPE a[] );
/**
* @see Collection#add(Object)
*/
boolean add( KEY_TYPE key );
/** Note that this method should be called {@link java.util.Collection#remove(Object) remove()}, but the clash
* with the similarly named index-based method in the {@link java.util.List} interface
* forces us to use a distinguished name. For simplicity, the set interfaces reinstates
* This class may be useful to implement your own in case you subclass
* a type-specific collection.
*/
public abstract static class EmptyCollection KEY_GENERIC extends ABSTRACT_COLLECTION KEY_GENERIC {
protected EmptyCollection() {}
public boolean add( KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public boolean contains( KEY_TYPE k ) { return false; }
public Object[] toArray() { return ObjectArrays.EMPTY_ARRAY; }
#if #keys(primitive)
public KEY_TYPE[] TO_KEY_ARRAY( KEY_TYPE[] a ) { return a; }
public KEY_TYPE[] TO_KEY_ARRAY() { return ARRAYS.EMPTY_ARRAY; }
public boolean rem( KEY_TYPE k ) { throw new UnsupportedOperationException(); }
public boolean addAll( COLLECTION c ) { throw new UnsupportedOperationException(); }
public boolean removeAll( COLLECTION c ) { throw new UnsupportedOperationException(); }
public boolean retainAll( COLLECTION c ) { throw new UnsupportedOperationException(); }
public boolean containsAll( COLLECTION c ) { return c.isEmpty(); }
#else
public boolean remove( final Object k ) { throw new UnsupportedOperationException(); }
public Note that Type-specific versions of For uniformity reasons, even maps returning objects implement the default
* return value (of course, in this case the default return value is
* initialized to Warning: to fall in line as much as possible with the
* {@linkplain java.util.Map standard map interface}, it is strongly suggested
* that standard versions of This class may be useful to implement your own in case you subclass
* a type-specific function.
*/
public static class EmptyFunction KEY_VALUE_GENERIC extends ABSTRACT_FUNCTION KEY_VALUE_GENERIC implements java.io.Serializable, Cloneable {
private static final long serialVersionUID = -7046029254386353129L;
protected EmptyFunction() {}
public VALUE_GENERIC_TYPE GET_VALUE( final KEY_TYPE k ) { return VALUE_NULL; }
public boolean containsKey( final KEY_TYPE k ) { return false; }
public VALUE_GENERIC_TYPE defaultReturnValue() { return VALUE_NULL; }
public void defaultReturnValue( final VALUE_GENERIC_TYPE defRetValue ) { throw new UnsupportedOperationException(); }
#if #keys(primitive)
public VALUE_GENERIC_CLASS get( final Object k ) { return null; }
#endif
public int size() { return 0; }
public void clear() {}
private Object readResolve() { return EMPTY_FUNCTION; }
public Object clone() { return EMPTY_FUNCTION; }
}
/** An empty type-specific function (immutable). It is serializable and cloneable. */
SUPPRESS_WARNINGS_KEY_VALUE_RAWTYPES
public static final EmptyFunction EMPTY_FUNCTION = new EmptyFunction();
/** An immutable class representing a type-specific singleton function.
*
* This class may be useful to implement your own in case you subclass
* a type-specific function.
*/
public static class Singleton KEY_VALUE_GENERIC extends ABSTRACT_FUNCTION KEY_VALUE_GENERIC implements java.io.Serializable, Cloneable {
private static final long serialVersionUID = -7046029254386353129L;
protected final KEY_GENERIC_TYPE key;
protected final VALUE_GENERIC_TYPE value;
protected Singleton( final KEY_GENERIC_TYPE key, final VALUE_GENERIC_TYPE value ) {
this.key = key;
this.value = value;
}
public boolean containsKey( final KEY_TYPE k ) { return KEY_EQUALS( key, k ); }
public VALUE_GENERIC_TYPE GET_VALUE( final KEY_TYPE k ) { if ( KEY_EQUALS( key, k ) ) return value; return defRetValue; }
public int size() { return 1; }
public Object clone() { return this; }
}
/** Returns a type-specific immutable function containing only the specified pair. The returned function is serializable and cloneable.
*
* Note that albeit the returned function is immutable, its default return value may be changed.
*
* @param key the only key of the returned function.
* @param value the only value of the returned function.
* @return a type-specific immutable function containing just the pair Note that albeit the returned function is immutable, its default return value may be changed.
*
* @param key the only key of the returned function.
* @param value the only value of the returned function.
* @return a type-specific immutable function containing just the pair Instances of this class are based on two indirect
* heap-based queues. The queues are enlarged as needed, but they are never
* shrunk. Use the {@link #trim()} method to reduce their size, if necessary.
*
* Either comparator may be This constructor uses as secondary comparator the opposite order of This constructor uses as secondary comparator the opposite of the natural order.
*
* @param refArray the reference array.
* @param capacity the initial capacity of this queue.
*/
public HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity ) {
this( refArray, capacity, null );
}
/** Creates a new empty queue with capacity equal to the length of the reference array.
*
* @param refArray the reference array.
* @param c the primary comparator used in this queue, or This constructor uses as secondary comparator the opposite order of This constructor uses as secondary comparator the opposite of the natural order.
*
* @param refArray the reference array.
*/
public HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray ) {
this( refArray, refArray.length, null );
}
/** Wraps a given array in a queue using the given comparators.
*
* The queue returned by this method will be backed by the given array.
* The first The queue returned by this method will be backed by the given array.
* The first elements of the array will be rearranged so to form a heap, and
* moreover the array will be cloned and wrapped in a secondary queue (this is
* more efficient than enqueing the elements of The queue returned by this method will be backed by the given array.
* The first This constructor uses as secondary comparator the opposite order of The queue returned by this method will be backed by the given array.
* The elements of the array will be rearranged so to form a heap, and
* moreover the array will be cloned and wrapped in a secondary queue (this is
* more efficient than enqueing the elements of This constructor uses as secondary comparator the opposite order of The queue returned by this method will be backed by the given array.
* The first This constructor uses as secondary comparator the opposite of the natural order.
*
* @param refArray the reference array.
* @param a an array of indices into The queue returned by this method will be backed by the given array.
* The elements of the array will be rearranged so to form a heap, and
* moreover the array will be cloned and wrapped in a secondary queue (this is
* more efficient than enqueing the elements of This constructor uses as secondary comparator the opposite of the natural order.
*
* @param refArray the reference array.
* @param a an array of indices into Instances of this class use an additional inversion array, of the same length of the reference array,
* to keep track of the heap position containing a given element of the reference array. The priority queue is
* represented using a heap. The heap is enlarged as needed, but it is never
* shrunk. Use the {@link #trim()} method to reduce its size, if necessary.
*
* This implementation does not allow one to enqueue several times the same index.
*/
public class HEAP_INDIRECT_PRIORITY_QUEUE KEY_GENERIC extends HEAP_SEMI_INDIRECT_PRIORITY_QUEUE KEY_GENERIC {
/** The inversion array. */
protected final int inv[];
/** Creates a new empty queue with a given capacity and comparator.
*
* @param refArray the reference array.
* @param capacity the initial capacity of this queue.
* @param c the comparator used in this queue, or The queue returned by this method will be backed by the given array.
* The first The queue returned by this method will be backed by the given array.
* The elements of the array will be rearranged so to form a heap (this is
* more efficient than enqueing the elements of The queue returned by this method will be backed by the given array.
* The first The queue returned by this method will be backed by the given array.
* The elements of the array will be rearranged so to form a heap (this is
* more efficient than enqueing the elements of Instances of this class represent a priority queue using a heap. The heap is enlarged as needed, but
* it is never shrunk. Use the {@link #trim()} method to reduce its size, if necessary.
*/
public class HEAP_PRIORITY_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KEY_GENERIC {
/** The heap array. */
SUPPRESS_WARNINGS_KEY_UNCHECKED
protected KEY_GENERIC_TYPE[] heap = KEY_GENERIC_ARRAY_CAST ARRAYS.EMPTY_ARRAY;
/** The number of elements in this queue. */
protected int size;
/** The type-specific comparator used in this queue. */
protected KEY_COMPARATOR KEY_SUPER_GENERIC c;
/** Creates a new empty queue with a given capacity and comparator.
*
* @param capacity the initial capacity of this queue.
* @param c the comparator used in this queue, or The queue returned by this method will be backed by the given array.
* The first The queue returned by this method will be backed by the given array.
* The elements of the array will be rearranged so to form a heap (this is
* more efficient than enqueing the elements of The queue returned by this method will be backed by the given array.
* The first The queue returned by this method will be backed by the given array.
* The elements of the array will be rearranged so to form a heap (this is
* more efficient than enqueing the elements of Instances of this class use as reference list a reference array,
* which must be provided to each constructor. The priority queue is
* represented using a heap. The heap is enlarged as needed, but it is never
* shrunk. Use the {@link #trim()} method to reduce its size, if necessary.
*
* This implementation allows one to enqueue several time the same index, but
* you must be careful when calling {@link #changed()}.
*/
public class HEAP_SEMI_INDIRECT_PRIORITY_QUEUE KEY_GENERIC extends AbstractIndirectPriorityQueue The queue returned by this method will be backed by the given array.
* The first The queue returned by this method will be backed by the given array.
* The elements of the array will be rearranged so to form a heap (this is
* more efficient than enqueing the elements of The queue returned by this method will be backed by the given array.
* The first The queue returned by this method will be backed by the given array.
* The elements of the array will be rearranged so to form a heap (this is
* more efficient than enqueing the elements of The caller must guarantee that when this method is called the
* index of the first element appears just once in the queue. Failure to do so
* will bring the queue in an inconsistent state, and will cause
* unpredictable behaviour.
*/
public void changed() {
SEMI_INDIRECT_HEAPS.downHeap( refArray, heap, size, 0, c );
}
/** Rebuilds this heap in a bottom-up fashion.
*/
public void allChanged() {
SEMI_INDIRECT_HEAPS.makeHeap( refArray, heap, size, c );
}
public int size() { return size; }
public void clear() { size = 0; }
/** Trims the backing array so that it has exactly {@link #size()} elements.
*/
public void trim() {
heap = IntArrays.trim( heap, size );
}
public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() { return c; }
public int front( final int[] a ) {
return c == null ? SEMI_INDIRECT_HEAPS.front( refArray, heap, size, a ) : SEMI_INDIRECT_HEAPS.front( refArray, heap, size, a, c );
}
public String toString() {
StringBuffer s = new StringBuffer();
s.append( "[" );
for ( int i = 0; i < size; i++ ) {
if ( i != 0 ) s.append( ", " );
s.append( refArray[ heap [ i ] ] );
}
s.append( "]" );
return s.toString();
}
#ifdef TEST
/** The original class, now just used for testing. */
private static class TestQueue {
/** The reference array */
private KEY_TYPE refArray[];
/** Its length */
private int N;
/** The number of elements in the heaps */
private int n;
/** The two comparators */
private KEY_COMPARATOR primaryComp, secondaryComp;
/** Two indirect heaps are used, called Instances of this class are based on a semi-indirect and an indirect
* heap-based queues. The queues are enlarged as needed, but they are never
* shrunk. Use the {@link #trim()} method to reduce their size, if necessary.
*
* Either comparator may be This constructor uses as secondary comparator the opposite order of This constructor uses as secondary comparator the opposite of the natural order.
*
* @param refArray the reference array.
* @param capacity the initial capacity of this queue.
*/
public HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity ) {
this( refArray, capacity, null );
}
/** Creates a new empty queue with capacity equal to the length of the reference array.
*
* @param refArray the reference array.
* @param c the primary comparator used in this queue, or This constructor uses as secondary comparator the opposite order of This constructor uses as secondary comparator the opposite of the natural order.
*
* @param refArray the reference array.
*/
public HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray ) {
this( refArray, refArray.length, null );
}
/** Wraps a given array in a queue using the given comparators.
*
* The queue returned by this method will be backed by the given array.
* The first The queue returned by this method will be backed by the given array.
* The first elements of the array will be rearranged so to form a heap, and
* moreover the array will be cloned and wrapped in a secondary queue (this is
* more efficient than enqueing the elements of The queue returned by this method will be backed by the given array.
* The first This constructor uses as secondary comparator the opposite order of The queue returned by this method will be backed by the given array.
* The elements of the array will be rearranged so to form a heap, and
* moreover the array will be cloned and wrapped in a secondary queue (this is
* more efficient than enqueing the elements of This constructor uses as secondary comparator the opposite order of The queue returned by this method will be backed by the given array.
* The first This constructor uses as secondary comparator the opposite of the natural order.
*
* @param refArray the reference array.
* @param a an array of indices into The queue returned by this method will be backed by the given array.
* The elements of the array will be rearranged so to form a heap, and
* moreover the array will be cloned and wrapped in a secondary queue (this is
* more efficient than enqueing the elements of This constructor uses as secondary comparator the opposite of the natural order.
*
* @param refArray the reference array.
* @param a an array of indices into The static methods of this class allow to treat arrays as 0-based heaps. They
* are used in the implementation of heap-based queues, but they may be also used
* directly.
*
*/
public class HEAPS {
private HEAPS() {}
/** Moves the given element down into the heap until it reaches the lowest possible position.
*
* @param heap the heap (starting at 0).
* @param size the number of elements in the heap.
* @param i the index of the element that must be moved down.
* @param c a type-specific comparator, or Additionally, this interface strengthens {@link #comparator()}.
*/
public interface INDIRECT_DOUBLE_PRIORITY_QUEUE extends INDIRECT_PRIORITY_QUEUE, IndirectDoublePriorityQueue An indirect heap is an extension of a semi-indirect heap using also an
* inversion array of the same length as the reference array,
* satisfying the relation Additionally, this interface strengthens {@link #comparator()}.
*/
public interface INDIRECT_PRIORITY_QUEUE extends IndirectPriorityQueue Warning: Java will let you write “colon” The effect of this call is exactly the same as that of
* calling {@link #next()} for This class may be useful to implement your own in case you subclass
* a type-specific iterator.
*/
public static class EmptyIterator KEY_GENERIC extends KEY_ABSTRACT_LIST_ITERATOR KEY_GENERIC implements java.io.Serializable, Cloneable {
private static final long serialVersionUID = -7046029254386353129L;
protected EmptyIterator() {}
public boolean hasNext() { return false; }
public boolean hasPrevious() { return false; }
public KEY_GENERIC_TYPE NEXT_KEY() { throw new NoSuchElementException(); }
public KEY_GENERIC_TYPE PREV_KEY() { throw new NoSuchElementException(); }
public int nextIndex() { return 0; }
public int previousIndex() { return -1; }
public int skip( int n ) { return 0; };
public int back( int n ) { return 0; };
public Object clone() { return EMPTY_ITERATOR; }
private Object readResolve() { return EMPTY_ITERATOR; }
}
/** An empty iterator (immutable). It is serializable and cloneable.
*
* The class of this objects represent an abstract empty iterator
* that can iterate as a type-specific (list) iterator.
*/
SUPPRESS_WARNINGS_KEY_RAWTYPES
public final static EmptyIterator EMPTY_ITERATOR = new EmptyIterator();
/** An iterator returning a single element. */
private static class SingletonIterator KEY_GENERIC extends KEY_ABSTRACT_LIST_ITERATOR KEY_GENERIC {
private final KEY_GENERIC_TYPE element;
private int curr;
public SingletonIterator( final KEY_GENERIC_TYPE element ) {
this.element = element;
}
public boolean hasNext() { return curr == 0; }
public boolean hasPrevious() { return curr == 1; }
public KEY_GENERIC_TYPE NEXT_KEY() {
if ( ! hasNext() ) throw new NoSuchElementException();
curr = 1;
return element;
}
public KEY_GENERIC_TYPE PREV_KEY() {
if ( ! hasPrevious() ) throw new NoSuchElementException();
curr = 0;
return element;
}
public int nextIndex() {
return curr;
}
public int previousIndex() {
return curr - 1;
}
}
/** Returns an iterator that iterates just over the given element.
*
* @param element the only element to be returned by a type-specific list iterator.
* @return an iterator that iterates just over The type-specific list iterator returned by this method will iterate
* The type-specific list iterator returned by this method will return
* all elements of the given array.
*
* @param array an array to wrap into a type-specific list iterator.
* @return an iterator that will the elements of This method iterates over the given type-specific iterator and stores the elements
* returned, up to a maximum of This method iterates over the given type-specific iterator and stores the
* elements returned in the given array. The iteration will stop when the
* iterator has no more elements or when the end of the array has been reached.
*
* @param i a type-specific iterator.
* @param array an array to contain the output of the iterator.
* @return the number of elements unwrapped.
*/
public static KEY_GENERIC int unwrap( final STD_KEY_ITERATOR KEY_EXTENDS_GENERIC i, final KEY_GENERIC_TYPE array[] ) {
return unwrap( i, array, 0, array.length );
}
/** Unwraps an iterator, returning an array, with a limit on the number of elements.
*
* This method iterates over the given type-specific iterator and returns an array
* containing the elements returned by the iterator. At most This method iterates over the given type-specific iterator and returns an array
* containing the elements returned by the iterator.
*
* @param i a type-specific iterator.
* @return an array containing the elements returned by the iterator.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[] unwrap( final STD_KEY_ITERATOR KEY_EXTENDS_GENERIC i ) {
return unwrap( i, Integer.MAX_VALUE );
}
/** Unwraps an iterator into a type-specific collection, with a limit on the number of elements.
*
* This method iterates over the given type-specific iterator and stores the elements
* returned, up to a maximum of This method iterates over the given type-specific iterator and stores the
* elements returned in the given type-specific collection. The returned count on the number
* unwrapped elements is a long, so that it will work also with very large collections.
*
* @param i a type-specific iterator.
* @param c a type-specific collection to contain the output of the iterator.
* @return the number of elements unwrapped. Note that
* this is the number of elements returned by the iterator, which is not necessarily the number
* of elements that have been added to the collection (because of duplicates).
*/
public static KEY_GENERIC long unwrap( final STD_KEY_ITERATOR KEY_GENERIC i, final COLLECTION KEY_SUPER_GENERIC c ) {
long n = 0;
while( i.hasNext() ) {
c.add( i.NEXT_KEY() );
n++;
}
return n;
}
/** Pours an iterator into a type-specific collection, with a limit on the number of elements.
*
* This method iterates over the given type-specific iterator and adds
* the returned elements to the given collection (up to This method iterates over the given type-specific iterator and adds
* the returned elements to the given collection.
*
* @param i a type-specific iterator.
* @param s a type-specific collection.
* @return the number of elements poured. Note that
* this is the number of elements returned by the iterator, which is not necessarily the number
* of elements that have been added to the collection (because of duplicates).
*/
public static KEY_GENERIC int pour( final STD_KEY_ITERATOR KEY_GENERIC i, final COLLECTION KEY_SUPER_GENERIC s ) {
return pour( i, s, Integer.MAX_VALUE );
}
/** Pours an iterator, returning a type-specific list, with a limit on the number of elements.
*
* This method iterates over the given type-specific iterator and returns
* a type-specific list containing the returned elements (up to This method iterates over the given type-specific iterator and returns
* a list containing the returned elements. Iteration
* on the returned list is guaranteed to produce the elements in the same order
* in which they appeared in the iterator.
*
* @param i a type-specific iterator.
* @return a type-specific list containing the returned elements.
*/
public static KEY_GENERIC LIST KEY_GENERIC pour( final STD_KEY_ITERATOR KEY_GENERIC i ) {
return pour( i, Integer.MAX_VALUE );
}
private static class IteratorWrapper KEY_GENERIC extends KEY_ABSTRACT_ITERATOR KEY_GENERIC {
final Iterator This method wraps a standard iterator into a type-specific one which will handle the
* type conversions for you. Of course, any attempt to wrap an iterator returning the
* instances of the wrong class will generate a {@link ClassCastException}. The
* returned iterator is backed by If This method wraps a standard list iterator into a type-specific one
* which will handle the type conversions for you. Of course, any attempt
* to wrap an iterator returning the instances of the wrong class will
* generate a {@link ClassCastException}. The
* returned iterator is backed by If The type-specific bidirectional iterator returned by this method will return the
* elements Note that all other type-specific interval iterator are list
* iterators. Of course, this is not possible with longs as the index
* returned by {@link java.util.ListIterator#nextIndex() nextIndex()}/{@link
* java.util.ListIterator#previousIndex() previousIndex()} would exceed an integer.
*
* @param from the starting element (inclusive).
* @param to the ending element (exclusive).
* @return a type-specific bidirectional iterator enumerating the elements from The type-specific list iterator returned by this method will return the
* elements This method returns an iterator that will enumerate in order the elements returned
* by all iterators contained in the given array.
*
* @param a an array of iterators.
* @return an iterator obtained by concatenation.
*/
public static KEY_GENERIC KEY_ITERATOR KEY_GENERIC concat( final KEY_ITERATOR KEY_EXTENDS_GENERIC a[] ) {
return concat( a, 0, a.length );
}
/** Concatenates a sequence of iterators contained in an array.
*
* This method returns an iterator that will enumerate in order the elements returned
* by Note that this type-specific interface extends {@link Comparable}: it is expected that implementing
* classes perform a lexicographical comparison using the standard operator "less then" for primitive types,
* and the usual {@link Comparable#compareTo(Object) compareTo()} method for objects.
*
* Additionally, this interface strengthens {@link #listIterator()},
* {@link #listIterator(int)} and {@link #subList(int,int)}.
*
* Besides polymorphic methods, this interfaces specifies methods to copy into an array or remove contiguous
* sublists. Although the abstract implementation of this interface provides simple, one-by-one implementations
* of these methods, it is expected that concrete implementation override them with optimized versions.
*
* @see List
*/
public interface LIST KEY_GENERIC extends List Additionally, this interface strengthens {@link #iterator()}, {@link #listIterator()},
* {@link #listIterator(int)} and {@link #subList(int,int)}. The former had been already
* strengthened upstream, but unfortunately {@link List} re-specifies it.
*
* Besides polymorphic methods, this interfaces specifies methods to copy into an array or remove contiguous
* sublists. Although the abstract implementation of this interface provides simple, one-by-one implementations
* of these methods, it is expected that concrete implementation override them with optimized versions.
*
* @see List
*/
public interface LIST KEY_GENERIC extends List Note that this specification strengthens the one given in {@link List#subList(int,int)}.
*
* @see List#subList(int,int)
*/
LIST KEY_GENERIC subList(int from, int to);
/** Sets the size of this list.
*
* If the specified size is smaller than the current size, the last elements are
* discarded. Otherwise, they are filled with 0/ This interface merges the methods provided by a {@link ListIterator} and
* a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator}. Moreover, it provides
* type-specific versions of {@link java.util.ListIterator#add(Object) add()}
* and {@link java.util.ListIterator#set(Object) set()}.
*
* @see java.util.ListIterator
* @see it.unimi.dsi.fastutil.BidirectionalIterator
*/
public interface KEY_LIST_ITERATOR KEY_GENERIC extends ListIterator This class may be useful to implement your own in case you subclass
* a type-specific list.
*/
public static class EmptyList KEY_GENERIC extends COLLECTIONS.EmptyCollection KEY_GENERIC implements LIST KEY_GENERIC, java.io.Serializable, Cloneable {
private static final long serialVersionUID = -7046029254386353129L;
protected EmptyList() {}
public void add( final int index, final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public boolean add( final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_TYPE REMOVE_KEY( int i ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_TYPE set( final int index, final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public int indexOf( KEY_TYPE k ) { return -1; }
public int lastIndexOf( KEY_TYPE k ) { return -1; }
public boolean addAll( Collection extends KEY_GENERIC_CLASS> c ) { throw new UnsupportedOperationException(); }
public boolean addAll( int i, Collection extends KEY_GENERIC_CLASS> c ) { throw new UnsupportedOperationException(); }
public boolean removeAll( Collection> c ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_CLASS get( int i ) { throw new IndexOutOfBoundsException(); }
#if #keys(primitive)
public boolean addAll( COLLECTION c ) { throw new UnsupportedOperationException(); }
public boolean addAll( LIST c ) { throw new UnsupportedOperationException(); }
public boolean addAll( int i, COLLECTION c ) { throw new UnsupportedOperationException(); }
public boolean addAll( int i, LIST c ) { throw new UnsupportedOperationException(); }
public void add( final int index, final KEY_GENERIC_CLASS k ) { throw new UnsupportedOperationException(); }
public boolean add( final KEY_GENERIC_CLASS k ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_CLASS set( final int index, final KEY_GENERIC_CLASS k ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_TYPE GET_KEY( int i ) { throw new IndexOutOfBoundsException(); }
public KEY_GENERIC_CLASS remove( int k ) { throw new UnsupportedOperationException(); }
public int indexOf( Object k ) { return -1; }
public int lastIndexOf( Object k ) { return -1; }
#endif
//SUPPRESS_WARNINGS_KEY_UNCHECKED
//public KEY_ITERATOR KEY_GENERIC iterator( int i ) { if ( i == 0 ) return ITERATORS.EMPTY_ITERATOR; throw new IndexOutOfBoundsException( String.valueOf( i ) ); }
@Deprecated
SUPPRESS_WARNINGS_KEY_UNCHECKED
public KEY_ITERATOR KEY_GENERIC KEY_ITERATOR_METHOD() { return ITERATORS.EMPTY_ITERATOR; }
SUPPRESS_WARNINGS_KEY_UNCHECKED
public KEY_LIST_ITERATOR KEY_GENERIC listIterator() { return ITERATORS.EMPTY_ITERATOR; }
SUPPRESS_WARNINGS_KEY_UNCHECKED
public KEY_LIST_ITERATOR KEY_GENERIC iterator() { return ITERATORS.EMPTY_ITERATOR; }
SUPPRESS_WARNINGS_KEY_UNCHECKED
public KEY_LIST_ITERATOR KEY_GENERIC listIterator( int i ) { if ( i == 0 ) return ITERATORS.EMPTY_ITERATOR; throw new IndexOutOfBoundsException( String.valueOf( i ) ); }
@Deprecated
public KEY_LIST_ITERATOR KEY_GENERIC KEY_LIST_ITERATOR_METHOD() { return listIterator(); }
@Deprecated
public KEY_LIST_ITERATOR KEY_GENERIC KEY_LIST_ITERATOR_METHOD( int i ) { return listIterator( i ); }
public LIST KEY_GENERIC subList( int from, int to ) { if ( from == 0 && to == 0 ) return this; throw new IndexOutOfBoundsException(); }
@Deprecated
public LIST KEY_GENERIC SUBLIST_METHOD( int from, int to ) { return subList( from, to ); }
public void getElements( int from, KEY_TYPE[] a, int offset, int length ) { if ( from == 0 && length == 0 && offset >= 0 && offset <= a.length ) return; throw new IndexOutOfBoundsException(); }
public void removeElements( int from, int to ) { throw new UnsupportedOperationException(); }
public void addElements( int index, final KEY_GENERIC_TYPE a[], int offset, int length ) { throw new UnsupportedOperationException(); }
public void addElements( int index, final KEY_GENERIC_TYPE a[] ) { throw new UnsupportedOperationException(); }
public void size( int s ) { throw new UnsupportedOperationException(); }
public int compareTo( final List extends KEY_GENERIC_CLASS> o ) {
if ( o == this ) return 0;
return ((List>)o).isEmpty() ? 0 : -1;
}
private Object readResolve() { return EMPTY_LIST; }
public Object clone() { return EMPTY_LIST; }
}
/** An empty list (immutable). It is serializable and cloneable.
*
* The class of this objects represent an abstract empty list
* that is a sublist of any type of list. Thus, {@link #EMPTY_LIST}
* may be assigned to a variable of any (sorted) type-specific list.
*/
SUPPRESS_WARNINGS_KEY_RAWTYPES
public static final EmptyList EMPTY_LIST = new EmptyList();
/** An immutable class representing a type-specific singleton list.
*
* This class may be useful to implement your own in case you subclass
* a type-specific list.
*/
public static class Singleton KEY_GENERIC extends ABSTRACT_LIST KEY_GENERIC implements java.io.Serializable, Cloneable {
private static final long serialVersionUID = -7046029254386353129L;
private final KEY_GENERIC_TYPE element;
private Singleton( final KEY_GENERIC_TYPE element ) {
this.element = element;
}
public KEY_GENERIC_TYPE GET_KEY( final int i ) { if ( i == 0 ) return element; throw new IndexOutOfBoundsException(); }
public KEY_GENERIC_TYPE REMOVE_KEY( final int i ) { throw new UnsupportedOperationException(); }
public boolean contains( final KEY_TYPE k ) { return KEY_EQUALS( k, element ); }
public boolean addAll( final Collection extends KEY_GENERIC_CLASS> c ) { throw new UnsupportedOperationException(); }
public boolean addAll( final int i, final Collection extends KEY_GENERIC_CLASS> c ) { throw new UnsupportedOperationException(); }
public boolean removeAll( final Collection> c ) { throw new UnsupportedOperationException(); }
public boolean retainAll( final Collection> c ) { throw new UnsupportedOperationException(); }
/* Slightly optimized w.r.t. the one in ABSTRACT_SET. */
public KEY_TYPE[] TO_KEY_ARRAY() {
KEY_TYPE a[] = new KEY_TYPE[ 1 ];
a[ 0 ] = element;
return a;
}
public KEY_LIST_ITERATOR KEY_GENERIC listIterator() { return ITERATORS.singleton( element ); }
public KEY_LIST_ITERATOR KEY_GENERIC iterator() { return listIterator(); }
public KEY_LIST_ITERATOR KEY_GENERIC listIterator( int i ) {
if ( i > 1 || i < 0 ) throw new IndexOutOfBoundsException();
KEY_LIST_ITERATOR KEY_GENERIC l = listIterator();
if ( i == 1 ) l.next();
return l;
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
public LIST KEY_GENERIC subList( final int from, final int to ) {
ensureIndex( from );
ensureIndex( to );
if ( from > to ) throw new IndexOutOfBoundsException( "Start index (" + from + ") is greater than end index (" + to + ")" );
if ( from != 0 || to != 1 ) return EMPTY_LIST;
return this;
}
public int size() { return 1; }
public void size( final int size ) { throw new UnsupportedOperationException(); }
public void clear() { throw new UnsupportedOperationException(); }
public Object clone() { return this; }
#if #keys(primitive)
public boolean rem( final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public boolean addAll( final COLLECTION c ) { throw new UnsupportedOperationException(); }
public boolean addAll( final int i, final COLLECTION c ) { throw new UnsupportedOperationException(); }
#else
public boolean remove( final Object k ) { throw new UnsupportedOperationException(); }
#endif
}
/** Returns a type-specific immutable list containing only the specified element. The returned list is serializable and cloneable.
*
* @param element the only element of the returned list.
* @return a type-specific immutable list containing just Besides extending the corresponding type-specific {@linkplain it.unimi.dsi.fastutil.Function function}, this interface strengthens {@link #entrySet()},
* {@link #keySet()} and {@link #values()}. Maps returning entry sets of type {@link FastEntrySet} support also fast iteration.
*
* A submap or subset may or may not have an
* independent default return value (which however must be initialized to the
* default return value of the originator).
*
* @see Map
*/
public interface MAP KEY_VALUE_GENERIC extends FUNCTION KEY_VALUE_GENERIC, Map In some cases (e.g., hash-based classes) iteration over an entry set requires the creation
* of a large number of {@link java.util.Map.Entry} objects. Some Note that this specification strengthens the one given in {@link Map#entrySet()}.
*
* @return a set view of the mappings contained in this map.
* @see Map#entrySet()
*/
ObjectSet This method is necessary because there is no inheritance along
* type parameters: it is thus impossible to strengthen {@link #entrySet()}
* so that it returns an {@link it.unimi.dsi.fastutil.objects.ObjectSet}
* of objects of type {@link java.util.Map.Entry} (the latter makes it possible to
* access keys and values with type-specific methods).
*
* @return a type-specific set view of the mappings contained in this map.
* @see #entrySet()
*/
ObjectSet Note that this specification strengthens the one given in {@link Map#keySet()}.
*
* @return a set view of the keys contained in this map.
* @see Map#keySet()
*/
SET KEY_GENERIC keySet();
/** Returns a set view of the values contained in this map.
* Note that this specification strengthens the one given in {@link Map#values()}.
*
* @return a set view of the values contained in this map.
* @see Map#values()
*/
VALUE_COLLECTION VALUE_GENERIC values();
#if #values(primitive)
/**
* @see Map#containsValue(Object)
*/
boolean containsValue( VALUE_TYPE value );
#endif
/** A type-specific {@link java.util.Map.Entry}; provides some additional methods
* that use polymorphism to avoid (un)boxing.
*
* @see java.util.Map.Entry
*/
interface Entry KEY_VALUE_GENERIC extends Map.Entry This class may be useful to implement your own in case you subclass
* a type-specific map.
*/
public static class EmptyMap KEY_VALUE_GENERIC extends FUNCTIONS.EmptyFunction KEY_VALUE_GENERIC implements MAP KEY_VALUE_GENERIC, java.io.Serializable, Cloneable {
private static final long serialVersionUID = -7046029254386353129L;
protected EmptyMap() {}
public boolean containsValue( final VALUE_TYPE v ) { return false; }
public void putAll( final Map extends KEY_GENERIC_CLASS, ? extends VALUE_GENERIC_CLASS> m ) { throw new UnsupportedOperationException(); }
@SuppressWarnings("unchecked")
public ObjectSet This class may be useful to implement your own in case you subclass
* a type-specific map.
*/
public static class Singleton KEY_VALUE_GENERIC extends FUNCTIONS.Singleton KEY_VALUE_GENERIC implements MAP KEY_VALUE_GENERIC, java.io.Serializable, Cloneable {
private static final long serialVersionUID = -7046029254386353129L;
protected transient volatile ObjectSet Note that albeit the returned map is immutable, its default return value may be changed.
*
* @param key the only key of the returned map.
* @param value the only value of the returned map.
* @return a type-specific immutable map containing just the pair Note that albeit the returned map is immutable, its default return value may be changed.
*
* @param key the only key of the returned map.
* @param value the only value of the returned map.
* @return a type-specific immutable map containing just the pair Instances of this class use a hash table to represent a map. The table is
* enlarged as needed when new entries are created, but it is never made
* smaller (even on a {@link #clear()}). A family of {@linkplain #trim() trimming
* methods} lets you control the size of the table; this is particularly useful
* if you reuse instances of this class.
*
* The enlargement speed is controlled by the growth factor, a
* positive number. If the growth factor is p, then the table is
* enlarged each time roughly by a factor 2p/16. By default, p is
* {@link Hash#DEFAULT_GROWTH_FACTOR}, which means that the table is doubled at
* each enlargement, but one can easily set more or less aggressive policies by
* calling {@link #growthFactor(int)} (note that the growth factor is not serialized:
* deserialized tables gets the {@linkplain Hash#DEFAULT_GROWTH_FACTOR default growth factor}).
*
* Iterators created by this map will enumerate pairs in the same order in which they
* have been added to the set (note that addition of pairs whose key is already present
* in the set will not change the iteration order). Note that this order has nothing in common with the natural
* order of the keys.
*
* This class implements the interface of a sorted map, so to allow easy
* access of the iteration order: for instance, you can get the first key
* in iteration order with {@link #firstKey()} without having to create an
* iterator; however, this class partially violates the {@link java.util.SortedMap}
* contract because all submap methods throw an exception and {@link
* #comparator()} returns always The iterators provided by the views of this class using are type-specific
* {@linkplain java.util.ListIterator list iterators}. However, creation of an
* iterator using a starting point is going to be very expensive, as the chosen
* starting point must be linearly searched for, unless it is {@link #lastKey()},
* in which case the iterator is created in constant time.
*
* Note that deletions in a linked table require scanning the list until the
* element to be removed is found. The only exceptions are the first element, the last element,
* and deletions performed using an iterator.
*
* @see Hash
* @see HashCommon
*/
public class OPEN_DOUBLE_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE_GENERIC implements java.io.Serializable, Cloneable, Hash {
#else
#ifdef Custom
/** A type-specific hash map with a fast, small-footprint implementation whose {@linkplain it.unimi.dsi.fastutil.Hash.Strategy hashing strategy}
* is specified at creation time.
*
* Instances of this class use a hash table to represent a map. The table is
* enlarged as needed when new entries are created, but it is never made
* smaller (even on a {@link #clear()}). A family of {@linkplain #trim() trimming
* methods} lets you control the size of the table; this is particularly useful
* if you reuse instances of this class.
*
* The enlargement speed is controlled by the growth factor, a
* positive number. If the growth factor is p, then the table is
* enlarged each time roughly by a factor 2p/16. By default, p is
* {@link Hash#DEFAULT_GROWTH_FACTOR}, which means that the table is doubled at
* each enlargement, but one can easily set more or less aggressive policies by
* calling {@link #growthFactor(int)} (note that the growth factor is not serialized:
* deserialized tables gets the {@linkplain Hash#DEFAULT_GROWTH_FACTOR default growth factor}).
*
* @see Hash
* @see HashCommon
*/
public class OPEN_DOUBLE_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENERIC implements java.io.Serializable, Cloneable, Hash {
#else
/** A type-specific hash map with a fast, small-footprint implementation.
*
* Instances of this class use a hash table to represent a map. The table is
* enlarged as needed when new entries are created, but it is never made
* smaller (even on a {@link #clear()}). A family of {@linkplain #trim() trimming
* methods} lets you control the size of the table; this is particularly useful
* if you reuse instances of this class.
*
* The enlargement speed is controlled by the growth factor, a
* positive number. If the growth factor is p, then the table is
* enlarged each time roughly by a factor 2p/16. By default, p is
* {@link Hash#DEFAULT_GROWTH_FACTOR}, which means that the table is doubled at
* each enlargement, but one can easily set more or less aggressive policies by
* calling {@link #growthFactor(int)} (note that the growth factor is not serialized:
* deserialized tables gets the {@linkplain Hash#DEFAULT_GROWTH_FACTOR default growth factor}).
*
* @see Hash
* @see HashCommon
*/
public class OPEN_DOUBLE_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENERIC implements java.io.Serializable, Cloneable, Hash {
#endif
#endif
/** The array of keys. */
protected transient KEY_GENERIC_TYPE key[];
/** The array of values. */
protected transient VALUE_GENERIC_TYPE value[];
/** The array of occupancy states. */
protected transient byte state[];
/** The acceptable load factor. */
protected final float f;
/** Index into the prime list, giving the current table size. */
protected transient int p;
/** Threshold after which we rehash. It must be the table size times {@link #f}. */
protected transient int maxFill;
/** Number of free entries in the table (may be less than the table size - {@link #count} because of deleted entries). */
protected transient int free;
/** Number of entries in the map. */
protected int count;
#ifdef Linked
/** Cached set of entries. */
protected transient volatile FastSortedEntrySet KEY_VALUE_GENERIC entries;
/** Cached set of keys. */
protected transient volatile SORTED_SET KEY_GENERIC keys;
#else
/** Cached set of entries. */
protected transient volatile FastEntrySet KEY_VALUE_GENERIC entries;
/** Cached set of keys. */
protected transient volatile SET KEY_GENERIC keys;
#endif
/** Cached collection of values. */
protected transient volatile VALUE_COLLECTION VALUE_GENERIC values;
/** The growth factor of the table. The next table size will be To increase object reuse, this method does not change the table size.
* If you want to reduce the table size, you must use {@link #trim()}.
*
*/
public void clear() {
if ( free == state.length ) return;
free = state.length;
count = 0;
Arrays.fill( state, FREE );
// We null all object entries so that the garbage collector can do its work.
#if #keys(reference)
Arrays.fill( key, null );
#endif
#if #values(reference)
Arrays.fill( value, null );
#endif
#ifdef Linked
first = last = -1;
#endif
}
/** The entry class for a hash map does not record key and value, but
* rather the position in the hash table of the corresponding entry. This
* is necessary so that calls to {@link java.util.Map.Entry#setValue(Object)} are reflected in
* the map */
private final class MapEntry implements MAP.Entry KEY_VALUE_GENERIC, Map.Entry If the given entry is the first or the last one, this method will complete
* in constant time; otherwise, it will have to search for the given entry.
*
* @param i the index of an entry.
*/
private void fixPointers( int i ) {
if ( count == 0 ) {
first = last = -1;
return;
}
if ( first == i ) {
first = link[ i ] ^ -1;
link[ first ] ^= i ^ -1;
return;
}
if ( last == i ) {
last = link[ i ] ^ -1;
link[ last ] ^= i ^ -1;
return;
}
int j = first, prev = -1, next;
while( ( next = link[ j ] ^ prev ) != i ) {
prev = j;
j = next;
}
link[ j ] ^= link[ i ] ^ i ^ j;
link[ link[ i ] ^ j ] ^= i ^ j;
}
/** Returns the first key of this map in iteration order.
*
* @return the first key in iteration order.
*/
public KEY_GENERIC_TYPE FIRST_KEY() {
if ( count == 0 ) throw new NoSuchElementException();
return key[ first ];
}
/** Returns the last key of this map in iteration order.
*
* @return the last key in iteration order.
*/
public KEY_GENERIC_TYPE LAST_KEY() {
if ( count == 0 ) throw new NoSuchElementException();
return key[ last ];
}
public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() { return null; }
public SORTED_MAP KEY_VALUE_GENERIC tailMap( KEY_GENERIC_TYPE from ) { throw new UnsupportedOperationException(); }
public SORTED_MAP KEY_VALUE_GENERIC headMap( KEY_GENERIC_TYPE to ) { throw new UnsupportedOperationException(); }
public SORTED_MAP KEY_VALUE_GENERIC subMap( KEY_GENERIC_TYPE from, KEY_GENERIC_TYPE to ) { throw new UnsupportedOperationException(); }
/** A list iterator over a linked map.
*
* This class provides a list iterator over a linked hash map. The empty constructor runs in
* constant time. The one-argoument constructor needs to search for the given key, but it is
* optimized for the case of {@link java.util.SortedMap#lastKey()}, in which case runs in constant time, too.
*/
private class MapIterator {
/** The entry that will be returned by the next call to {@link java.util.ListIterator#previous()} (or We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods
* (and possibly their type-specific counterparts) so that they return keys
* instead of entries.
*/
#ifdef Linked
private final class KeyIterator extends MapIterator implements KEY_LIST_ITERATOR KEY_GENERIC {
public KeyIterator( final KEY_GENERIC_TYPE k ) { super( k ); }
public KEY_GENERIC_TYPE PREV_KEY() { return key[ previousEntry() ]; }
public void set( KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public void add( KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
#if ! #keys(reference)
public KEY_GENERIC_CLASS previous() { return KEY2OBJ( key[ previousEntry() ] ); }
public void set( KEY_CLASS ok ) { throw new UnsupportedOperationException(); }
public void add( KEY_CLASS ok ) { throw new UnsupportedOperationException(); }
#endif
#else
private final class KeyIterator extends MapIterator implements KEY_ITERATOR KEY_GENERIC {
#endif
public KeyIterator() { super(); }
public KEY_GENERIC_TYPE NEXT_KEY() { return key[ nextEntry() ]; }
#if ! #keys(reference)
public KEY_GENERIC_CLASS next() { return KEY2OBJ( key[ nextEntry() ] ); }
#endif
}
#ifdef Linked
private final class KeySet extends ABSTRACT_SORTED_SET KEY_GENERIC {
public KEY_BIDI_ITERATOR KEY_GENERIC iterator( final KEY_GENERIC_TYPE from ) {
return new KeyIterator( from );
}
public KEY_BIDI_ITERATOR KEY_GENERIC iterator() {
return new KeyIterator();
}
#else
private final class KeySet extends ABSTRACT_SET KEY_GENERIC {
public KEY_ITERATOR KEY_GENERIC iterator() {
return new KeyIterator();
}
#endif
public int size() {
return count;
}
public boolean contains( KEY_TYPE k ) {
return containsKey( k );
}
public boolean remove( KEY_TYPE k ) {
int oldCount = count;
OPEN_DOUBLE_HASH_MAP.this.remove( k );
return count != oldCount;
}
public void clear() {
OPEN_DOUBLE_HASH_MAP.this.clear();
}
#ifdef Linked
public KEY_GENERIC_TYPE FIRST() {
if ( count == 0 ) throw new NoSuchElementException();
return key[ first ];
}
public KEY_GENERIC_TYPE LAST() {
if ( count == 0 ) throw new NoSuchElementException();
return key[ last ];
}
public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() { return null; }
final public SORTED_SET KEY_GENERIC tailSet( KEY_GENERIC_TYPE from ) { throw new UnsupportedOperationException(); }
final public SORTED_SET KEY_GENERIC headSet( KEY_GENERIC_TYPE to ) { throw new UnsupportedOperationException(); }
final public SORTED_SET KEY_GENERIC subSet( KEY_GENERIC_TYPE from, KEY_GENERIC_TYPE to ) { throw new UnsupportedOperationException(); }
#endif
}
#ifdef Linked
public SORTED_SET KEY_GENERIC keySet() {
#else
public SET KEY_GENERIC keySet() {
#endif
if ( keys == null ) keys = new KeySet();
return keys;
}
/** An iterator on values.
*
* We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods
* (and possibly their type-specific counterparts) so that they return values
* instead of entries.
*/
#ifdef Linked
private final class ValueIterator extends MapIterator implements VALUE_LIST_ITERATOR VALUE_GENERIC {
public VALUE_GENERIC_TYPE PREV_VALUE() { return value[ previousEntry() ]; }
#if ! #values(reference)
public VALUE_GENERIC_CLASS previous() { return VALUE2OBJ( value[ previousEntry() ] ); }
public void set( VALUE_CLASS ok ) { throw new UnsupportedOperationException(); }
public void add( VALUE_CLASS ok ) { throw new UnsupportedOperationException(); }
#endif
public void set( VALUE_GENERIC_TYPE v ) { throw new UnsupportedOperationException(); }
public void add( VALUE_GENERIC_TYPE v ) { throw new UnsupportedOperationException(); }
#else
private final class ValueIterator extends MapIterator implements VALUE_ITERATOR VALUE_GENERIC {
#endif
public ValueIterator() { super(); }
public VALUE_GENERIC_TYPE NEXT_VALUE() { return value[ nextEntry() ]; }
#if ! #values(reference)
public VALUE_GENERIC_CLASS next() { return VALUE2OBJ( value[ nextEntry() ] ); }
#endif
}
public VALUE_COLLECTION VALUE_GENERIC values() {
if ( values == null ) values = new VALUE_ABSTRACT_COLLECTION VALUE_GENERIC() {
public VALUE_ITERATOR VALUE_GENERIC iterator() {
return new ValueIterator();
}
public int size() {
return count;
}
public boolean contains( VALUE_TYPE v ) {
return containsValue( v );
}
public void clear() {
OPEN_DOUBLE_HASH_MAP.this.clear();
}
};
return values;
}
/** Rehashes this map without changing the table size.
* This method should be called when the map underwent numerous deletions and insertions.
* In this case, free entries become rare, and unsuccessful searches
* require probing all entries. For reasonable load factors this method is linear in the number of entries.
* You will need as much additional free memory as
* that occupied by the table.
*
* If you need to reduce the table siza to fit exactly
* this map, you must use {@link #trim()}.
*
* @return This method rehashes to the smallest size satisfying
* the load factor. It can be used when the map will not be
* changed anymore, so to optimize access speed (by collecting
* deleted entries) and size.
*
* If the table size is already the minimum possible, this method
* does nothing. If you want to guarantee rehashing, use {@link #rehash()}.
*
* @return true if there was enough memory to trim the map.
* @see #trim(int)
* @see #rehash()
*/
public boolean trim() {
int l = Arrays.binarySearch( PRIMES, (int)( count / f ) + 1 );
if ( l < 0 ) l = -l - 1;
if ( l >= p ) return true;
try {
rehash( l );
}
catch(OutOfMemoryError cantDoIt) { return false; }
return true;
}
/** Rehashes this map if the table is too large.
*
* Let N be the smallest table size that can hold
* This method is useful when reusing maps. {@linkplain #clear() Clearing a
* map} leaves the table size untouched. If you are reusing a map
* many times, you can call this method with a typical
* size to avoid keeping around a very large table just
* because of a few large transient maps.
*
* @param n the threshold for the trimming.
* @return true if there was enough memory to trim the map.
* @see #trim()
* @see #rehash()
*/
public boolean trim( final int n ) {
int l = Arrays.binarySearch( PRIMES, (int)( Math.min( Integer.MAX_VALUE - 1, Math.max( n, count ) / f ) ) + 1 );
if ( l < 0 ) l = -l - 1;
if ( p <= l ) return true;
try {
rehash( l );
}
catch( OutOfMemoryError cantDoIt ) { return false; }
return true;
}
/** Resizes the map.
*
* This method implements the basic rehashing strategy, and may be
* overriden by subclasses implementing different rehashing strategies (e.g.,
* disk-based rehashing). However, you should not override this method
* unless you understand the internal workings of this class.
*
* @param newP the new size as an index in {@link Hash#PRIMES}.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
protected void rehash( final int newP ) {
#ifdef Linked
int i = first, j = count, prev = -1, newPrev = -1, t, k2i, h1, h2;
#else
int i = 0, j = count, k2i, h1, h2;
final byte state[] = this.state;
#endif
KEY_GENERIC_TYPE k;
VALUE_GENERIC_TYPE v;
final int newN = PRIMES[newP];
final KEY_GENERIC_TYPE key[] = this.key, newKey[] = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[newN];
final VALUE_GENERIC_TYPE value[] = this.value, newValue[] = VALUE_GENERIC_ARRAY_CAST new VALUE_TYPE[newN];
final byte newState[] = new byte[newN];
#ifdef Linked
final int link[] = this.link, newLink[] = new int[ newN ];
first = -1;
#endif
while(j-- != 0) {
#ifndef Linked
while(state[i] != OCCUPIED ) i++;
#endif
k = key[i];
v = value[i];
k2i = KEY2INTHASH(k) & 0x7FFFFFFF;
h1 = k2i % newN;
h2 = (k2i % (newN - 2)) + 1;
if ( newState[h1] != FREE ) {
h2 = (k2i % (newN - 2)) + 1;
do {
h1 += h2;
if ( h1 >= newN || h1 < 0 ) h1 -= newN;
} while( newState[h1] != FREE );
}
newState[h1] = OCCUPIED;
newKey[h1] = k;
newValue[h1] = v;
#ifdef Linked
t = i;
i = link[ i ] ^ prev;
prev = t;
if ( first != -1 ) {
newLink[ newPrev ] ^= h1;
newLink[ h1 ] = newPrev;
newPrev = h1;
}
else {
newPrev = first = h1;
newLink[ h1 ] = -1;
}
#else
i++;
#endif
}
p = newP;
free = newN - count;
maxFill = (int)( newN * f );
this.key = newKey;
this.value = newValue;
this.state = newState;
#ifdef Linked
this.link = newLink;
this.last = newPrev;
if ( newPrev != -1 ) newLink[ newPrev ] ^= -1;
#endif
}
/** Returns a deep copy of this map.
*
* This method performs a deep copy of this hash map; the data stored in the
* map, however, is not cloned. Note that this makes a difference only for object keys.
*
* @return a deep copy of this map.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public OPEN_DOUBLE_HASH_MAP KEY_VALUE_GENERIC clone() {
OPEN_DOUBLE_HASH_MAP KEY_VALUE_GENERIC c;
try {
c = (OPEN_DOUBLE_HASH_MAP KEY_VALUE_GENERIC)super.clone();
}
catch(CloneNotSupportedException cantHappen) {
throw new InternalError();
}
c.keys = null;
c.values = null;
c.entries = null;
c.key = key.clone();
c.value = value.clone();
c.state = state.clone();
#ifdef Linked
c.link = link.clone();
#endif
#ifdef Custom
c.strategy = strategy;
#endif
return c;
}
/** Returns a hash code for this map.
*
* This method overrides the generic method provided by the superclass.
* Since 2) f = Float.parseFloat(args[2]);
if ( args.length > 3 ) r = new java.util.Random( seed = Long.parseLong( args[ 3 ] ) );
try {
if ("speedTest".equals(args[0]) || "speedComp".equals(args[0])) speedTest( n, f, "speedComp".equals(args[0]) );
else if ( "test".equals( args[0] ) ) test(n, f);
} catch( Throwable e ) {
e.printStackTrace( System.err );
System.err.println( "seed: " + seed );
}
}
#endif
}
fastutil-7.0.2/drv/OpenDoubleHashSet.drv 0000644 0000000 0000000 00000170204 12502261336 017022 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import it.unimi.dsi.fastutil.Hash;
import it.unimi.dsi.fastutil.HashCommon;
import it.unimi.dsi.fastutil.bytes.ByteArrays;
import java.util.Arrays;
import java.util.Collection;
#if #keys(primitive)
import java.util.Iterator;
#endif
import java.util.NoSuchElementException;
#ifdef Linked
#if #keys(reference)
import java.util.Comparator;
#endif
/** A type-specific linked hash set with with a fast, small-footprint implementation.
*
* Instances of this class use a hash table to represent a set. The table is
* enlarged as needed when new entries are created, but it is never made
* smaller (even on a {@link #clear()}). A family of {@linkplain #trim() trimming
* methods} lets you control the size of the table; this is particularly useful
* if you reuse instances of this class.
*
* The enlargement speed is controlled by the growth factor, a
* positive number. If the growth factor is p, then the table is
* enlarged each time roughly by a factor 2p/16. By default, p is
* {@link Hash#DEFAULT_GROWTH_FACTOR}, which means that the table is doubled at
* each enlargement, but one can easily set more or less aggressive policies by
* calling {@link #growthFactor(int)} (note that the growth factor is not serialized:
* deserialized tables gets the {@linkplain Hash#DEFAULT_GROWTH_FACTOR default growth factor}).
*
* Iterators created by this map will enumerate elements in the same order in which they
* have been added to the set (note that addition of elements already present
* in the set does not change the iteration order). Note that this order has nothing in common with the natural
* order of the keys.
*
* This class implements the interface of a sorted set, so to allow easy
* access of the iteration order: for instance, you can get the first element
* in iteration order with {@link #first()} without having to create an
* iterator; however, this class partially violates the {@link java.util.SortedSet}
* contract because all subset methods throw an exception and {@link
* #comparator()} returns always The iterators provided by this class are type-specific {@linkplain
* java.util.ListIterator list iterators}. However, creation of an iterator
* using a starting point is going to be very expensive, as the chosen starting
* point must be linearly searched for, unless it is {@link #last()}, in which
* case the iterator is created in constant time.
*
* Note that deletions in a linked table require scanning the list until the
* element to be removed is found. The only exceptions are the first element, the last element,
* and deletions performed using an iterator.
*
* @see Hash
* @see HashCommon
*/
public class OPEN_DOUBLE_HASH_SET KEY_GENERIC extends ABSTRACT_SORTED_SET KEY_GENERIC implements java.io.Serializable, Cloneable, Hash {
#else
#ifdef Custom
/** A hash set with with a fast, small-footprint implementation whose {@linkplain it.unimi.dsi.fastutil.Hash.Strategy hashing strategy}
* is specified at creation time.
*
* Instances of this class use a hash table to represent a set. The table is
* enlarged as needed when new entries are created, but it is never made
* smaller (even on a {@link #clear()}). A family of {@linkplain #trim() trimming
* methods} lets you control the size of the table; this is particularly useful
* if you reuse instances of this class.
*
* The enlargement speed is controlled by the growth factor, a
* positive number. If the growth factor is p, then the table is
* enlarged each time roughly by a factor 2p/16. By default, p is
* {@link Hash#DEFAULT_GROWTH_FACTOR}, which means that the table is doubled at
* each enlargement, but one can easily set more or less aggressive policies by
* calling {@link #growthFactor(int)} (note that the growth factor is not serialized:
* deserialized tables gets the {@linkplain Hash#DEFAULT_GROWTH_FACTOR default growth factor}).
*
*
* @see Hash
* @see HashCommon
*/
public class OPEN_DOUBLE_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implements java.io.Serializable, Cloneable, Hash {
#else
/** A type-specific hash set with with a fast, small-footprint implementation.
*
* Instances of this class use a hash table to represent a set. The table is
* enlarged as needed when new entries are created, but it is never made
* smaller (even on a {@link #clear()}). A family of {@linkplain #trim() trimming
* methods} lets you control the size of the table; this is particularly useful
* if you reuse instances of this class.
*
* The enlargement speed is controlled by the growth factor, a
* positive number. If the growth factor is p, then the table is
* enlarged each time roughly by a factor 2p/16. By default, p is
* {@link Hash#DEFAULT_GROWTH_FACTOR}, which means that the table is doubled at
* each enlargement, but one can easily set more or less aggressive policies by
* calling {@link #growthFactor(int)} (note that the growth factor is not serialized:
* deserialized tables gets the {@linkplain Hash#DEFAULT_GROWTH_FACTOR default growth factor}).
*
*
* @see Hash
* @see HashCommon
*/
public class OPEN_DOUBLE_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implements java.io.Serializable, Cloneable, Hash {
#endif
#endif
/** The array of keys. */
protected transient KEY_GENERIC_TYPE key[];
/** The array of occupancy states. */
protected transient byte state[];
/** The acceptable load factor. */
protected final float f;
/** Index into the prime list, giving the current table size. */
protected transient int p;
/** Threshold after which we rehash. It must be the table size times {@link #f}. */
protected transient int maxFill;
/** Number of free entries in the table (may be less than the table size - {@link #count} because of deleted entries). */
protected transient int free;
/** Number of entries in the set. */
protected int count;
/** The growth factor of the table. The next table size will be To increase object reuse, this method does not change the table size.
* If you want to reduce the table size, you must use {@link #trim()}.
*
*/
public void clear() {
if ( free == state.length ) return;
free = state.length;
count = 0;
Arrays.fill( state, FREE );
#if #keys(reference)
Arrays.fill( key, null );
#endif
#ifdef Linked
first = last = -1;
#endif
}
#ifdef Linked
/** Modifies the {@link #link} vector so that the given entry is removed.
*
* If the given entry is the first or the last one, this method will complete
* in constant time; otherwise, it will have to search for the given entry.
*
* @param i the index of an entry.
*/
private void fixPointers( int i ) {
if ( count == 0 ) {
first = last = -1;
return;
}
if ( first == i ) {
first = link[ i ] ^ -1;
link[ first ] ^= i ^ -1;
return;
}
if ( last == i ) {
last = link[ i ] ^ -1;
link[ last ] ^= i ^ -1;
return;
}
int j = first, prev = -1, next;
while( ( next = link[ j ] ^ prev ) != i ) {
prev = j;
j = next;
}
link[ j ] ^= link[ i ] ^ i ^ j;
link[ link[ i ] ^ j ] ^= i ^ j;
}
/** Returns the first element of this set in iteration order.
*
* @return the first element in iteration order.
*/
public KEY_GENERIC_TYPE FIRST() {
if ( count == 0 ) throw new NoSuchElementException();
return key[ first ];
}
/** Returns the last element of this set in iteration order.
*
* @return the last element in iteration order.
*/
public KEY_GENERIC_TYPE LAST() {
if ( count == 0 ) throw new NoSuchElementException();
return key[ last ];
}
public SORTED_SET KEY_GENERIC tailSet( KEY_GENERIC_TYPE from ) { throw new UnsupportedOperationException(); }
public SORTED_SET KEY_GENERIC headSet( KEY_GENERIC_TYPE to ) { throw new UnsupportedOperationException(); }
public SORTED_SET KEY_GENERIC subSet( KEY_GENERIC_TYPE from, KEY_GENERIC_TYPE to ) { throw new UnsupportedOperationException(); }
public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() { return null; }
/** A list iterator over a linked set.
*
* This class provides a list iterator over a linked hash set. The empty constructor runs in
* constant time. The one-argoument constructor needs to search for the given element, but it is
* optimized for the case of {@link java.util.SortedSet#last()}, in which case runs in constant time, too.
*/
private class SetIterator extends KEY_ABSTRACT_LIST_ITERATOR KEY_GENERIC {
/** The entry that will be returned by the next call to {@link java.util.ListIterator#previous()} (or iterator()
can be safely cast
* to a type-specific {@linkplain java.util.ListIterator list iterator}.
*/
public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE_GENERIC implements java.io.Serializable, Cloneable {
/** A reference to the root entry. */
protected transient Entry KEY_VALUE_GENERIC tree;
/** Number of entries in this map. */
protected int count;
/** The first key in this map. */
protected transient Entry KEY_VALUE_GENERIC firstEntry;
/** The last key in this map. */
protected transient Entry KEY_VALUE_GENERIC lastEntry;
/** Cached set of entries. */
protected transient volatile ObjectSortedSetput()
* or a remove()
, whether the domain of the map
* has been modified. */
protected transient boolean modified;
/** This map's comparator, as provided in the constructor. */
protected Comparator super KEY_GENERIC_CLASS> storedComparator;
/** This map's actual comparator; it may differ from {@link #storedComparator} because it is
always a type-specific comparator, so it could be derived from the former by wrapping. */
protected transient KEY_COMPARATOR KEY_SUPER_GENERIC actualComparator;
private static final long serialVersionUID = -7046029254386353129L;
private static final boolean ASSERTS = ASSERTS_VALUE;
{
allocatePaths();
}
/** Creates a new empty tree map.
*/
public AVL_TREE_MAP() {
tree = null;
count = 0;
}
/** Generates the comparator that will be actually used.
*
* k
and v
have different lengths.
*/
public AVL_TREE_MAP( final KEY_GENERIC_TYPE[] k, final VALUE_GENERIC_TYPE v[], final Comparator super KEY_GENERIC_CLASS> c ) {
this( c );
if ( k.length != v.length ) throw new IllegalArgumentException( "The key array and the value array have different lengths (" + k.length + " and " + v.length + ")" );
for( int i = 0; i < k.length; i++ ) this.put( k[ i ], v[ i ] );
}
/** Creates a new tree map using the elements of two parallel arrays.
*
* @param k the array of keys of the new tree map.
* @param v the array of corresponding values in the new tree map.
* @throws IllegalArgumentException if k
and v
have different lengths.
*/
public AVL_TREE_MAP( final KEY_GENERIC_TYPE[] k, final VALUE_GENERIC_TYPE v[] ) {
this( k, v, null );
}
/*
* The following methods implements some basic building blocks used by
* all accessors. They are (and should be maintained) identical to those used in AVLTreeSet.drv.
*
* The put()/remove() code is derived from Ben Pfaff's GNU libavl
* (http://www.msu.edu/~pfaffben/avl/). If you want to understand what's
* going on, you should have a look at the literate code contained therein
* first.
*/
/** Compares two keys in the right way.
*
* null
.
* Otherwise, it resorts to primitive type comparisons or to {@link Comparable#compareTo(Object) compareTo()}.
*
* @param k1 the first key.
* @param k2 the second key.
* @return a number smaller than, equal to or greater than 0, as usual
* (i.e., when k1 < k2, k1 = k2 or k1 > k2, respectively).
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
final int compare( final KEY_GENERIC_TYPE k1, final KEY_GENERIC_TYPE k2 ) {
return actualComparator == null ? KEY_CMP( k1, k2 ) : actualComparator.compare( k1, k2 );
}
/** Returns the entry corresponding to the given key, if it is in the tree; null
, otherwise.
*
* @param k the key to search for.
* @return the corresponding entry, or null
if no entry with the given key exists.
*/
final Entry KEY_VALUE_GENERIC findKey( final KEY_GENERIC_TYPE k ) {
Entry KEY_VALUE_GENERIC e = tree;
int cmp;
while ( e != null && ( cmp = compare( k, e.key ) ) != 0 ) e = cmp < 0 ? e.left() : e.right();
return e;
}
/** Locates a key.
*
* @param k a key.
* @return the last entry on a search for the given key; this will be
* the given key, if it present; otherwise, it will be either the smallest greater key or the greatest smaller key.
*/
final Entry KEY_VALUE_GENERIC locateKey( final KEY_GENERIC_TYPE k ) {
Entry KEY_VALUE_GENERIC e = tree, last = tree;
int cmp = 0;
while ( e != null && ( cmp = compare( k, e.key ) ) != 0 ) {
last = e;
e = cmp < 0 ? e.left() : e.right();
}
return cmp == 0 ? e : last;
}
/** This vector remembers the directions followed during
* the current insertion. It suffices for about 232 entries. */
private transient boolean dirPath[];
private void allocatePaths() {
dirPath = new boolean[ 48 ];
}
/* After execution of this method, modified is true iff a new entry has
been inserted. */
public VALUE_GENERIC_TYPE put( final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE v ) {
modified = false;
if ( tree == null ) { // The case of the empty tree is treated separately.
count++;
tree = lastEntry = firstEntry = new Entry KEY_VALUE_GENERIC( k, v );
modified = true;
}
else {
Entry KEY_VALUE_GENERIC p = tree, q = null, y = tree, z = null, e = null, w = null;
int cmp, i = 0;
while( true ) {
if ( ( cmp = compare( k, p.key ) ) == 0 ) {
final VALUE_GENERIC_TYPE oldValue = p.value;
p.value = v;
return oldValue;
}
if ( p.balance() != 0 ) {
i = 0;
z = q;
y = p;
}
if ( dirPath[ i++ ] = cmp > 0 ) {
if ( p.succ() ) {
count++;
e = new Entry KEY_VALUE_GENERIC( k, v );
modified = true;
if ( p.right == null ) lastEntry = e;
e.left = p;
e.right = p.right;
p.right( e );
break;
}
q = p;
p = p.right;
}
else {
if ( p.pred() ) {
count++;
e = new Entry KEY_VALUE_GENERIC( k, v );
modified = true;
if ( p.left == null ) firstEntry = e;
e.right = p;
e.left = p.left;
p.left( e );
break;
}
q = p;
p = p.left;
}
}
p = y;
i = 0;
while( p != e ) {
if ( dirPath[ i ] ) p.incBalance();
else p.decBalance();
p = dirPath[ i++ ] ? p.right : p.left;
}
if ( y.balance() == -2 ) {
Entry KEY_VALUE_GENERIC x = y.left;
if ( x.balance() == -1 ) {
w = x;
if ( x.succ() ) {
x.succ( false );
y.pred( x );
}
else y.left = x.right;
x.right = y;
x.balance( 0 );
y.balance( 0 );
}
else {
if ( ASSERTS ) assert x.balance() == 1;
w = x.right;
x.right = w.left;
w.left = x;
y.left = w.right;
w.right = y;
if ( w.balance() == -1 ) {
x.balance( 0 );
y.balance( 1 );
}
else if ( w.balance() == 0 ) {
x.balance( 0 );
y.balance( 0 );
}
else {
x.balance( -1 );
y.balance( 0 );
}
w.balance( 0 );
if ( w.pred() ) {
x.succ( w );
w.pred( false );
}
if ( w.succ() ) {
y.pred( w );
w.succ( false );
}
}
}
else if ( y.balance() == +2 ) {
Entry KEY_VALUE_GENERIC x = y.right;
if ( x.balance() == 1 ) {
w = x;
if ( x.pred() ) {
x.pred( false );
y.succ( x );
}
else y.right = x.left;
x.left = y;
x.balance( 0 );
y.balance( 0 );
}
else {
if ( ASSERTS ) assert x.balance() == -1;
w = x.left;
x.left = w.right;
w.right = x;
y.right = w.left;
w.left = y;
if ( w.balance() == 1 ) {
x.balance( 0 );
y.balance( -1 );
}
else if ( w.balance() == 0 ) {
x.balance( 0 );
y.balance( 0 );
}
else {
x.balance( 1 );
y.balance( 0 );
}
w.balance( 0 );
if ( w.pred() ) {
y.succ( w );
w.pred( false );
}
if ( w.succ() ) {
x.pred( w );
w.succ( false );
}
}
}
else return defRetValue;
if ( z == null ) tree = w;
else {
if ( z.left == y ) z.left = w;
else z.right = w;
}
}
if ( ASSERTS ) checkTree( tree );
return defRetValue;
}
/** Finds the parent of an entry.
*
* @param e a node of the tree.
* @return the parent of the given node, or null
for the root.
*/
private Entry KEY_VALUE_GENERIC parent( final Entry KEY_VALUE_GENERIC e ) {
if ( e == tree ) return null;
Entry KEY_VALUE_GENERIC x, y, p;
x = y = e;
while( true ) {
if ( y.succ() ) {
p = y.right;
if ( p == null || p.left != e ) {
while( ! x.pred() ) x = x.left;
p = x.left;
}
return p;
}
else if ( x.pred() ) {
p = x.left;
if ( p == null || p.right != e ) {
while( ! y.succ() ) y = y.right;
p = y.right;
}
return p;
}
x = x.left;
y = y.right;
}
}
/* After execution of this method, {@link #modified} is true iff an entry
has been deleted. */
SUPPRESS_WARNINGS_KEY_UNCHECKED
public VALUE_GENERIC_TYPE REMOVE_VALUE( final KEY_TYPE k ) {
modified = false;
if ( tree == null ) return defRetValue;
int cmp;
Entry KEY_VALUE_GENERIC p = tree, q = null;
boolean dir = false;
final KEY_GENERIC_TYPE kk = KEY_GENERIC_CAST k;
while( true ) {
if ( ( cmp = compare( kk, p.key ) ) == 0 ) break;
else if ( dir = cmp > 0 ) {
q = p;
if ( ( p = p.right() ) == null ) return defRetValue;
}
else {
q = p;
if ( ( p = p.left() ) == null ) return defRetValue;
}
}
if ( p.left == null ) firstEntry = p.next();
if ( p.right == null ) lastEntry = p.prev();
if ( p.succ() ) {
if ( p.pred() ) {
if ( q != null ) {
if ( dir ) q.succ( p.right );
else q.pred( p.left );
}
else tree = dir ? p.right : p.left;
}
else {
p.prev().right = p.right;
if ( q != null ) {
if ( dir ) q.right = p.left;
else q.left = p.left;
}
else tree = p.left;
}
}
else {
Entry KEY_VALUE_GENERIC r = p.right;
if ( r.pred() ) {
r.left = p.left;
r.pred( p.pred() );
if ( ! r.pred() ) r.prev().right = r;
if ( q != null ) {
if ( dir ) q.right = r;
else q.left = r;
}
else tree = r;
r.balance( p.balance() );
q = r;
dir = true;
}
else {
Entry KEY_VALUE_GENERIC s;
while( true ) {
s = r.left;
if ( s.pred() ) break;
r = s;
}
if ( s.succ() ) r.pred( s );
else r.left = s.right;
s.left = p.left;
if ( ! p.pred() ) {
p.prev().right = s;
s.pred( false );
}
s.right = p.right;
s.succ( false );
if ( q != null ) {
if ( dir ) q.right = s;
else q.left = s;
}
else tree = s;
s.balance( p.balance() );
q = r;
dir = false;
}
}
Entry KEY_VALUE_GENERIC y;
while( q != null ) {
y = q;
q = parent( y );
if ( ! dir ) {
dir = q != null && q.left != y;
y.incBalance();
if ( y.balance() == 1 ) break;
else if ( y.balance() == 2 ) {
Entry KEY_VALUE_GENERIC x = y.right;
if ( ASSERTS ) assert x != null;
if ( x.balance() == -1 ) {
Entry KEY_VALUE_GENERIC w;
if ( ASSERTS ) assert x.balance() == -1;
w = x.left;
x.left = w.right;
w.right = x;
y.right = w.left;
w.left = y;
if ( w.balance() == 1 ) {
x.balance( 0 );
y.balance( -1 );
}
else if ( w.balance() == 0 ) {
x.balance( 0 );
y.balance( 0 );
}
else {
if ( ASSERTS ) assert w.balance() == -1;
x.balance( 1 );
y.balance( 0 );
}
w.balance( 0 );
if ( w.pred() ) {
y.succ( w );
w.pred( false );
}
if ( w.succ() ) {
x.pred( w );
w.succ( false );
}
if ( q != null ) {
if ( dir ) q.right = w;
else q.left = w;
}
else tree = w;
}
else {
if ( q != null ) {
if ( dir ) q.right = x;
else q.left = x;
}
else tree = x;
if ( x.balance() == 0 ) {
y.right = x.left;
x.left = y;
x.balance( -1 );
y.balance( +1 );
break;
}
if ( ASSERTS ) assert x.balance() == 1;
if ( x.pred() ) {
y.succ( true );
x.pred( false );
}
else y.right = x.left;
x.left = y;
y.balance( 0 );
x.balance( 0 );
}
}
}
else {
dir = q != null && q.left != y;
y.decBalance();
if ( y.balance() == -1 ) break;
else if ( y.balance() == -2 ) {
Entry KEY_VALUE_GENERIC x = y.left;
if ( ASSERTS ) assert x != null;
if ( x.balance() == 1 ) {
Entry KEY_VALUE_GENERIC w;
if ( ASSERTS ) assert x.balance() == 1;
w = x.right;
x.right = w.left;
w.left = x;
y.left = w.right;
w.right = y;
if ( w.balance() == -1 ) {
x.balance( 0 );
y.balance( 1 );
}
else if ( w.balance() == 0 ) {
x.balance( 0 );
y.balance( 0 );
}
else {
if ( ASSERTS ) assert w.balance() == 1;
x.balance( -1 );
y.balance( 0 );
}
w.balance( 0 );
if ( w.pred() ) {
x.succ( w );
w.pred( false );
}
if ( w.succ() ) {
y.pred( w );
w.succ( false );
}
if ( q != null ) {
if ( dir ) q.right = w;
else q.left = w;
}
else tree = w;
}
else {
if ( q != null ) {
if ( dir ) q.right = x;
else q.left = x;
}
else tree = x;
if ( x.balance() == 0 ) {
y.left = x.right;
x.right = y;
x.balance( +1 );
y.balance( -1 );
break;
}
if ( ASSERTS ) assert x.balance() == -1;
if ( x.succ() ) {
y.pred( true );
x.succ( false );
}
else y.left = x.right;
x.right = y;
y.balance( 0 );
x.balance( 0 );
}
}
}
}
modified = true;
count--;
if ( ASSERTS ) checkTree( tree );
return p.value;
}
#if ! #keyclass(Object) || #values(primitive)
public VALUE_GENERIC_CLASS put( final KEY_GENERIC_CLASS ok, final VALUE_GENERIC_CLASS ov ) {
final VALUE_GENERIC_TYPE oldValue = put( KEY_CLASS2TYPE(ok), VALUE_CLASS2TYPE(ov) );
return modified ? OBJECT_DEFAULT_RETURN_VALUE : VALUE2OBJ( oldValue );
}
#endif
#if ! #keyclass(Object) || #values(primitive)
public VALUE_GENERIC_CLASS remove( final Object ok ) {
final VALUE_GENERIC_TYPE oldValue = REMOVE_VALUE( KEY_OBJ2TYPE( ok ) );
return modified ? VALUE2OBJ( oldValue ) : OBJECT_DEFAULT_RETURN_VALUE;
}
#endif
public boolean containsValue( final VALUE_TYPE v ) {
final ValueIterator i = new ValueIterator();
VALUE_GENERIC_TYPE ev;
int j = count;
while( j-- != 0 ) {
ev = i.NEXT_VALUE();
if ( VALUE_EQUALS( ev, v ) ) return true;
}
return false;
}
public void clear() {
count = 0;
tree = null;
entries = null;
values = null;
keys = null;
firstEntry = lastEntry = null;
}
/** This class represent an entry in a tree map.
*
* null
if the left
* subtree is empty).
*/
Entry KEY_VALUE_GENERIC left() {
return ( info & PRED_MASK ) != 0 ? null : left;
}
/** Returns the right subtree.
*
* @return the right subtree (null
if the right
* subtree is empty).
*/
Entry KEY_VALUE_GENERIC right() {
return ( info & SUCC_MASK ) != 0 ? null : right;
}
/** Checks whether the left pointer is really a predecessor.
* @return true if the left pointer is a predecessor.
*/
boolean pred() {
return ( info & PRED_MASK ) != 0;
}
/** Checks whether the right pointer is really a successor.
* @return true if the right pointer is a successor.
*/
boolean succ() {
return ( info & SUCC_MASK ) != 0;
}
/** Sets whether the left pointer is really a predecessor.
* @param pred if true then the left pointer will be considered a predecessor.
*/
void pred( final boolean pred ) {
if ( pred ) info |= PRED_MASK;
else info &= ~PRED_MASK;
}
/** Sets whether the right pointer is really a successor.
* @param succ if true then the right pointer will be considered a successor.
*/
void succ( final boolean succ ) {
if ( succ ) info |= SUCC_MASK;
else info &= ~SUCC_MASK;
}
/** Sets the left pointer to a predecessor.
* @param pred the predecessr.
*/
void pred( final Entry KEY_VALUE_GENERIC pred ) {
info |= PRED_MASK;
left = pred;
}
/** Sets the right pointer to a successor.
* @param succ the successor.
*/
void succ( final Entry KEY_VALUE_GENERIC succ ) {
info |= SUCC_MASK;
right = succ;
}
/** Sets the left pointer to the given subtree.
* @param left the new left subtree.
*/
void left( final Entry KEY_VALUE_GENERIC left ) {
info &= ~PRED_MASK;
this.left = left;
}
/** Sets the right pointer to the given subtree.
* @param right the new right subtree.
*/
void right( final Entry KEY_VALUE_GENERIC right ) {
info &= ~SUCC_MASK;
this.right = right;
}
/** Returns the current level of the node.
* @return the current level of this node.
*/
int balance() {
return (byte)info;
}
/** Sets the level of this node.
* @param level the new level of this node.
*/
void balance( int level ) {
info &= ~BALANCE_MASK;
info |= ( level & BALANCE_MASK );
}
/** Increments the level of this node. */
void incBalance() {
info = info & ~BALANCE_MASK | ( (byte)info + 1 ) & 0xFF;
}
/** Decrements the level of this node. */
protected void decBalance() {
info = info & ~BALANCE_MASK | ( (byte)info - 1 ) & 0xFF;
}
/** Computes the next entry in the set order.
*
* @return the next entry (null
) if this is the last entry).
*/
Entry KEY_VALUE_GENERIC next() {
Entry KEY_VALUE_GENERIC next = this.right;
if ( ( info & SUCC_MASK ) == 0 ) while ( ( next.info & PRED_MASK ) == 0 ) next = next.left;
return next;
}
/** Computes the previous entry in the set order.
*
* @return the previous entry (null
) if this is the first entry).
*/
Entry KEY_VALUE_GENERIC prev() {
Entry KEY_VALUE_GENERIC prev = this.left;
if ( ( info & PRED_MASK ) == 0 ) while ( ( prev.info & SUCC_MASK ) == 0 ) prev = prev.right;
return prev;
}
public KEY_GENERIC_CLASS getKey() {
return KEY2OBJ(key);
}
#if ! #keyclass(Object)
public KEY_GENERIC_TYPE ENTRY_GET_KEY() {
return key;
}
#endif
public VALUE_GENERIC_CLASS getValue() {
return VALUE2OBJ(value);
}
#if #values(primitive)
public VALUE_TYPE ENTRY_GET_VALUE() {
return value;
}
#endif
public VALUE_GENERIC_TYPE setValue(final VALUE_GENERIC_TYPE value) {
final VALUE_GENERIC_TYPE oldValue = this.value;
this.value = value;
return oldValue;
}
#if #values(primitive)
public VALUE_GENERIC_CLASS setValue(final VALUE_GENERIC_CLASS value) {
return VALUE2OBJ(setValue(VALUE_CLASS2TYPE(value)));
}
#endif
SUPPRESS_WARNINGS_KEY_VALUE_UNCHECKED
public Entry KEY_VALUE_GENERIC clone() {
Entry KEY_VALUE_GENERIC c;
try {
c = (Entry KEY_VALUE_GENERIC)super.clone();
}
catch(CloneNotSupportedException cantHappen) {
throw new InternalError();
}
c.key = key;
c.value = value;
c.info = info;
return c;
}
@SuppressWarnings("unchecked")
public boolean equals( final Object o ) {
if (!(o instanceof Map.Entry)) return false;
Map.Entrynull
if no previous entry exists). */
Entry KEY_VALUE_GENERIC prev;
/** The entry that will be returned by the next call to {@link java.util.ListIterator#next()} (or null
if no next entry exists). */
Entry KEY_VALUE_GENERIC next;
/** The last entry that was returned (or null
if we did not iterate or used {@link #remove()}). */
Entry KEY_VALUE_GENERIC curr;
/** The current index (in the sense of a {@link java.util.ListIterator}). Note that this value is not meaningful when this {@link TreeIterator} has been created using the nonempty constructor.*/
int index = 0;
TreeIterator() {
next = firstEntry;
}
TreeIterator( final KEY_GENERIC_TYPE k ) {
if ( ( next = locateKey( k ) ) != null ) {
if ( compare( next.key, k ) <= 0 ) {
prev = next;
next = next.next();
}
else prev = next.prev();
}
}
public boolean hasNext() { return next != null; }
public boolean hasPrevious() { return prev != null; }
void updateNext() {
next = next.next();
}
Entry KEY_VALUE_GENERIC nextEntry() {
if ( ! hasNext() ) throw new NoSuchElementException();
curr = prev = next;
index++;
updateNext();
return curr;
}
void updatePrevious() {
prev = prev.prev();
}
Entry KEY_VALUE_GENERIC previousEntry() {
if ( ! hasPrevious() ) throw new NoSuchElementException();
curr = next = prev;
index--;
updatePrevious();
return curr;
}
public int nextIndex() {
return index;
}
public int previousIndex() {
return index - 1;
}
public void remove() {
if ( curr == null ) throw new IllegalStateException();
/* If the last operation was a next(), we are removing an entry that preceeds
the current index, and thus we must decrement it. */
if ( curr == prev ) index--;
next = prev = curr;
updatePrevious();
updateNext();
AVL_TREE_MAP.this.REMOVE_VALUE( curr.key );
curr = null;
}
public int skip( final int n ) {
int i = n;
while( i-- != 0 && hasNext() ) nextEntry();
return n - i - 1;
}
public int back( final int n ) {
int i = n;
while( i-- != 0 && hasPrevious() ) previousEntry();
return n - i - 1;
}
}
/** An iterator on the whole range.
*
* null
if the submap is empty.
*/
public AVL_TREE_MAP.Entry KEY_VALUE_GENERIC firstEntry() {
if ( tree == null ) return null;
// If this submap goes to -infinity, we return the main map first entry; otherwise, we locate the start of the map.
AVL_TREE_MAP.Entry KEY_VALUE_GENERIC e;
if ( bottom ) e = firstEntry;
else {
e = locateKey( from );
// If we find either the start or something greater we're OK.
if ( compare( e.key, from ) < 0 ) e = e.next();
}
// Finally, if this subset doesn't go to infinity, we check that the resulting key isn't greater than the end.
if ( e == null || ! top && compare( e.key, to ) >= 0 ) return null;
return e;
}
/** Locates the last entry.
*
* @return the last entry of this submap, or null
if the submap is empty.
*/
public AVL_TREE_MAP.Entry KEY_VALUE_GENERIC lastEntry() {
if ( tree == null ) return null;
// If this submap goes to infinity, we return the main map last entry; otherwise, we locate the end of the map.
AVL_TREE_MAP.Entry KEY_VALUE_GENERIC e;
if ( top ) e = lastEntry;
else {
e = locateKey( to );
// If we find something smaller than the end we're OK.
if ( compare( e.key, to ) >= 0 ) e = e.prev();
}
// Finally, if this subset doesn't go to -infinity, we check that the resulting key isn't smaller than the start.
if ( e == null || ! bottom && compare( e.key, from ) < 0 ) return null;
return e;
}
public KEY_GENERIC_TYPE FIRST_KEY() {
AVL_TREE_MAP.Entry KEY_VALUE_GENERIC e = firstEntry();
if ( e == null ) throw new NoSuchElementException();
return e.key;
}
public KEY_GENERIC_TYPE LAST_KEY() {
AVL_TREE_MAP.Entry KEY_VALUE_GENERIC e = lastEntry();
if ( e == null ) throw new NoSuchElementException();
return e.key;
}
#if !#keyclass(Object)
public KEY_GENERIC_CLASS firstKey() {
AVL_TREE_MAP.Entry KEY_VALUE_GENERIC e = firstEntry();
if ( e == null ) throw new NoSuchElementException();
return e.getKey();
}
public KEY_GENERIC_CLASS lastKey() {
AVL_TREE_MAP.Entry KEY_VALUE_GENERIC e = lastEntry();
if ( e == null ) throw new NoSuchElementException();
return e.getKey();
}
#endif
/** An iterator for subranges.
*
* null
.
*/
private class SubmapIterator extends TreeIterator {
SubmapIterator() {
next = firstEntry();
}
SubmapIterator( final KEY_GENERIC_TYPE k ) {
this();
if ( next != null ) {
if ( ! bottom && compare( k, next.key ) < 0 ) prev = null;
else if ( ! top && compare( k, ( prev = lastEntry() ).key ) >= 0 ) next = null;
else {
next = locateKey( k );
if ( compare( next.key, k ) <= 0 ) {
prev = next;
next = next.next();
}
else prev = next.prev();
}
}
}
void updatePrevious() {
prev = prev.prev();
if ( ! bottom && prev != null && AVL_TREE_MAP.this.compare( prev.key, from ) < 0 ) prev = null;
}
void updateNext() {
next = next.next();
if ( ! top && next != null && AVL_TREE_MAP.this.compare( next.key, to ) >= 0 ) next = null;
}
}
private class SubmapEntryIterator extends SubmapIterator implements ObjectListIteratoriterator()
can be safely cast
* to a type-specific {@linkplain java.util.ListIterator list iterator}.
*/
public class AVL_TREE_SET KEY_GENERIC extends ABSTRACT_SORTED_SET KEY_GENERIC implements java.io.Serializable, Cloneable, SORTED_SET KEY_GENERIC {
/** A reference to the root entry. */
protected transient Entry KEY_GENERIC tree;
/** Number of elements in this set. */
protected int count;
/** The entry of the first element of this set. */
protected transient Entry KEY_GENERIC firstEntry;
/** The entry of the last element of this set. */
protected transient Entry KEY_GENERIC lastEntry;
/** This set's comparator, as provided in the constructor. */
protected Comparator super KEY_GENERIC_CLASS> storedComparator;
/** This set's actual comparator; it may differ from {@link #storedComparator} because it is
always a type-specific comparator, so it could be derived from the former by wrapping. */
protected transient KEY_COMPARATOR KEY_SUPER_GENERIC actualComparator;
private static final long serialVersionUID = -7046029254386353130L;
private static final boolean ASSERTS = ASSERTS_VALUE;
{
allocatePaths();
}
/** Creates a new empty tree set.
*/
public AVL_TREE_SET() {
tree = null;
count = 0;
}
/** Generates the comparator that will be actually used.
*
* null
.
* Otherwise, it resorts to primitive type comparisons or to {@link Comparable#compareTo(Object) compareTo()}.
*
* @param k1 the first key.
* @param k2 the second key.
* @return a number smaller than, equal to or greater than 0, as usual
* (i.e., when k1 < k2, k1 = k2 or k1 > k2, respectively).
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
final int compare( final KEY_GENERIC_TYPE k1, final KEY_GENERIC_TYPE k2 ) {
return actualComparator == null ? KEY_CMP( k1, k2 ) : actualComparator.compare( k1, k2 );
}
/** Returns the entry corresponding to the given key, if it is in the tree; null
, otherwise.
*
* @param k the key to search for.
* @return the corresponding entry, or null
if no entry with the given key exists.
*/
private Entry KEY_GENERIC findKey( final KEY_GENERIC_TYPE k ) {
Entry KEY_GENERIC e = tree;
int cmp;
while ( e != null && ( cmp = compare( k, e.key ) ) != 0 )
e = cmp < 0 ? e.left() : e.right();
return e;
}
/** Locates a key.
*
* @param k a key.
* @return the last entry on a search for the given key; this will be
* the given key, if it present; otherwise, it will be either the smallest greater key or the greatest smaller key.
*/
final Entry KEY_GENERIC locateKey( final KEY_GENERIC_TYPE k ) {
Entry KEY_GENERIC e = tree, last = tree;
int cmp = 0;
while ( e != null && ( cmp = compare( k, e.key ) ) != 0 ) {
last = e;
e = cmp < 0 ? e.left() : e.right();
}
return cmp == 0 ? e : last;
}
/** This vector remembers the path followed during the current insertion. It suffices for
about 232 entries. */
private transient boolean dirPath[];
private void allocatePaths() {
dirPath = new boolean[ 48 ];
}
public boolean add( final KEY_GENERIC_TYPE k ) {
if ( tree == null ) { // The case of the empty tree is treated separately.
count++;
tree = lastEntry = firstEntry = new Entry KEY_GENERIC( k );
}
else {
Entry KEY_GENERIC p = tree, q = null, y = tree, z = null, e = null, w = null;
int cmp, i = 0;
while( true ) {
if ( ( cmp = compare( k, p.key ) ) == 0 ) return false;
if ( p.balance() != 0 ) {
i = 0;
z = q;
y = p;
}
if ( dirPath[ i++ ] = cmp > 0 ) {
if ( p.succ() ) {
count++;
e = new Entry KEY_GENERIC( k );
if ( p.right == null ) lastEntry = e;
e.left = p;
e.right = p.right;
p.right( e );
break;
}
q = p;
p = p.right;
}
else {
if ( p.pred() ) {
count++;
e = new Entry KEY_GENERIC( k );
if ( p.left == null ) firstEntry = e;
e.right = p;
e.left = p.left;
p.left( e );
break;
}
q = p;
p = p.left;
}
}
p = y;
i = 0;
while( p != e ) {
if ( dirPath[ i ] ) p.incBalance();
else p.decBalance();
p = dirPath[ i++ ] ? p.right : p.left;
}
if ( y.balance() == -2 ) {
Entry KEY_GENERIC x = y.left;
if ( x.balance() == -1 ) {
w = x;
if ( x.succ() ) {
x.succ( false );
y.pred( x );
}
else y.left = x.right;
x.right = y;
x.balance( 0 );
y.balance( 0 );
}
else {
if ( ASSERTS ) assert x.balance() == 1;
w = x.right;
x.right = w.left;
w.left = x;
y.left = w.right;
w.right = y;
if ( w.balance() == -1 ) {
x.balance( 0 );
y.balance( 1 );
}
else if ( w.balance() == 0 ) {
x.balance( 0 );
y.balance( 0 );
}
else {
x.balance( -1 );
y.balance( 0 );
}
w.balance( 0 );
if ( w.pred() ) {
x.succ( w );
w.pred( false );
}
if ( w.succ() ) {
y.pred( w );
w.succ( false );
}
}
}
else if ( y.balance() == +2 ) {
Entry KEY_GENERIC x = y.right;
if ( x.balance() == 1 ) {
w = x;
if ( x.pred() ) {
x.pred( false );
y.succ( x );
}
else y.right = x.left;
x.left = y;
x.balance( 0 );
y.balance( 0 );
}
else {
if ( ASSERTS ) assert x.balance() == -1;
w = x.left;
x.left = w.right;
w.right = x;
y.right = w.left;
w.left = y;
if ( w.balance() == 1 ) {
x.balance( 0 );
y.balance( -1 );
}
else if ( w.balance() == 0 ) {
x.balance( 0 );
y.balance( 0 );
}
else {
x.balance( 1 );
y.balance( 0 );
}
w.balance( 0 );
if ( w.pred() ) {
y.succ( w );
w.pred( false );
}
if ( w.succ() ) {
x.pred( w );
w.succ( false );
}
}
}
else return true;
if ( z == null ) tree = w;
else {
if ( z.left == y ) z.left = w;
else z.right = w;
}
}
if ( ASSERTS ) checkTree( tree );
return true;
}
/** Finds the parent of an entry.
*
* @param e a node of the tree.
* @return the parent of the given node, or null
for the root.
*/
private Entry KEY_GENERIC parent( final Entry KEY_GENERIC e ) {
if ( e == tree ) return null;
Entry KEY_GENERIC x, y, p;
x = y = e;
while( true ) {
if ( y.succ() ) {
p = y.right;
if ( p == null || p.left != e ) {
while( ! x.pred() ) x = x.left;
p = x.left;
}
return p;
}
else if ( x.pred() ) {
p = x.left;
if ( p == null || p.right != e ) {
while( ! y.succ() ) y = y.right;
p = y.right;
}
return p;
}
x = x.left;
y = y.right;
}
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
public boolean remove( final KEY_TYPE k ) {
if ( tree == null ) return false;
int cmp;
Entry KEY_GENERIC p = tree, q = null;
boolean dir = false;
final KEY_GENERIC_TYPE kk = KEY_GENERIC_CAST k;
while( true ) {
if ( ( cmp = compare( kk, p.key ) ) == 0 ) break;
else if ( dir = cmp > 0 ) {
q = p;
if ( ( p = p.right() ) == null ) return false;
}
else {
q = p;
if ( ( p = p.left() ) == null ) return false;
}
}
if ( p.left == null ) firstEntry = p.next();
if ( p.right == null ) lastEntry = p.prev();
if ( p.succ() ) {
if ( p.pred() ) {
if ( q != null ) {
if ( dir ) q.succ( p.right );
else q.pred( p.left );
}
else tree = dir ? p.right : p.left;
}
else {
p.prev().right = p.right;
if ( q != null ) {
if ( dir ) q.right = p.left;
else q.left = p.left;
}
else tree = p.left;
}
}
else {
Entry KEY_GENERIC r = p.right;
if ( r.pred() ) {
r.left = p.left;
r.pred( p.pred() );
if ( ! r.pred() ) r.prev().right = r;
if ( q != null ) {
if ( dir ) q.right = r;
else q.left = r;
}
else tree = r;
r.balance( p.balance() );
q = r;
dir = true;
}
else {
Entry KEY_GENERIC s;
while( true ) {
s = r.left;
if ( s.pred() ) break;
r = s;
}
if ( s.succ() ) r.pred( s );
else r.left = s.right;
s.left = p.left;
if ( ! p.pred() ) {
p.prev().right = s;
s.pred( false );
}
s.right = p.right;
s.succ( false );
if ( q != null ) {
if ( dir ) q.right = s;
else q.left = s;
}
else tree = s;
s.balance( p.balance() );
q = r;
dir = false;
}
}
Entry KEY_GENERIC y;
while( q != null ) {
y = q;
q = parent( y );
if ( ! dir ) {
dir = q != null && q.left != y;
y.incBalance();
if ( y.balance() == 1 ) break;
else if ( y.balance() == 2 ) {
Entry KEY_GENERIC x = y.right;
if ( ASSERTS ) assert x != null;
if ( x.balance() == -1 ) {
Entry KEY_GENERIC w;
if ( ASSERTS ) assert x.balance() == -1;
w = x.left;
x.left = w.right;
w.right = x;
y.right = w.left;
w.left = y;
if ( w.balance() == 1 ) {
x.balance( 0 );
y.balance( -1 );
}
else if ( w.balance() == 0 ) {
x.balance( 0 );
y.balance( 0 );
}
else {
if ( ASSERTS ) assert w.balance() == -1;
x.balance( 1 );
y.balance( 0 );
}
w.balance( 0 );
if ( w.pred() ) {
y.succ( w );
w.pred( false );
}
if ( w.succ() ) {
x.pred( w );
w.succ( false );
}
if ( q != null ) {
if ( dir ) q.right = w;
else q.left = w;
}
else tree = w;
}
else {
if ( q != null ) {
if ( dir ) q.right = x;
else q.left = x;
}
else tree = x;
if ( x.balance() == 0 ) {
y.right = x.left;
x.left = y;
x.balance( -1 );
y.balance( +1 );
break;
}
if ( ASSERTS ) assert x.balance() == 1;
if ( x.pred() ) {
y.succ( true );
x.pred( false );
}
else y.right = x.left;
x.left = y;
y.balance( 0 );
x.balance( 0 );
}
}
}
else {
dir = q != null && q.left != y;
y.decBalance();
if ( y.balance() == -1 ) break;
else if ( y.balance() == -2 ) {
Entry KEY_GENERIC x = y.left;
if ( ASSERTS ) assert x != null;
if ( x.balance() == 1 ) {
Entry KEY_GENERIC w;
if ( ASSERTS ) assert x.balance() == 1;
w = x.right;
x.right = w.left;
w.left = x;
y.left = w.right;
w.right = y;
if ( w.balance() == -1 ) {
x.balance( 0 );
y.balance( 1 );
}
else if ( w.balance() == 0 ) {
x.balance( 0 );
y.balance( 0 );
}
else {
if ( ASSERTS ) assert w.balance() == 1;
x.balance( -1 );
y.balance( 0 );
}
w.balance( 0 );
if ( w.pred() ) {
x.succ( w );
w.pred( false );
}
if ( w.succ() ) {
y.pred( w );
w.succ( false );
}
if ( q != null ) {
if ( dir ) q.right = w;
else q.left = w;
}
else tree = w;
}
else {
if ( q != null ) {
if ( dir ) q.right = x;
else q.left = x;
}
else tree = x;
if ( x.balance() == 0 ) {
y.left = x.right;
x.right = y;
x.balance( +1 );
y.balance( -1 );
break;
}
if ( ASSERTS ) assert x.balance() == -1;
if ( x.succ() ) {
y.pred( true );
x.succ( false );
}
else y.left = x.right;
x.right = y;
y.balance( 0 );
x.balance( 0 );
}
}
}
}
count--;
if ( ASSERTS ) checkTree( tree );
return true;
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
public boolean contains( final KEY_TYPE k ) {
return findKey( KEY_GENERIC_CAST k ) != null;
}
#if #keysclass(Object)
public K get( final KEY_TYPE k ) {
final Entry KEY_GENERIC entry = findKey( KEY_GENERIC_CAST k );
return entry == null ? null : entry.getKey();
}
#endif
public void clear() {
count = 0;
tree = null;
firstEntry = lastEntry = null;
}
/** This class represent an entry in a tree set.
*
* null
if the left
* subtree is empty).
*/
Entry KEY_GENERIC left() {
return ( info & PRED_MASK ) != 0 ? null : left;
}
/** Returns the right subtree.
*
* @return the right subtree (null
if the right
* subtree is empty).
*/
Entry KEY_GENERIC right() {
return ( info & SUCC_MASK ) != 0 ? null : right;
}
/** Checks whether the left pointer is really a predecessor.
* @return true if the left pointer is a predecessor.
*/
boolean pred() {
return ( info & PRED_MASK ) != 0;
}
/** Checks whether the right pointer is really a successor.
* @return true if the right pointer is a successor.
*/
boolean succ() {
return ( info & SUCC_MASK ) != 0;
}
/** Sets whether the left pointer is really a predecessor.
* @param pred if true then the left pointer will be considered a predecessor.
*/
void pred( final boolean pred ) {
if ( pred ) info |= PRED_MASK;
else info &= ~PRED_MASK;
}
/** Sets whether the right pointer is really a successor.
* @param succ if true then the right pointer will be considered a successor.
*/
void succ( final boolean succ ) {
if ( succ ) info |= SUCC_MASK;
else info &= ~SUCC_MASK;
}
/** Sets the left pointer to a predecessor.
* @param pred the predecessr.
*/
void pred( final Entry KEY_GENERIC pred ) {
info |= PRED_MASK;
left = pred;
}
/** Sets the right pointer to a successor.
* @param succ the successor.
*/
void succ( final Entry KEY_GENERIC succ ) {
info |= SUCC_MASK;
right = succ;
}
/** Sets the left pointer to the given subtree.
* @param left the new left subtree.
*/
void left( final Entry KEY_GENERIC left ) {
info &= ~PRED_MASK;
this.left = left;
}
/** Sets the right pointer to the given subtree.
* @param right the new right subtree.
*/
void right( final Entry KEY_GENERIC right ) {
info &= ~SUCC_MASK;
this.right = right;
}
/** Returns the current level of the node.
* @return the current level of this node.
*/
int balance() {
return (byte)info;
}
/** Sets the level of this node.
* @param level the new level of this node.
*/
void balance( int level ) {
info &= ~BALANCE_MASK;
info |= ( level & BALANCE_MASK );
}
/** Increments the level of this node. */
void incBalance() {
info = info & ~BALANCE_MASK | ( (byte)info + 1 ) & 0xFF;
}
/** Decrements the level of this node. */
protected void decBalance() {
info = info & ~BALANCE_MASK | ( (byte)info - 1 ) & 0xFF;
}
/** Computes the next entry in the set order.
*
* @return the next entry (null
) if this is the last entry).
*/
Entry KEY_GENERIC next() {
Entry KEY_GENERIC next = this.right;
if ( ( info & SUCC_MASK ) == 0 ) while ( ( next.info & PRED_MASK ) == 0 ) next = next.left;
return next;
}
/** Computes the previous entry in the set order.
*
* @return the previous entry (null
) if this is the first entry).
*/
Entry KEY_GENERIC prev() {
Entry KEY_GENERIC prev = this.left;
if ( ( info & PRED_MASK ) == 0 ) while ( ( prev.info & SUCC_MASK ) == 0 ) prev = prev.right;
return prev;
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
public Entry KEY_GENERIC clone() {
Entry KEY_GENERIC c;
try {
c = (Entry KEY_GENERIC)super.clone();
}
catch(CloneNotSupportedException cantHappen) {
throw new InternalError();
}
c.key = key;
c.info = info;
return c;
}
public boolean equals( final Object o ) {
if (!(o instanceof Entry)) return false;
Entry KEY_GENERIC_WILDCARD e = (Entry KEY_GENERIC_WILDCARD)o;
return KEY_EQUALS(key, e.key);
}
public int hashCode() {
return KEY2JAVAHASH_NOT_NULL(key);
}
public String toString() {
return String.valueOf( key );
}
/*
public void prettyPrint() {
prettyPrint(0);
}
public void prettyPrint(int level) {
if ( pred() ) {
for (int i = 0; i < level; i++)
System.err.print(" ");
System.err.println("pred: " + left );
}
else if (left != null)
left.prettyPrint(level +1 );
for (int i = 0; i < level; i++)
System.err.print(" ");
System.err.println(key + " (" + level() + ")");
if ( succ() ) {
for (int i = 0; i < level; i++)
System.err.print(" ");
System.err.println("succ: " + right );
}
else if (right != null)
right.prettyPrint(level + 1);
}
*/
}
/*
public void prettyPrint() {
System.err.println("size: " + count);
if (tree != null) tree.prettyPrint();
}
*/
public int size() {
return count;
}
public boolean isEmpty() {
return count == 0;
}
public KEY_GENERIC_TYPE FIRST() {
if ( tree == null ) throw new NoSuchElementException();
return firstEntry.key;
}
public KEY_GENERIC_TYPE LAST() {
if ( tree == null ) throw new NoSuchElementException();
return lastEntry.key;
}
/** An iterator on the whole range.
*
* null
if no previous entry exists). */
Entry KEY_GENERIC prev;
/** The entry that will be returned by the next call to {@link java.util.ListIterator#next()} (or null
if no next entry exists). */
Entry KEY_GENERIC next;
/** The last entry that was returned (or null
if we did not iterate or used {@link #remove()}). */
Entry KEY_GENERIC curr;
/** The current index (in the sense of a {@link java.util.ListIterator}). Note that this value is not meaningful when this {@link SetIterator} has been created using the nonempty constructor.*/
int index = 0;
SetIterator() {
next = firstEntry;
}
SetIterator( final KEY_GENERIC_TYPE k ) {
if ( ( next = locateKey( k ) ) != null ) {
if ( compare( next.key, k ) <= 0 ) {
prev = next;
next = next.next();
}
else prev = next.prev();
}
}
public boolean hasNext() { return next != null; }
public boolean hasPrevious() { return prev != null; }
void updateNext() {
next = next.next();
}
Entry KEY_GENERIC nextEntry() {
if ( ! hasNext() ) throw new NoSuchElementException();
curr = prev = next;
index++;
updateNext();
return curr;
}
public KEY_GENERIC_TYPE NEXT_KEY() { return nextEntry().key; }
public KEY_GENERIC_TYPE PREV_KEY() { return previousEntry().key; }
void updatePrevious() {
prev = prev.prev();
}
Entry KEY_GENERIC previousEntry() {
if ( ! hasPrevious() ) throw new NoSuchElementException();
curr = next = prev;
index--;
updatePrevious();
return curr;
}
public int nextIndex() {
return index;
}
public int previousIndex() {
return index - 1;
}
public void remove() {
if ( curr == null ) throw new IllegalStateException();
/* If the last operation was a next(), we are removing an entry that preceeds
the current index, and thus we must decrement it. */
if ( curr == prev ) index--;
next = prev = curr;
updatePrevious();
updateNext();
AVL_TREE_SET.this.remove( curr.key );
curr = null;
}
}
public KEY_BIDI_ITERATOR KEY_GENERIC iterator() {
return new SetIterator();
}
public KEY_BIDI_ITERATOR KEY_GENERIC iterator( final KEY_GENERIC_TYPE from ) {
return new SetIterator( from );
}
public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() {
return actualComparator;
}
public SORTED_SET KEY_GENERIC headSet( final KEY_GENERIC_TYPE to ) {
return new Subset( KEY_NULL, true, to, false );
}
public SORTED_SET KEY_GENERIC tailSet( final KEY_GENERIC_TYPE from ) {
return new Subset( from, false, KEY_NULL, true );
}
public SORTED_SET KEY_GENERIC subSet( final KEY_GENERIC_TYPE from, final KEY_GENERIC_TYPE to ) {
return new Subset( from, false, to, false );
}
/** A subset with given range.
*
* null
if the subset is empty.
*/
public AVL_TREE_SET.Entry KEY_GENERIC firstEntry() {
if ( tree == null ) return null;
// If this subset goes to -infinity, we return the main set first entry; otherwise, we locate the start of the set.
AVL_TREE_SET.Entry KEY_GENERIC e;
if ( bottom ) e = firstEntry;
else {
e = locateKey( from );
// If we find either the start or something greater we're OK.
if ( compare( e.key, from ) < 0 ) e = e.next();
}
// Finally, if this subset doesn't go to infinity, we check that the resulting key isn't greater than the end.
if ( e == null || ! top && compare( e.key, to ) >= 0 ) return null;
return e;
}
/** Locates the last entry.
*
* @return the last entry of this subset, or null
if the subset is empty.
*/
public AVL_TREE_SET.Entry KEY_GENERIC lastEntry() {
if ( tree == null ) return null;
// If this subset goes to infinity, we return the main set last entry; otherwise, we locate the end of the set.
AVL_TREE_SET.Entry KEY_GENERIC e;
if ( top ) e = lastEntry;
else {
e = locateKey( to );
// If we find something smaller than the end we're OK.
if ( compare( e.key, to ) >= 0 ) e = e.prev();
}
// Finally, if this subset doesn't go to -infinity, we check that the resulting key isn't smaller than the start.
if ( e == null || ! bottom && compare( e.key, from ) < 0 ) return null;
return e;
}
public KEY_GENERIC_TYPE FIRST() {
AVL_TREE_SET.Entry KEY_GENERIC e = firstEntry();
if ( e == null ) throw new NoSuchElementException();
return e.key;
}
public KEY_GENERIC_TYPE LAST() {
AVL_TREE_SET.Entry KEY_GENERIC e = lastEntry();
if ( e == null ) throw new NoSuchElementException();
return e.key;
}
/** An iterator for subranges.
*
* null
.
*/
private final class SubsetIterator extends SetIterator {
SubsetIterator() {
next = firstEntry();
}
SubsetIterator( final KEY_GENERIC_TYPE k ) {
this();
if ( next != null ) {
if ( ! bottom && compare( k, next.key ) < 0 ) prev = null;
else if ( ! top && compare( k, ( prev = lastEntry() ).key ) >= 0 ) next = null;
else {
next = locateKey( k );
if ( compare( next.key, k ) <= 0 ) {
prev = next;
next = next.next();
}
else prev = next.prev();
}
}
}
void updatePrevious() {
prev = prev.prev();
if ( ! bottom && prev != null && AVL_TREE_SET.this.compare( prev.key, from ) < 0 ) prev = null;
}
void updateNext() {
next = next.next();
if ( ! top && next != null && AVL_TREE_SET.this.compare( next.key, to ) >= 0 ) next = null;
}
}
}
/** Returns a deep copy of this tree set.
*
* n
times, stopping if {@link
* #hasPrevious()} becomes false. */
public int back( final int n ) {
int i = n;
while( i-- != 0 && hasPrevious() ) PREV_KEY();
return n - i - 1;
}
}
fastutil-7.0.2/drv/AbstractBigList.drv 0000644 0000000 0000000 00000047441 12502266146 016541 0 ustar root wheel /*
* Copyright (C) 2010-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
#if #keys(reference)
import it.unimi.dsi.fastutil.Stack;
#endif
import java.util.Iterator;
import java.util.Collection;
import java.util.NoSuchElementException;
import it.unimi.dsi.fastutil.BigList;
import it.unimi.dsi.fastutil.BigListIterator;
/** An abstract class providing basic methods for big lists implementing a type-specific big list interface. */
public abstract class ABSTRACT_BIG_LIST KEY_GENERIC extends ABSTRACT_COLLECTION KEY_GENERIC implements BIG_LIST KEY_GENERIC, STACK KEY_GENERIC {
protected ABSTRACT_BIG_LIST() {}
/** Ensures that the given index is nonnegative and not greater than this big-list size.
*
* @param index an index.
* @throws IndexOutOfBoundsException if the given index is negative or greater than this big-list size.
*/
protected void ensureIndex( final long index ) {
if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" );
if ( index > size64() ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than list size (" + ( size64() ) + ")" );
}
/** Ensures that the given index is nonnegative and smaller than this big-list size.
*
* @param index an index.
* @throws IndexOutOfBoundsException if the given index is negative or not smaller than this big-list size.
*/
protected void ensureRestrictedIndex( final long index ) {
if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" );
if ( index >= size64() ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + ( size64() ) + ")" );
}
public void add( final long index, final KEY_GENERIC_TYPE k ) {
throw new UnsupportedOperationException();
}
public boolean add( final KEY_GENERIC_TYPE k ) {
add( size64(), k );
return true;
}
public KEY_GENERIC_TYPE REMOVE_KEY( long i ) {
throw new UnsupportedOperationException();
}
public KEY_GENERIC_TYPE REMOVE_KEY( int i ) {
return REMOVE_KEY( (long)i );
}
public KEY_GENERIC_TYPE set( final long index, final KEY_GENERIC_TYPE k ) {
throw new UnsupportedOperationException();
}
public KEY_GENERIC_TYPE set( final int index, final KEY_GENERIC_TYPE k ) {
return set( (long)index, k );
}
public boolean addAll( long index, final Collection extends KEY_GENERIC_CLASS> c ) {
ensureIndex( index );
int n = c.size();
if ( n == 0 ) return false;
Iterator extends KEY_GENERIC_CLASS> i = c.iterator();
while( n-- != 0 ) add( index++, i.next() );
return true;
}
public boolean addAll( int index, final Collection extends KEY_GENERIC_CLASS> c ) {
return addAll( (long)index, c );
}
/** Delegates to a more generic method. */
public boolean addAll( final Collection extends KEY_GENERIC_CLASS> c ) {
return addAll( size64(), c );
}
public KEY_BIG_LIST_ITERATOR KEY_GENERIC iterator() {
return listIterator();
}
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator() {
return listIterator( 0L );
}
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator( final long index ) {
return new KEY_ABSTRACT_BIG_LIST_ITERATOR KEY_GENERIC() {
long pos = index, last = -1;
public boolean hasNext() { return pos < ABSTRACT_BIG_LIST.this.size64(); }
public boolean hasPrevious() { return pos > 0; }
public KEY_GENERIC_TYPE NEXT_KEY() { if ( ! hasNext() ) throw new NoSuchElementException(); return ABSTRACT_BIG_LIST.this.GET_KEY( last = pos++ ); }
public KEY_GENERIC_TYPE PREV_KEY() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return ABSTRACT_BIG_LIST.this.GET_KEY( last = --pos ); }
public long nextIndex() { return pos; }
public long previousIndex() { return pos - 1; }
public void add( KEY_GENERIC_TYPE k ) {
if ( last == -1 ) throw new IllegalStateException();
ABSTRACT_BIG_LIST.this.add( pos++, k );
last = -1;
}
public void set( KEY_GENERIC_TYPE k ) {
if ( last == -1 ) throw new IllegalStateException();
ABSTRACT_BIG_LIST.this.set( last, k );
}
public void remove() {
if ( last == -1 ) throw new IllegalStateException();
ABSTRACT_BIG_LIST.this.REMOVE_KEY( last );
/* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */
if ( last < pos ) pos--;
last = -1;
}
};
}
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator( final int index ) {
return listIterator( (long)index );
}
public boolean contains( final KEY_TYPE k ) {
return indexOf( k ) >= 0;
}
public long indexOf( final KEY_TYPE k ) {
final KEY_BIG_LIST_ITERATOR KEY_GENERIC i = listIterator();
KEY_GENERIC_TYPE e;
while( i.hasNext() ) {
e = i.NEXT_KEY();
if ( KEY_EQUALS( k, e ) ) return i.previousIndex();
}
return -1;
}
public long lastIndexOf( final KEY_TYPE k ) {
KEY_BIG_LIST_ITERATOR KEY_GENERIC i = listIterator( size64() );
KEY_GENERIC_TYPE e;
while( i.hasPrevious() ) {
e = i.PREV_KEY();
if ( KEY_EQUALS( k, e ) ) return i.nextIndex();
}
return -1;
}
public void size( final long size ) {
long i = size64();
if ( size > i ) while( i++ < size ) add( KEY_NULL );
else while( i-- != size ) remove( i );
}
public void size( final int size ) {
size( (long)size );
}
public BIG_LIST KEY_GENERIC subList( final long from, final long to ) {
ensureIndex( from );
ensureIndex( to );
if ( from > to ) throw new IndexOutOfBoundsException( "Start index (" + from + ") is greater than end index (" + to + ")" );
return new SUBLIST KEY_GENERIC( this, from, to );
}
/** Removes elements of this type-specific big list one-by-one.
*
* ClassCastException
.
*
* @param l a big list.
* @return if the argument is a {@link BigList}, a negative integer,
* zero, or a positive integer as this list is lexicographically less than, equal
* to, or greater than the argument.
* @throws ClassCastException if the argument is not a big list.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public int compareTo( final BigList extends KEY_GENERIC_CLASS> l ) {
if ( l == this ) return 0;
if ( l instanceof BIG_LIST ) {
final KEY_BIG_LIST_ITERATOR KEY_GENERIC i1 = listIterator(), i2 = ((BIG_LIST KEY_GENERIC)l).listIterator();
int r;
KEY_GENERIC_TYPE e1, e2;
while( i1.hasNext() && i2.hasNext() ) {
e1 = i1.NEXT_KEY();
e2 = i2.NEXT_KEY();
if ( ( r = KEY_CMP( e1, e2 ) ) != 0 ) return r;
}
return i2.hasNext() ? -1 : ( i1.hasNext() ? 1 : 0 );
}
BigListIterator extends KEY_GENERIC_CLASS> i1 = listIterator(), i2 = l.listIterator();
int r;
while( i1.hasNext() && i2.hasNext() ) {
if ( ( r = ((Comparable super KEY_GENERIC_CLASS>)i1.next()).compareTo( i2.next() ) ) != 0 ) return r;
}
return i2.hasNext() ? -1 : ( i1.hasNext() ? 1 : 0 );
}
#endif
/** Returns the hash code for this big list, which is identical to {@link java.util.List#hashCode()}.
*
* @return the hash code for this big list.
*/
public int hashCode() {
KEY_ITERATOR KEY_GENERIC i = iterator();
int h = 1;
long s = size64();
while ( s-- != 0 ) {
KEY_GENERIC_TYPE k = i.NEXT_KEY();
h = 31 * h + KEY2JAVAHASH( k );
}
return h;
}
public void push( KEY_GENERIC_TYPE o ) {
add( o );
}
public KEY_GENERIC_TYPE POP() {
if ( isEmpty() ) throw new NoSuchElementException();
return REMOVE_KEY( size64() - 1 );
}
public KEY_GENERIC_TYPE TOP() {
if ( isEmpty() ) throw new NoSuchElementException();
return GET_KEY( size64() - 1 );
}
public KEY_GENERIC_TYPE PEEK( int i ) {
return GET_KEY( size64() - 1 - i );
}
#if #keys(primitive)
public KEY_TYPE GET_KEY( final int index ) {
return GET_KEY( (long)index );
}
public boolean rem( KEY_TYPE k ) {
long index = indexOf( k );
if ( index == -1 ) return false;
REMOVE_KEY( index );
return true;
}
/** Delegates to a more generic method. */
public boolean addAll( final long index, final COLLECTION c ) {
return addAll( index, (Collection extends KEY_CLASS>)c );
}
/** Delegates to a more generic method. */
public boolean addAll( final long index, final BIG_LIST l ) {
return addAll( index, (COLLECTION)l );
}
public boolean addAll( final COLLECTION c ) {
return addAll( size64(), c );
}
public boolean addAll( final BIG_LIST l ) {
return addAll( size64(), l );
}
/** Delegates to the corresponding type-specific method. */
public void add( final long index, final KEY_CLASS ok ) {
add( index, ok.KEY_VALUE() );
}
/** Delegates to the corresponding type-specific method. */
public KEY_CLASS set( final long index, final KEY_CLASS ok ) {
return KEY2OBJ( set( index, ok.KEY_VALUE() ) );
}
/** Delegates to the corresponding type-specific method. */
public KEY_CLASS get( final long index ) {
return KEY2OBJ( GET_KEY( index ) );
}
/** Delegates to the corresponding type-specific method. */
public long indexOf( final Object ok ) {
return indexOf( KEY_OBJ2TYPE( ok ) );
}
/** Delegates to the corresponding type-specific method. */
public long lastIndexOf( final Object ok ) {
return lastIndexOf( KEY_OBJ2TYPE( ok ) );
}
/** Delegates to the corresponding type-specific method. */
public KEY_CLASS remove( final int index ) {
return KEY2OBJ( REMOVE_KEY( index ) );
}
/** Delegates to the corresponding type-specific method. */
public KEY_CLASS remove( final long index ) {
return KEY2OBJ( REMOVE_KEY( index ) );
}
/** Delegates to the corresponding type-specific method. */
public void push( KEY_CLASS o ) {
push( o.KEY_VALUE() );
}
/** Delegates to the corresponding type-specific method. */
public KEY_CLASS pop() {
return KEY_CLASS.valueOf( POP() );
}
/** Delegates to the corresponding type-specific method. */
public KEY_CLASS top() {
return KEY_CLASS.valueOf( TOP() );
}
/** Delegates to the corresponding type-specific method. */
public KEY_CLASS peek( int i ) {
return KEY_CLASS.valueOf( PEEK( i ) );
}
#else
public KEY_GENERIC_CLASS get( int index ) {
return get( (long)index );
}
#endif
public String toString() {
final StringBuilder s = new StringBuilder();
final KEY_ITERATOR KEY_GENERIC i = iterator();
long n = size64();
KEY_GENERIC_TYPE k;
boolean first = true;
s.append("[");
while( n-- != 0 ) {
if (first) first = false;
else s.append(", ");
k = i.NEXT_KEY();
#if #keys(reference)
if (this == k) s.append("(this big list)"); else
#endif
s.append( String.valueOf( k ) );
}
s.append("]");
return s.toString();
}
public static class SUBLIST KEY_GENERIC extends ABSTRACT_BIG_LIST KEY_GENERIC implements java.io.Serializable {
private static final long serialVersionUID = -7046029254386353129L;
/** The list this sublist restricts. */
protected final BIG_LIST KEY_GENERIC l;
/** Initial (inclusive) index of this sublist. */
protected final long from;
/** Final (exclusive) index of this sublist. */
protected long to;
private static final boolean ASSERTS = ASSERTS_VALUE;
public SUBLIST( final BIG_LIST KEY_GENERIC l, final long from, final long to ) {
this.l = l;
this.from = from;
this.to = to;
}
private void assertRange() {
if ( ASSERTS ) {
assert from <= l.size64();
assert to <= l.size64();
assert to >= from;
}
}
public boolean add( final KEY_GENERIC_TYPE k ) {
l.add( to, k );
to++;
if ( ASSERTS ) assertRange();
return true;
}
public void add( final long index, final KEY_GENERIC_TYPE k ) {
ensureIndex( index );
l.add( from + index, k );
to++;
if ( ASSERTS ) assertRange();
}
public boolean addAll( final long index, final Collection extends KEY_GENERIC_CLASS> c ) {
ensureIndex( index );
to += c.size();
if ( ASSERTS ) {
boolean retVal = l.addAll( from + index, c );
assertRange();
return retVal;
}
return l.addAll( from + index, c );
}
public KEY_GENERIC_TYPE GET_KEY( long index ) {
ensureRestrictedIndex( index );
return l.GET_KEY( from + index );
}
public KEY_GENERIC_TYPE REMOVE_KEY( long index ) {
ensureRestrictedIndex( index );
to--;
return l.REMOVE_KEY( from + index );
}
public KEY_GENERIC_TYPE set( long index, KEY_GENERIC_TYPE k ) {
ensureRestrictedIndex( index );
return l.set( from + index, k );
}
public void clear() {
removeElements( 0, size64() );
if ( ASSERTS ) assertRange();
}
public long size64() {
return to - from;
}
public void getElements( final long from, final KEY_TYPE[][] a, final long offset, final long length ) {
ensureIndex( from );
if ( from + length > size64() ) throw new IndexOutOfBoundsException( "End index (" + from + length + ") is greater than list size (" + size64() + ")" );
l.getElements( this.from + from, a, offset, length );
}
public void removeElements( final long from, final long to ) {
ensureIndex( from );
ensureIndex( to );
l.removeElements( this.from + from, this.from + to );
this.to -= ( to - from );
if ( ASSERTS ) assertRange();
}
public void addElements( final long index, final KEY_GENERIC_TYPE a[][], long offset, long length ) {
ensureIndex( index );
l.addElements( this.from + index, a, offset, length );
this.to += length;
if ( ASSERTS ) assertRange();
}
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator( final long index ) {
ensureIndex( index );
return new KEY_ABSTRACT_BIG_LIST_ITERATOR KEY_GENERIC() {
long pos = index, last = -1;
public boolean hasNext() { return pos < size64(); }
public boolean hasPrevious() { return pos > 0; }
public KEY_GENERIC_TYPE NEXT_KEY() { if ( ! hasNext() ) throw new NoSuchElementException(); return l.GET_KEY( from + ( last = pos++ ) ); }
public KEY_GENERIC_TYPE PREV_KEY() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return l.GET_KEY( from + ( last = --pos ) ); }
public long nextIndex() { return pos; }
public long previousIndex() { return pos - 1; }
public void add( KEY_GENERIC_TYPE k ) {
if ( last == -1 ) throw new IllegalStateException();
SUBLIST.this.add( pos++, k );
last = -1;
if ( ASSERTS ) assertRange();
}
public void set( KEY_GENERIC_TYPE k ) {
if ( last == -1 ) throw new IllegalStateException();
SUBLIST.this.set( last, k );
}
public void remove() {
if ( last == -1 ) throw new IllegalStateException();
SUBLIST.this.REMOVE_KEY( last );
/* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */
if ( last < pos ) pos--;
last = -1;
if ( ASSERTS ) assertRange();
}
};
}
public BIG_LIST KEY_GENERIC subList( final long from, final long to ) {
ensureIndex( from );
ensureIndex( to );
if ( from > to ) throw new IllegalArgumentException( "Start index (" + from + ") is greater than end index (" + to + ")" );
return new SUBLIST KEY_GENERIC( this, from, to );
}
#if #keys(primitive)
public boolean rem( KEY_TYPE k ) {
long index = indexOf( k );
if ( index == -1 ) return false;
to--;
l.REMOVE_KEY( from + index );
if ( ASSERTS ) assertRange();
return true;
}
public boolean remove( final Object o ) {
return rem( KEY_OBJ2TYPE( o ) );
}
public boolean addAll( final long index, final COLLECTION c ) {
ensureIndex( index );
to += c.size();
if ( ASSERTS ) {
boolean retVal = l.addAll( from + index, c );
assertRange();
return retVal;
}
return l.addAll( from + index, c );
}
public boolean addAll( final long index, final LIST l ) {
ensureIndex( index );
to += l.size();
if ( ASSERTS ) {
boolean retVal = this.l.addAll( from + index, l );
assertRange();
return retVal;
}
return this.l.addAll( from + index, l );
}
#else
public boolean remove( final Object o ) {
long index = indexOf( o );
if ( index == -1 ) return false;
REMOVE_KEY( index );
return true;
}
#endif
}
}
fastutil-7.0.2/drv/AbstractBigListIterator.drv 0000644 0000000 0000000 00000004771 12502261336 020246 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import java.util.ListIterator;
import it.unimi.dsi.fastutil.BigListIterator;
/** An abstract class facilitating the creation of type-specific {@linkplain it.unimi.dsi.fastutil.BigListIterator big-list iterators}.
*
* n
times, stopping if {@link #hasNext()} becomes false.*/
public long skip( final long n ) {
long i = n;
while( i-- != 0 && hasNext() ) NEXT_KEY();
return n - i - 1;
}
/** This method just iterates the type-specific version of {@link #previous()} for
* at most n
times, stopping if {@link
* #hasPrevious()} becomes false. */
public long back( final long n ) {
long i = n;
while( i-- != 0 && hasPrevious() ) PREV_KEY();
return n - i - 1;
}
}
fastutil-7.0.2/drv/AbstractCollection.drv 0000644 0000000 0000000 00000016323 12502261336 017266 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import java.util.AbstractCollection;
import java.util.Collection;
import java.util.Iterator;
/** An abstract class providing basic methods for collections implementing a type-specific interface.
*
* add()
, {@link #remove(Object)} and
* {@link #contains(Object)} methods that just call the type-specific counterpart.
*/
public abstract class ABSTRACT_COLLECTION KEY_GENERIC extends AbstractCollectiontrue
if this collection changed as a result of the call.
*/
public boolean addAll( COLLECTION c ) {
boolean retVal = false;
final KEY_ITERATOR i = c.iterator();
int n = c.size();
while( n-- != 0 ) if ( add( i.NEXT_KEY() ) ) retVal = true;
return retVal;
}
/** Checks whether this collection contains all elements from the given type-specific collection.
*
* @param c a type-specific collection.
* @return true
if this collection contains all elements of the argument.
*/
public boolean containsAll( COLLECTION c ) {
final KEY_ITERATOR i = c.iterator();
int n = c.size();
while( n-- != 0 ) if ( ! contains( i.NEXT_KEY() ) ) return false;
return true;
}
/** Retains in this collection only elements from the given type-specific collection.
*
* @param c a type-specific collection.
* @return true
if this collection changed as a result of the call.
*/
public boolean retainAll( COLLECTION c ) {
boolean retVal = false;
int n = size();
final KEY_ITERATOR i = iterator();
while( n-- != 0 ) {
if ( ! c.contains( i.NEXT_KEY() ) ) {
i.remove();
retVal = true;
}
}
return retVal;
}
/** Remove from this collection all elements in the given type-specific collection.
*
* @param c a type-specific collection.
* @return true
if this collection changed as a result of the call.
*/
public boolean removeAll( COLLECTION c ) {
boolean retVal = false;
int n = c.size();
final KEY_ITERATOR i = c.iterator();
while( n-- != 0 ) if ( rem( i.NEXT_KEY() ) ) retVal = true;
return retVal;
}
#endif
public Object[] toArray() {
final Object[] a = new Object[ size() ];
it.unimi.dsi.fastutil.objects.ObjectIterators.unwrap( iterator(), a );
return a;
}
@SuppressWarnings("unchecked")
public true
if this collection changed as a result of the call.
*/
public boolean addAll( Collection extends KEY_GENERIC_CLASS> c ) {
boolean retVal = false;
final Iterator extends KEY_GENERIC_CLASS> i = c.iterator();
int n = c.size();
while( n-- != 0 ) if ( add( i.next() ) ) retVal = true;
return retVal;
}
public boolean add( KEY_GENERIC_TYPE k ) {
throw new UnsupportedOperationException();
}
/** Delegates to the new covariantly stronger generic method. */
@Deprecated
public KEY_ITERATOR KEY_GENERIC KEY_ITERATOR_METHOD() {
return iterator();
}
public abstract KEY_ITERATOR KEY_GENERIC iterator();
#if #keys(primitive)
/** Delegates to the type-specific rem()
method. */
public boolean remove( Object ok ) {
return rem( KEY_OBJ2TYPE( ok ) );
}
/** Delegates to the corresponding type-specific method. */
public boolean add( final KEY_CLASS o ) {
return add( o.KEY_VALUE() );
}
/** Delegates to the corresponding type-specific method. */
public boolean rem( final Object o ) {
return rem( KEY_OBJ2TYPE(o) );
}
/** Delegates to the corresponding type-specific method. */
public boolean contains( final Object o ) {
return contains( KEY_OBJ2TYPE(o) );
}
public boolean contains( final KEY_TYPE k ) {
final KEY_ITERATOR iterator = iterator();
while ( iterator.hasNext() ) if ( k == iterator.NEXT_KEY() ) return true;
return false;
}
public boolean rem( final KEY_TYPE k ) {
final KEY_ITERATOR iterator = iterator();
while ( iterator.hasNext() )
if ( k == iterator.NEXT_KEY() ) {
iterator.remove();
return true;
}
return false;
}
#endif
/** Checks whether this collection contains all elements from the given collection.
*
* @param c a collection.
* @return true
if this collection contains all elements of the argument.
*/
public boolean containsAll( Collection> c ) {
int n = c.size();
final Iterator> i = c.iterator();
while( n-- != 0 ) if ( ! contains( i.next() ) ) return false;
return true;
}
/** Retains in this collection only elements from the given collection.
*
* @param c a collection.
* @return true
if this collection changed as a result of the call.
*/
public boolean retainAll( Collection> c ) {
boolean retVal = false;
int n = size();
final Iterator> i = iterator();
while( n-- != 0 ) {
if ( ! c.contains( i.next() ) ) {
i.remove();
retVal = true;
}
}
return retVal;
}
/** Remove from this collection all elements in the given collection.
* If the collection is an instance of this class, it uses faster iterators.
*
* @param c a collection.
* @return true
if this collection changed as a result of the call.
*/
public boolean removeAll( Collection> c ) {
boolean retVal = false;
int n = c.size();
final Iterator> i = c.iterator();
while( n-- != 0 ) if ( remove( i.next() ) ) retVal = true;
return retVal;
}
public boolean isEmpty() {
return size() == 0;
}
public String toString() {
final StringBuilder s = new StringBuilder();
final KEY_ITERATOR KEY_GENERIC i = iterator();
int n = size();
KEY_TYPE k;
boolean first = true;
s.append("{");
while(n-- != 0) {
if (first) first = false;
else s.append(", ");
k = i.NEXT_KEY();
#if #keys(reference)
if (this == k) s.append("(this collection)"); else
#endif
s.append(String.valueOf(k));
}
s.append("}");
return s.toString();
}
}
fastutil-7.0.2/drv/AbstractComparator.drv 0000644 0000000 0000000 00000002512 12502261336 017275 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
/** An abstract class facilitating the creation of type-specific {@linkplain java.util.Comparator comparators}.
*
* null
on a missing key).
*
* defRetValue
to denote lack of a key in type-specific methods. The value
* is serialized.
*
* get()
,
* type-specific containsKey()
, and size()
methods.
*
*/
public abstract class ABSTRACT_FUNCTION KEY_VALUE_GENERIC implements FUNCTION KEY_VALUE_GENERIC, java.io.Serializable {
private static final long serialVersionUID = -4940583368468432370L;
protected ABSTRACT_FUNCTION() {}
/**
* The default return value for get()
, put()
and
* remove()
.
*/
protected VALUE_GENERIC_TYPE defRetValue;
public void defaultReturnValue( final VALUE_GENERIC_TYPE rv ) {
defRetValue = rv;
}
public VALUE_GENERIC_TYPE defaultReturnValue() {
return defRetValue;
}
public VALUE_GENERIC_TYPE put( KEY_GENERIC_TYPE key, VALUE_GENERIC_TYPE value ) {
throw new UnsupportedOperationException();
}
public VALUE_GENERIC_TYPE REMOVE_VALUE( KEY_TYPE key ) {
throw new UnsupportedOperationException();
}
public void clear() {
throw new UnsupportedOperationException();
}
#if #keys(primitive)
public boolean containsKey( final Object ok ) {
return containsKey( KEY_OBJ2TYPE( ok ) );
}
#endif
#if #keys(primitive) || #values(primitive)
/** Delegates to the corresponding type-specific method, taking care of returning null
on a missing key.
*
* containsKey()
. Thus,
* it probes the map twice. Implementors of subclasses should override it with a more efficient method.
*/
public VALUE_GENERIC_CLASS get( final Object ok ) {
final KEY_TYPE k = KEY_OBJ2TYPE( ok );
return containsKey( k ) ? VALUE2OBJ( GET_VALUE( k ) ) : null;
}
/** Delegates to the corresponding type-specific method, taking care of returning null
on a missing key.
*
* containsKey()
. Thus,
* it probes the map twice. Implementors of subclasses should override it with a more efficient method.
*/
public VALUE_GENERIC_CLASS put( final KEY_GENERIC_CLASS ok, final VALUE_GENERIC_CLASS ov ) {
final KEY_GENERIC_TYPE k = KEY_CLASS2TYPE( ok );
final boolean containsKey = containsKey( k );
final VALUE_GENERIC_TYPE v = put( k, VALUE_CLASS2TYPE( ov ) );
return containsKey ? VALUE2OBJ( v ) : null;
}
/** Delegates to the corresponding type-specific method, taking care of returning null
on a missing key.
*
* containsKey()
. Thus,
* it probes the map twice. Implementors of subclasses should override it with a more efficient method.
*/
public VALUE_GENERIC_CLASS remove( final Object ok ) {
final KEY_TYPE k = KEY_OBJ2TYPE( ok );
final boolean containsKey = containsKey( k );
final VALUE_GENERIC_TYPE v = REMOVE_VALUE( k );
return containsKey ? VALUE2OBJ( v ) : null;
}
#endif
} fastutil-7.0.2/drv/AbstractIterator.drv 0000644 0000000 0000000 00000003753 12502261336 016767 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
/** An abstract class facilitating the creation of type-specific iterators.
*
* n
times, stopping if {@link #hasNext()} becomes false.*/
public int skip( final int n ) {
int i = n;
while( i-- != 0 && hasNext() ) NEXT_KEY();
return n - i - 1;
}
}
fastutil-7.0.2/drv/AbstractList.drv 0000644 0000000 0000000 00000047273 12502266175 016124 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
#if #keys(reference)
import it.unimi.dsi.fastutil.Stack;
#endif
import java.util.List;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Collection;
import java.util.NoSuchElementException;
/** An abstract class providing basic methods for lists implementing a type-specific list interface.
*
* ClassCastException
.
*
* @param l a list.
* @return if the argument is a {@link java.util.List}, a negative integer,
* zero, or a positive integer as this list is lexicographically less than, equal
* to, or greater than the argument.
* @throws ClassCastException if the argument is not a list.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public int compareTo( final List extends KEY_GENERIC_CLASS> l ) {
if ( l == this ) return 0;
if ( l instanceof LIST ) {
final KEY_LIST_ITERATOR KEY_GENERIC i1 = listIterator(), i2 = ((LIST KEY_GENERIC)l).listIterator();
int r;
KEY_GENERIC_TYPE e1, e2;
while( i1.hasNext() && i2.hasNext() ) {
e1 = i1.NEXT_KEY();
e2 = i2.NEXT_KEY();
if ( ( r = KEY_CMP( e1, e2 ) ) != 0 ) return r;
}
return i2.hasNext() ? -1 : ( i1.hasNext() ? 1 : 0 );
}
ListIterator extends KEY_GENERIC_CLASS> i1 = listIterator(), i2 = l.listIterator();
int r;
while( i1.hasNext() && i2.hasNext() ) {
if ( ( r = ((Comparable super KEY_GENERIC_CLASS>)i1.next()).compareTo( i2.next() ) ) != 0 ) return r;
}
return i2.hasNext() ? -1 : ( i1.hasNext() ? 1 : 0 );
}
#endif
/** Returns the hash code for this list, which is identical to {@link java.util.List#hashCode()}.
*
* @return the hash code for this list.
*/
public int hashCode() {
KEY_ITERATOR KEY_GENERIC i = iterator();
int h = 1, s = size();
while ( s-- != 0 ) {
KEY_GENERIC_TYPE k = i.NEXT_KEY();
h = 31 * h + KEY2JAVAHASH( k );
}
return h;
}
public void push( KEY_GENERIC_TYPE o ) {
add( o );
}
public KEY_GENERIC_TYPE POP() {
if ( isEmpty() ) throw new NoSuchElementException();
return REMOVE_KEY( size() - 1 );
}
public KEY_GENERIC_TYPE TOP() {
if ( isEmpty() ) throw new NoSuchElementException();
return GET_KEY( size() - 1 );
}
public KEY_GENERIC_TYPE PEEK( int i ) {
return GET_KEY( size() - 1 - i );
}
#if #keys(primitive)
public boolean rem( KEY_TYPE k ) {
int index = indexOf( k );
if ( index == -1 ) return false;
REMOVE_KEY( index );
return true;
}
/** Delegates to rem()
. */
public boolean remove( final Object o ) {
return rem( KEY_OBJ2TYPE( o ) );
}
/** Delegates to a more generic method. */
public boolean addAll( final int index, final COLLECTION c ) {
return addAll( index, (Collection extends KEY_CLASS>)c );
}
/** Delegates to a more generic method. */
public boolean addAll( final int index, final LIST l ) {
return addAll( index, (COLLECTION)l );
}
public boolean addAll( final COLLECTION c ) {
return addAll( size(), c );
}
public boolean addAll( final LIST l ) {
return addAll( size(), l );
}
/** Delegates to the corresponding type-specific method. */
public void add( final int index, final KEY_CLASS ok ) {
add( index, ok.KEY_VALUE() );
}
/** Delegates to the corresponding type-specific method. */
public KEY_CLASS set( final int index, final KEY_CLASS ok ) {
return KEY2OBJ( set( index, ok.KEY_VALUE() ) );
}
/** Delegates to the corresponding type-specific method. */
public KEY_CLASS get( final int index ) {
return KEY2OBJ( GET_KEY( index ) );
}
/** Delegates to the corresponding type-specific method. */
public int indexOf( final Object ok) {
return indexOf( KEY_OBJ2TYPE( ok ) );
}
/** Delegates to the corresponding type-specific method. */
public int lastIndexOf( final Object ok ) {
return lastIndexOf( KEY_OBJ2TYPE( ok ) );
}
/** Delegates to the corresponding type-specific method. */
public KEY_CLASS remove( final int index ) {
return KEY2OBJ( REMOVE_KEY( index ) );
}
/** Delegates to the corresponding type-specific method. */
public void push( KEY_CLASS o ) {
push( o.KEY_VALUE() );
}
/** Delegates to the corresponding type-specific method. */
public KEY_CLASS pop() {
return KEY_CLASS.valueOf( POP() );
}
/** Delegates to the corresponding type-specific method. */
public KEY_CLASS top() {
return KEY_CLASS.valueOf( TOP() );
}
/** Delegates to the corresponding type-specific method. */
public KEY_CLASS peek( int i ) {
return KEY_CLASS.valueOf( PEEK( i ) );
}
#endif
public String toString() {
final StringBuilder s = new StringBuilder();
final KEY_ITERATOR KEY_GENERIC i = iterator();
int n = size();
KEY_GENERIC_TYPE k;
boolean first = true;
s.append("[");
while( n-- != 0 ) {
if (first) first = false;
else s.append(", ");
k = i.NEXT_KEY();
#if #keys(reference)
if (this == k) s.append("(this list)"); else
#endif
s.append( String.valueOf( k ) );
}
s.append("]");
return s.toString();
}
public static class SUBLIST KEY_GENERIC extends ABSTRACT_LIST KEY_GENERIC implements java.io.Serializable {
private static final long serialVersionUID = -7046029254386353129L;
/** The list this sublist restricts. */
protected final LIST KEY_GENERIC l;
/** Initial (inclusive) index of this sublist. */
protected final int from;
/** Final (exclusive) index of this sublist. */
protected int to;
private static final boolean ASSERTS = ASSERTS_VALUE;
public SUBLIST( final LIST KEY_GENERIC l, final int from, final int to ) {
this.l = l;
this.from = from;
this.to = to;
}
private void assertRange() {
if ( ASSERTS ) {
assert from <= l.size();
assert to <= l.size();
assert to >= from;
}
}
public boolean add( final KEY_GENERIC_TYPE k ) {
l.add( to, k );
to++;
if ( ASSERTS ) assertRange();
return true;
}
public void add( final int index, final KEY_GENERIC_TYPE k ) {
ensureIndex( index );
l.add( from + index, k );
to++;
if ( ASSERTS ) assertRange();
}
public boolean addAll( final int index, final Collection extends KEY_GENERIC_CLASS> c ) {
ensureIndex( index );
to += c.size();
if ( ASSERTS ) {
boolean retVal = l.addAll( from + index, c );
assertRange();
return retVal;
}
return l.addAll( from + index, c );
}
public KEY_GENERIC_TYPE GET_KEY( int index ) {
ensureRestrictedIndex( index );
return l.GET_KEY( from + index );
}
public KEY_GENERIC_TYPE REMOVE_KEY( int index ) {
ensureRestrictedIndex( index );
to--;
return l.REMOVE_KEY( from + index );
}
public KEY_GENERIC_TYPE set( int index, KEY_GENERIC_TYPE k ) {
ensureRestrictedIndex( index );
return l.set( from + index, k );
}
public void clear() {
removeElements( 0, size() );
if ( ASSERTS ) assertRange();
}
public int size() {
return to - from;
}
public void getElements( final int from, final KEY_TYPE[] a, final int offset, final int length ) {
ensureIndex( from );
if ( from + length > size() ) throw new IndexOutOfBoundsException( "End index (" + from + length + ") is greater than list size (" + size() + ")" );
l.getElements( this.from + from, a, offset, length );
}
public void removeElements( final int from, final int to ) {
ensureIndex( from );
ensureIndex( to );
l.removeElements( this.from + from, this.from + to );
this.to -= ( to - from );
if ( ASSERTS ) assertRange();
}
public void addElements( int index, final KEY_GENERIC_TYPE a[], int offset, int length ) {
ensureIndex( index );
l.addElements( this.from + index, a, offset, length );
this.to += length;
if ( ASSERTS ) assertRange();
}
public KEY_LIST_ITERATOR KEY_GENERIC listIterator( final int index ) {
ensureIndex( index );
return new KEY_ABSTRACT_LIST_ITERATOR KEY_GENERIC() {
int pos = index, last = -1;
public boolean hasNext() { return pos < size(); }
public boolean hasPrevious() { return pos > 0; }
public KEY_GENERIC_TYPE NEXT_KEY() { if ( ! hasNext() ) throw new NoSuchElementException(); return l.GET_KEY( from + ( last = pos++ ) ); }
public KEY_GENERIC_TYPE PREV_KEY() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return l.GET_KEY( from + ( last = --pos ) ); }
public int nextIndex() { return pos; }
public int previousIndex() { return pos - 1; }
public void add( KEY_GENERIC_TYPE k ) {
if ( last == -1 ) throw new IllegalStateException();
SUBLIST.this.add( pos++, k );
last = -1;
if ( ASSERTS ) assertRange();
}
public void set( KEY_GENERIC_TYPE k ) {
if ( last == -1 ) throw new IllegalStateException();
SUBLIST.this.set( last, k );
}
public void remove() {
if ( last == -1 ) throw new IllegalStateException();
SUBLIST.this.REMOVE_KEY( last );
/* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */
if ( last < pos ) pos--;
last = -1;
if ( ASSERTS ) assertRange();
}
};
}
public LIST KEY_GENERIC subList( final int from, final int to ) {
ensureIndex( from );
ensureIndex( to );
if ( from > to ) throw new IllegalArgumentException( "Start index (" + from + ") is greater than end index (" + to + ")" );
return new SUBLIST KEY_GENERIC( this, from, to );
}
#if #keys(primitive)
public boolean rem( KEY_TYPE k ) {
int index = indexOf( k );
if ( index == -1 ) return false;
to--;
l.REMOVE_KEY( from + index );
if ( ASSERTS ) assertRange();
return true;
}
public boolean remove( final Object o ) {
return rem( KEY_OBJ2TYPE( o ) );
}
public boolean addAll( final int index, final COLLECTION c ) {
ensureIndex( index );
to += c.size();
if ( ASSERTS ) {
boolean retVal = l.addAll( from + index, c );
assertRange();
return retVal;
}
return l.addAll( from + index, c );
}
public boolean addAll( final int index, final LIST l ) {
ensureIndex( index );
to += l.size();
if ( ASSERTS ) {
boolean retVal = this.l.addAll( from + index, l );
assertRange();
return retVal;
}
return this.l.addAll( from + index, l );
}
#else
public boolean remove( final Object o ) {
int index = indexOf( o );
if ( index == -1 ) return false;
REMOVE_KEY( index );
return true;
}
#endif
}
}
fastutil-7.0.2/drv/AbstractListIterator.drv 0000644 0000000 0000000 00000004001 12502261336 017606 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
/** An abstract class facilitating the creation of type-specific {@linkplain java.util.ListIterator list iterators}.
*
* null
on a missing key).
*
* remove()
.
*
* @param k the element to be removed.
* @return true if the set was modified.
*/
public boolean rem( KEY_TYPE k ) {
return remove( k );
}
/** Delegates to the corresponding type-specific method. */
public boolean remove( final Object o ) {
return remove( KEY_OBJ2TYPE( o ) );
}
#endif
}
fastutil-7.0.2/drv/AbstractSortedMap.drv 0000644 0000000 0000000 00000015632 12502261336 017073 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import VALUE_PACKAGE.VALUE_COLLECTION;
import VALUE_PACKAGE.VALUE_ABSTRACT_COLLECTION;
import VALUE_PACKAGE.VALUE_ABSTRACT_ITERATOR;
import VALUE_PACKAGE.VALUE_ITERATOR;
import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator;
import it.unimi.dsi.fastutil.objects.ObjectSortedSet;
import java.util.Map;
#if #keys(reference)
import java.util.Comparator;
#endif
/** An abstract class providing basic methods for sorted maps implementing a type-specific interface. */
public abstract class ABSTRACT_SORTED_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENERIC implements SORTED_MAP KEY_VALUE_GENERIC {
private static final long serialVersionUID = -1773560792952436569L;
protected ABSTRACT_SORTED_MAP() {}
#if #keys(primitive)
/** Delegates to the corresponding type-specific method. */
public SORTED_MAP KEY_VALUE_GENERIC headMap( final KEY_GENERIC_CLASS to ) {
return headMap( KEY_CLASS2TYPE( to ) );
}
/** Delegates to the corresponding type-specific method. */
public SORTED_MAP KEY_VALUE_GENERIC tailMap( final KEY_GENERIC_CLASS from ) {
return tailMap( KEY_CLASS2TYPE( from ) );
}
/** Delegates to the corresponding type-specific method. */
public SORTED_MAP KEY_VALUE_GENERIC subMap( final KEY_GENERIC_CLASS from, final KEY_GENERIC_CLASS to ) {
return subMap( KEY_CLASS2TYPE( from ), KEY_CLASS2TYPE( to ) );
}
/** Delegates to the corresponding type-specific method. */
public KEY_GENERIC_CLASS firstKey() {
return KEY2OBJ( FIRST_KEY() );
}
/** Delegates to the corresponding type-specific method. */
public KEY_GENERIC_CLASS lastKey() {
return KEY2OBJ( LAST_KEY() );
}
#endif
/** Returns a type-specific-sorted-set view of the keys of this map.
*
* null
(FIFO queues have no comparator).
* @return null
.
*/
@Override
public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() {
return null;
}
@Override
public KEY_GENERIC_TYPE DEQUEUE() {
if ( start == end ) throw new NoSuchElementException();
final KEY_GENERIC_TYPE t = array[ start ];
#if #keys(reference)
array[ start ] = null; // Clean-up for the garbage collector.
#endif
if ( ++start == length ) start = 0;
reduce();
return t;
}
/** Dequeues the {@linkplain #last() last} element from the queue.
*
* @return the dequeued element.
* @throws NoSuchElementException if the queue is empty.
*/
public KEY_GENERIC_TYPE DEQUEUE_LAST() {
if ( start == end ) throw new NoSuchElementException();
if ( end == 0 ) end = length;
final KEY_GENERIC_TYPE t = array[ --end ];
#if #keys(reference)
array[ end ] = null; // Clean-up for the garbage collector.
#endif
reduce();
return t;
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
private final void resize( final int size, final int newLength ) {
final KEY_GENERIC_TYPE[] newArray = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ newLength ];
if ( start >= end ) {
if ( size != 0 ) {
System.arraycopy( array, start, newArray, 0, length - start );
System.arraycopy( array, 0, newArray, length - start, end );
}
}
else System.arraycopy( array, start, newArray, 0, end - start );
start = 0;
end = size;
array = newArray;
length = newLength;
}
private final void expand() {
resize( length, (int)Math.min( it.unimi.dsi.fastutil.Arrays.MAX_ARRAY_SIZE, 2L * length ) );
}
private final void reduce() {
final int size = size();
if ( length > INITIAL_CAPACITY && size <= length / 4 ) resize( size, length / 2 );
}
@Override
public void enqueue( KEY_GENERIC_TYPE x ) {
array[ end++ ] = x;
if ( end == length ) end = 0;
if ( end == start ) expand();
}
/** Enqueues a new element as the {@linkplain #first() first} element (in dequeuing order) of the queue.
*/
public void enqueueFirst( KEY_GENERIC_TYPE x ) {
if ( start == 0 ) start = length;
array[ --start ] = x;
if ( end == start ) expand();
}
/** Returns the first element of the queue.
* @return the first element of the queue.
*/
public KEY_GENERIC_TYPE FIRST() {
if ( start == end ) throw new NoSuchElementException();
return array[ start ];
}
/** Returns the last element of the queue.
* @return the last element of the queue.
*/
public KEY_GENERIC_TYPE LAST() {
if ( start == end ) throw new NoSuchElementException();
return array[ ( end == 0 ? length : end ) - 1 ];
}
@Override
public void clear() {
#if #keys(reference)
if ( start <= end ) Arrays.fill( array, start, end, null );
else {
Arrays.fill( array, start, length, null );
Arrays.fill( array, 0, end, null );
}
#endif
start = end = 0;
}
/** Trims the queue to the smallest possible size. */
SUPPRESS_WARNINGS_KEY_UNCHECKED
public void trim() {
final int size = size();
final KEY_GENERIC_TYPE[] newArray =
#if #keys(primitive)
new KEY_GENERIC_TYPE[ size + 1 ];
#else
(KEY_GENERIC_TYPE[])new Object[ size + 1 ];
#endif
if ( start <= end ) System.arraycopy( array, start, newArray, 0, end - start );
else {
System.arraycopy( array, start, newArray, 0, length - start );
System.arraycopy( array, 0, newArray, length - start, end );
}
start = 0;
length = ( end = size ) + 1;
array = newArray;
}
@Override
public int size() {
final int apparentLength = end - start;
return apparentLength >= 0 ? apparentLength : length + apparentLength;
}
private void writeObject( java.io.ObjectOutputStream s ) throws java.io.IOException {
s.defaultWriteObject();
int size = size();
s.writeInt( size );
for( int i = start; size-- != 0; ) {
s.WRITE_KEY( array[ i++ ] );
if ( i == length ) i = 0;
}
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
private void readObject( java.io.ObjectInputStream s ) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
end = s.readInt();
array = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ length = HashCommon.nextPowerOfTwo( end + 1 ) ];
for( int i = 0; i < end; i++ ) array[ i ] = KEY_GENERIC_CAST s.READ_KEY();
}
}
fastutil-7.0.2/drv/ArrayFrontCodedList.drv 0000644 0000000 0000000 00000055651 12502265775 017413 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import it.unimi.dsi.fastutil.objects.AbstractObjectListIterator;
import it.unimi.dsi.fastutil.objects.AbstractObjectList;
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
import it.unimi.dsi.fastutil.longs.LongArrays;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Collection;
import java.util.NoSuchElementException;
import java.util.RandomAccess;
/** Compact storage of lists of arrays using front coding.
*
* get()
* methods.
*
* Implementation Details
*
* common
the
* length of the maximum common prefix between the array and its predecessor.
* Then we store the array length decremented by common
, followed
* by common
, followed by the array elements whose index is
* greater than or equal to common
. For instance, if we store
* foo
, foobar
, football
and
* fool
in a front-coded character-array list with ratio 3, the
* character array will contain
*
*
* 3 f o o 3 3 b a r 5 3 t b a l l 4 f o o l
*
*/
public class ARRAY_FRONT_CODED_LIST extends AbstractObjectListpos
.
*/
private static int readInt( final KEY_TYPE a[][], long pos ) {
#if #keyclass(Integer)
return IntBigArrays.get( a, pos );
#elif #keyclass(Long)
return (int)LongBigArrays.get( a, pos );
#elif #keyclass(Character)
final char c0 = CharBigArrays.get( a, pos );
return c0 < 0x8000 ? c0 : ( c0 & 0x7FFF ) << 16 | CharBigArrays.get( a, pos + 1 );
#elif #keyclass(Short)
final short s0 = ShortBigArrays.get( a, pos );
return s0 >= 0 ? s0 : s0 << 16 | ( ShortBigArrays.get( a, pos + 1 ) & 0xFFFF );
#else
final byte b0 = ByteBigArrays.get( a, pos );
if ( b0 >= 0 ) return b0;
final byte b1 = ByteBigArrays.get( a, pos + 1 );
if ( b1 >= 0 ) return ( - b0 - 1 ) << 7 | b1;
final byte b2 = ByteBigArrays.get( a, pos + 2 );
if ( b2 >= 0 ) return ( - b0 - 1 ) << 14 | ( - b1 - 1 ) << 7 | b2;
final byte b3 = ByteBigArrays.get( a, pos + 3 );
if ( b3 >= 0 ) return ( - b0 - 1 ) << 21 | ( - b1 - 1 ) << 14 | ( - b2 - 1 ) << 7 | b3;
return ( - b0 - 1 ) << 28 | ( - b1 - 1 ) << 21 | ( - b2 - 1 ) << 14 | ( - b3 - 1 ) << 7 | ByteBigArrays.get( a, pos + 4 );
#endif
}
/** Computes the number of elements coding a given length.
* @param length the length to be coded.
* @return the number of elements coding length
.
*/
private static int count( final int length ) {
#if #keyclass(Integer) || #keyclass(Long)
return 1;
#elif #keyclass(Character) || #keyclass(Short)
return length < ( 1 << 15 ) ? 1 : 2;
#else
if ( length < ( 1 << 7 ) ) return 1;
if ( length < ( 1 << 14 ) ) return 2;
if ( length < ( 1 << 21 ) ) return 3;
if ( length < ( 1 << 28 ) ) return 4;
return 5;
#endif
}
/** Writes a length.
* @param a the data array.
* @param length the length to be written.
* @param pos the starting position.
* @return the number of elements coding length
.
*/
private static int writeInt( final KEY_TYPE a[][], int length, long pos ) {
#if #keyclass(Long)
LongBigArrays.set( a, pos, length );
return 1;
#elif #keyclass(Integer)
IntBigArrays.set( a, pos, length );
return 1;
#elif #keyclass(Character)
if ( length < ( 1 << 15 ) ) {
CharBigArrays.set( a, pos, (char)length );
return 1;
}
CharBigArrays.set( a, pos++, (char)( length >>> 16 | 0x8000 ) );
CharBigArrays.set( a, pos, (char)( length & 0xFFFF ) );
return 2;
#elif #keyclass(Short)
if ( length < ( 1 << 15 ) ) {
ShortBigArrays.set( a, pos, (short)length );
return 1;
}
ShortBigArrays.set( a, pos++, (short)( - ( length >>> 16 ) - 1 ) );
ShortBigArrays.set( a, pos, (short)( length & 0xFFFF ) );
return 2;
#else
final int count = count( length );
ByteBigArrays.set( a, pos + count - 1, (byte)( length & 0x7F ) );
if ( count != 1 ) {
int i = count - 1;
while( i-- != 0 ) {
length >>>= 7;
ByteBigArrays.set( a, pos + i, (byte)( - ( length & 0x7F ) - 1 ) );
}
}
return count;
#endif
}
/** Returns the ratio of this list.
*
* @return the ratio of this list.
*/
public int ratio() {
return ratio;
}
/** Computes the length of the array at the given index.
*
* index
-th array.
*/
private int length( final int index ) {
final KEY_TYPE[][] array = this.array;
final int delta = index % ratio; // The index into the p array, and the delta inside the block.
long pos = p[ index / ratio ]; // The position into the array of the first entire word before the index-th.
int length = readInt( array, pos );
if ( delta == 0 ) return length;
// First of all, we recover the array length and the maximum amount of copied elements.
int common;
pos += count( length ) + length;
length = readInt( array, pos );
common = readInt( array, pos + count( length ) );
for( int i = 0; i < delta - 1; i++ ) {
pos += count( length ) + count( common ) + length;
length = readInt( array, pos );
common = readInt( array, pos + count( length ) );
}
return length + common;
}
/** Computes the length of the array at the given index.
*
* @param index an index.
* @return the length of the index
-th array.
*/
public int arrayLength( final int index ) {
ensureRestrictedIndex( index );
return length( index );
}
/** Extracts the array at the given index.
*
* @param index an index.
* @param a the array that will store the result (we assume that it can hold the result).
* @param offset an offset into a
where elements will be store.
* @param length a maximum number of elements to store in a
.
* @return the length of the extracted array.
*/
private int extract( final int index, final KEY_TYPE a[], final int offset, final int length ) {
final int delta = index % ratio; // The delta inside the block.
final long startPos = p[ index / ratio ]; // The position into the array of the first entire word before the index-th.
long pos, prevArrayPos;
int arrayLength = readInt( array, pos = startPos ), currLen = 0, actualCommon;
if ( delta == 0 ) {
pos = p[ index / ratio ] + count( arrayLength );
BIG_ARRAYS.copyFromBig( array, pos, a, offset, Math.min( length, arrayLength ) );
return arrayLength;
}
int common = 0;
for( int i = 0; i < delta; i++ ) {
prevArrayPos = pos + count( arrayLength ) + ( i != 0 ? count( common ) : 0 );
pos = prevArrayPos + arrayLength;
arrayLength = readInt( array, pos );
common = readInt( array, pos + count( arrayLength ) );
actualCommon = Math.min( common, length );
if ( actualCommon <= currLen ) currLen = actualCommon;
else {
BIG_ARRAYS.copyFromBig( array, prevArrayPos, a, currLen + offset, actualCommon - currLen );
currLen = actualCommon;
}
}
if ( currLen < length ) BIG_ARRAYS.copyFromBig( array, pos + count( arrayLength ) + count( common ), a, currLen + offset, Math.min( arrayLength, length - currLen ) );
return arrayLength + common;
}
public KEY_TYPE[] get( final int index ) {
return getArray( index );
}
/**
* @see #get(int)
*/
public KEY_TYPE[] getArray( final int index ) {
ensureRestrictedIndex( index );
final int length = length( index );
final KEY_TYPE a[] = new KEY_TYPE[ length ];
extract( index, a, 0, length );
return a;
}
/** Stores in the given array elements from an array stored in this front-coded list.
*
* @param index an index.
* @param a the array that will store the result.
* @param offset an offset into a
where elements will be store.
* @param length a maximum number of elements to store in a
.
* @return if a
can hold the extracted elements, the number of extracted elements;
* otherwise, the number of remaining elements with the sign changed.
*/
public int get( final int index, final KEY_TYPE[] a, final int offset, final int length ) {
ensureRestrictedIndex( index );
ARRAYS.ensureOffsetLength( a, offset, length );
final int arrayLength = extract( index, a, offset, length );
if ( length >= arrayLength ) return arrayLength;
return length - arrayLength;
}
/** Stores in the given array an array stored in this front-coded list.
*
* @param index an index.
* @param a the array that will store the content of the result (we assume that it can hold the result).
* @return if a
can hold the extracted elements, the number of extracted elements;
* otherwise, the number of remaining elements with the sign changed.
*/
public int get( final int index, final KEY_TYPE[] a ) {
return get( index, a, 0, a.length );
}
public int size() {
return n;
}
public ObjectListIteratornull
, indicating that natural comparison should take place. Of course,
* it makes little sense having them equal.
*/
public class ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUE KEY_GENERIC extends ARRAY_INDIRECT_PRIORITY_QUEUE KEY_GENERIC implements INDIRECT_DOUBLE_PRIORITY_QUEUE KEY_GENERIC {
/** The secondary comparator. */
protected KEY_COMPARATOR KEY_SUPER_GENERIC secondaryComparator;
/** Creates a new empty queue with a given capacity.
*
* @param refArray the reference array.
* @param capacity the initial capacity of this queue.
* @param c the primary comparator used in this queue, or null
for the natural order.
* @param d the secondary comparator used in this queue, or null
for the natural order.
*/
public ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity, KEY_COMPARATOR KEY_SUPER_GENERIC c, KEY_COMPARATOR KEY_SUPER_GENERIC d ) {
super( refArray, capacity, c );
secondaryComparator = d;
}
/** Creates a new empty queue with a given capacity.
*
* c
.
*
* @param refArray the reference array.
* @param capacity the initial capacity of this queue.
* @param c the primary comparator used in this queue, or null
for the natural order.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
super( refArray, capacity, c == null ? COMPARATORS.OPPOSITE_COMPARATOR : COMPARATORS.oppositeComparator( c ) );
}
/** Creates a new empty queue with a given capacity and natural order as primary comparator.
*
* null
for the natural order.
* @param d the secondary comparator used in this queue, or null
for the natural order.
*/
public ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, KEY_COMPARATOR KEY_SUPER_GENERIC c, KEY_COMPARATOR KEY_SUPER_GENERIC d ) {
this( refArray, refArray.length, c, d );
}
/** Creates a new empty queue with capacity equal to the length of the reference array.
*
* c
.
*
* @param refArray the reference array.
* @param c the primary comparator used in this queue, or null
for the natural order.
*/
public ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, refArray.length, c );
}
/** Creates a new empty queue with capacity equal to the length of the reference array and natural order as primary comparator.
*
* refArray
.
* @param size the number of elements to be included in the queue.
* @param c the primary comparator used in this queue, or null
for the natural order.
* @param d the secondary comparator used in this queue, or null
for the natural order.
*/
public ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size, final KEY_COMPARATOR KEY_SUPER_GENERIC c, final KEY_COMPARATOR KEY_SUPER_GENERIC d ) {
this( refArray, 0, c, d );
this.array = a;
this.size = size;
}
/** Wraps a given array in a queue using the given comparators.
*
* refArray
.
* @param c the primary comparator used in this queue, or null
for the natural order.
* @param d the secondary comparator used in this queue, or null
for the natural order.
*/
public ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, final KEY_COMPARATOR KEY_SUPER_GENERIC c, final KEY_COMPARATOR KEY_SUPER_GENERIC d ) {
this( refArray, a, a.length, c, d );
}
/** Wraps a given array in a queue using a given comparator and its opposite.
*
* refArray
.
* @param size the number of elements to be included in the queue.
* @param c the comparator used in this queue, or null
for the natural order.
*/
public ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, 0, c );
this.array = a;
this.size = size;
}
/** Wraps a given array in a queue using a given comparator and its opposite.
*
* refArray
.
* @param c the comparator used in this queue, or null
for the natural order.
*/
public ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, a, a.length, c );
}
/** Wraps a given array in a queue using the natural order and its opposite.
*
* refArray
.
* @param size the number of elements to be included in the queue.
*/
public ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size ) {
this( refArray, a, size, null );
}
/** Wraps a given array in a queue using the natural order and its opposite.
*
* refArray
.
*/
public ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a ) {
this( refArray, a, a.length );
}
/** Returns the index (in {@link #array}) of the smallest element w.r.t. the {@linkplain #secondaryComparator secondary comparator}. */
SUPPRESS_WARNINGS_KEY_UNCHECKED
private int findSecondaryFirst() {
int i = size;
int firstIndex = --i;
KEY_GENERIC_TYPE first = refArray[ array[ firstIndex ] ];
if ( secondaryComparator == null ) while( i-- != 0 ) { if ( KEY_LESS( refArray[ array[ i ] ], first ) ) first = refArray[ array[ firstIndex = i ] ]; }
else while( i-- != 0 ) { if ( secondaryComparator.compare( refArray[ array[ i ] ], first ) < 0 ) first = refArray[ array[ firstIndex = i ] ]; }
return firstIndex;
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
private int findSecondaryLast() {
int i = size;
int lastIndex = --i;
KEY_GENERIC_TYPE last = refArray[ array[ lastIndex ] ];
if ( secondaryComparator == null ) while( i-- != 0 ) { if ( KEY_LESS( last, refArray[ array[ i ] ] ) ) last = refArray[ array[ lastIndex = i ] ]; }
else while( i-- != 0 ) { if ( secondaryComparator.compare( last, refArray[ array[ i ] ] ) < 0 ) last = refArray[ array[ lastIndex = i ] ]; }
return lastIndex;
}
public int secondaryFirst() {
return array[ findSecondaryFirst() ];
}
public int secondaryLast() {
return array[ findSecondaryLast() ];
}
public int secondaryFront( int[] a ) {
final KEY_GENERIC_TYPE secondaryTop = refArray[ array[ findSecondaryFirst() ] ];
int i = size, c = 0;
while( i-- != 0 ) if ( KEY_EQUALS_NOT_NULL( secondaryTop, refArray[ array[ i ] ] ) ) a[ c++ ] = array[ i ];
return c;
}
public void changed( int i ) {}
/** Returns the secondary comparator of this queue.
*
* @return the secondary comparator of this queue.
* @see #secondaryFirst()
*/
public KEY_COMPARATOR KEY_SUPER_GENERIC secondaryComparator() { return secondaryComparator; }
#ifdef TEST
/** The original class, now just used for testing. */
private static class TestQueue {
/** The reference array */
private KEY_TYPE refArray[];
/** Its length */
private int N;
/** The number of elements in the heaps */
private int n;
/** The two comparators */
private KEY_COMPARATOR primaryComp, secondaryComp;
/** Two indirect heaps are used, called primary
and secondary
. Each of them contains
a permutation of n
among the indices 0, 1, ..., N
-1 in such a way that the corresponding
objects be sorted with respect to the two comparators.
We also need an array inSec[]
so that inSec[k]
is the index of secondary
containing k
.
*/
private int primary[], secondary[], inSec[];
/** Builds a double indirect priority queue.
* @param refArray The reference array.
* @param primaryComp The primary comparator.
* @param secondaryComp The secondary comparator.
*/
public TestQueue( KEY_TYPE refArray[], KEY_COMPARATOR primaryComp, KEY_COMPARATOR secondaryComp ) {
this.refArray = refArray;
this.N = refArray.length;
assert this.N != 0;
this.n = 0;
this.primaryComp = primaryComp;
this.secondaryComp = secondaryComp;
this.primary = new int[N];
this.secondary = new int[N];
this.inSec = new int[N];
java.util.Arrays.fill( inSec, -1 );
}
/** Adds an index to the queue. Notice that the index should not be already present in the queue.
* @param i The index to be added
*/
public void add( int i ) {
if ( i < 0 || i >= refArray.length ) throw new IndexOutOfBoundsException();
if ( inSec[ i ] >= 0 ) throw new IllegalArgumentException();
primary[n] = i;
secondary[n] = i; inSec[i] = n;
n++;
swimPrimary( n-1 );
swimSecondary( n-1 );
}
/** Heapify the primary heap.
* @param i The index of the heap to be heapified.
*/
private void heapifyPrimary( int i ) {
int dep = primary[i];
int child;
while ( ( child = 2*i+1 ) < n ) {
if ( child+1 < n && primaryComp.compare( refArray[primary[child+1]], refArray[primary[child]] ) < 0 ) child++;
if ( primaryComp.compare( refArray[dep], refArray[primary[child]] ) <= 0 ) break;
primary[i] = primary[child];
i = child;
}
primary[i] = dep;
}
/** Heapify the secondary heap.
* @param i The index of the heap to be heapified.
*/
private void heapifySecondary( int i ) {
int dep = secondary[i];
int child;
while ( ( child = 2*i+1 ) < n ) {
if ( child+1 < n && secondaryComp.compare( refArray[secondary[child+1]], refArray[secondary[child]] ) < 0 ) child++;
if ( secondaryComp.compare( refArray[dep], refArray[secondary[child]] ) <= 0 ) break;
secondary[i] = secondary[child]; inSec[secondary[i]] = i;
i = child;
}
secondary[i] = dep; inSec[secondary[i]] = i;
}
/** Swim and heapify the primary heap.
* @param i The index to be moved.
*/
private void swimPrimary( int i ) {
int dep = primary[i];
int parent;
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( primaryComp.compare( refArray[primary[parent]], refArray[dep] ) <= 0 ) break;
primary[i] = primary[parent];
i = parent;
}
primary[i] = dep;
heapifyPrimary( i );
}
/** Swim and heapify the secondary heap.
* @param i The index to be moved.
*/
private void swimSecondary( int i ) {
int dep = secondary[i];
int parent;
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( secondaryComp.compare( refArray[secondary[parent]], refArray[dep] ) <= 0 ) break;
secondary[i] = secondary[parent]; inSec[secondary[i]] = i;
i = parent;
}
secondary[i] = dep; inSec[secondary[i]] = i;
heapifySecondary( i );
}
/** Returns the minimum element with respect to the primary comparator.
@return the minimum element.
*/
public int top() {
if ( n == 0 ) throw new java.util.NoSuchElementException();
return primary[0];
}
/** Returns the minimum element with respect to the secondary comparator.
@return the minimum element.
*/
public int secTop() {
if ( n == 0 ) throw new java.util.NoSuchElementException();
return secondary[0];
}
/** Removes the minimum element with respect to the primary comparator.
* @return the removed element.
*/
public void remove() {
if ( n == 0 ) throw new java.util.NoSuchElementException();
int result = primary[0];
int ins = inSec[result];
inSec[ result ] = -1;
// Copy a leaf
primary[0] = primary[n-1];
if ( ins == n-1 ) {
n--;
heapifyPrimary( 0 );
return;
}
secondary[ins] = secondary[n-1];
inSec[secondary[ins]] = ins;
// Heapify
n--;
heapifyPrimary( 0 );
swimSecondary( ins );
}
public void clear() {
while( size() != 0 ) remove();
}
public void remove( int index ) {
if ( n == 0 ) throw new java.util.NoSuchElementException();
int result = primary[index];
int ins = inSec[result];
inSec[ result ] = -1;
// Copy a leaf
primary[index] = primary[n-1];
if ( ins == n-1 ) {
n--;
swimPrimary( index );
return;
}
secondary[ins] = secondary[n-1];
inSec[secondary[ins]] = ins;
// Heapify
n--;
swimPrimary( index );
swimSecondary( ins );
}
/** Signals that the minimum element with respect to the comparator has changed.
*/
public void change() {
int ins = inSec[primary[0]];
heapifyPrimary( 0 );
swimSecondary( ins );
}
public void change(int index) {
int ins = inSec[primary[index]];
swimPrimary( index );
swimSecondary( ins );
}
/** Returns the number of elements in the queue.
* @return the size of the queue
*/
public int size() {
return n;
}
}
private static long seed = System.currentTimeMillis();
private static java.util.Random r = new java.util.Random( seed );
private static KEY_TYPE genKey() {
#if #keyclass(Byte) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#elif #keyclass(Object)
return Integer.toBinaryString( r.nextInt() );
#else
return new java.io.Serializable() {};
#endif
}
private static java.text.NumberFormat format = new java.text.DecimalFormat( "#,###.00" );
private static java.text.FieldPosition p = new java.text.FieldPosition( 0 );
private static String format( double d ) {
StringBuffer s = new StringBuffer();
return format.format( d, s, p ).toString();
}
private static void speedTest( int n, boolean comp ) {
System.out.println( "There are presently no speed tests for this class." );
}
private static void fatal( String msg ) {
System.out.println( msg );
System.exit( 1 );
}
private static void ensure( boolean cond, String msg ) {
if ( cond ) return;
fatal( msg );
}
private static boolean heapEqual( int[] a, int[] b, int sizea, int sizeb ) {
if ( sizea != sizeb ) return false;
while( sizea-- != 0 ) if ( a[sizea] != b[sizea] ) return false;
return true;
}
private static boolean invEqual( int inva[], int[] invb ) {
int i = inva.length;
while( i-- != 0 ) if ( inva[ i ] != invb[ i ] ) return false;
return true;
}
protected static void test( int n ) {
long ms;
Exception mThrowsIllegal, tThrowsIllegal, mThrowsOutOfBounds, tThrowsOutOfBounds, mThrowsNoElement, tThrowsNoElement;
int rm = 0, rt = 0;
KEY_TYPE[] refArray = new KEY_TYPE[ n ];
for( int i = 0; i < n; i++ ) refArray[ i ] = genKey();
HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE m = new HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( refArray );
TestQueue t = new TestQueue( refArray, COMPARATORS.NATURAL_COMPARATOR, COMPARATORS.OPPOSITE_COMPARATOR );
/* We add pairs to t. */
for( int i = 0; i < n / 2; i++ ) {
t.add( i );
m.enqueue( i );
}
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in primary heap after creation (" + m + ", " + t + ")" );
ensure( heapEqual( m.secondaryQueue.heap, t.secondary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in secondary heap after creation (" + m + ", " + t + ")" );
ensure( invEqual( m.secondaryQueue.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after creation (" + java.util.Arrays.toString( m.secondaryQueue.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
/* Now we add and remove random data in m and t, checking that the result is the same. */
for(int i=0; i<2*n; i++ ) {
if ( r.nextDouble() < 0.01 ) {
t.clear();
m.clear();
for( int j = 0; j < n / 2; j++ ) {
t.add( j );
m.enqueue( j );
}
}
int T = r.nextInt( 2 * n );
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
m.enqueue( T );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
try {
t.add( T );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): enqueue() divergence in IndexOutOfBoundsException for " + T + " (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): enqueue() divergence in IllegalArgumentException for " + T + " (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in primary heap after enqueue (" + m + ", " + t + ")" );
ensure( heapEqual( m.secondaryQueue.heap, t.secondary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in secondary heap after enqueue (" + m + ", " + t + ")" );
ensure( invEqual( m.secondaryQueue.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after enqueue (" + java.util.Arrays.toString( m.secondaryQueue.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
if ( m.size() != 0 ) {
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after enqueue (" + m.first() + ", " + t.top() + ")");
ensure( m.secondaryFirst() == t.secTop(), "Error (" + seed + "): m and t differ in secondary first element after enqueue (" + m.secondaryFirst() + ", " + t.secTop() + ")");
}
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
rm = m.dequeue();
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { mThrowsNoElement = e; }
try {
rt = t.top();
t.remove();
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { tThrowsNoElement = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): dequeue() divergence in IndexOutOfBoundsException (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): dequeue() divergence in IllegalArgumentException (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( ( mThrowsNoElement == null ) == ( tThrowsNoElement == null ), "Error (" + seed + "): dequeue() divergence in java.util.NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
if ( mThrowsOutOfBounds == null ) ensure( rt == rm , "Error (" + seed + "): divergence in dequeue() between t and m (" + rt + ", " + rm + ")" );
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in primary heap after dequeue (" + m + ", " + t + ")" );
ensure( heapEqual( m.secondaryQueue.heap, t.secondary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in secondary heap after dequeue (" + m + ", " + t + ")" );
ensure( invEqual( m.secondaryQueue.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after dequeue (" + java.util.Arrays.toString( m.secondaryQueue.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
if ( m.size() != 0 ) {
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after dequeue (" + m.first() + ", " + t.top() + ")");
ensure( m.secondaryFirst() == t.secTop(), "Error (" + seed + "): m and t differ in secondary first element after dequeue (" + m.secondaryFirst() + ", " + t.secTop() + ")");
}
if ( m.size() != 0 ) {
refArray[ m.first() ] = genKey();
m.changed();
t.change();
ensure( m.size() == t.size(), "Error (" + seed + "): m and t differ in size after change (" + m.size() + ", " + t.size() + ")");
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after change (" + m.first() + ", " + t.top() + ")");
ensure( m.secondaryFirst() == t.secTop(), "Error (" + seed + "): m and t differ in secondary first element after change (" + m.secondaryFirst() + ", " + t.secTop() + ")");
}
}
/* Now we check that m actually holds the same data. */
m.clear();
ensure( m.isEmpty(), "Error (" + seed + "): m is not empty after clear()" );
System.out.println("Test OK");
}
public static void main( String args[] ) {
int n = Integer.parseInt(args[1]);
if ( args.length > 2 ) r = new java.util.Random( seed = Long.parseLong( args[ 2 ] ) );
try {
if ("speedTest".equals(args[0]) || "speedComp".equals(args[0])) speedTest( n, "speedComp".equals(args[0]) );
else if ( "test".equals( args[0] ) ) test(n);
} catch( Throwable e ) {
e.printStackTrace( System.err );
System.err.println( "seed: " + seed );
}
}
#endif
}
fastutil-7.0.2/drv/ArrayIndirectPriorityQueue.drv 0000644 0000000 0000000 00000060202 12502261336 021011 0 ustar root wheel /*
* Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
#if #keyclass(Object)
import java.util.Comparator;
import it.unimi.dsi.fastutil.IndirectPriorityQueue;
#endif
import it.unimi.dsi.fastutil.ints.IntArrays;
import it.unimi.dsi.fastutil.AbstractIndirectPriorityQueue;
import java.util.NoSuchElementException;
/** A type-specific array-based semi-indirect priority queue.
*
* null
for the natural order.
*/
public ARRAY_INDIRECT_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
if ( capacity > 0 ) this.array = new int[ capacity ];
this.refArray = refArray;
this.c = c;
}
/** Creates a new empty queue with given capacity and using the natural order.
*
* @param refArray the reference array.
* @param capacity the initial capacity of this queue.
*/
public ARRAY_INDIRECT_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity ) {
this( refArray, capacity, null );
}
/** Creates a new empty queue with capacity equal to the length of the reference array and a given comparator.
*
* @param refArray the reference array.
* @param c the comparator used in this queue, or null
for the natural order.
*/
public ARRAY_INDIRECT_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, refArray.length, c );
}
/** Creates a new empty queue with capacity equal to the length of the reference array and using the natural order.
* @param refArray the reference array.
*/
public ARRAY_INDIRECT_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray ) {
this( refArray, refArray.length, null );
}
/** Wraps a given array in a queue using a given comparator.
*
* refArray
.
* @param size the number of elements to be included in the queue.
* @param c the comparator used in this queue, or null
for the natural order.
*/
public ARRAY_INDIRECT_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, 0, c );
this.array = a;
this.size = size;
}
/** Wraps a given array in a queue using a given comparator.
*
* refArray
.
* @param c the comparator used in this queue, or null
for the natural order.
*/
public ARRAY_INDIRECT_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, a, a.length, c );
}
/** Wraps a given array in a queue using the natural order.
*
* refArray
.
* @param size the number of elements to be included in the queue.
*/
public ARRAY_INDIRECT_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size ) {
this( refArray, a, size, null );
}
/** Wraps a given array in a queue using the natural order.
*
* refArray
.
*/
public ARRAY_INDIRECT_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a ) {
this( refArray, a, a.length );
}
/** Returns the index (in {@link #array}) of the smallest element. */
SUPPRESS_WARNINGS_KEY_UNCHECKED
private int findFirst() {
if ( firstIndexValid ) return this.firstIndex;
firstIndexValid = true;
int i = size;
int firstIndex = --i;
KEY_GENERIC_TYPE first = refArray[ array[ firstIndex ] ];
if ( c == null ) while( i-- != 0 ) { if ( KEY_LESS( refArray[ array[ i ] ], first ) ) first = refArray[ array[ firstIndex = i ] ]; }
else while( i-- != 0 ) { if ( c.compare( refArray[ array[ i ] ], first ) < 0 ) first = refArray[ array[ firstIndex = i ] ]; }
return this.firstIndex = firstIndex;
}
/** Returns the index (in {@link #array}) of the largest element. */
SUPPRESS_WARNINGS_KEY_UNCHECKED
private int findLast() {
int i = size;
int lastIndex = --i;
KEY_GENERIC_TYPE last = refArray[ array[ lastIndex ] ];
if ( c == null ) { while( i-- != 0 ) if ( KEY_LESS( last, refArray[ array[ i ] ] ) ) last = refArray[ array[ lastIndex = i ] ]; }
else { while( i-- != 0 ) if ( c.compare( last, refArray[ array[ i ] ] ) < 0 ) last = refArray[ array[ lastIndex = i ] ]; }
return lastIndex;
}
protected final void ensureNonEmpty() {
if ( size == 0 ) throw new NoSuchElementException();
}
/** Ensures that the given index is a firstIndexValid reference.
*
* @param index an index in the reference array.
* @throws IndexOutOfBoundsException if the given index is negative or larger than the reference array length.
*/
protected void ensureElement( final int index ) {
if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" );
if ( index >= refArray.length ) throw new IndexOutOfBoundsException( "Index (" + index + ") is larger than or equal to reference array size (" + refArray.length + ")" );
}
/** Enqueues a new element.
*
* x
is already in the queue. However, the queue state will become
* inconsistent and the following behaviour will not be predictable.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public void enqueue( int x ) {
ensureElement( x );
if ( size == array.length ) array = IntArrays.grow( array, size + 1 );
if ( firstIndexValid ) {
if ( c == null ) { if ( KEY_LESS( refArray[ x ], refArray[ array[ firstIndex ] ] ) ) firstIndex = size; }
else if ( c.compare( refArray[ x ], refArray[ array[ firstIndex ] ] ) < 0 ) firstIndex = size;
}
else firstIndexValid = false;
array[ size++ ] = x;
}
public int dequeue() {
ensureNonEmpty();
final int firstIndex = findFirst();
final int result = array[ firstIndex ];
if ( --size != 0 ) System.arraycopy( array, firstIndex + 1, array, firstIndex, size - firstIndex );
firstIndexValid = false;
return result;
}
public int first() {
ensureNonEmpty();
return array[ findFirst() ];
}
public int last() {
ensureNonEmpty();
return array[ findLast() ];
}
public void changed() {
ensureNonEmpty();
firstIndexValid = false;
}
/** {@inheritDoc}
*
* index
is not in the queue.
*/
public void changed( int index ) {
ensureElement( index );
if ( index == firstIndex ) firstIndexValid = false;
}
public void allChanged() {
firstIndexValid = false;
}
public boolean remove( int index ) {
ensureElement( index );
final int[] a = array;
int i = size;
while( i-- != 0 ) if ( a[ i ] == index ) break;
if ( i < 0 ) return false;
firstIndexValid = false;
if ( --size != 0 ) System.arraycopy( a, i + 1, a, i, size - i );
return true;
}
public int front( int[] a ) {
final KEY_GENERIC_TYPE top = refArray[ array[ findFirst() ] ];
int i = size, c = 0;
while( i-- != 0 ) if ( KEY_EQUALS_NOT_NULL( top, refArray[ array[ i ] ] ) ) a[ c++ ] = array[ i ];
return c;
}
public int size() { return size; }
public void clear() { size = 0; firstIndexValid = false; }
/** Trims the backing array so that it has exactly {@link #size()} elements.
*/
public void trim() {
array = IntArrays.trim( array, size );
}
public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() { return c; }
public String toString() {
StringBuffer s = new StringBuffer();
s.append( "[" );
for ( int i = 0; i < size; i++ ) {
if ( i != 0 ) s.append( ", " );
s.append( refArray[ array [ i ] ] );
}
s.append( "]" );
return s.toString();
}
#ifdef TEST
private static long seed = System.currentTimeMillis();
private static java.util.Random r = new java.util.Random( seed );
private static KEY_TYPE genKey() {
#if #keyclass(Byte) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#elif #keyclass(Object)
return Integer.toBinaryString( r.nextInt() );
#else
return new java.io.Serializable() {};
#endif
}
private static java.text.NumberFormat format = new java.text.DecimalFormat( "#,###.00" );
private static java.text.FieldPosition p = new java.text.FieldPosition( 0 );
private static String format( double d ) {
StringBuffer s = new StringBuffer();
return format.format( d, s, p ).toString();
}
private static void speedTest( int n, boolean comp ) {
int i, j, s;
ARRAY_INDIRECT_PRIORITY_QUEUE[] m = new ARRAY_INDIRECT_PRIORITY_QUEUE[ 100000 ];
HEAP_INDIRECT_PRIORITY_QUEUE[] t = new HEAP_INDIRECT_PRIORITY_QUEUE[ m.length ];
KEY_TYPE k[] = new KEY_TYPE[n];
KEY_TYPE nk[] = new KEY_TYPE[m.length];
long ms;
for( i = 0; i < n; i++ ) k[i] = genKey();
for( i = 0; i < m.length; i++ ) nk[i] = genKey();
double totEnq = 0, totDeq = 0, totChange = 0, d;
for( i = 0; i < m.length; i++ ) {
t[ i ] = new HEAP_INDIRECT_PRIORITY_QUEUE( k );
m[ i ] = new ARRAY_INDIRECT_PRIORITY_QUEUE( k );
}
if ( comp ) {
for( j = 0; j < 20; j++ ) {
for( i = 0; i < m.length; i++ ) t[ i ].clear();
ms = System.currentTimeMillis();
s = m.length;
while( s-- != 0 ) { i = n; while( i-- != 0 ) t[ s ].enqueue( i ); }
d = System.currentTimeMillis() - ms;
if ( j > 2 ) totEnq += d;
System.out.print("Enqueue: " + format( m.length * n/d ) +" K/s " );
ms = System.currentTimeMillis();
s = m.length;
while( s-- != 0 ) { i = n; while( i-- != 0 ) { k[ t[ s ].first() ] = nk[ i ]; t[ s ].changed(); } }
d = System.currentTimeMillis() - ms;
if ( j > 2 ) totChange += d;
System.out.print("Change: " + format( m.length * n/d ) +" K/s " );
ms = System.currentTimeMillis();
s = m.length;
while( s-- != 0 ) { i = n; while( i-- != 0 ) t[ s ].dequeue(); }
d = System.currentTimeMillis() - ms;
if ( j > 2 ) totDeq += d;
System.out.print("Dequeue: " + format( m.length * n/d ) +" K/s " );
System.out.println();
}
System.out.println();
System.out.println( "Heap: Enqueue: " + format( m.length * (j-3)*n/totEnq ) + " K/s Dequeue: " + format( m.length * (j-3)*n/totDeq ) + " K/s Change: " + format( m.length * (j-3)*n/totChange ) + " K/s" );
System.out.println();
totEnq = totChange = totDeq = 0;
}
for( j = 0; j < 20; j++ ) {
for( i = 0; i < m.length; i++ ) m[ i ].clear();
ms = System.currentTimeMillis();
s = m.length;
while( s-- != 0 ) { i = n; while( i-- != 0 ) m[ s ].enqueue( i ); }
d = System.currentTimeMillis() - ms;
if ( j > 2 ) totEnq += d;
System.out.print("Enqueue: " + format( m.length * n/d ) +" K/s " );
ms = System.currentTimeMillis();
s = m.length;
while( s-- != 0 ) { i = n; while( i-- != 0 ) { k[ m[ s ].first() ] = nk[ i ]; m[ s ].changed(); } }
d = System.currentTimeMillis() - ms;
if ( j > 2 ) totChange += d;
System.out.print("Change: " + format( m.length * n/d ) +" K/s " );
ms = System.currentTimeMillis();
s = m.length;
while( s-- != 0 ) { i = n; while( i-- != 0 ) m[ s ].dequeue(); }
d = System.currentTimeMillis() - ms;
if ( j > 2 ) totDeq += d;
System.out.print("Dequeue: " + format( m.length * n/d ) +" K/s " );
System.out.println();
}
System.out.println();
System.out.println( "Array: Enqueue: " + format( m.length * (j-3)*n/totEnq ) + " K/s Dequeue: " + format( m.length * (j-3)*n/totDeq ) + " K/s Change: " + format( m.length * (j-3)*n/totChange ) + " K/s" );
System.out.println();
}
private static void fatal( String msg ) {
System.out.println( msg );
System.exit( 1 );
}
private static void ensure( boolean cond, String msg ) {
if ( cond ) return;
fatal( msg );
}
private static boolean heapEqual( int[] a, int[] b, int sizea, int sizeb ) {
if ( sizea != sizeb ) return false;
KEY_TYPE[] aa = new KEY_TYPE[ sizea ];
KEY_TYPE[] bb = new KEY_TYPE[ sizea ];
for( int i = 0; i < sizea; i++ ) {
aa[ i ] = ref[ a[ i ] ];
bb[ i ] = ref[ b[ i ] ];
}
java.util.Arrays.sort( aa );
java.util.Arrays.sort( bb );
while( sizea-- != 0 ) if ( !KEY_EQUALS(aa[sizea], bb[sizea]) ) return false;
return true;
}
private static KEY_TYPE[] ref;
protected static void test( int n ) {
long ms;
Exception mThrowsIllegal, tThrowsIllegal, mThrowsOutOfBounds, tThrowsOutOfBounds, mThrowsNoElement, tThrowsNoElement;
int rm = 0, rt = 0;
ref = new KEY_TYPE[ n ];
for( int i = 0; i < n; i++ ) ref[ i ] = genKey();
ARRAY_INDIRECT_PRIORITY_QUEUE m = new ARRAY_INDIRECT_PRIORITY_QUEUE( ref );
HEAP_INDIRECT_PRIORITY_QUEUE t = new HEAP_INDIRECT_PRIORITY_QUEUE( ref );
/* We add pairs to t. */
for( int i = 0; i < n / 2; i++ ) {
t.enqueue( i );
m.enqueue( i );
}
ensure( heapEqual( m.array, t.heap, m.size(), t.size() ), "Error (" + seed + "): m and t differ after creation (" + m + ", " + t + ")" );
/* Now we add and remove random data in m and t, checking that the result is the same. */
for(int i=0; i<2*n; i++ ) {
if ( r.nextDouble() < 0.01 ) {
t.clear();
m.clear();
for( int j = 0; j < n / 2; j++ ) {
t.enqueue( j );
m.enqueue( j );
}
}
int T = r.nextInt( 2 * n );
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
t.enqueue( T );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
if ( tThrowsIllegal == null ) { // To skip duplicates
try {
m.enqueue( T );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
}
mThrowsIllegal = tThrowsIllegal = null; // To skip duplicates
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): enqueue() divergence in IndexOutOfBoundsException for " + T + " (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): enqueue() divergence in IllegalArgumentException for " + T + " (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( heapEqual( m.array, t.heap, m.size(), t.size() ), "Error (" + seed + "): m and t differ after enqueue (" + m + ", " + t + ")" );
if ( m.size() != 0 ) {
ensure( KEY_EQUALS( ref[ m.first() ], ref[ t.first() ] ), "Error (" + seed + "): m and t differ in first element after enqueue (" + m.first() + "->" + ref[ m.first() ] + ", " + t.first() + "->" + ref[ t.first() ] + ")");
}
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
rm = m.dequeue();
while( ! m.isEmpty() && KEY_EQUALS( ref[ m.first() ], ref[ rm ] ) ) m.dequeue();
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { mThrowsNoElement = e; }
try {
rt = t.dequeue();
while( ! t.isEmpty() && KEY_EQUALS( ref[ t.first() ], ref[ rt ] ) ) t.dequeue();
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { tThrowsNoElement = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): dequeue() divergence in IndexOutOfBoundsException (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): dequeue() divergence in IllegalArgumentException (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( ( mThrowsNoElement == null ) == ( tThrowsNoElement == null ), "Error (" + seed + "): dequeue() divergence in java.util.NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
if ( mThrowsOutOfBounds == null ) ensure( KEY_EQUALS( ref[ rt ], ref[ rm ]), "Error (" + seed + "): divergence in dequeue() between m and t (" + rm + "->" + ref[ rm ] + ", " + rt + "->" + ref[ rt ] + ")" );
ensure( heapEqual( m.array, t.heap, m.size(), t.size() ), "Error (" + seed + "): m and t differ after dequeue (" + m + ", " + t + ")");
if ( m.size() != 0 ) {
ensure( KEY_EQUALS( ref[ m.first() ], ref[ t.first() ] ), "Error (" + seed + "): m and t differ in first element after dequeue (" + m.first() + "->" + ref[ m.first() ] + ", " + t.first() + "->" + ref[ t.first() ] + ")");
}
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
int pos = r.nextInt( n * 2 );
try {
m.remove( pos );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { mThrowsNoElement = e; }
try {
t.remove( pos );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { tThrowsNoElement = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): remove(int) divergence in IndexOutOfBoundsException (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): remove(int) divergence in IllegalArgumentException (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( ( mThrowsNoElement == null ) == ( tThrowsNoElement == null ), "Error (" + seed + "): remove(int) divergence in java.util.NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
ensure( heapEqual( m.array, t.heap, m.size(), t.size() ), "Error (" + seed + "): m and t differ after remove(int) (" + m + ", " + t + ")" );
if ( m.size() != 0 ) {
ensure( KEY_EQUALS( ref[ m.first() ], ref[ t.first() ] ), "Error (" + seed + "): m and t differ in first element after remove(int) (" + m.first() + "->" + ref[ m.first() ] + ", " + t.first() + "->" + ref[ t.first() ] + ")");
}
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
pos = r.nextInt( n );
try {
t.changed( pos );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { tThrowsNoElement = e; }
if ( tThrowsIllegal == null ) {
try {
m.changed( pos );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { mThrowsNoElement = e; }
}
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): change(int) divergence in IndexOutOfBoundsException (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
//ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): change(int) divergence in IllegalArgumentException (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( ( mThrowsNoElement == null ) == ( tThrowsNoElement == null ), "Error (" + seed + "): change(int) divergence in java.util.NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
ensure( heapEqual( m.array, t.heap, m.size(), t.size() ), "Error (" + seed + "): m and t differ after change(int) (" + m + ", " + t + ")" );
if ( m.size() != 0 ) {
ensure( KEY_EQUALS( ref[ m.first() ], ref[ t.first() ] ), "Error (" + seed + "): m and t differ in first element after change(int) (" + m.first() + "->" + ref[ m.first() ] + ", " + t.first() + "->" + ref[ t.first() ] + ")");
}
int[] temp = (int[])t.heap.clone();
java.util.Arrays.sort( temp, 0, t.size() ); // To scramble a bit
m = new ARRAY_INDIRECT_PRIORITY_QUEUE( m.refArray, temp, t.size() );
ensure( heapEqual( m.array, t.heap, m.size(), t.size() ), "Error (" + seed + "): m and t differ after wrap (" + m + ", " + t + ")" );
if ( m.size() != 0 ) {
ensure( KEY_EQUALS( ref[ m.first() ], ref[ t.first() ] ), "Error (" + seed + "): m and t differ in first element after wrap (" + m.first() + "->" + ref[ m.first() ] + ", " + t.first() + "->" + ref[ t.first() ] + ")");
}
if ( m.size() != 0 && ( ( new it.unimi.dsi.fastutil.ints.IntOpenHashSet( m.array, 0, m.size ) ).size() == m.size() ) ) {
int first = m.first();
ref[ first ] = genKey();
//System.err.println("Pre-change m: " +m );
//System.err.println("Pre-change t: " +t );
m.changed();
t.changed( first );
//System.err.println("Post-change m: " +m );
//System.err.println("Post-change t: " +t );
ensure( heapEqual( m.array, t.heap, m.size(), t.size() ), "Error (" + seed + "): m and t differ after change (" + m + ", " + t + ")");
if ( m.size() != 0 ) {
ensure( KEY_EQUALS( ref[ m.first() ], ref[ t.first() ] ), "Error (" + seed + "): m and t differ in first element after change (" + m.first() + "->" + ref[ m.first() ] + ", " + t.first() + "->" + ref[ t.first() ] + ")");
}
}
}
/* Now we check that m actually holds the same data. */
m.clear();
ensure( m.isEmpty(), "Error (" + seed + "): m is not empty after clear()" );
System.out.println("Test OK");
}
public static void main( String args[] ) {
int n = Integer.parseInt(args[1]);
if ( args.length > 2 ) r = new java.util.Random( seed = Long.parseLong( args[ 2 ] ) );
try {
if ("speedTest".equals(args[0]) || "speedComp".equals(args[0])) speedTest( n, "speedComp".equals(args[0]) );
else if ( "test".equals( args[0] ) ) test(n);
} catch( Throwable e ) {
e.printStackTrace( System.err );
System.err.println( "seed: " + seed );
}
}
#endif
}
fastutil-7.0.2/drv/ArrayList.drv 0000644 0000000 0000000 00000127160 12502266727 015434 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.RandomAccess;
import java.util.NoSuchElementException;
#if #keys(primitive)
/** A type-specific array-based list; provides some additional methods that use polymorphism to avoid (un)boxing.
*
* removeElements()
,
* addElements()
and getElements()
using
* high-performance system calls (e.g., {@link
* System#arraycopy(Object,int,Object,int,int) System.arraycopy()} instead of
* expensive loops.
*
* @see java.util.ArrayList
*/
public class ARRAY_LIST KEY_GENERIC extends ABSTRACT_LIST KEY_GENERIC implements RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = -7046029254386353130L;
#else
/** A type-specific array-based list; provides some additional methods that use polymorphism to avoid (un)boxing.
*
* removeElements()
,
* addElements()
and getElements()
using
* high-performance system calls (e.g., {@link
* System#arraycopy(Object,int,Object,int,int) System.arraycopy()} instead of
* expensive loops.
*
* @see java.util.ArrayList
*/
public class ARRAY_LIST KEY_GENERIC extends ABSTRACT_LIST KEY_GENERIC implements RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = -7046029254386353131L;
#endif
/** The initial default capacity of an array list. */
public final static int DEFAULT_INITIAL_CAPACITY = 16;
#if ! #keys(primitive)
/** Whether the backing array was passed to wrap()
. In
* this case, we must reallocate with the same type of array. */
protected final boolean wrapped;
#endif
/** The backing array. */
protected transient KEY_GENERIC_TYPE a[];
/** The current actual size of the list (never greater than the backing-array length). */
protected int size;
private static final boolean ASSERTS = ASSERTS_VALUE;
/** Creates a new array list using a given array.
*
* K[]
, but this methods returns an array
* of type {@link Object Object[]}.
*
* @return the backing array.
*/
public K[] elements() {
return a;
}
#endif
/** Wraps a given array into an array list of given size.
*
* @param a an array to wrap.
* @param length the length of the resulting array list.
* @return a new array list of the given size, wrapping the given array.
*/
public static KEY_GENERIC ARRAY_LIST KEY_GENERIC wrap( final KEY_GENERIC_TYPE a[], final int length ) {
if ( length > a.length ) throw new IllegalArgumentException( "The specified length (" + length + ") is greater than the array size (" + a.length + ")" );
final ARRAY_LIST KEY_GENERIC l = new ARRAY_LIST KEY_GENERIC( a, false );
l.size = length;
return l;
}
/** Wraps a given array into an array list.
*
* @param a an array to wrap.
* @return a new array list wrapping the given array.
*/
public static KEY_GENERIC ARRAY_LIST KEY_GENERIC wrap( final KEY_GENERIC_TYPE a[] ) {
return wrap( a, a.length );
}
/** Ensures that this array list can contain the given number of entries without resizing.
*
* @param capacity the new minimum capacity for this array list.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public void ensureCapacity( final int capacity ) {
#if #keys(primitive)
a = ARRAYS.ensureCapacity( a, capacity, size );
#else
if ( wrapped ) a = ARRAYS.ensureCapacity( a, capacity, size );
else {
if ( capacity > a.length ) {
final Object t[] = new Object[ capacity ];
System.arraycopy( a, 0, t, 0, size );
a = (KEY_GENERIC_TYPE[])t;
}
}
#endif
if ( ASSERTS ) assert size <= a.length;
}
/** Grows this array list, ensuring that it can contain the given number of entries without resizing,
* and in case enlarging it at least by a factor of two.
*
* @param capacity the new minimum capacity for this array list.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
private void grow( final int capacity ) {
#if #keys(primitive)
a = ARRAYS.grow( a, capacity, size );
#else
if ( wrapped ) a = ARRAYS.grow( a, capacity, size );
else {
if ( capacity > a.length ) {
final int newLength = (int)Math.max( Math.min( 2L * a.length, it.unimi.dsi.fastutil.Arrays.MAX_ARRAY_SIZE ), capacity );
final Object t[] = new Object[ newLength ];
System.arraycopy( a, 0, t, 0, size );
a = (KEY_GENERIC_TYPE[])t;
}
}
#endif
if ( ASSERTS ) assert size <= a.length;
}
public void add( final int index, final KEY_GENERIC_TYPE k ) {
ensureIndex( index );
grow( size + 1 );
if ( index != size ) System.arraycopy( a, index, a, index + 1, size - index );
a[ index ] = k;
size++;
if ( ASSERTS ) assert size <= a.length;
}
public boolean add( final KEY_GENERIC_TYPE k ) {
grow( size + 1 );
a[ size++ ] = k;
if ( ASSERTS ) assert size <= a.length;
return true;
}
public KEY_GENERIC_TYPE GET_KEY( final int index ) {
if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" );
return a[ index ];
}
public int indexOf( final KEY_TYPE k ) {
for( int i = 0; i < size; i++ ) if ( KEY_EQUALS( k, a[ i ] ) ) return i;
return -1;
}
public int lastIndexOf( final KEY_TYPE k ) {
for( int i = size; i-- != 0; ) if ( KEY_EQUALS( k, a[ i ] ) ) return i;
return -1;
}
public KEY_GENERIC_TYPE REMOVE_KEY( final int index ) {
if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" );
final KEY_GENERIC_TYPE old = a[ index ];
size--;
if ( index != size ) System.arraycopy( a, index + 1, a, index, size - index );
#if #keys(reference)
a[ size ] = null;
#endif
if ( ASSERTS ) assert size <= a.length;
return old;
}
public boolean rem( final KEY_TYPE k ) {
int index = indexOf( k );
if ( index == -1 ) return false;
REMOVE_KEY( index );
if ( ASSERTS ) assert size <= a.length;
return true;
}
#if #keys(reference)
public boolean remove( final Object o ) {
return rem( o );
}
#endif
public KEY_GENERIC_TYPE set( final int index, final KEY_GENERIC_TYPE k ) {
if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" );
KEY_GENERIC_TYPE old = a[ index ];
a[ index ] = k;
return old;
}
public void clear() {
#if #keys(reference)
Arrays.fill( a, 0, size, null );
#endif
size = 0;
if ( ASSERTS ) assert size <= a.length;
}
public int size() {
return size;
}
public void size( final int size ) {
if ( size > a.length ) ensureCapacity( size );
if ( size > this.size ) Arrays.fill( a, this.size, size, KEY_NULL );
#if #keys(reference)
else Arrays.fill( a, size, this.size, KEY_NULL );
#endif
this.size = size;
}
public boolean isEmpty() {
return size == 0;
}
/** Trims this array list so that the capacity is equal to the size.
*
* @see java.util.ArrayList#trimToSize()
*/
public void trim() {
trim( 0 );
}
/** Trims the backing array if it is too large.
*
* If the current array length is smaller than or equal to
* n
, this method does nothing. Otherwise, it trims the
* array length to the maximum between n
and {@link #size()}.
*
* key
are distinct.
*
* @param key the key array.
* @param value the value array (it must have the same length as key
).
*/
public ARRAY_MAP( final KEY_TYPE[] key, final VALUE_TYPE[] value ) {
this.key = key;
this.value = value;
size = key.length;
if( key.length != value.length ) throw new IllegalArgumentException( "Keys and values have different lengths (" + key.length + ", " + value.length + ")" );
}
/** Creates a new empty array map.
*/
public ARRAY_MAP() {
this.key = ARRAYS.EMPTY_ARRAY;
this.value = VALUE_ARRAYS.EMPTY_ARRAY;
}
/** Creates a new empty array map of given capacity.
*
* @param capacity the initial capacity.
*/
public ARRAY_MAP( final int capacity ) {
this.key = new KEY_TYPE[ capacity ];
this.value = new VALUE_TYPE[ capacity ];
}
/** Creates a new empty array map copying the entries of a given map.
*
* @param m a map.
*/
public ARRAY_MAP( final MAP KEY_VALUE_GENERIC m ) {
this( m.size() );
putAll( m );
}
/** Creates a new empty array map copying the entries of a given map.
*
* @param m a map.
*/
public ARRAY_MAP( final Map extends KEY_GENERIC_CLASS, ? extends VALUE_GENERIC_CLASS> m ) {
this( m.size() );
putAll( m );
}
/** Creates a new array map with given key and value backing arrays, using the given number of elements.
*
* size
elements of key
are distinct.
*
* @param key the key array.
* @param value the value array (it must have the same length as key
).
* @param size the number of valid elements in key
and value
.
*/
public ARRAY_MAP( final KEY_TYPE[] key, final VALUE_TYPE[] value, final int size ) {
this.key = key;
this.value = value;
this.size = size;
if( key.length != value.length ) throw new IllegalArgumentException( "Keys and values have different lengths (" + key.length + ", " + value.length + ")" );
if ( size > key.length ) throw new IllegalArgumentException( "The provided size (" + size + ") is larger than or equal to the backing-arrays size (" + key.length + ")" );
}
private final class EntrySet extends AbstractObjectSetnull
for the natural order.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public ARRAY_PRIORITY_QUEUE( int capacity, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
if ( capacity > 0 ) this.array = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ capacity ];
this.c = c;
}
/** Creates a new empty queue with a given capacity and using the natural order.
*
* @param capacity the initial capacity of this queue.
*/
public ARRAY_PRIORITY_QUEUE( int capacity ) {
this( capacity, null );
}
/** Creates a new empty queue with a given comparator.
*
* @param c the comparator used in this queue, or null
for the natural order.
*/
public ARRAY_PRIORITY_QUEUE( KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( 0, c );
}
/** Creates a new empty queue using the natural order.
*/
public ARRAY_PRIORITY_QUEUE() {
this( 0, null );
}
/** Wraps a given array in a queue using a given comparator.
*
* null
for the natural order.
*/
public ARRAY_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] a, int size, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( c );
this.array = a;
this.size = size;
}
/** Wraps a given array in a queue using a given comparator.
*
* null
for the natural order.
*/
public ARRAY_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] a, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( a, a.length, c );
}
/** Wraps a given array in a queue using the natural order.
*
* a
are distinct.
*
* @param a the backing array.
*/
public ARRAY_SET( final KEY_TYPE[] a ) {
this.a = a;
size = a.length;
}
/** Creates a new empty array set.
*/
public ARRAY_SET() {
this.a = ARRAYS.EMPTY_ARRAY;
}
/** Creates a new empty array set of given initial capacity.
*
* @param capacity the initial capacity.
*/
public ARRAY_SET( final int capacity ) {
this.a = new KEY_TYPE[ capacity ];
}
/** Creates a new array set copying the contents of a given collection.
* @param c a collection.
*/
public ARRAY_SET( COLLECTION KEY_GENERIC c ) {
this( c.size () );
addAll( c );
}
/** Creates a new array set copying the contents of a given set.
* @param c a collection.
*/
public ARRAY_SET( final Collection extends KEY_GENERIC_CLASS> c ) {
this( c.size() );
addAll( c );
}
/** Creates a new array set using the given backing array and the given number of elements of the array.
*
* size
elements of a
are distinct.
*
* @param a the backing array.
* @param size the number of valid elements in a
.
*/
public ARRAY_SET( final KEY_TYPE[] a, final int size ) {
this.a = a;
this.size = size;
if ( size > a.length ) throw new IllegalArgumentException( "The provided size (" + size + ") is larger than or equal to the array size (" + a.length + ")" );
}
private int findKey( final KEY_TYPE o ) {
for( int i = size; i-- != 0; ) if ( KEY_EQUALS( a[ i ], o ) ) return i;
return -1;
}
@Override
SUPPRESS_WARNINGS_KEY_UNCHECKED
public KEY_ITERATOR KEY_GENERIC iterator() {
return ITERATORS.wrap( KEY_GENERIC_ARRAY_CAST a, 0, size );
}
public boolean contains( final KEY_TYPE k ) {
return findKey( k ) != -1;
}
public int size() {
return size;
}
@Override
public boolean remove( final KEY_TYPE k ) {
final int pos = findKey( k );
if ( pos == -1 ) return false;
final int tail = size - pos - 1;
for( int i = 0; i < tail; i++ ) a[ pos + i ] = a[ pos + i + 1 ];
size--;
#if #keys(reference)
a[ size ] = null;
#endif
return true;
}
@Override
public boolean add( final KEY_GENERIC_TYPE k ) {
final int pos = findKey( k );
if ( pos != -1 ) return false;
if ( size == a.length ) {
final KEY_TYPE[] b = new KEY_TYPE[ size == 0 ? 2 : size * 2 ];
for( int i = size; i-- != 0; ) b[ i ] = a[ i ];
a = b;
}
a[ size++ ] = k;
return true;
}
@Override
public void clear() {
#if #keys(reference)
for( int i = size; i-- != 0; ) a[ i ] = null;
#endif
size = 0;
}
@Override
public boolean isEmpty() {
return size == 0;
}
/** Returns a deep copy of this set.
*
* ensureCapacity()
, grow()
,
* trim()
and setLength()
methods allow to handle
* arrays much like array lists. This can be very useful when efficiency (or
* syntactic simplicity) reasons make array lists unsuitable.
*
* Sorting
*
* ensureCapacity()
, grow()
,
* trim()
and setLength()
methods allow to handle
* arrays much like array lists. This can be very useful when efficiency (or
* syntactic simplicity) reasons make array lists unsuitable.
*
* new
. This phenomenon is particularly
* evident in the first growth phases of an array reallocated with doubling (or similar) logic.
*
* Sorting
*
* prototype
. In case
* of an empty array, it tries to return {@link #EMPTY_ARRAY}, if possible.
*
* @param prototype an array that will be used to type the new one.
* @param length the length of the new array.
* @return a new array of given type and length.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
private static grow()
instead.
*
* @param array an array.
* @param length the new minimum length for this array.
* @return array
, if it contains length
entries or more; otherwise,
* an array with length
entries whose first array.length
* entries are the same as those of array
.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[] ensureCapacity( final KEY_GENERIC_TYPE[] array, final int length ) {
if ( length > array.length ) {
final KEY_GENERIC_TYPE t[] =
#if #keyclass(Object)
newArray( array, length );
#else
new KEY_TYPE[ length ];
#endif
System.arraycopy( array, 0, t, 0, array.length );
return t;
}
return array;
}
/** Ensures that an array can contain the given number of entries, preserving just a part of the array.
*
* @param array an array.
* @param length the new minimum length for this array.
* @param preserve the number of elements of the array that must be preserved in case a new allocation is necessary.
* @return array
, if it can contain length
entries or more; otherwise,
* an array with length
entries whose first preserve
* entries are the same as those of array
.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[] ensureCapacity( final KEY_GENERIC_TYPE[] array, final int length, final int preserve ) {
if ( length > array.length ) {
final KEY_GENERIC_TYPE t[] =
#if #keyclass(Object)
newArray( array, length );
#else
new KEY_TYPE[ length ];
#endif
System.arraycopy( array, 0, t, 0, preserve );
return t;
}
return array;
}
/** Grows the given array to the maximum between the given length and
* the current length multiplied by two, provided that the given
* length is larger than the current length.
*
* ensureCapacity()
instead.
*
* @param array an array.
* @param length the new minimum length for this array.
* @return array
, if it can contain length
* entries; otherwise, an array with
* max(length
,array.length
/φ) entries whose first
* array.length
entries are the same as those of array
.
* */
public static KEY_GENERIC KEY_GENERIC_TYPE[] grow( final KEY_GENERIC_TYPE[] array, final int length ) {
if ( length > array.length ) {
final int newLength = (int)Math.max( Math.min( 2L * array.length, Arrays.MAX_ARRAY_SIZE ), length );
final KEY_GENERIC_TYPE t[] =
#if #keyclass(Object)
newArray( array, newLength );
#else
new KEY_TYPE[ newLength ];
#endif
System.arraycopy( array, 0, t, 0, array.length );
return t;
}
return array;
}
/** Grows the given array to the maximum between the given length and
* the current length multiplied by two, provided that the given
* length is larger than the current length, preserving just a part of the array.
*
* ensureCapacity()
instead.
*
* @param array an array.
* @param length the new minimum length for this array.
* @param preserve the number of elements of the array that must be preserved in case a new allocation is necessary.
* @return array
, if it can contain length
* entries; otherwise, an array with
* max(length
,array.length
/φ) entries whose first
* preserve
entries are the same as those of array
.
* */
public static KEY_GENERIC KEY_GENERIC_TYPE[] grow( final KEY_GENERIC_TYPE[] array, final int length, final int preserve ) {
if ( length > array.length ) {
final int newLength = (int)Math.max( Math.min( 2L * array.length, Arrays.MAX_ARRAY_SIZE ), length );
final KEY_GENERIC_TYPE t[] =
#if #keyclass(Object)
newArray( array, newLength );
#else
new KEY_TYPE[ newLength ];
#endif
System.arraycopy( array, 0, t, 0, preserve );
return t;
}
return array;
}
/** Trims the given array to the given length.
*
* @param array an array.
* @param length the new maximum length for the array.
* @return array
, if it contains length
* entries or less; otherwise, an array with
* length
entries whose entries are the same as
* the first length
entries of array
.
*
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[] trim( final KEY_GENERIC_TYPE[] array, final int length ) {
if ( length >= array.length ) return array;
final KEY_GENERIC_TYPE t[] =
#if #keyclass(Object)
newArray( array, length );
#else
length == 0 ? EMPTY_ARRAY : new KEY_TYPE[ length ];
#endif
System.arraycopy( array, 0, t, 0, length );
return t;
}
/** Sets the length of the given array.
*
* @param array an array.
* @param length the new length for the array.
* @return array
, if it contains exactly length
* entries; otherwise, if it contains more than
* length
entries, an array with length
entries
* whose entries are the same as the first length
entries of
* array
; otherwise, an array with length
entries
* whose first array.length
entries are the same as those of
* array
.
*
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[] setLength( final KEY_GENERIC_TYPE[] array, final int length ) {
if ( length == array.length ) return array;
if ( length < array.length ) return trim( array, length );
return ensureCapacity( array, length );
}
/** Returns a copy of a portion of an array.
*
* @param array an array.
* @param offset the first element to copy.
* @param length the number of elements to copy.
* @return a new array containing length
elements of array
starting at offset
.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[] copy( final KEY_GENERIC_TYPE[] array, final int offset, final int length ) {
ensureOffsetLength( array, offset, length );
final KEY_GENERIC_TYPE[] a =
#if #keyclass(Object)
newArray( array, length );
#else
length == 0 ? EMPTY_ARRAY : new KEY_TYPE[ length ];
#endif
System.arraycopy( array, offset, a, 0, length );
return a;
}
/** Returns a copy of an array.
*
* @param array an array.
* @return a copy of array
.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[] copy( final KEY_GENERIC_TYPE[] array ) {
return array.clone();
}
/** Fills the given array with the given value.
*
* @param array an array.
* @param value the new value for all elements of the array.
* @deprecated Please use the corresponding {@link java.util.Arrays} method.
*/
@Deprecated
public static KEY_GENERIC void fill( final KEY_GENERIC_TYPE[] array, final KEY_GENERIC_TYPE value ) {
int i = array.length;
while( i-- != 0 ) array[ i ] = value;
}
/** Fills a portion of the given array with the given value.
*
* @param array an array.
* @param from the starting index of the portion to fill (inclusive).
* @param to the end index of the portion to fill (exclusive).
* @param value the new value for all elements of the specified portion of the array.
* @deprecated Please use the corresponding {@link java.util.Arrays} method.
*/
@Deprecated
public static KEY_GENERIC void fill( final KEY_GENERIC_TYPE[] array, final int from, int to, final KEY_GENERIC_TYPE value ) {
ensureFromTo( array, from, to );
if ( from == 0 ) while( to-- != 0 ) array[ to ] = value;
else for( int i = from; i < to; i++ ) array[ i ] = value;
}
/** Returns true if the two arrays are elementwise equal.
*
* @param a1 an array.
* @param a2 another array.
* @return true if the two arrays are of the same length, and their elements are equal.
* @deprecated Please use the corresponding {@link java.util.Arrays} method, which is intrinsified in recent JVMs.
*/
@Deprecated
public static KEY_GENERIC boolean equals( final KEY_GENERIC_TYPE[] a1, final KEY_GENERIC_TYPE a2[] ) {
int i = a1.length;
if ( i != a2.length ) return false;
while( i-- != 0 ) if (! KEY_EQUALS( a1[ i ], a2[ i ] ) ) return false;
return true;
}
/** Ensures that a range given by its first (inclusive) and last (exclusive) elements fits an array.
*
* from
is greater than to
.
* @throws ArrayIndexOutOfBoundsException if from
or to
are greater than the array length or negative.
*/
public static KEY_GENERIC void ensureFromTo( final KEY_GENERIC_TYPE[] a, final int from, final int to ) {
Arrays.ensureFromTo( a.length, from, to );
}
/** Ensures that a range given by an offset and a length fits an array.
*
* length
is negative.
* @throws ArrayIndexOutOfBoundsException if offset
is negative or offset
+length
is greater than the array length.
*/
public static KEY_GENERIC void ensureOffsetLength( final KEY_GENERIC_TYPE[] a, final int offset, final int length ) {
Arrays.ensureOffsetLength( a.length, offset, length );
}
/** Ensures that two arrays are of the same length.
*
* @param a an array.
* @param b another array.
* @throws IllegalArgumentException if the two argument arrays are not of the same length.
*/
public static KEY_GENERIC void ensureSameLength( final KEY_GENERIC_TYPE[] a, final KEY_GENERIC_TYPE[] b ) {
if ( a.length != b.length ) throw new IllegalArgumentException( "Array size mismatch: " + a.length + " != " + b.length );
}
private static final int QUICKSORT_NO_REC = 16;
private static final int PARALLEL_QUICKSORT_NO_FORK = 8192;
private static final int QUICKSORT_MEDIAN_OF_9 = 128;
private static final int MERGESORT_NO_REC = 16;
/** Swaps two elements of an anrray.
*
* @param x an array.
* @param a a position in {@code x}.
* @param b another position in {@code x}.
*/
public static KEY_GENERIC void swap( final KEY_GENERIC_TYPE x[], final int a, final int b ) {
final KEY_GENERIC_TYPE t = x[ a ];
x[ a ] = x[ b ];
x[ b ] = t;
}
/** Swaps two sequences of elements of an array.
*
* @param x an array.
* @param a a position in {@code x}.
* @param b another position in {@code x}.
* @param n the number of elements to exchange starting at {@code a} and {@code b}.
*/
public static KEY_GENERIC void swap( final KEY_GENERIC_TYPE[] x, int a, int b, final int n ) {
for( int i = 0; i < n; i++, a++, b++ ) swap( x, a, b );
}
private static KEY_GENERIC int med3( final KEY_GENERIC_TYPE x[], final int a, final int b, final int c, KEY_COMPARATOR KEY_GENERIC comp ) {
final int ab = comp.compare( x[ a ], x[ b ] );
final int ac = comp.compare( x[ a ], x[ c ] );
final int bc = comp.compare( x[ b ], x[ c ] );
return ( ab < 0 ?
( bc < 0 ? b : ac < 0 ? c : a ) :
( bc > 0 ? b : ac > 0 ? c : a ) );
}
private static KEY_GENERIC void selectionSort( final KEY_GENERIC_TYPE[] a, final int from, final int to, final KEY_COMPARATOR KEY_GENERIC comp ) {
for( int i = from; i < to - 1; i++ ) {
int m = i;
for( int j = i + 1; j < to; j++ ) if ( comp.compare( a[ j ], a[ m ] ) < 0 ) m = j;
if ( m != i ) {
final KEY_GENERIC_TYPE u = a[ i ];
a[ i ] = a[ m ];
a[ m ] = u;
}
}
}
private static KEY_GENERIC void insertionSort( final KEY_GENERIC_TYPE[] a, final int from, final int to, final KEY_COMPARATOR KEY_GENERIC comp ) {
for ( int i = from; ++i < to; ) {
KEY_GENERIC_TYPE t = a[ i ];
int j = i;
for ( KEY_GENERIC_TYPE u = a[ j - 1 ]; comp.compare( t, u ) < 0; u = a[ --j - 1 ] ) {
a[ j ] = u;
if ( from == j - 1 ) {
--j;
break;
}
}
a[ j ] = t;
}
}
/** Sorts the specified range of elements according to the order induced by the specified
* comparator using quicksort.
*
* perm
(which must
* be exactly the numbers in the interval [0..perm.length)
) will be permuted so that
* x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]
.
*
* perm
(which must
* be exactly the numbers in the interval [0..perm.length)
) will be permuted so that
* x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]
.
*
* perm
(which must
* be exactly the numbers in the interval [0..perm.length)
) will be permuted so that
* x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]
.
*
* perm
(which must
* be exactly the numbers in the interval [0..perm.length)
) will be permuted so that
* x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]
.
*
* x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]
, after
* stabilization we will also have that x[ perm[ i ] ] = x[ perm[ i + 1 ] ]
implies
* perm[ i ] ≤ perm[ i + 1 ]
.
*
* @param perm a permutation array indexing {@code x} so that it is sorted.
* @param x the sorted array to be stabilized.
*/
public static KEY_GENERIC void stabilize( final int perm[], final KEY_GENERIC_TYPE[] x, final int from, final int to ) {
int curr = from;
for( int i = from + 1; i < to; i++ ) {
if ( x[ perm[ i ] ] != x[ perm[ curr ] ] ) {
if ( i - curr > 1 ) IntArrays.parallelQuickSort( perm, curr, i );
curr = i;
}
}
if ( to - curr > 1 ) IntArrays.parallelQuickSort( perm, curr, to );
}
/** Stabilizes a permutation.
*
* x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]
, after
* stabilization we will also have that x[ perm[ i ] ] = x[ perm[ i + 1 ] ]
implies
* perm[ i ] ≤ perm[ i + 1 ]
.
*
* @param perm a permutation array indexing {@code x} so that it is sorted.
* @param x the sorted array to be stabilized.
*/
public static KEY_GENERIC void stabilize( final int perm[], final KEY_GENERIC_TYPE[] x ) {
stabilize( perm, x, 0, perm.length );
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
private static KEY_GENERIC int med3( final KEY_GENERIC_TYPE x[], final KEY_GENERIC_TYPE[] y, final int a, final int b, final int c ) {
int t;
final int ab = ( t = KEY_CMP( x[ a ], x[ b ] ) ) == 0 ? KEY_CMP( y[ a ], y[ b ] ) : t;
final int ac = ( t = KEY_CMP( x[ a ], x[ c ] ) ) == 0 ? KEY_CMP( y[ a ], y[ c ] ) : t;
final int bc = ( t = KEY_CMP( x[ b ], x[ c ] ) ) == 0 ? KEY_CMP( y[ b ], y[ c ] ) : t;
return ( ab < 0 ?
( bc < 0 ? b : ac < 0 ? c : a ) :
( bc > 0 ? b : ac > 0 ? c : a ) );
}
private static KEY_GENERIC void swap( final KEY_GENERIC_TYPE x[], final KEY_GENERIC_TYPE[] y, final int a, final int b ) {
final KEY_GENERIC_TYPE t = x[ a ];
final KEY_GENERIC_TYPE u = y[ a ];
x[ a ] = x[ b ];
y[ a ] = y[ b ];
x[ b ] = t;
y[ b ] = u;
}
private static KEY_GENERIC void swap( final KEY_GENERIC_TYPE[] x, final KEY_GENERIC_TYPE[] y, int a, int b, final int n ) {
for ( int i = 0; i < n; i++, a++, b++ ) swap( x, y, a, b );
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
private static KEY_GENERIC void selectionSort( final KEY_GENERIC_TYPE[] a, final KEY_GENERIC_TYPE[] b, final int from, final int to ) {
for( int i = from; i < to - 1; i++ ) {
int m = i, u;
for( int j = i + 1; j < to; j++ )
if ( ( u = KEY_CMP( a[ j ], a[ m ] ) ) < 0 || u == 0 && KEY_LESS( b[ j ], b[ m ] ) ) m = j;
if ( m != i ) {
KEY_GENERIC_TYPE t = a[ i ];
a[ i ] = a[ m ];
a[ m ] = t;
t = b[ i ];
b[ i ] = b[ m ];
b[ m ] = t;
}
}
}
/** Sorts the specified range of elements of two arrays according to the natural lexicographical
* ascending order using quicksort.
*
* x[ i ] < x[ i + 1 ]
or x[ i ]
* == x[ i + 1 ]
and y[ i ] ≤ y[ i + 1 ]
.
*
* @param x the first array to be sorted.
* @param y the second array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static KEY_GENERIC void quickSort( final KEY_GENERIC_TYPE[] x, final KEY_GENERIC_TYPE[] y, final int from, final int to ) {
final int len = to - from;
if ( len < QUICKSORT_NO_REC ) {
selectionSort( x, y, from, to );
return;
}
// Choose a partition element, v
int m = from + len / 2;
int l = from;
int n = to - 1;
if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9
int s = len / 8;
l = med3( x, y, l, l + s, l + 2 * s );
m = med3( x, y, m - s, m, m + s );
n = med3( x, y, n - 2 * s, n - s, n );
}
m = med3( x, y, l, m, n ); // Mid-size, med of 3
final KEY_GENERIC_TYPE v = x[ m ], w = y[ m ];
// Establish Invariant: v* (x[ i ] < x[ i + 1 ]
or x[ i ]
* == x[ i + 1 ]
and y[ i ] ≤ y[ i + 1 ]
.
*
* @param x the first array to be sorted.
* @param y the second array to be sorted.
*/
public static KEY_GENERIC void quickSort( final KEY_GENERIC_TYPE[] x, final KEY_GENERIC_TYPE[] y ) {
ensureSameLength( x, y );
quickSort( x, y, 0, x.length );
}
protected static class ForkJoinQuickSort2 KEY_GENERIC extends RecursiveAction {
private static final long serialVersionUID = 1L;
private final int from;
private final int to;
private final KEY_GENERIC_TYPE[] x, y;
public ForkJoinQuickSort2( final KEY_GENERIC_TYPE[] x, final KEY_GENERIC_TYPE[] y, final int from , final int to ) {
this.from = from;
this.to = to;
this.x = x;
this.y = y;
}
@Override
SUPPRESS_WARNINGS_KEY_UNCHECKED
protected void compute() {
final KEY_GENERIC_TYPE[] x = this.x;
final KEY_GENERIC_TYPE[] y = this.y;
final int len = to - from;
if ( len < PARALLEL_QUICKSORT_NO_FORK ) {
quickSort( x, y, from, to );
return;
}
// Choose a partition element, v
int m = from + len / 2;
int l = from;
int n = to - 1;
int s = len / 8;
l = med3( x, y, l, l + s, l + 2 * s );
m = med3( x, y, m - s, m, m + s );
n = med3( x, y, n - 2 * s, n - s, n );
m = med3( x, y, l, m, n );
final KEY_GENERIC_TYPE v = x[ m ], w = y[ m ];
// Establish Invariant: v* (x[ i ] < x[ i + 1 ]
or x[ i ]
* == x[ i + 1 ]
and y[ i ] ≤ y[ i + 1 ]
.
*
* x[ i ] < x[ i + 1 ]
or x[ i ]
* == x[ i + 1 ]
and y[ i ] ≤ y[ i + 1 ]
.
*
* to
elements, and whose entries are identical to those
* of {@code a} in the specified range.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static KEY_GENERIC void mergeSort( final KEY_GENERIC_TYPE a[], final int from, final int to, final KEY_GENERIC_TYPE supp[] ) {
int len = to - from;
// Insertion sort on smallest arrays
if ( len < MERGESORT_NO_REC ) {
insertionSort( a, from, to );
return;
}
// Recursively sort halves of a into supp
final int mid = ( from + to ) >>> 1;
mergeSort( supp, from, mid, a );
mergeSort( supp, mid, to, a );
// If list is already sorted, just copy from supp to a. This is an
// optimization that results in faster sorts for nearly ordered lists.
if ( KEY_LESSEQ( supp[ mid - 1 ], supp[ mid ] ) ) {
System.arraycopy( supp, from, a, from, len );
return;
}
// Merge sorted halves (now in supp) into a
for( int i = from, p = from, q = mid; i < to; i++ ) {
if ( q >= to || p < mid && KEY_LESSEQ( supp[ p ], supp[ q ] ) ) a[ i ] = supp[ p++ ];
else a[ i ] = supp[ q++ ];
}
}
/** Sorts the specified range of elements according to the natural ascending order using mergesort.
*
* a
will be allocated by this method.
* @param a the array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
public static KEY_GENERIC void mergeSort( final KEY_GENERIC_TYPE a[], final int from, final int to ) {
mergeSort( a, from, to, a.clone() );
}
/** Sorts an array according to the natural ascending order using mergesort.
*
* a
will be allocated by this method.
* @param a the array to be sorted.
*/
public static KEY_GENERIC void mergeSort( final KEY_GENERIC_TYPE a[] ) {
mergeSort( a, 0, a.length );
}
/** Sorts the specified range of elements according to the order induced by the specified
* comparator using mergesort, using a given pre-filled support array.
*
* to
elements, and whose entries are identical to those
* of {@code a} in the specified range.
*/
public static KEY_GENERIC void mergeSort( final KEY_GENERIC_TYPE a[], final int from, final int to, KEY_COMPARATOR KEY_GENERIC comp, final KEY_GENERIC_TYPE supp[] ) {
int len = to - from;
// Insertion sort on smallest arrays
if ( len < MERGESORT_NO_REC ) {
insertionSort( a, from, to, comp );
return;
}
// Recursively sort halves of a into supp
final int mid = ( from + to ) >>> 1;
mergeSort( supp, from, mid, comp, a );
mergeSort( supp, mid, to, comp, a );
// If list is already sorted, just copy from supp to a. This is an
// optimization that results in faster sorts for nearly ordered lists.
if ( comp.compare( supp[ mid - 1 ], supp[ mid ] ) <= 0 ) {
System.arraycopy( supp, from, a, from, len );
return;
}
// Merge sorted halves (now in supp) into a
for( int i = from, p = from, q = mid; i < to; i++ ) {
if ( q >= to || p < mid && comp.compare( supp[ p ], supp[ q ] ) <= 0 ) a[ i ] = supp[ p++ ];
else a[ i ] = supp[ q++ ];
}
}
/** Sorts the specified range of elements according to the order induced by the specified
* comparator using mergesort.
*
* a
will be allocated by this method.
*
* @param a the array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
* @param comp the comparator to determine the sorting order.
*/
public static KEY_GENERIC void mergeSort( final KEY_GENERIC_TYPE a[], final int from, final int to, KEY_COMPARATOR KEY_GENERIC comp ) {
mergeSort( a, from, to, comp, a.clone() );
}
/** Sorts an array according to the order induced by the specified
* comparator using mergesort.
*
* a
will be allocated by this method.
* @param a the array to be sorted.
* @param comp the comparator to determine the sorting order.
*/
public static KEY_GENERIC void mergeSort( final KEY_GENERIC_TYPE a[], KEY_COMPARATOR KEY_GENERIC comp ) {
mergeSort( a, 0, a.length, comp );
}
#if ! #keyclass(Boolean)
/**
* Searches a range of the specified array for the specified value using
* the binary search algorithm. The range must be sorted prior to making this call.
* If it is not sorted, the results are undefined. If the range contains multiple elements with
* the specified value, there is no guarantee which one will be found.
*
* @param a the array to be searched.
* @param from the index of the first element (inclusive) to be searched.
* @param to the index of the last element (exclusive) to be searched.
* @param key the value to be searched for.
* @return index of the search key, if it is contained in the array;
* otherwise, (-(insertion point) - 1)
. The insertion
* point is defined as the the point at which the value would
* be inserted into the array: the index of the first
* element greater than the key, or the length of the array, if all
* elements in the array are less than the specified key. Note
* that this guarantees that the return value will be ≥ 0 if
* and only if the key is found.
* @see java.util.Arrays
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static KEY_GENERIC int binarySearch( final KEY_GENERIC_TYPE[] a, int from, int to, final KEY_GENERIC_TYPE key ) {
KEY_GENERIC_TYPE midVal;
to--;
while (from <= to) {
final int mid = (from + to) >>> 1;
midVal = a[ mid ];
#if #keys(primitive)
if (midVal < key) from = mid + 1;
else if (midVal > key) to = mid - 1;
else return mid;
#else
final int cmp = ((Comparable KEY_SUPER_GENERIC)midVal).compareTo( key );
if ( cmp < 0 ) from = mid + 1;
else if (cmp > 0) to = mid - 1;
else return mid;
#endif
}
return -( from + 1 );
}
/**
* Searches an array for the specified value using
* the binary search algorithm. The range must be sorted prior to making this call.
* If it is not sorted, the results are undefined. If the range contains multiple elements with
* the specified value, there is no guarantee which one will be found.
*
* @param a the array to be searched.
* @param key the value to be searched for.
* @return index of the search key, if it is contained in the array;
* otherwise, (-(insertion point) - 1)
. The insertion
* point is defined as the the point at which the value would
* be inserted into the array: the index of the first
* element greater than the key, or the length of the array, if all
* elements in the array are less than the specified key. Note
* that this guarantees that the return value will be ≥ 0 if
* and only if the key is found.
* @see java.util.Arrays
*/
public static KEY_GENERIC int binarySearch( final KEY_GENERIC_TYPE[] a, final KEY_GENERIC_TYPE key ) {
return binarySearch( a, 0, a.length, key );
}
/**
* Searches a range of the specified array for the specified value using
* the binary search algorithm and a specified comparator. The range must be sorted following the comparator prior to making this call.
* If it is not sorted, the results are undefined. If the range contains multiple elements with
* the specified value, there is no guarantee which one will be found.
*
* @param a the array to be searched.
* @param from the index of the first element (inclusive) to be searched.
* @param to the index of the last element (exclusive) to be searched.
* @param key the value to be searched for.
* @param c a comparator.
* @return index of the search key, if it is contained in the array;
* otherwise, (-(insertion point) - 1)
. The insertion
* point is defined as the the point at which the value would
* be inserted into the array: the index of the first
* element greater than the key, or the length of the array, if all
* elements in the array are less than the specified key. Note
* that this guarantees that the return value will be ≥ 0 if
* and only if the key is found.
* @see java.util.Arrays
*/
public static KEY_GENERIC int binarySearch( final KEY_GENERIC_TYPE[] a, int from, int to, final KEY_GENERIC_TYPE key, final KEY_COMPARATOR KEY_GENERIC c ) {
KEY_GENERIC_TYPE midVal;
to--;
while (from <= to) {
final int mid = (from + to) >>> 1;
midVal = a[ mid ];
final int cmp = c.compare( midVal, key );
if ( cmp < 0 ) from = mid + 1;
else if (cmp > 0) to = mid - 1;
else return mid; // key found
}
return -( from + 1 );
}
/**
* Searches an array for the specified value using
* the binary search algorithm and a specified comparator. The range must be sorted following the comparator prior to making this call.
* If it is not sorted, the results are undefined. If the range contains multiple elements with
* the specified value, there is no guarantee which one will be found.
*
* @param a the array to be searched.
* @param key the value to be searched for.
* @param c a comparator.
* @return index of the search key, if it is contained in the array;
* otherwise, (-(insertion point) - 1)
. The insertion
* point is defined as the the point at which the value would
* be inserted into the array: the index of the first
* element greater than the key, or the length of the array, if all
* elements in the array are less than the specified key. Note
* that this guarantees that the return value will be ≥ 0 if
* and only if the key is found.
* @see java.util.Arrays
*/
public static KEY_GENERIC int binarySearch( final KEY_GENERIC_TYPE[] a, final KEY_GENERIC_TYPE key, final KEY_COMPARATOR KEY_GENERIC c ) {
return binarySearch( a, 0, a.length, key, c );
}
#if #keys(primitive)
/** The size of a digit used during radix sort (must be a power of 2). */
private static final int DIGIT_BITS = 8;
/** The mask to extract a digit of {@link #DIGIT_BITS} bits. */
private static final int DIGIT_MASK = ( 1 << DIGIT_BITS ) - 1;
/** The number of digits per element. */
private static final int DIGITS_PER_ELEMENT = KEY_CLASS.SIZE / DIGIT_BITS;
private static final int RADIXSORT_NO_REC = 1024;
private static final int PARALLEL_RADIXSORT_NO_FORK = 1024;
/** This method fixes negative numbers so that the combination exponent/significand is lexicographically sorted. */
#if #keyclass(Double)
private static final long fixDouble( final double d ) {
final long l = Double.doubleToLongBits( d );
return l >= 0 ? l : l ^ 0x7FFFFFFFFFFFFFFFL;
}
#elif #keyclass(Float)
private static final int fixFloat( final float f ) {
final int i = Float.floatToIntBits( f );
return i >= 0 ? i : i ^ 0x7FFFFFFF;
}
#endif
/** Sorts the specified array using radix sort.
*
* perm
(which must
* be exactly the numbers in the interval [0..perm.length)
) will be permuted so that
* a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]
.
*
* perm
(note that the stable
* version is slightly faster).
*
* @param perm a permutation array indexing a
.
* @param a the array to be sorted.
* @param stable whether the sorting algorithm should be stable.
*/
public static void radixSortIndirect( final int[] perm, final KEY_TYPE[] a, final boolean stable ) {
radixSortIndirect( perm, a, 0, perm.length, stable );
}
/** Sorts the specified array using indirect radix sort.
*
* perm
(which must
* be exactly the numbers in the interval [0..perm.length)
) will be permuted so that
* a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]
.
*
* perm
(note that the stable
* version is slightly faster).
*
* @param perm a permutation array indexing a
.
* @param a the array to be sorted.
* @param from the index of the first element of perm
(inclusive) to be permuted.
* @param to the index of the last element of perm
(exclusive) to be permuted.
* @param stable whether the sorting algorithm should be stable.
*/
public static void radixSortIndirect( final int[] perm, final KEY_TYPE[] a, final int from, final int to, final boolean stable ) {
if ( to - from < RADIXSORT_NO_REC ) {
insertionSortIndirect( perm, a, from, to );
return;
}
final int maxLevel = DIGITS_PER_ELEMENT - 1;
final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( DIGITS_PER_ELEMENT - 1 ) + 1;
final int[] offsetStack = new int[ stackSize ];
int offsetPos = 0;
final int[] lengthStack = new int[ stackSize ];
int lengthPos = 0;
final int[] levelStack = new int[ stackSize ];
int levelPos = 0;
offsetStack[ offsetPos++ ] = from;
lengthStack[ lengthPos++ ] = to - from;
levelStack[ levelPos++ ] = 0;
final int[] count = new int[ 1 << DIGIT_BITS ];
final int[] pos = new int[ 1 << DIGIT_BITS ];
final int[] support = stable ? new int[ perm.length ] : null;
while( offsetPos > 0 ) {
final int first = offsetStack[ --offsetPos ];
final int length = lengthStack[ --lengthPos ];
final int level = levelStack[ --levelPos ];
#if #keyclass(Character)
final int signMask = 0;
#else
final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif
final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key
// Count keys.
for( int i = first + length; i-- != first; ) count[ INT( KEY2LEXINT( a[ perm[ i ] ] ) >>> shift & DIGIT_MASK ^ signMask ) ]++;
// Compute cumulative distribution
int lastUsed = -1;
for ( int i = 0, p = stable ? 0 : first; i < 1 << DIGIT_BITS; i++ ) {
if ( count[ i ] != 0 ) lastUsed = i;
pos[ i ] = ( p += count[ i ] );
}
if ( stable ) {
for( int i = first + length; i-- != first; ) support[ --pos[ INT( KEY2LEXINT( a[ perm[ i ] ] ) >>> shift & DIGIT_MASK ^ signMask ) ] ] = perm[ i ];
System.arraycopy( support, 0, perm, first, length );
for( int i = 0, p = first; i <= lastUsed; i++ ) {
if ( level < maxLevel && count[ i ] > 1 ) {
if ( count[ i ] < RADIXSORT_NO_REC ) insertionSortIndirect( perm, a, p, p + count[ i ] );
else {
offsetStack[ offsetPos++ ] = p;
lengthStack[ lengthPos++ ] = count[ i ];
levelStack[ levelPos++ ] = level + 1;
}
}
p += count[ i ];
}
java.util.Arrays.fill( count, 0 );
}
else {
final int end = first + length - count[ lastUsed ];
// i moves through the start of each block
for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) {
int t = perm[ i ];
c = INT( KEY2LEXINT( a[ t ] ) >>> shift & DIGIT_MASK ^ signMask );
if ( i < end ) { // When all slots are OK, the last slot is necessarily OK.
while( ( d = --pos[ c ] ) > i ) {
final int z = t;
t = perm[ d ];
perm[ d ] = z;
c = INT( KEY2LEXINT( a[ t ] ) >>> shift & DIGIT_MASK ^ signMask );
}
perm[ i ] = t;
}
if ( level < maxLevel && count[ c ] > 1 ) {
if ( count[ c ] < RADIXSORT_NO_REC ) insertionSortIndirect( perm, a, i, i + count[ c ] );
else {
offsetStack[ offsetPos++ ] = i;
lengthStack[ lengthPos++ ] = count[ c ];
levelStack[ levelPos++ ] = level + 1;
}
}
}
}
}
}
/** Sorts the specified range of an array using parallel indirect radix sort.
*
* perm
(which must
* be exactly the numbers in the interval [0..perm.length)
) will be permuted so that
* a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]
.
*
* a
.
* @param a the array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
* @param stable whether the sorting algorithm should be stable.
*/
public static void parallelRadixSortIndirect( final int perm[], final KEY_TYPE[] a, final int from, final int to, final boolean stable ) {
if ( to - from < PARALLEL_RADIXSORT_NO_FORK ) {
radixSortIndirect( perm, a, from, to, stable );
return;
}
final int maxLevel = DIGITS_PER_ELEMENT - 1;
final LinkedBlockingQueueperm
(which must
* be exactly the numbers in the interval [0..perm.length)
) will be permuted so that
* a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]
.
*
* a
.
* @param a the array to be sorted.
* @param stable whether the sorting algorithm should be stable.
*/
public static void parallelRadixSortIndirect( final int perm[], final KEY_TYPE[] a, final boolean stable ) {
parallelRadixSortIndirect( perm, a, 0, a.length, stable );
}
/** Sorts the specified pair of arrays lexicographically using radix sort.
* a[ i ] < a[ i + 1 ]
or a[ i ] == a[ i + 1 ]
and b[ i ] ≤ b[ i + 1 ]
.
*
* @param a the first array to be sorted.
* @param b the second array to be sorted.
*/
public static void radixSort( final KEY_TYPE[] a, final KEY_TYPE[] b ) {
ensureSameLength( a, b );
radixSort( a, b, 0, a.length );
}
/** Sorts the specified range of elements of two arrays using radix sort.
*
* a[ i ] < a[ i + 1 ]
or a[ i ] == a[ i + 1 ]
and b[ i ] ≤ b[ i + 1 ]
.
*
* @param a the first array to be sorted.
* @param b the second array to be sorted.
* @param from the index of the first element (inclusive) to be sorted.
* @param to the index of the last element (exclusive) to be sorted.
*/
public static void radixSort( final KEY_TYPE[] a, final KEY_TYPE[] b, final int from, final int to ) {
if ( to - from < RADIXSORT_NO_REC ) {
selectionSort( a, b, from, to );
return;
}
final int layers = 2;
final int maxLevel = DIGITS_PER_ELEMENT * layers - 1;
final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( layers * DIGITS_PER_ELEMENT - 1 ) + 1;
final int[] offsetStack = new int[ stackSize ];
int offsetPos = 0;
final int[] lengthStack = new int[ stackSize ];
int lengthPos = 0;
final int[] levelStack = new int[ stackSize ];
int levelPos = 0;
offsetStack[ offsetPos++ ] = from;
lengthStack[ lengthPos++ ] = to - from;
levelStack[ levelPos++ ] = 0;
final int[] count = new int[ 1 << DIGIT_BITS ];
final int[] pos = new int[ 1 << DIGIT_BITS ];
while( offsetPos > 0 ) {
final int first = offsetStack[ --offsetPos ];
final int length = lengthStack[ --lengthPos ];
final int level = levelStack[ --levelPos ];
#if #keyclass(Character)
final int signMask = 0;
#else
final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif
final KEY_TYPE[] k = level < DIGITS_PER_ELEMENT ? a : b; // This is the key array
final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key
// Count keys.
for( int i = first + length; i-- != first; ) count[ INT( KEY2LEXINT( k[ i ] ) >>> shift & DIGIT_MASK ^ signMask ) ]++;
// Compute cumulative distribution
int lastUsed = -1;
for ( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) {
if ( count[ i ] != 0 ) lastUsed = i;
pos[ i ] = ( p += count[ i ] );
}
final int end = first + length - count[ lastUsed ];
// i moves through the start of each block
for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) {
KEY_TYPE t = a[ i ];
KEY_TYPE u = b[ i ];
c = INT( KEY2LEXINT( k[ i ] ) >>> shift & DIGIT_MASK ^ signMask );
if ( i < end ) { // When all slots are OK, the last slot is necessarily OK.
while( ( d = --pos[ c ] ) > i ) {
c = INT( KEY2LEXINT( k[ d ] ) >>> shift & DIGIT_MASK ^ signMask );
KEY_TYPE z = t;
t = a[ d ];
a[ d ] = z;
z = u;
u = b[ d ];
b[ d ] = z;
}
a[ i ] = t;
b[ i ] = u;
}
if ( level < maxLevel && count[ c ] > 1 ) {
if ( count[ c ] < RADIXSORT_NO_REC ) selectionSort( a, b, i, i + count[ c ] );
else {
offsetStack[ offsetPos++ ] = i;
lengthStack[ lengthPos++ ] = count[ c ];
levelStack[ levelPos++ ] = level + 1;
}
}
}
}
}
/** Sorts the specified range of elements of two arrays using a parallel radix sort.
*
* a[ i ] < a[ i + 1 ]
or a[ i ] == a[ i + 1 ]
and b[ i ] ≤ b[ i + 1 ]
.
*
* a[ i ] < a[ i + 1 ]
or a[ i ] == a[ i + 1 ]
and b[ i ] ≤ b[ i + 1 ]
.
*
* perm
(which must
* be exactly the numbers in the interval [0..perm.length)
) will be permuted so that
* a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]
.
*
* perm
(note that the stable
* version is slightly faster).
*
* @param perm a permutation array indexing a
.
* @param a the array to be sorted.
* @param b the second array to be sorted.
* @param stable whether the sorting algorithm should be stable.
*/
public static void radixSortIndirect( final int[] perm, final KEY_TYPE[] a, final KEY_TYPE[] b, final boolean stable ) {
ensureSameLength( a, b );
radixSortIndirect( perm, a, b, 0, a.length, stable );
}
/** Sorts the specified pair of arrays lexicographically using indirect radix sort.
*
* perm
(which must
* be exactly the numbers in the interval [0..perm.length)
) will be permuted so that
* a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]
.
*
* perm
(note that the stable
* version is slightly faster).
*
* @param perm a permutation array indexing a
.
* @param a the array to be sorted.
* @param b the second array to be sorted.
* @param from the index of the first element of perm
(inclusive) to be permuted.
* @param to the index of the last element of perm
(exclusive) to be permuted.
* @param stable whether the sorting algorithm should be stable.
*/
public static void radixSortIndirect( final int[] perm, final KEY_TYPE[] a, final KEY_TYPE[] b, final int from, final int to, final boolean stable ) {
if ( to - from < RADIXSORT_NO_REC ) {
insertionSortIndirect( perm, a, b, from, to );
return;
}
final int layers = 2;
final int maxLevel = DIGITS_PER_ELEMENT * layers - 1;
final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( layers * DIGITS_PER_ELEMENT - 1 ) + 1;
final int[] offsetStack = new int[ stackSize ];
int offsetPos = 0;
final int[] lengthStack = new int[ stackSize ];
int lengthPos = 0;
final int[] levelStack = new int[ stackSize ];
int levelPos = 0;
offsetStack[ offsetPos++ ] = from;
lengthStack[ lengthPos++ ] = to - from;
levelStack[ levelPos++ ] = 0;
final int[] count = new int[ 1 << DIGIT_BITS ];
final int[] pos = new int[ 1 << DIGIT_BITS ];
final int[] support = stable ? new int[ perm.length ] : null;
while( offsetPos > 0 ) {
final int first = offsetStack[ --offsetPos ];
final int length = lengthStack[ --lengthPos ];
final int level = levelStack[ --levelPos ];
#if #keyclass(Character)
final int signMask = 0;
#else
final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif
final KEY_TYPE[] k = level < DIGITS_PER_ELEMENT ? a : b; // This is the key array
final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key
// Count keys.
for( int i = first + length; i-- != first; ) count[ INT( KEY2LEXINT( k[ perm[ i ] ] ) >>> shift & DIGIT_MASK ^ signMask ) ]++;
// Compute cumulative distribution
int lastUsed = -1;
for ( int i = 0, p = stable ? 0 : first; i < 1 << DIGIT_BITS; i++ ) {
if ( count[ i ] != 0 ) lastUsed = i;
pos[ i ] = ( p += count[ i ] );
}
if ( stable ) {
for( int i = first + length; i-- != first; ) support[ --pos[ INT( KEY2LEXINT( k[ perm[ i ] ] ) >>> shift & DIGIT_MASK ^ signMask ) ] ] = perm[ i ];
System.arraycopy( support, 0, perm, first, length );
for( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) {
if ( level < maxLevel && count[ i ] > 1 ) {
if ( count[ i ] < RADIXSORT_NO_REC ) insertionSortIndirect( perm, a, b, p, p + count[ i ] );
else {
offsetStack[ offsetPos++ ] = p;
lengthStack[ lengthPos++ ] = count[ i ];
levelStack[ levelPos++ ] = level + 1;
}
}
p += count[ i ];
}
java.util.Arrays.fill( count, 0 );
}
else {
final int end = first + length - count[ lastUsed ];
// i moves through the start of each block
for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) {
int t = perm[ i ];
c = INT( KEY2LEXINT( k[ t ] ) >>> shift & DIGIT_MASK ^ signMask );
if ( i < end ) { // When all slots are OK, the last slot is necessarily OK.
while( ( d = --pos[ c ] ) > i ) {
final int z = t;
t = perm[ d ];
perm[ d ] = z;
c = INT( KEY2LEXINT( k[ t ] ) >>> shift & DIGIT_MASK ^ signMask );
}
perm[ i ] = t;
}
if ( level < maxLevel && count[ c ] > 1 ) {
if ( count[ c ] < RADIXSORT_NO_REC ) insertionSortIndirect( perm, a, b, i, i + count[ c ] );
else {
offsetStack[ offsetPos++ ] = i;
lengthStack[ lengthPos++ ] = count[ c ];
levelStack[ levelPos++ ] = level + 1;
}
}
}
}
}
}
private static void selectionSort( final KEY_TYPE[][] a, final int from, final int to, final int level ) {
final int layers = a.length;
final int firstLayer = level / DIGITS_PER_ELEMENT;
for( int i = from; i < to - 1; i++ ) {
int m = i;
for( int j = i + 1; j < to; j++ ) {
for( int p = firstLayer; p < layers; p++ ) {
if ( a[ p ][ j ] < a[ p ][ m ] ) {
m = j;
break;
}
else if ( a[ p ][ j ] > a[ p ][ m ] ) break;
}
}
if ( m != i ) {
for( int p = layers; p-- != 0; ) {
final KEY_TYPE u = a[ p ][ i ];
a[ p ][ i ] = a[ p ][ m ];
a[ p ][ m ] = u;
}
}
}
}
/** Sorts the specified array of arrays lexicographically using radix sort.
*
* a
.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[] shuffle( final KEY_GENERIC_TYPE[] a, final int from, final int to, final Random random ) {
for( int i = to - from; i-- != 0; ) {
final int p = random.nextInt( i + 1 );
final KEY_GENERIC_TYPE t = a[ from + i ];
a[ from + i ] = a[ from + p ];
a[ from + p ] = t;
}
return a;
}
/** Shuffles the specified array using the specified pseudorandom number generator.
*
* @param a the array to be shuffled.
* @param random a pseudorandom number generator (please use a XorShift* generator).
* @return a
.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[] shuffle( final KEY_GENERIC_TYPE[] a, final Random random ) {
for( int i = a.length; i-- != 0; ) {
final int p = random.nextInt( i + 1 );
final KEY_GENERIC_TYPE t = a[ i ];
a[ i ] = a[ p ];
a[ p ] = t;
}
return a;
}
/** Reverses the order of the elements in the specified array.
*
* @param a the array to be reversed.
* @return a
.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[] reverse( final KEY_GENERIC_TYPE[] a ) {
final int length = a.length;
for( int i = length / 2; i-- != 0; ) {
final KEY_GENERIC_TYPE t = a[ length - i - 1 ];
a[ length - i - 1 ] = a[ i ];
a[ i ] = t;
}
return a;
}
/** Reverses the order of the elements in the specified array fragment.
*
* @param a the array to be reversed.
* @param from the index of the first element (inclusive) to be reversed.
* @param to the index of the last element (exclusive) to be reversed.
* @return a
.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[] reverse( final KEY_GENERIC_TYPE[] a, final int from, final int to ) {
final int length = to - from;
for( int i = length / 2; i-- != 0; ) {
final KEY_GENERIC_TYPE t = a[ from + length - i - 1 ];
a[ from + length - i - 1 ] = a[ from + i ];
a[ from + i ] = t;
}
return a;
}
/** A type-specific content-based hash strategy for arrays. */
private static final class ArrayHashStrategy KEY_GENERIC implements Hash.Strategynull
correctly, and it is serializable.
*/
#if #keys(primitive)
public final static Hash.Strategyn
times (possibly stopping
* if {@link #hasPrevious()} becomes false).
*
* @param n the number of elements to skip back.
* @return the number of elements actually skipped.
* @see java.util.Iterator#next()
*/
int back( int n );
}
fastutil-7.0.2/drv/BigArrayBigList.drv 0000644 0000000 0000000 00000122761 12502266646 016502 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import java.util.Iterator;
import java.util.RandomAccess;
import java.util.NoSuchElementException;
import it.unimi.dsi.fastutil.BigArrays;
#if #keys(primitive)
/** A type-specific big list based on a big array; provides some additional methods that use polymorphism to avoid (un)boxing.
*
* removeElements()
,
* addElements()
and getElements()
using
* high-performance system calls (e.g., {@link
* System#arraycopy(Object,int,Object,int,int) System.arraycopy()} instead of
* expensive loops.
*
* @see java.util.ArrayList
*/
public class BIG_ARRAY_BIG_LIST KEY_GENERIC extends ABSTRACT_BIG_LIST KEY_GENERIC implements RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = -7046029254386353130L;
#else
/** A type-specific big-array-based big list; provides some additional methods that use polymorphism to avoid (un)boxing.
*
* removeElements()
,
* addElements()
and getElements()
using
* high-performance system calls (e.g., {@link
* System#arraycopy(Object,int,Object,int,int) System.arraycopy()} instead of
* expensive loops.
*
* @see java.util.ArrayList
*/
public class BIG_ARRAY_BIG_LIST KEY_GENERIC extends ABSTRACT_BIG_LIST KEY_GENERIC implements RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = -7046029254386353131L;
#endif
/** The initial default capacity of a big-array big list. */
public final static int DEFAULT_INITIAL_CAPACITY = 16;
#if ! #keys(primitive)
/** Whether the backing big array was passed to wrap()
. In
* this case, we must reallocate with the same type of big array. */
protected final boolean wrapped;
#endif
/** The backing big array. */
protected transient KEY_GENERIC_TYPE a[][];
/** The current actual size of the big list (never greater than the backing-array length). */
protected long size;
private static final boolean ASSERTS = ASSERTS_VALUE;
/** Creates a new big-array big list using a given array.
*
* type[][] {{ init_values }}
.
* The only constraint is that the number of initialisation values is
* below {@link it.unimi.dsi.fastutil.BigArrays#SEGMENT_SIZE}.
*
* @param a a big array whose elements will be used to fill the array list.
*/
public BIG_ARRAY_BIG_LIST( final KEY_GENERIC_TYPE a[][] ) {
this( a, 0, BIG_ARRAYS.length( a ) );
}
/** Creates a new big-array big list and fills it with the elements of a given big array.
*
* type[][] {{ init_values }}
.
* The only constraint is that the number of initialisation values is
* below {@link it.unimi.dsi.fastutil.BigArrays#SEGMENT_SIZE}.
*
* @param a a big array whose elements will be used to fill the array list.
* @param offset the first element to use.
* @param length the number of elements to use.
*/
public BIG_ARRAY_BIG_LIST( final KEY_GENERIC_TYPE a[][], final long offset, final long length ) {
this( length );
BIG_ARRAYS.copy( a, offset, this.a, 0, length );
size = length;
}
/** Creates a new big-array big list and fills it with the elements returned by an iterator..
*
* @param i an iterator whose returned elements will fill the array list.
*/
public BIG_ARRAY_BIG_LIST( final Iterator extends KEY_GENERIC_CLASS> i ) {
this();
while( i.hasNext() ) this.add( i.next() );
}
/** Creates a new big-array big list and fills it with the elements returned by a type-specific iterator..
*
* @param i a type-specific iterator whose returned elements will fill the array list.
*/
public BIG_ARRAY_BIG_LIST( final KEY_ITERATOR KEY_EXTENDS_GENERIC i ) {
this();
while( i.hasNext() ) this.add( i.NEXT_KEY() );
}
#if #keys(primitive)
/** Returns the backing big array of this big list.
*
* @return the backing big array.
*/
public KEY_GENERIC_TYPE[][] elements() {
return a;
}
#else
/** Returns the backing big array of this big list.
*
* n
, this method does nothing. Otherwise, it trims the
* big-array length to the maximum between n
and {@link #size64()}.
*
* ensureCapacity()
, grow()
,
* trim()
and setLength()
methods allow to handle
* big arrays much like array lists.
*
* ensureCapacity()
, grow()
,
* trim()
and setLength()
methods allow to handle
* arrays much like array lists.
*
* new
. This phenomenon is particularly
* evident in the first growth phases of an array reallocated with doubling (or similar) logic.
*
* @see BigArrays
*/
public class BIG_ARRAYS {
#endif
private BIG_ARRAYS() {}
/** A static, final, empty big array. */
public final static KEY_TYPE[][] EMPTY_BIG_ARRAY = {};
/** Returns the element of the given big array of specified index.
*
* @param array a big array.
* @param index a position in the big array.
* @return the element of the big array at the specified position.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE get( final KEY_GENERIC_TYPE[][] array, final long index ) {
return array[ segment( index ) ][ displacement( index ) ];
}
/** Sets the element of the given big array of specified index.
*
* @param array a big array.
* @param index a position in the big array.
* @param value the new value for the array element at the specified position.
*/
public static KEY_GENERIC void set( final KEY_GENERIC_TYPE[][] array, final long index, KEY_GENERIC_TYPE value ) {
array[ segment( index ) ][ displacement( index ) ] = value;
}
/** Swaps the element of the given big array of specified indices.
*
* @param array a big array.
* @param first a position in the big array.
* @param second a position in the big array.
*/
public static KEY_GENERIC void swap( final KEY_GENERIC_TYPE[][] array, final long first, final long second ) {
final KEY_GENERIC_TYPE t = array[ segment( first ) ][ displacement( first ) ];
array[ segment( first ) ][ displacement( first ) ] = array[ segment( second ) ][ displacement( second ) ];
array[ segment( second ) ][ displacement( second ) ] = t;
}
#if #keys(primitive) && ! #keyclass(Boolean)
/** Adds the specified increment the element of the given big array of specified index.
*
* @param array a big array.
* @param index a position in the big array.
* @param incr the increment
*/
public static void add( final KEY_GENERIC_TYPE[][] array, final long index, KEY_GENERIC_TYPE incr ) {
array[ segment( index ) ][ displacement( index ) ] += incr;
}
/** Multiplies by the specified factor the element of the given big array of specified index.
*
* @param array a big array.
* @param index a position in the big array.
* @param factor the factor
*/
public static void mul( final KEY_GENERIC_TYPE[][] array, final long index, KEY_GENERIC_TYPE factor ) {
array[ segment( index ) ][ displacement( index ) ] *= factor;
}
/** Increments the element of the given big array of specified index.
*
* @param array a big array.
* @param index a position in the big array.
*/
public static void incr( final KEY_GENERIC_TYPE[][] array, final long index ) {
array[ segment( index ) ][ displacement( index ) ]++;
}
/** Decrements the element of the given big array of specified index.
*
* @param array a big array.
* @param index a position in the big array.
*/
public static void decr( final KEY_GENERIC_TYPE[][] array, final long index ) {
array[ segment( index ) ][ displacement( index ) ]--;
}
#endif
/** Returns the length of the given big array.
*
* @param array a big array.
* @return the length of the given big array.
*/
public static KEY_GENERIC long length( final KEY_GENERIC_TYPE[][] array ) {
final int length = array.length;
return length == 0 ? 0 : start( length - 1 ) + array[ length - 1 ].length;
}
/** Copies a big array from the specified source big array, beginning at the specified position, to the specified position of the destination big array.
* Handles correctly overlapping regions of the same big array.
*
* @param srcArray the source big array.
* @param srcPos the starting position in the source big array.
* @param destArray the destination big array.
* @param destPos the starting position in the destination data.
* @param length the number of elements to be copied.
*/
public static KEY_GENERIC void copy( final KEY_GENERIC_TYPE[][] srcArray, final long srcPos, final KEY_GENERIC_TYPE[][] destArray, final long destPos, long length ) {
if ( destPos <= srcPos ) {
int srcSegment = segment( srcPos );
int destSegment = segment( destPos );
int srcDispl = displacement( srcPos );
int destDispl = displacement( destPos );
int l;
while( length > 0 ) {
l = (int)Math.min( length, Math.min( srcArray[ srcSegment ].length - srcDispl, destArray[ destSegment ].length - destDispl ) );
System.arraycopy( srcArray[ srcSegment ], srcDispl, destArray[ destSegment ], destDispl, l );
if ( ( srcDispl += l ) == SEGMENT_SIZE ) {
srcDispl = 0;
srcSegment++;
}
if ( ( destDispl += l ) == SEGMENT_SIZE ) {
destDispl = 0;
destSegment++;
}
length -= l;
}
}
else {
int srcSegment = segment( srcPos + length );
int destSegment = segment( destPos + length );
int srcDispl = displacement( srcPos + length );
int destDispl = displacement( destPos + length );
int l;
while( length > 0 ) {
if ( srcDispl == 0 ) {
srcDispl = SEGMENT_SIZE;
srcSegment--;
}
if ( destDispl == 0 ) {
destDispl = SEGMENT_SIZE;
destSegment--;
}
l = (int)Math.min( length, Math.min( srcDispl, destDispl ) );
System.arraycopy( srcArray[ srcSegment ], srcDispl - l, destArray[ destSegment ], destDispl - l, l );
srcDispl -= l;
destDispl -= l;
length -= l;
}
}
}
/** Copies a big array from the specified source big array, beginning at the specified position, to the specified position of the destination array.
*
* @param srcArray the source big array.
* @param srcPos the starting position in the source big array.
* @param destArray the destination array.
* @param destPos the starting position in the destination data.
* @param length the number of elements to be copied.
*/
public static KEY_GENERIC void copyFromBig( final KEY_GENERIC_TYPE[][] srcArray, final long srcPos, final KEY_GENERIC_TYPE[] destArray, int destPos, int length ) {
int srcSegment = segment( srcPos );
int srcDispl = displacement( srcPos );
int l;
while( length > 0 ) {
l = Math.min( srcArray[ srcSegment ].length - srcDispl, length );
System.arraycopy( srcArray[ srcSegment ], srcDispl, destArray, destPos, l );
if ( ( srcDispl += l ) == SEGMENT_SIZE ) {
srcDispl = 0;
srcSegment++;
}
destPos += l;
length -= l;
}
}
/** Copies an array from the specified source array, beginning at the specified position, to the specified position of the destination big array.
*
* @param srcArray the source array.
* @param srcPos the starting position in the source array.
* @param destArray the destination big array.
* @param destPos the starting position in the destination data.
* @param length the number of elements to be copied.
*/
public static KEY_GENERIC void copyToBig( final KEY_GENERIC_TYPE[] srcArray, int srcPos, final KEY_GENERIC_TYPE[][] destArray, final long destPos, long length ) {
int destSegment = segment( destPos );
int destDispl = displacement( destPos );
int l;
while( length > 0 ) {
l = (int)Math.min( destArray[ destSegment ].length - destDispl, length );
System.arraycopy( srcArray, srcPos, destArray[ destSegment ], destDispl, l );
if ( ( destDispl += l ) == SEGMENT_SIZE ) {
destDispl = 0;
destSegment++;
}
srcPos += l;
length -= l;
}
}
#if #keyclass(Object)
/** Creates a new big array using the given one as prototype.
*
* prototype
. In case
* of an empty big array, it tries to return {@link #EMPTY_BIG_ARRAY}, if possible.
*
* @param prototype a big array that will be used to type the new one.
* @param length the length of the new big array.
* @return a new big array of given type and length.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static componentType
. In case
* of an empty big array, it tries to return {@link #EMPTY_BIG_ARRAY}, if possible.
*
* @param componentType a class representing the type of segments of the array to be created.
* @param length the length of the new big array.
* @return a new big array of given type and length.
*/
private static Object[][] newBigArray( Class> componentType, final long length ) {
if ( length == 0 && componentType == Object[].class ) return EMPTY_BIG_ARRAY;
final int baseLength = (int)((length + SEGMENT_MASK) / SEGMENT_SIZE);
Object[][] base = (Object[][])java.lang.reflect.Array.newInstance( componentType, baseLength );
final int residual = (int)(length & SEGMENT_MASK);
if ( residual != 0 ) {
for( int i = 0; i < baseLength - 1; i++ ) base[ i ] = (Object[])java.lang.reflect.Array.newInstance( componentType.getComponentType(), SEGMENT_SIZE );
base[ baseLength - 1 ] = (Object[])java.lang.reflect.Array.newInstance( componentType.getComponentType(), residual );
}
else for( int i = 0; i < baseLength; i++ ) base[ i ] = (Object[])java.lang.reflect.Array.newInstance( componentType.getComponentType(), SEGMENT_SIZE );
return base;
}
#endif
/** Creates a new big array.
*
* @param length the length of the new big array.
* @return a new big array of given length.
*/
public static KEY_TYPE[][] newBigArray( final long length ) {
if ( length == 0 ) return EMPTY_BIG_ARRAY;
final int baseLength = (int)((length + SEGMENT_MASK) / SEGMENT_SIZE);
KEY_TYPE[][] base = new KEY_TYPE[ baseLength ][];
final int residual = (int)(length & SEGMENT_MASK);
if ( residual != 0 ) {
for( int i = 0; i < baseLength - 1; i++ ) base[ i ] = new KEY_TYPE[ SEGMENT_SIZE ];
base[ baseLength - 1 ] = new KEY_TYPE[ residual ];
}
else for( int i = 0; i < baseLength; i++ ) base[ i ] = new KEY_TYPE[ SEGMENT_SIZE ];
return base;
}
#if #keyclass(Object)
/** Turns a standard array into a big array.
*
* array
.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static array
.
*/
public static KEY_TYPE[][] wrap( final KEY_TYPE[] array ) {
if ( array.length == 0 ) return EMPTY_BIG_ARRAY;
if ( array.length <= SEGMENT_SIZE ) return new KEY_TYPE[][] { array };
final KEY_TYPE[][] bigArray = newBigArray( array.length );
for( int i = 0; i < bigArray.length; i++ ) System.arraycopy( array, (int)start( i ), bigArray[ i ], 0, bigArray[ i ].length );
return bigArray;
}
#endif
/** Ensures that a big array can contain the given number of entries.
*
* grow()
instead.
*
* array
, if it contains length
entries or more; otherwise,
* a big array with length
entries whose first length(array)
* entries are the same as those of array
.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[][] ensureCapacity( final KEY_GENERIC_TYPE[][] array, final long length ) {
return ensureCapacity( array, length, length( array ) );
}
#if #keyclass(Object)
/** Ensures that a big array can contain the given number of entries, preserving just a part of the big array.
*
* array
.
*
* array
, if it can contain length
entries or more; otherwise,
* a big array with length
entries whose first preserve
* entries are the same as those of array
.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static KEY_GENERIC KEY_GENERIC_TYPE[][] ensureCapacity( final KEY_GENERIC_TYPE[][] array, final long length, final long preserve ) {
final long oldLength = length( array );
if ( length > oldLength ) {
final int valid = array.length - ( array.length == 0 || array.length > 0 && array[ array.length - 1 ].length == SEGMENT_SIZE ? 0 : 1 );
final int baseLength = (int)((length + SEGMENT_MASK) / SEGMENT_SIZE);
final KEY_GENERIC_TYPE[][] base = Arrays.copyOf( array, baseLength );
final Class> componentType = array.getClass().getComponentType();
final int residual = (int)(length & SEGMENT_MASK);
if ( residual != 0 ) {
for( int i = valid; i < baseLength - 1; i++ ) base[ i ] = (KEY_GENERIC_TYPE[])java.lang.reflect.Array.newInstance( componentType.getComponentType(), SEGMENT_SIZE );
base[ baseLength - 1 ] = (KEY_GENERIC_TYPE[])java.lang.reflect.Array.newInstance( componentType.getComponentType(), residual );
}
else for( int i = valid; i < baseLength; i++ ) base[ i ] = (KEY_GENERIC_TYPE[])java.lang.reflect.Array.newInstance( componentType.getComponentType(), SEGMENT_SIZE );
if ( preserve - ( valid * (long)SEGMENT_SIZE ) > 0 ) copy( array, valid * (long)SEGMENT_SIZE, base, valid * (long)SEGMENT_SIZE, preserve - ( valid * (long)SEGMENT_SIZE ) );
return base;
}
return array;
}
#else
/** Ensures that a big array can contain the given number of entries, preserving just a part of the big array.
*
* array
, if it can contain length
entries or more; otherwise,
* a big array with length
entries whose first preserve
* entries are the same as those of array
.
*/
public static KEY_TYPE[][] ensureCapacity( final KEY_TYPE[][] array, final long length, final long preserve ) {
final long oldLength = length( array );
if ( length > oldLength ) {
final int valid = array.length - ( array.length == 0 || array.length > 0 && array[ array.length - 1 ].length == SEGMENT_SIZE ? 0 : 1 );
final int baseLength = (int)((length + SEGMENT_MASK) / SEGMENT_SIZE);
final KEY_TYPE[][] base = Arrays.copyOf( array, baseLength );
final int residual = (int)(length & SEGMENT_MASK);
if ( residual != 0 ) {
for( int i = valid; i < baseLength - 1; i++ ) base[ i ] = new KEY_TYPE[ SEGMENT_SIZE ];
base[ baseLength - 1 ] = new KEY_TYPE[ residual ];
}
else for( int i = valid; i < baseLength; i++ ) base[ i ] = new KEY_TYPE[ SEGMENT_SIZE ];
if ( preserve - ( valid * (long)SEGMENT_SIZE ) > 0 ) copy( array, valid * (long)SEGMENT_SIZE, base, valid * (long)SEGMENT_SIZE, preserve - ( valid * (long)SEGMENT_SIZE ) );
return base;
}
return array;
}
#endif
/** Grows the given big array to the maximum between the given length and
* the current length multiplied by two, provided that the given
* length is larger than the current length.
*
* ensureCapacity()
instead.
*
* array
, if it can contain length
* entries; otherwise, a big array with
* max(length
,length(array)
/φ) entries whose first
* length(array)
entries are the same as those of array
.
* */
public static KEY_GENERIC KEY_GENERIC_TYPE[][] grow( final KEY_GENERIC_TYPE[][] array, final long length ) {
final long oldLength = length( array );
return length > oldLength ? grow( array, length, oldLength ) : array;
}
/** Grows the given big array to the maximum between the given length and
* the current length multiplied by two, provided that the given
* length is larger than the current length, preserving just a part of the big array.
*
* ensureCapacity()
instead.
*
* array
, if it can contain length
* entries; otherwise, a big array with
* max(length
,length(array)
/φ) entries whose first
* preserve
entries are the same as those of array
.
* */
public static KEY_GENERIC KEY_GENERIC_TYPE[][] grow( final KEY_GENERIC_TYPE[][] array, final long length, final long preserve ) {
final long oldLength = length( array );
return length > oldLength ? ensureCapacity( array, Math.max( 2 * oldLength, length ), preserve ) : array;
}
#if #keyclass(Object)
/** Trims the given big array to the given length.
*
* array
, if it contains length
* entries or less; otherwise, a big array with
* length
entries whose entries are the same as
* the first length
entries of array
.
*
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[][] trim( final KEY_GENERIC_TYPE[][] array, final long length ) {
final long oldLength = length( array );
if ( length >= oldLength ) return array;
final int baseLength = (int)((length + SEGMENT_MASK) / SEGMENT_SIZE);
final KEY_GENERIC_TYPE[][] base = Arrays.copyOf( array, baseLength );
final int residual = (int)(length & SEGMENT_MASK);
if ( residual != 0 ) base[ baseLength - 1 ] = ARRAYS.trim( base[ baseLength - 1 ], residual );
return base;
}
#else
/** Trims the given big array to the given length.
*
* array
, if it contains length
* entries or less; otherwise, a big array with
* length
entries whose entries are the same as
* the first length
entries of array
.
*
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[][] trim( final KEY_GENERIC_TYPE[][] array, final long length ) {
final long oldLength = length( array );
if ( length >= oldLength ) return array;
final int baseLength = (int)((length + SEGMENT_MASK) / SEGMENT_SIZE);
final KEY_TYPE[][] base = Arrays.copyOf( array, baseLength );
final int residual = (int)(length & SEGMENT_MASK);
if ( residual != 0 ) base[ baseLength - 1 ] = ARRAYS.trim( base[ baseLength - 1 ], residual );
return base;
}
#endif
/** Sets the length of the given big array.
*
* array
, if it contains exactly length
* entries; otherwise, if it contains more than
* length
entries, a big array with length
entries
* whose entries are the same as the first length
entries of
* array
; otherwise, a big array with length
entries
* whose first length(array)
entries are the same as those of
* array
.
*
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[][] setLength( final KEY_GENERIC_TYPE[][] array, final long length ) {
final long oldLength = length( array );
if ( length == oldLength ) return array;
if ( length < oldLength ) return trim( array, length );
return ensureCapacity( array, length );
}
/** Returns a copy of a portion of a big array.
*
* @param array a big array.
* @param offset the first element to copy.
* @param length the number of elements to copy.
* @return a new big array containing length
elements of array
starting at offset
.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[][] copy( final KEY_GENERIC_TYPE[][] array, final long offset, final long length ) {
ensureOffsetLength( array, offset, length );
final KEY_GENERIC_TYPE[][] a =
#if #keyclass(Object)
newBigArray( array, length );
#else
newBigArray( length );
#endif
copy( array, offset, a, 0, length );
return a;
}
/** Returns a copy of a big array.
*
* @param array a big array.
* @return a copy of array
.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[][] copy( final KEY_GENERIC_TYPE[][] array ) {
final KEY_GENERIC_TYPE[][] base = array.clone();
for( int i = base.length; i-- != 0; ) base[ i ] = array[ i ].clone();
return base;
}
/** Fills the given big array with the given value.
*
* from
is 0) this method uses a
* backward loop. In this case, it is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param array a big array.
* @param from the starting index of the portion to fill.
* @param to the end index of the portion to fill.
* @param value the new value for all elements of the specified portion of the big array.
*/
public static KEY_GENERIC void fill( final KEY_GENERIC_TYPE[][] array, final long from, long to, final KEY_GENERIC_TYPE value ) {
final long length = length( array );
BigArrays.ensureFromTo( length, from, to );
int fromSegment = segment( from );
int toSegment = segment( to );
int fromDispl = displacement( from );
int toDispl = displacement( to );
if ( fromSegment == toSegment ) {
Arrays.fill( array[ fromSegment ], fromDispl, toDispl, value );
return;
}
if ( toDispl != 0 ) Arrays.fill( array[ toSegment ], 0, toDispl, value );
while( --toSegment > fromSegment ) Arrays.fill( array[ toSegment ], value );
Arrays.fill( array[ fromSegment ], fromDispl, SEGMENT_SIZE, value );
}
/** Returns true if the two big arrays are elementwise equal.
*
* a
is null.
* @param a the big array whose string representation to return.
* @return the string representation of a
.
*/
public static KEY_GENERIC String toString( final KEY_GENERIC_TYPE[][] a ) {
if ( a == null ) return "null";
final long last = length( a ) - 1;
if ( last == - 1 ) return "[]";
final StringBuilder b = new StringBuilder();
b.append('[');
for ( long i = 0; ; i++ ) {
b.append( String.valueOf( get( a, i ) ) );
if ( i == last ) return b.append(']').toString();
b.append(", ");
}
}
/** Ensures that a range given by its first (inclusive) and last (exclusive) elements fits a big array.
*
* from
is greater than to
.
* @throws ArrayIndexOutOfBoundsException if from
or to
are greater than the big array length or negative.
*/
public static KEY_GENERIC void ensureFromTo( final KEY_GENERIC_TYPE[][] a, final long from, final long to ) {
BigArrays.ensureFromTo( length( a ), from, to );
}
/** Ensures that a range given by an offset and a length fits a big array.
*
* length
is negative.
* @throws ArrayIndexOutOfBoundsException if offset
is negative or offset
+length
is greater than the big array length.
*/
public static KEY_GENERIC void ensureOffsetLength( final KEY_GENERIC_TYPE[][] a, final long offset, final long length ) {
BigArrays.ensureOffsetLength( length( a ), offset, length );
}
/** A type-specific content-based hash strategy for big arrays. */
private static final class BigArrayHashStrategy KEY_GENERIC implements Hash.Strategynull
correctly, and it is serializable.
*/
@SuppressWarnings({"rawtypes"})
public final static Hash.Strategy HASH_STRATEGY = new BigArrayHashStrategy();
private static final int SMALL = 7;
private static final int MEDIUM = 40;
private static KEY_GENERIC void vecSwap( final KEY_GENERIC_TYPE[][] x, long a, long b, final long n ) {
for( int i = 0; i < n; i++, a++, b++ ) swap( x, a, b );
}
private static KEY_GENERIC long med3( final KEY_GENERIC_TYPE x[][], final long a, final long b, final long c, KEY_COMPARATOR KEY_GENERIC comp ) {
int ab = comp.compare( get( x, a ), get( x, b ) );
int ac = comp.compare( get( x, a ), get( x, c ) );
int bc = comp.compare( get( x, b ), get( x, c ) );
return ( ab < 0 ?
( bc < 0 ? b : ac < 0 ? c : a ) :
( bc > 0 ? b : ac > 0 ? c : a ) );
}
private static KEY_GENERIC void selectionSort( final KEY_GENERIC_TYPE[][] a, final long from, final long to, final KEY_COMPARATOR KEY_GENERIC comp ) {
for( long i = from; i < to - 1; i++ ) {
long m = i;
for( long j = i + 1; j < to; j++ ) if ( comp.compare( BIG_ARRAYS.get( a, j ), BIG_ARRAYS.get( a, m ) ) < 0 ) m = j;
if ( m != i ) swap( a, i, m );
}
}
/** Sorts the specified range of elements according to the order induced by the specified
* comparator using quicksort.
*
* a[ i ] < a[ i + 1 ]
or a[ i ] == a[ i + 1 ]
and b[ i ] <= b[ i + 1 ]
.
*
* a[ i ] < a[ i + 1 ]
or a[ i ] == a[ i + 1 ]
and b[ i ] <= b[ i + 1 ]
.
*
* a
.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[][] shuffle( final KEY_GENERIC_TYPE[][] a, final long from, final long to, final Random random ) {
for( long i = to - from; i-- != 0; ) {
final long p = ( random.nextLong() & 0x7FFFFFFFFFFFFFFFL ) % ( i + 1 );
final KEY_GENERIC_TYPE t = get( a, from + i );
set( a, from + i, get( a, from + p ) );
set( a, from + p, t );
}
return a;
}
/** Shuffles the specified big array using the specified pseudorandom number generator.
*
* @param a the big array to be shuffled.
* @param random a pseudorandom number generator (please use a XorShift* generator).
* @return a
.
*/
public static KEY_GENERIC KEY_GENERIC_TYPE[][] shuffle( final KEY_GENERIC_TYPE[][] a, final Random random ) {
for( long i = length( a ); i-- != 0; ) {
final long p = ( random.nextLong() & 0x7FFFFFFFFFFFFFFFL ) % ( i + 1 );
final KEY_GENERIC_TYPE t = get( a, i );
set( a, i, get( a, p ) );
set( a, p, t );
}
return a;
}
#if #keyclass(Integer)
#ifdef TEST
private static long seed = System.currentTimeMillis();
private static java.util.Random r = new java.util.Random( seed );
private static KEY_TYPE genKey() {
#if #keyclass(Byte) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#elif #keyclass(Object)
return Integer.toBinaryString( r.nextInt() );
#else
return new java.io.Serializable() {};
#endif
}
private static Object[] k, v, nk;
private static KEY_TYPE kt[];
private static KEY_TYPE nkt[];
private static BIG_ARRAY_BIG_LIST topList;
protected static void speedTest( int n, boolean b ) {}
protected static void test( int n ) {
KEY_TYPE[][] a = BIG_ARRAYS.newBigArray( n );
for( int i = 0; i < n; i++ ) set( a, i, i );
BIG_ARRAYS.copy( a, 0, a, 1, n - 2 );
assert a[ 0 ][ 0 ] == 0;
for( int i = 0; i < n - 2; i++ ) assert get( a, i + 1 ) == i;
for( int i = 0; i < n; i++ ) set( a, i, i );
BIG_ARRAYS.copy( a, 1, a, 0, n - 1 );
for( int i = 0; i < n - 1; i++ ) assert get( a, i ) == i + 1;
for( int i = 0; i < n; i++ ) set( a, i, i );
KEY_TYPE[] b = new KEY_TYPE[ n ];
for( int i = 0; i < n; i++ ) b[ i ] = i;
assert equals( wrap( b ), a );
System.out.println("Test OK");
return;
}
public static void main( String args[] ) {
int n = Integer.parseInt(args[1]);
if ( args.length > 2 ) r = new java.util.Random( seed = Long.parseLong( args[ 2 ] ) );
try {
if ("speedTest".equals(args[0]) || "speedComp".equals(args[0])) speedTest( n, "speedComp".equals(args[0]) );
else if ( "test".equals( args[0] ) ) test(n);
} catch( Throwable e ) {
e.printStackTrace( System.err );
System.err.println( "seed: " + seed );
}
}
#endif
#endif
}
fastutil-7.0.2/drv/BigList.drv 0000644 0000000 0000000 00000012113 12502261336 015035 0 ustar root wheel /*
* Copyright (C) 2010-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import java.util.List;
import it.unimi.dsi.fastutil.BigList;
#if ! #keyclass(Reference)
/** A type-specific {@link BigList}; provides some additional methods that use polymorphism to avoid (un)boxing.
*
* from
, inclusive, to the index to
, exclusive.
*
* element
.
*/
public static KEY_GENERIC KEY_BIG_LIST_ITERATOR KEY_GENERIC singleton( final KEY_GENERIC_TYPE element ) {
return new SingletonBigListIterator KEY_GENERIC( element );
}
/** An unmodifiable wrapper class for big list iterators. */
public static class UnmodifiableBigListIterator KEY_GENERIC extends KEY_ABSTRACT_BIG_LIST_ITERATOR KEY_GENERIC {
final protected KEY_BIG_LIST_ITERATOR KEY_GENERIC i;
public UnmodifiableBigListIterator( final KEY_BIG_LIST_ITERATOR KEY_GENERIC i ) {
this.i = i;
}
public boolean hasNext() { return i.hasNext(); }
public boolean hasPrevious() { return i.hasPrevious(); }
public KEY_GENERIC_TYPE NEXT_KEY() { return i.NEXT_KEY(); }
public KEY_GENERIC_TYPE PREV_KEY() { return i.PREV_KEY(); }
public long nextIndex() { return i.nextIndex(); }
public long previousIndex() { return i.previousIndex(); }
#if #keys(primitive)
public KEY_GENERIC_CLASS next() { return i.next(); }
public KEY_GENERIC_CLASS previous() { return i.previous(); }
#endif
}
/** Returns an unmodifiable list iterator backed by the specified list iterator.
*
* @param i the list iterator to be wrapped in an unmodifiable list iterator.
* @return an unmodifiable view of the specified list iterator.
*/
public static KEY_GENERIC KEY_BIG_LIST_ITERATOR KEY_GENERIC unmodifiable( final KEY_BIG_LIST_ITERATOR KEY_GENERIC i ) { return new UnmodifiableBigListIterator KEY_GENERIC( i ); }
/** A class exposing a list iterator as a big-list iterator.. */
public static class BigListIteratorListIterator KEY_GENERIC extends KEY_ABSTRACT_BIG_LIST_ITERATOR KEY_GENERIC {
protected final KEY_LIST_ITERATOR KEY_GENERIC i;
protected BigListIteratorListIterator( final KEY_LIST_ITERATOR KEY_GENERIC i ) {
this.i = i;
}
private int intDisplacement( long n ) {
if ( n < Integer.MIN_VALUE || n > Integer.MAX_VALUE ) throw new IndexOutOfBoundsException( "This big iterator is restricted to 32-bit displacements" );
return (int)n;
}
public void set( KEY_GENERIC_TYPE ok ) { i.set( ok ); }
public void add( KEY_GENERIC_TYPE ok ) { i.add( ok ); }
public int back( int n ) { return i.back( n ); }
public long back( long n ) { return i.back( intDisplacement( n ) ); }
public void remove() { i.remove(); }
public int skip( int n ) { return i.skip( n ); }
public long skip( long n ) { return i.skip( intDisplacement( n ) ); }
public boolean hasNext() { return i.hasNext(); }
public boolean hasPrevious() { return i.hasPrevious(); }
public KEY_GENERIC_TYPE NEXT_KEY() { return i.NEXT_KEY(); }
public KEY_GENERIC_TYPE PREV_KEY() { return i.PREV_KEY(); }
public long nextIndex() { return i.nextIndex(); }
public long previousIndex() { return i.previousIndex(); }
}
/** Returns a big-list iterator backed by the specified list iterator.
*
* @param i the list iterator to adapted to the big-list-iterator interface.
* @return a big-list iterator backed by the specified list iterator.
*/
public static KEY_GENERIC KEY_BIG_LIST_ITERATOR KEY_GENERIC asBigListIterator( final KEY_LIST_ITERATOR KEY_GENERIC i ) { return new BigListIteratorListIterator KEY_GENERIC( i ); }
}
fastutil-7.0.2/drv/BigLists.drv 0000644 0000000 0000000 00000132720 12502266603 015231 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import it.unimi.dsi.fastutil.BigList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
/** A class providing static methods and objects that do useful things with type-specific big lists.
*
* @see java.util.Collections
* @see it.unimi.dsi.fastutil.BigList
*/
public class BIG_LISTS {
private BIG_LISTS() {}
/** Shuffles the specified big list using the specified pseudorandom number generator.
*
* @param l the big list to be shuffled.
* @param random a pseudorandom number generator (please use a XorShift* generator).
* @return l
.
*/
public static KEY_GENERIC BIG_LIST KEY_GENERIC shuffle( final BIG_LIST KEY_GENERIC l, final Random random ) {
for( long i = l.size64(); i-- != 0; ) {
final long p = ( random.nextLong() & 0x7FFFFFFFFFFFFFFFL ) % ( i + 1 );
final KEY_GENERIC_TYPE t = l.GET_KEY( i );
l.set( i, l.GET_KEY( p ) );
l.set( p, t );
}
return l;
}
/** An immutable class representing an empty type-specific big list.
*
* element
.
*/
public static KEY_GENERIC BIG_LIST KEY_GENERIC singleton( final KEY_GENERIC_TYPE element ) { return new Singleton KEY_GENERIC( element ); }
#if ! #keys(reference)
/** Returns a type-specific immutable big list containing only the specified element. The returned big list is serializable and cloneable.
*
* @param element the only element of the returned big list.
* @return a type-specific immutable big list containing just element
.
*/
public static KEY_GENERIC BIG_LIST KEY_GENERIC singleton( final Object element ) { return new Singleton KEY_GENERIC( KEY_OBJ2TYPE( element ) ); }
#endif
/** A synchronized wrapper class for big lists. */
public static class SynchronizedBigList KEY_GENERIC extends COLLECTIONS.SynchronizedCollection KEY_GENERIC implements BIG_LIST KEY_GENERIC, java.io.Serializable {
private static final long serialVersionUID = -7046029254386353129L;
protected final BIG_LIST KEY_GENERIC list; // Due to the large number of methods that are not in COLLECTION, this is worth caching.
protected SynchronizedBigList( final BIG_LIST KEY_GENERIC l, final Object sync ) {
super( l, sync );
this.list = l;
}
protected SynchronizedBigList( final BIG_LIST KEY_GENERIC l ) {
super( l );
this.list = l;
}
public KEY_GENERIC_TYPE GET_KEY( final long i ) { synchronized( sync ) { return list.GET_KEY( i ); } }
public KEY_GENERIC_TYPE set( final long i, final KEY_GENERIC_TYPE k ) { synchronized( sync ) { return list.set( i, k ); } }
public void add( final long i, final KEY_GENERIC_TYPE k ) { synchronized( sync ) { list.add( i, k ); } }
public KEY_GENERIC_TYPE REMOVE_KEY( final long i ) { synchronized( sync ) { return list.REMOVE_KEY( i ); } }
public long indexOf( final KEY_TYPE k ) { synchronized( sync ) { return list.indexOf( k ); } }
public long lastIndexOf( final KEY_TYPE k ) { synchronized( sync ) { return list.lastIndexOf( k ); } }
public boolean addAll( final long index, final Collection extends KEY_GENERIC_CLASS> c ) { synchronized( sync ) { return list.addAll( index, c ); } }
public void getElements( final long from, final KEY_TYPE a[][], final long offset, final long length ) { synchronized( sync ) { list.getElements( from, a, offset, length ); } }
public void removeElements( final long from, final long to ) { synchronized( sync ) { list.removeElements( from, to ); } }
public void addElements( long index, final KEY_GENERIC_TYPE a[][], long offset, long length ) { synchronized( sync ) { list.addElements( index, a, offset, length ); } }
public void addElements( long index, final KEY_GENERIC_TYPE a[][] ) { synchronized( sync ) { list.addElements( index, a ); } }
public void size( final long size ) { synchronized( sync ) { list.size( size ); } }
public long size64() { synchronized( sync ) { return list.size64(); } }
public KEY_BIG_LIST_ITERATOR KEY_GENERIC iterator() { return list.listIterator(); }
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator() { return list.listIterator(); }
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator( final long i ) { return list.listIterator( i ); }
public BIG_LIST KEY_GENERIC subList( final long from, final long to ) { synchronized( sync ) { return synchronize( list.subList( from, to ), sync ); } }
public boolean equals( final Object o ) { synchronized( sync ) { return list.equals( o ); } }
public int hashCode() { synchronized( sync ) { return list.hashCode(); } }
#if ! #keyclass(Reference)
public int compareTo( final BigList extends KEY_GENERIC_CLASS> o ) { synchronized( sync ) { return list.compareTo( o ); } }
#endif
#if #keys(primitive)
public boolean addAll( final long index, final COLLECTION c ) { synchronized( sync ) { return list.addAll( index, c ); } }
public boolean addAll( final long index, BIG_LIST l ) { synchronized( sync ) { return list.addAll( index, l ); } }
public boolean addAll( BIG_LIST l ) { synchronized( sync ) { return list.addAll( l ); } }
public KEY_GENERIC_CLASS get( final long i ) { synchronized( sync ) { return list.get( i ); } }
public void add( final long i, KEY_GENERIC_CLASS k ) { synchronized( sync ) { list.add( i, k ); } }
public KEY_GENERIC_CLASS set( final long index, KEY_GENERIC_CLASS k ) { synchronized( sync ) { return list.set( index, k ); } }
public KEY_GENERIC_CLASS remove( final long i ) { synchronized( sync ) { return list.remove( i ); } }
public long indexOf( final Object o ) { synchronized( sync ) { return list.indexOf( o ); } }
public long lastIndexOf( final Object o ) { synchronized( sync ) { return list.lastIndexOf( o ); } }
#endif
}
/** Returns a synchronized type-specific big list backed by the given type-specific big list.
*
* @param l the big list to be wrapped in a synchronized big list.
* @return a synchronized view of the specified big list.
* @see java.util.Collections#synchronizedList(List)
*/
public static KEY_GENERIC BIG_LIST KEY_GENERIC synchronize( final BIG_LIST KEY_GENERIC l ) { return new SynchronizedBigList KEY_GENERIC( l ); }
/** Returns a synchronized type-specific big list backed by the given type-specific big list, using an assigned object to synchronize.
*
* @param l the big list to be wrapped in a synchronized big list.
* @param sync an object that will be used to synchronize the access to the big list.
* @return a synchronized view of the specified big list.
* @see java.util.Collections#synchronizedList(List)
*/
public static KEY_GENERIC BIG_LIST KEY_GENERIC synchronize( final BIG_LIST KEY_GENERIC l, final Object sync ) { return new SynchronizedBigList KEY_GENERIC( l, sync ); }
/** An unmodifiable wrapper class for big lists. */
public static class UnmodifiableBigList KEY_GENERIC extends COLLECTIONS.UnmodifiableCollection KEY_GENERIC implements BIG_LIST KEY_GENERIC, java.io.Serializable {
private static final long serialVersionUID = -7046029254386353129L;
protected final BIG_LIST KEY_GENERIC list; // Due to the large number of methods that are not in COLLECTION, this is worth caching.
protected UnmodifiableBigList( final BIG_LIST KEY_GENERIC l ) {
super( l );
this.list = l;
}
public KEY_GENERIC_TYPE GET_KEY( final long i ) { return list.GET_KEY( i ); }
public KEY_GENERIC_TYPE set( final long i, final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public void add( final long i, final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_TYPE REMOVE_KEY( final long i ) { throw new UnsupportedOperationException(); }
public long indexOf( final KEY_TYPE k ) { return list.indexOf( k ); }
public long lastIndexOf( final KEY_TYPE k ) { return list.lastIndexOf( k ); }
public boolean addAll( final long index, final Collection extends KEY_GENERIC_CLASS> c ) { throw new UnsupportedOperationException(); }
public void getElements( final long from, final KEY_TYPE a[][], final long offset, final long length ) { list.getElements( from, a, offset, length ); }
public void removeElements( final long from, final long to ) { throw new UnsupportedOperationException(); }
public void addElements( long index, final KEY_GENERIC_TYPE a[][], long offset, long length ) { throw new UnsupportedOperationException(); }
public void addElements( long index, final KEY_GENERIC_TYPE a[][] ) { throw new UnsupportedOperationException(); }
public void size( final long size ) { list.size( size ); }
public long size64() { return list.size64(); }
public KEY_BIG_LIST_ITERATOR KEY_GENERIC iterator() { return listIterator(); }
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator() { return BIG_LIST_ITERATORS.unmodifiable( list.listIterator() ); }
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator( final long i ) { return BIG_LIST_ITERATORS.unmodifiable( list.listIterator( i ) ); }
public BIG_LIST KEY_GENERIC subList( final long from, final long to ) { return unmodifiable( list.subList( from, to ) ); }
public boolean equals( final Object o ) { return list.equals( o ); }
public int hashCode() { return list.hashCode(); }
#if ! #keyclass(Reference)
public int compareTo( final BigList extends KEY_GENERIC_CLASS> o ) { return list.compareTo( o ); }
#endif
#if #keys(primitive)
public boolean addAll( final long index, final COLLECTION c ) { throw new UnsupportedOperationException(); }
public boolean addAll( final BIG_LIST l ) { throw new UnsupportedOperationException(); }
public boolean addAll( final long index, final BIG_LIST l ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_CLASS get( final long i ) { return list.get( i ); }
public void add( final long i, KEY_GENERIC_CLASS k ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_CLASS set( final long index, KEY_GENERIC_CLASS k ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_CLASS remove( final long i ) { throw new UnsupportedOperationException(); }
public long indexOf( final Object o ) { return list.indexOf( o ); }
public long lastIndexOf( final Object o ) { return list.lastIndexOf( o ); }
#endif
}
/** Returns an unmodifiable type-specific big list backed by the given type-specific big list.
*
* @param l the big list to be wrapped in an unmodifiable big list.
* @return an unmodifiable view of the specified big list.
* @see java.util.Collections#unmodifiableList(List)
*/
public static KEY_GENERIC BIG_LIST KEY_GENERIC unmodifiable( final BIG_LIST KEY_GENERIC l ) { return new UnmodifiableBigList KEY_GENERIC( l ); }
/** A class exposing a list as a big list. */
public static class ListBigList KEY_GENERIC extends ABSTRACT_BIG_LIST KEY_GENERIC implements java.io.Serializable {
private static final long serialVersionUID = -7046029254386353129L;
private final LIST KEY_GENERIC list;
protected ListBigList( final LIST KEY_GENERIC list ) {
this.list = list;
}
private int intIndex( long index ) {
if ( index >= Integer.MAX_VALUE ) throw new IndexOutOfBoundsException( "This big list is restricted to 32-bit indices" );
return (int)index;
}
public long size64() { return list.size(); }
@Deprecated
public int size() { return list.size(); }
public void size( final long size ) { list.size( intIndex( size ) ); }
public KEY_BIG_LIST_ITERATOR KEY_GENERIC iterator() { return BIG_LIST_ITERATORS.asBigListIterator( list.iterator() ); }
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator() { return BIG_LIST_ITERATORS.asBigListIterator( list.listIterator() ); }
public boolean addAll( final long index, final Collection extends KEY_GENERIC_CLASS> c ) { return list.addAll( intIndex( index ), c ); }
public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator( final long index ) { return BIG_LIST_ITERATORS.asBigListIterator( list.listIterator( intIndex( index ) ) ); }
public BIG_LIST KEY_GENERIC subList( long from, long to ) { return new ListBigList KEY_GENERIC( list.subList( intIndex( from ), intIndex( to ) ) ); }
public boolean contains( final KEY_TYPE key ) { return list.contains( key ); }
public KEY_TYPE[] TO_KEY_ARRAY() { return list.TO_KEY_ARRAY(); }
public void removeElements( final long from, final long to ) { list.removeElements( intIndex( from ), intIndex( to ) ); }
#if #keys(primitive)
public KEY_TYPE[] TO_KEY_ARRAY( KEY_TYPE[] a ) { return list.TO_KEY_ARRAY( a ); }
#endif
public void add( long index, KEY_GENERIC_TYPE key ) { list.add( intIndex( index ), key ); }
public boolean addAll( long index, COLLECTION KEY_GENERIC c ) { return list.addAll( intIndex( index ), c ); }
public boolean addAll( long index, BIG_LIST KEY_GENERIC c ) { return list.addAll( intIndex( index ), c ); }
public boolean add( KEY_GENERIC_TYPE key ) { return list.add( key ); }
public boolean addAll( BIG_LIST KEY_GENERIC c ) { return list.addAll( c ); }
public KEY_GENERIC_TYPE GET_KEY( long index ) { return list.GET_KEY( intIndex( index ) ); }
public long indexOf( KEY_TYPE k ) { return list.indexOf( k ); }
public long lastIndexOf( KEY_TYPE k ) { return list.lastIndexOf( k ); }
public KEY_GENERIC_TYPE REMOVE_KEY( long index ) { return list.REMOVE_KEY( intIndex( index ) ); }
public KEY_GENERIC_TYPE set( long index, KEY_GENERIC_TYPE k ) { return list.set( intIndex( index ), k ); }
public boolean addAll( COLLECTION KEY_GENERIC c ) { return list.addAll( c ); }
public boolean containsAll( COLLECTION KEY_GENERIC c ) { return list.containsAll( c ); }
public boolean removeAll( COLLECTION KEY_GENERIC c ) { return list.removeAll( c ); }
public boolean retainAll( COLLECTION KEY_GENERIC c ) { return list.retainAll( c ); }
public boolean isEmpty() { return list.isEmpty(); }
public s
, and flushes all wrappers after
* calling writeObject()
, but does not close s
.
*
* @param o an object.
* @param s an output stream.
* @see #loadObject(InputStream)
*/
public static void storeObject( final Object o, final OutputStream s ) throws IOException {
@SuppressWarnings("resource")
final ObjectOutputStream oos = new ObjectOutputStream( new FastBufferedOutputStream( s ) );
oos.writeObject( o );
oos.flush();
}
/** Loads an object from a given input stream.
*
* readObject()
.
* This is a feature, as this method is targeted at one-shot reading from streams,
* e.g., reading exactly one object from {@link System#in}.
*
* @param s an input stream.
* @return the object read from the given input stream.
* @see #storeObject(Object, OutputStream)
*/
public static Object loadObject( final InputStream s ) throws IOException, ClassNotFoundException {
@SuppressWarnings("resource")
final ObjectInputStream ois = new ObjectInputStream( new FastBufferedInputStream( s ) );
final Object result = ois.readObject();
return result;
}
#include "src/it/unimi/dsi/fastutil/io/BooleanBinIOFragment.h"
#include "src/it/unimi/dsi/fastutil/io/ByteBinIOFragment.h"
#include "src/it/unimi/dsi/fastutil/io/ShortBinIOFragment.h"
#include "src/it/unimi/dsi/fastutil/io/CharBinIOFragment.h"
#include "src/it/unimi/dsi/fastutil/io/IntBinIOFragment.h"
#include "src/it/unimi/dsi/fastutil/io/LongBinIOFragment.h"
#include "src/it/unimi/dsi/fastutil/io/FloatBinIOFragment.h"
#include "src/it/unimi/dsi/fastutil/io/DoubleBinIOFragment.h"
}
fastutil-7.0.2/drv/BinIOFragment.drv 0000644 0000000 0000000 00000103400 12502261336 016124 0 ustar root wheel /*
* Copyright (C) 2004-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if #keyclass(Byte)
// HORRIBLE kluges to work around bug #6478546
private final static int MAX_IO_LENGTH = 1024 * 1024;
private static int read( final InputStream is, final byte a[], final int offset, final int length ) throws IOException {
if ( length == 0 ) return 0;
int read = 0, result;
do {
result = is.read( a, offset + read, Math.min( length - read, MAX_IO_LENGTH ) );
if ( result < 0 ) return read;
read += result;
} while( read < length );
return read;
}
private static void write( final OutputStream outputStream, final byte a[], final int offset, final int length ) throws IOException {
int written = 0;
while( written < length ) {
outputStream.write( a, offset + written, Math.min( length - written, MAX_IO_LENGTH ) );
written += Math.min( length - written, MAX_IO_LENGTH );
}
}
private static void write( final DataOutput dataOutput, final byte a[], final int offset, final int length ) throws IOException {
int written = 0;
while( written < length ) {
dataOutput.write( a, offset + written, Math.min( length - written, MAX_IO_LENGTH ) );
written += Math.min( length - written, MAX_IO_LENGTH );
}
}
// Additional read/write methods to work around the DataInput/DataOutput schizophrenia.
/** Loads bytes from a given input stream, storing them in a given array fragment.
*
* inputStream
.
* @param offset the index of the first element of array
to be filled.
* @param length the number of elements of array
to be filled.
* @return the number of elements actually read from inputStream
(it might be less than length
if inputStream
ends).
*/
public static int LOAD_KEYS( final InputStream inputStream, final KEY_TYPE[] array, final int offset, final int length ) throws IOException {
return read( inputStream, array, offset, length );
}
/** Loads bytes from a given input stream, storing them in a given array.
*
* inputStream
.
* @return the number of elements actually read from inputStream
(it might be less than the array length if inputStream
ends).
*/
public static int LOAD_KEYS( final InputStream inputStream, final KEY_TYPE[] array ) throws IOException {
return read( inputStream, array, 0, array.length );
}
/** Stores an array fragment to a given output stream.
*
* outputStream
.
* @param offset the index of the first element of array
to be written.
* @param length the number of elements of array
to be written.
* @param outputStream an output stream.
*/
public static void STORE_KEYS( final KEY_TYPE array[], final int offset, final int length, final OutputStream outputStream ) throws IOException {
write( outputStream, array, offset, length );
}
/** Stores an array to a given output stream.
*
* outputStream
.
* @param outputStream an output stream.
*/
public static void STORE_KEYS( final KEY_TYPE array[], final OutputStream outputStream ) throws IOException {
write( outputStream, array, 0, array.length );
}
private static long read( final InputStream is, final byte a[][], final long offset, final long length ) throws IOException {
if ( length == 0 ) return 0;
long read = 0;
int segment = segment( offset );
int displacement = displacement( offset );
int result;
do {
result = is.read( a[ segment ], displacement, (int)Math.min( a[ segment ].length - displacement, Math.min( length - read, MAX_IO_LENGTH ) ) );
if ( result < 0 ) return read;
read += result;
displacement += result;
if ( displacement == a[ segment ].length ) {
segment++;
displacement = 0;
}
} while( read < length );
return read;
}
private static void write( final OutputStream outputStream, final byte a[][], final long offset, final long length ) throws IOException {
if ( length == 0 ) return;
long written = 0;
int toWrite;
int segment = segment( offset );
int displacement = displacement( offset );
do {
toWrite = (int)Math.min( a[ segment ].length - displacement, Math.min( length - written, MAX_IO_LENGTH ) );
outputStream.write( a[ segment ], displacement, toWrite );
written += toWrite;
displacement += toWrite;
if ( displacement == a[ segment ].length ) {
segment++;
displacement = 0;
}
} while( written < length );
}
private static void write( final DataOutput dataOutput, final byte a[][], final long offset, final long length ) throws IOException {
if ( length == 0 ) return;
long written = 0;
int toWrite;
int segment = segment( offset );
int displacement = displacement( offset );
do {
toWrite = (int)Math.min( a[ segment ].length - displacement, Math.min( length - written, MAX_IO_LENGTH ) );
dataOutput.write( a[ segment ], displacement, toWrite );
written += toWrite;
displacement += toWrite;
if ( displacement == a[ segment ].length ) {
segment++;
displacement = 0;
}
} while( written < length );
}
// Additional read/write methods to work around the DataInput/DataOutput schizophrenia.
/** Loads bytes from a given input stream, storing them in a given big-array fragment.
*
* inputStream
.
* @param offset the index of the first element of array
to be filled.
* @param length the number of elements of array
to be filled.
* @return the number of elements actually read from inputStream
(it might be less than length
if inputStream
ends).
*/
public static long LOAD_KEYS( final InputStream inputStream, final KEY_TYPE[][] array, final long offset, final long length ) throws IOException {
return read( inputStream, array, offset, length );
}
/** Loads bytes from a given input stream, storing them in a given big array.
*
* inputStream
.
* @return the number of elements actually read from inputStream
(it might be less than the array length if inputStream
ends).
*/
public static long LOAD_KEYS( final InputStream inputStream, final KEY_TYPE[][] array ) throws IOException {
return read( inputStream, array, 0, BIG_ARRAYS.length( array ) );
}
/** Stores a big-array fragment to a given output stream.
*
* outputStream
.
* @param offset the index of the first element of array
to be written.
* @param length the number of elements of array
to be written.
* @param outputStream an output stream.
*/
public static void STORE_KEYS( final KEY_TYPE array[][], final long offset, final long length, final OutputStream outputStream ) throws IOException {
write( outputStream, array, offset, length );
}
/** Stores a big array to a given output stream.
*
* outputStream
.
* @param outputStream an output stream.
*/
public static void STORE_KEYS( final KEY_TYPE array[][], final OutputStream outputStream ) throws IOException {
write( outputStream, array, 0, BIG_ARRAYS.length( array ) );
}
#endif
/** Loads elements from a given data input, storing them in a given array fragment.
*
* @param dataInput a data input.
* @param array an array which will be filled with data from dataInput
.
* @param offset the index of the first element of array
to be filled.
* @param length the number of elements of array
to be filled.
* @return the number of elements actually read from dataInput
(it might be less than length
if dataInput
ends).
*/
public static int LOAD_KEYS( final DataInput dataInput, final KEY_TYPE[] array, final int offset, final int length ) throws IOException {
PACKAGE.ARRAYS.ensureOffsetLength( array, offset, length );
int i = 0;
try {
for( i = 0; i < length; i++ ) array[ i + offset ] = dataInput.READ_KEY();
}
catch( EOFException itsOk ) {}
return i;
}
/** Loads elements from a given data input, storing them in a given array.
*
* @param dataInput a data input.
* @param array an array which will be filled with data from dataInput
.
* @return the number of elements actually read from dataInput
(it might be less than the array length if dataInput
ends).
*/
public static int LOAD_KEYS( final DataInput dataInput, final KEY_TYPE[] array ) throws IOException {
int i = 0;
try {
final int length = array.length;
for( i = 0; i < length; i++ ) array[ i ] = dataInput.READ_KEY();
}
catch( EOFException itsOk ) {}
return i;
}
/** Loads elements from a file given by a {@link File} object, storing them in a given array fragment.
*
* @param file a file.
* @param array an array which will be filled with data from the specified file.
* @param offset the index of the first element of array
to be filled.
* @param length the number of elements of array
to be filled.
* @return the number of elements actually read from the given file (it might be less than length
if the file is too short).
*/
public static int LOAD_KEYS( final File file, final KEY_TYPE[] array, final int offset, final int length ) throws IOException {
PACKAGE.ARRAYS.ensureOffsetLength( array, offset, length );
final FileInputStream fis = new FileInputStream( file );
#if #keyclass(Byte)
final int result = read( fis, array, offset, length );
fis.close();
return result;
#else
final DataInputStream dis = new DataInputStream( new FastBufferedInputStream( fis ) );
int i = 0;
try {
for( i = 0; i < length; i++ ) array[ i + offset ] = dis.READ_KEY();
}
catch( EOFException itsOk ) {}
dis.close();
return i;
#endif
}
/** Loads elements from a file given by a pathname, storing them in a given array fragment.
*
* @param filename a filename.
* @param array an array which will be filled with data from the specified file.
* @param offset the index of the first element of array
to be filled.
* @param length the number of elements of array
to be filled.
* @return the number of elements actually read from the given file (it might be less than length
if the file is too short).
*/
public static int LOAD_KEYS( final CharSequence filename, final KEY_TYPE[] array, final int offset, final int length ) throws IOException {
return LOAD_KEYS( new File( filename.toString() ), array, offset, length );
}
/** Loads elements from a file given by a {@link File} object, storing them in a given array.
*
* @param file a file.
* @param array an array which will be filled with data from the specified file.
* @return the number of elements actually read from the given file (it might be less than the array length if the file is too short).
*/
public static int LOAD_KEYS( final File file, final KEY_TYPE[] array ) throws IOException {
final FileInputStream fis = new FileInputStream( file );
#if #keyclass(Byte)
final int result = read( fis, array, 0, array.length );
fis.close();
return result;
#else
final DataInputStream dis = new DataInputStream( new FastBufferedInputStream( fis ) );
int i = 0;
try {
final int length = array.length;
for( i = 0; i < length; i++ ) array[ i ] = dis.READ_KEY();
}
catch( EOFException itsOk ) {}
dis.close();
return i;
#endif
}
/** Loads elements from a file given by a pathname, storing them in a given array.
*
* @param filename a filename.
* @param array an array which will be filled with data from the specified file.
* @return the number of elements actually read from the given file (it might be less than the array length if the file is too short).
*/
public static int LOAD_KEYS( final CharSequence filename, final KEY_TYPE[] array ) throws IOException {
return LOAD_KEYS( new File( filename.toString() ), array );
}
/** Loads elements from a file given by a {@link File} object, storing them in a new array.
*
* dataOutput
.
* @param offset the index of the first element of array
to be written.
* @param length the number of elements of array
to be written.
* @param dataOutput a data output.
*/
public static void STORE_KEYS( final KEY_TYPE array[], final int offset, final int length, final DataOutput dataOutput ) throws IOException {
PACKAGE.ARRAYS.ensureOffsetLength( array, offset, length );
#if #keyclass(Byte)
write( dataOutput, array, offset, length );
#else
for( int i = 0; i < length; i++ ) dataOutput.WRITE_KEY( array[ offset + i ] );
#endif
}
/** Stores an array to a given data output.
*
* @param array an array whose elements will be written to dataOutput
.
* @param dataOutput a data output.
*/
public static void STORE_KEYS( final KEY_TYPE array[], final DataOutput dataOutput ) throws IOException {
#if #keyclass(Byte)
write( dataOutput, array, 0, array.length );
#else
final int length = array.length;
for( int i = 0; i < length; i++ ) dataOutput.WRITE_KEY( array[ i ] );
#endif
}
/** Stores an array fragment to a file given by a {@link File} object.
*
* @param array an array whose elements will be written to filename
.
* @param offset the index of the first element of array
to be written.
* @param length the number of elements of array
to be written.
* @param file a file.
*/
public static void STORE_KEYS( final KEY_TYPE array[], final int offset, final int length, final File file ) throws IOException {
PACKAGE.ARRAYS.ensureOffsetLength( array, offset, length );
#if #keyclass(Byte)
final OutputStream os = new FastBufferedOutputStream( new FileOutputStream( file ) );
write( os, array, offset, length );
os.close();
#else
final DataOutputStream dos = new DataOutputStream( new FastBufferedOutputStream( new FileOutputStream( file ) ) );
for( int i = 0; i < length; i++ ) dos.WRITE_KEY( array[ offset + i ] );
dos.close();
#endif
}
/** Stores an array fragment to a file given by a pathname.
*
* @param array an array whose elements will be written to filename
.
* @param offset the index of the first element of array
to be written.
* @param length the number of elements of array
to be written.
* @param filename a filename.
*/
public static void STORE_KEYS( final KEY_TYPE array[], final int offset, final int length, final CharSequence filename ) throws IOException {
STORE_KEYS( array, offset, length, new File( filename.toString() ) );
}
/** Stores an array to a file given by a {@link File} object.
*
* @param array an array whose elements will be written to filename
.
* @param file a file.
*/
public static void STORE_KEYS( final KEY_TYPE array[], final File file ) throws IOException {
#if #keyclass(Byte)
final OutputStream os = new FastBufferedOutputStream( new FileOutputStream( file ) );
write( os, array, 0, array.length );
os.close();
#else
final int length = array.length;
final DataOutputStream dos = new DataOutputStream( new FastBufferedOutputStream( new FileOutputStream( file ) ) );
for( int i = 0; i < length; i++ ) dos.WRITE_KEY( array[ i ] );
dos.close();
#endif
}
/** Stores an array to a file given by a pathname.
*
* @param array an array whose elements will be written to filename
.
* @param filename a filename.
*/
public static void STORE_KEYS( final KEY_TYPE array[], final CharSequence filename ) throws IOException {
STORE_KEYS( array, new File( filename.toString() ) );
}
/** Loads elements from a given data input, storing them in a given big-array fragment.
*
* @param dataInput a data input.
* @param array a big array which will be filled with data from dataInput
.
* @param offset the index of the first element of bigArray
to be filled.
* @param length the number of elements of bigArray
to be filled.
* @return the number of elements actually read from dataInput
(it might be less than length
if dataInput
ends).
*/
public static long LOAD_KEYS( final DataInput dataInput, final KEY_TYPE[][] array, final long offset, final long length ) throws IOException {
PACKAGE.BIG_ARRAYS.ensureOffsetLength( array, offset, length );
long c = 0;
try {
for( int i = segment( offset ); i < segment( offset + length + SEGMENT_MASK ); i++ ) {
final KEY_TYPE[] t = array[ i ];
final int l = (int)Math.min( t.length, offset + length - start( i ) );
for( int d = (int)Math.max( 0, offset - start( i ) ); d < l; d++ ) {
t[ d ] = dataInput.READ_KEY();
c++;
}
}
}
catch( EOFException itsOk ) {}
return c;
}
/** Loads elements from a given data input, storing them in a given big array.
*
* @param dataInput a data input.
* @param array a big array which will be filled with data from dataInput
.
* @return the number of elements actually read from dataInput
(it might be less than the array length if dataInput
ends).
*/
public static long LOAD_KEYS( final DataInput dataInput, final KEY_TYPE[][] array ) throws IOException {
long c = 0;
try {
for( int i = 0; i < array.length; i++ ) {
final KEY_TYPE[] t = array[ i ];
final int l = t.length;
for( int d = 0; d < l; d++ ) {
t[ d ] = dataInput.READ_KEY();
c++;
}
}
}
catch( EOFException itsOk ) {}
return c;
}
/** Loads elements from a file given by a {@link File} object, storing them in a given big-array fragment.
*
* @param file a file.
* @param array a big array which will be filled with data from the specified file.
* @param offset the index of the first element of array
to be filled.
* @param length the number of elements of array
to be filled.
* @return the number of elements actually read from the given file (it might be less than length
if the file is too short).
*/
public static long LOAD_KEYS( final File file, final KEY_TYPE[][] array, final long offset, final long length ) throws IOException {
PACKAGE.BIG_ARRAYS.ensureOffsetLength( array, offset, length );
final FileInputStream fis = new FileInputStream( file );
#if #keyclass(Byte)
final long result = read( fis, array, offset, length );
fis.close();
return result;
#else
final DataInputStream dis = new DataInputStream( new FastBufferedInputStream( fis ) );
long c = 0;
try {
for( int i = segment( offset ); i < segment( offset + length + SEGMENT_MASK ); i++ ) {
final KEY_TYPE[] t = array[ i ];
final int l = (int)Math.min( t.length, offset + length - start( i ) );
for( int d = (int)Math.max( 0, offset - start( i ) ); d < l; d++ ) {
t[ d ] = dis.READ_KEY();
c++;
}
}
}
catch( EOFException itsOk ) {}
dis.close();
return c;
#endif
}
/** Loads elements from a file given by a pathname, storing them in a given big-array fragment.
*
* @param filename a filename.
* @param array an array which will be filled with data from the specified file.
* @param offset the index of the first element of array
to be filled.
* @param length the number of elements of array
to be filled.
* @return the number of elements actually read from the given file (it might be less than length
if the file is too short).
*/
public static long LOAD_KEYS( final CharSequence filename, final KEY_TYPE[][] array, final long offset, final long length ) throws IOException {
return LOAD_KEYS( new File( filename.toString() ), array, offset, length );
}
/** Loads elements from a file given by a {@link File} object, storing them in a given big array.
*
* @param file a file.
* @param array a big array which will be filled with data from the specified file.
* @return the number of elements actually read from the given file (it might be less than the array length if the file is too short).
*/
public static long LOAD_KEYS( final File file, final KEY_TYPE[][] array ) throws IOException {
final FileInputStream fis = new FileInputStream( file );
#if #keyclass(Byte)
final long result = read( fis, array, 0, BIG_ARRAYS.length( array ) );
fis.close();
return result;
#else
final DataInputStream dis = new DataInputStream( new FastBufferedInputStream( fis ) );
long c = 0;
try {
for( int i = 0; i < array.length; i++ ) {
final KEY_TYPE[] t = array[ i ];
final int l = t.length;
for( int d = 0; d < l; d++ ) {
t[ d ] = dis.READ_KEY();
c++;
}
}
}
catch( EOFException itsOk ) {}
dis.close();
return c;
#endif
}
/** Loads elements from a file given by a pathname, storing them in a given big array.
*
* @param filename a filename.
* @param array a big array which will be filled with data from the specified file.
* @return the number of elements actually read from the given file (it might be less than the array length if the file is too short).
*/
public static long LOAD_KEYS( final CharSequence filename, final KEY_TYPE[][] array ) throws IOException {
return LOAD_KEYS( new File( filename.toString() ), array );
}
/** Loads elements from a file given by a {@link File} object, storing them in a new big array.
*
* dataOutput
.
* @param offset the index of the first element of array
to be written.
* @param length the number of elements of array
to be written.
* @param dataOutput a data output.
*/
public static void STORE_KEYS( final KEY_TYPE array[][], final long offset, final long length, final DataOutput dataOutput ) throws IOException {
PACKAGE.BIG_ARRAYS.ensureOffsetLength( array, offset, length );
#if #keyclass(Byte)
write( dataOutput, array, offset, length );
#else
for( int i = segment( offset ); i < segment( offset + length + SEGMENT_MASK ); i++ ) {
final KEY_TYPE[] t = array[ i ];
final int l = (int)Math.min( t.length, offset + length - start( i ) );
for( int d = (int)Math.max( 0, offset - start( i ) ); d < l; d++ ) dataOutput.WRITE_KEY( t[ d ] );
}
#endif
}
/** Stores a big array to a given data output.
*
* @param array a big array whose elements will be written to dataOutput
.
* @param dataOutput a data output.
*/
public static void STORE_KEYS( final KEY_TYPE array[][], final DataOutput dataOutput ) throws IOException {
#if #keyclass(Byte)
write( dataOutput, array, 0, BIG_ARRAYS.length( array ) );
#else
for( int i = 0; i < array.length; i++ ) {
final KEY_TYPE[] t = array[ i ];
final int l = t.length;
for( int d = 0; d < l; d++ ) dataOutput.WRITE_KEY( t[ d ] );
}
#endif
}
/** Stores a big-array fragment to a file given by a {@link File} object.
*
* @param array a big array whose elements will be written to filename
.
* @param offset the index of the first element of array
to be written.
* @param length the number of elements of array
to be written.
* @param file a file.
*/
public static void STORE_KEYS( final KEY_TYPE array[][], final long offset, final long length, final File file ) throws IOException {
PACKAGE.BIG_ARRAYS.ensureOffsetLength( array, offset, length );
#if #keyclass(Byte)
final OutputStream os = new FastBufferedOutputStream( new FileOutputStream( file ) );
write( os, array, offset, length );
os.close();
#else
final DataOutputStream dos = new DataOutputStream( new FastBufferedOutputStream( new FileOutputStream( file ) ) );
for( int i = segment( offset ); i < segment( offset + length + SEGMENT_MASK ); i++ ) {
final KEY_TYPE[] t = array[ i ];
final int l = (int)Math.min( t.length, offset + length - start( i ) );
for( int d = (int)Math.max( 0, offset - start( i ) ); d < l; d++ ) dos.WRITE_KEY( t[ d ] );
}
dos.close();
#endif
}
/** Stores a big-array fragment to a file given by a pathname.
*
* @param array a big array whose elements will be written to filename
.
* @param offset the index of the first element of array
to be written.
* @param length the number of elements of array
to be written.
* @param filename a filename.
*/
public static void STORE_KEYS( final KEY_TYPE array[][], final long offset, final long length, final CharSequence filename ) throws IOException {
STORE_KEYS( array, offset, length, new File( filename.toString() ) );
}
/** Stores an array to a file given by a {@link File} object.
*
* @param array an array whose elements will be written to filename
.
* @param file a file.
*/
public static void STORE_KEYS( final KEY_TYPE array[][], final File file ) throws IOException {
#if #keyclass(Byte)
final OutputStream os = new FastBufferedOutputStream( new FileOutputStream( file ) );
write( os, array, 0, BIG_ARRAYS.length( array ) );
os.close();
#else
final DataOutputStream dos = new DataOutputStream( new FastBufferedOutputStream( new FileOutputStream( file ) ) );
for( int i = 0; i < array.length; i++ ) {
final KEY_TYPE[] t = array[ i ];
final int l = t.length;
for( int d = 0; d < l; d++ ) dos.WRITE_KEY( t[ d ] );
}
dos.close();
#endif
}
/** Stores a big array to a file given by a pathname.
*
* @param array a big array whose elements will be written to filename
.
* @param filename a filename.
*/
public static void STORE_KEYS( final KEY_TYPE array[][], final CharSequence filename ) throws IOException {
STORE_KEYS( array, new File( filename.toString() ) );
}
/** Stores the element returned by an iterator to a given data output.
*
* @param i an iterator whose output will be written to dataOutput
.
* @param dataOutput a filename.
*/
public static void STORE_KEYS( final KEY_ITERATOR i, final DataOutput dataOutput ) throws IOException {
while( i.hasNext() ) dataOutput.WRITE_KEY( i.NEXT_KEY() );
}
/** Stores the element returned by an iterator to a file given by a {@link File} object.
*
* @param i an iterator whose output will be written to filename
.
* @param file a file.
*/
public static void STORE_KEYS( final KEY_ITERATOR i, final File file ) throws IOException {
final DataOutputStream dos = new DataOutputStream( new FastBufferedOutputStream( new FileOutputStream( file ) ) );
while( i.hasNext() ) dos.WRITE_KEY( i.NEXT_KEY() );
dos.close();
}
/** Stores the element returned by an iterator to a file given by a pathname.
*
* @param i an iterator whose output will be written to filename
.
* @param filename a filename.
*/
public static void STORE_KEYS( final KEY_ITERATOR i, final CharSequence filename ) throws IOException {
STORE_KEYS( i, new File( filename.toString() ) );
}
/** A wrapper that exhibits the content of a data input stream as a type-specific iterator. */
final private static class KEY_DATA_INPUT_WRAPPER extends KEY_ABSTRACT_ITERATOR {
final private DataInput dataInput;
private boolean toAdvance = true;
private boolean endOfProcess = false;
private KEY_TYPE next;
public KEY_DATA_INPUT_WRAPPER( final DataInput dataInput ) {
this.dataInput = dataInput;
}
public boolean hasNext() {
if ( ! toAdvance ) return ! endOfProcess;
toAdvance = false;
try {
next = dataInput.READ_KEY();
}
catch( EOFException eof ) {
endOfProcess = true;
}
catch( IOException rethrow ) { throw new RuntimeException( rethrow ); }
return ! endOfProcess;
}
public KEY_TYPE NEXT_KEY() {
if (! hasNext()) throw new NoSuchElementException();
toAdvance = true;
return next;
}
}
/** Wraps the given data input stream into an iterator.
*
* @param dataInput a data input.
*/
public static KEY_ITERATOR AS_KEY_ITERATOR( final DataInput dataInput ) {
return new KEY_DATA_INPUT_WRAPPER( dataInput );
}
/** Wraps a file given by a {@link File} object into an iterator.
*
* @param file a file.
*/
public static KEY_ITERATOR AS_KEY_ITERATOR( final File file ) throws IOException {
return new KEY_DATA_INPUT_WRAPPER( new DataInputStream( new FastBufferedInputStream( new FileInputStream( file ) ) ) );
}
/** Wraps a file given by a pathname into an iterator.
*
* @param filename a filename.
*/
public static KEY_ITERATOR AS_KEY_ITERATOR( final CharSequence filename ) throws IOException {
return AS_KEY_ITERATOR( new File( filename.toString() ) );
}
/** Wraps a file given by a {@link File} object into an iterable object.
*
* @param file a file.
*/
public static KEY_ITERABLE AS_KEY_ITERABLE( final File file ) {
return new KEY_ITERABLE() {
public KEY_ITERATOR iterator() {
try {
return AS_KEY_ITERATOR( file );
}
catch( IOException e ) {
throw new RuntimeException( e );
}
}
};
}
/** Wraps a file given by a pathname into an iterable object.
*
* @param filename a filename.
*/
public static KEY_ITERABLE AS_KEY_ITERABLE( final CharSequence filename ) {
return new KEY_ITERABLE() {
public KEY_ITERATOR iterator() {
try {
return AS_KEY_ITERATOR( filename );
}
catch( IOException e ) {
throw new RuntimeException( e );
}
}
};
}
fastutil-7.0.2/drv/Collection.drv 0000644 0000000 0000000 00000010723 12502261336 015600 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import java.util.Collection;
/** A type-specific {@link Collection}; provides some additional methods
* that use polymorphism to avoid (un)boxing.
*
* fastutil
5, replaced by {@link #iterator()}.
*/
@Deprecated
KEY_ITERATOR KEY_GENERIC KEY_ITERATOR_METHOD();
/** Returns an containing the items of this collection;
* the runtime type of the returned array is that of the specified array.
*
* remove()
.
*
* @see Collection#remove(Object)
*/
boolean rem( KEY_TYPE key );
/**
* @see Collection#addAll(Collection)
*/
boolean addAll( COLLECTION c );
/**
* @see Collection#containsAll(Collection)
*/
boolean containsAll( COLLECTION c );
/**
* @see Collection#removeAll(Collection)
*/
boolean removeAll( COLLECTION c );
/**
* @see Collection#retainAll(Collection)
*/
boolean retainAll( COLLECTION c );
#endif
}
fastutil-7.0.2/drv/Collections.drv 0000644 0000000 0000000 00000026201 12502266557 015773 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import java.util.Collection;
import it.unimi.dsi.fastutil.objects.ObjectArrays;
/** A class providing static methods and objects that do useful things with type-specific collections.
*
* @see java.util.Collections
*/
public class COLLECTIONS {
private COLLECTIONS() {}
/** An immutable class representing an empty type-specific collection.
*
* fastutil
provides a corresponding abstract class that
* can be used to implement this interface just by specifying the type-specific
* comparator.
*
* @see Comparator
*/
public interface KEY_COMPARATOR KEY_GENERIC extends Comparatorc
.
*/
public static KEY_GENERIC KEY_COMPARATOR KEY_GENERIC oppositeComparator( final KEY_COMPARATOR KEY_GENERIC c ) {
return new KEY_ABSTRACT_COMPARATOR KEY_GENERIC() {
private final KEY_COMPARATOR KEY_GENERIC comparator = c;
public final int compare( final KEY_GENERIC_TYPE a, final KEY_GENERIC_TYPE b ) {
return - comparator.compare( a, b );
}
};
}
}
fastutil-7.0.2/drv/Function.drv 0000644 0000000 0000000 00000007230 12502261336 015271 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import it.unimi.dsi.fastutil.Function;
/** A type-specific {@link Function}; provides some additional methods that use polymorphism to avoid (un)boxing.
*
* get()
, put()
and
* remove()
cannot rely on null
to denote absence of
* a key. Rather, they return a {@linkplain #defaultReturnValue() default
* return value}, which is set to 0 cast to the return type (false
* for booleans) at creation, but can be changed using the
* defaultReturnValue()
method.
*
* null
).
*
* get()
, put()
and
* remove()
for maps with primitive-type values return
* null
to denote missing keys rather than wrap the default
* return value in an object (of course, for maps with object keys and values
* this is not possible, as there is no type-specific version).
*
* @see Function
*/
public interface FUNCTION KEY_VALUE_GENERIC extends Functionget()
, put()
and remove()
to
* denote that the map does not contain the specified key. It must be
* 0/false
/null
by default.
*
* @param rv the new default return value.
* @see #defaultReturnValue()
*/
void defaultReturnValue( VALUE_GENERIC_TYPE rv );
/** Gets the default return value.
*
* @return the current default return value.
*/
VALUE_GENERIC_TYPE defaultReturnValue();
}
fastutil-7.0.2/drv/Functions.drv 0000644 0000000 0000000 00000023720 12502264124 015454 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
/** A class providing static methods and objects that do useful things with type-specific functions.
*
* @see it.unimi.dsi.fastutil.Function
* @see java.util.Collections
*/
public class FUNCTIONS {
private FUNCTIONS() {}
/** An immutable class representing an empty type-specific function.
*
* <key,value>
.
*/
public static KEY_VALUE_GENERIC FUNCTION KEY_VALUE_GENERIC singleton( final KEY_GENERIC_TYPE key, VALUE_GENERIC_TYPE value ) {
return new Singleton KEY_VALUE_GENERIC( key, value );
}
#if #keys(primitive) || #values(primitive)
/** Returns a type-specific immutable function containing only the specified pair. The returned function is serializable and cloneable.
*
* <key,value>
.
*/
public static KEY_VALUE_GENERIC FUNCTION KEY_VALUE_GENERIC singleton( final KEY_GENERIC_CLASS key, final VALUE_GENERIC_CLASS value ) {
return new Singleton KEY_VALUE_GENERIC( KEY_CLASS2TYPE( key ), VALUE_CLASS2TYPE( value ) );
}
#endif
/** A synchronized wrapper class for functions. */
public static class SynchronizedFunction KEY_VALUE_GENERIC extends ABSTRACT_FUNCTION KEY_VALUE_GENERIC implements java.io.Serializable {
private static final long serialVersionUID = -7046029254386353129L;
protected final FUNCTION KEY_VALUE_GENERIC function;
protected final Object sync;
protected SynchronizedFunction( final FUNCTION KEY_VALUE_GENERIC f, final Object sync ) {
if ( f == null ) throw new NullPointerException();
this.function = f;
this.sync = sync;
}
protected SynchronizedFunction( final FUNCTION KEY_VALUE_GENERIC f ) {
if ( f == null ) throw new NullPointerException();
this.function = f;
this.sync = this;
}
public int size() { synchronized( sync ) { return function.size(); } }
public boolean containsKey( final KEY_TYPE k ) { synchronized( sync ) { return function.containsKey( k ); } }
public VALUE_GENERIC_TYPE defaultReturnValue() { synchronized( sync ) { return function.defaultReturnValue(); } }
public void defaultReturnValue( final VALUE_GENERIC_TYPE defRetValue ) { synchronized( sync ) { function.defaultReturnValue( defRetValue ); } }
public VALUE_GENERIC_TYPE put( final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE v ) { synchronized( sync ) { return function.put( k, v ); } }
public void clear() { synchronized( sync ) { function.clear(); } }
public String toString() { synchronized( sync ) { return function.toString(); } }
#if #keys(primitive) || #values(primitive)
public VALUE_GENERIC_CLASS put( final KEY_GENERIC_CLASS k, final VALUE_GENERIC_CLASS v ) { synchronized( sync ) { return function.put( k, v ); } }
public VALUE_GENERIC_CLASS get( final Object k ) { synchronized( sync ) { return function.get( k ); } }
public VALUE_GENERIC_CLASS remove( final Object k ) { synchronized( sync ) { return function.remove( k ); } }
#endif
#if #keys(primitive)
public VALUE_GENERIC_TYPE remove( final KEY_GENERIC_TYPE k ) { synchronized( sync ) { return function.remove( k ); } }
public VALUE_GENERIC_TYPE get( final KEY_GENERIC_TYPE k ) { synchronized( sync ) { return function.get( k ); } }
public boolean containsKey( final Object ok ) { synchronized( sync ) { return function.containsKey( ok ); } }
#endif
#if #keys(reference)
public VALUE_GENERIC_TYPE REMOVE_VALUE( final Object k ) { synchronized( sync ) { return function.REMOVE_VALUE( k ); } }
public VALUE_GENERIC_TYPE GET_VALUE( final Object k ) { synchronized( sync ) { return function.GET_VALUE( k ); } }
#endif
}
/** Returns a synchronized type-specific function backed by the given type-specific function.
*
* @param f the function to be wrapped in a synchronized function.
* @return a synchronized view of the specified function.
* @see java.util.Collections#synchronizedMap(java.util.Map)
*/
public static KEY_VALUE_GENERIC FUNCTION KEY_VALUE_GENERIC synchronize( final FUNCTION KEY_VALUE_GENERIC f ) { return new SynchronizedFunction KEY_VALUE_GENERIC( f ); }
/** Returns a synchronized type-specific function backed by the given type-specific function, using an assigned object to synchronize.
*
* @param f the function to be wrapped in a synchronized function.
* @param sync an object that will be used to synchronize the access to the function.
* @return a synchronized view of the specified function.
* @see java.util.Collections#synchronizedMap(java.util.Map)
*/
public static KEY_VALUE_GENERIC FUNCTION KEY_VALUE_GENERIC synchronize( final FUNCTION KEY_VALUE_GENERIC f, final Object sync ) { return new SynchronizedFunction KEY_VALUE_GENERIC( f, sync ); }
/** An unmodifiable wrapper class for functions. */
public static class UnmodifiableFunction KEY_VALUE_GENERIC extends ABSTRACT_FUNCTION KEY_VALUE_GENERIC implements java.io.Serializable {
private static final long serialVersionUID = -7046029254386353129L;
protected final FUNCTION KEY_VALUE_GENERIC function;
protected UnmodifiableFunction( final FUNCTION KEY_VALUE_GENERIC f ) {
if ( f == null ) throw new NullPointerException();
this.function = f;
}
public int size() { return function.size(); }
public boolean containsKey( final KEY_TYPE k ) { return function.containsKey( k ); }
public VALUE_GENERIC_TYPE defaultReturnValue() { return function.defaultReturnValue(); }
public void defaultReturnValue( final VALUE_GENERIC_TYPE defRetValue ) { throw new UnsupportedOperationException(); }
public VALUE_GENERIC_TYPE put( final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE v ) { throw new UnsupportedOperationException(); }
public void clear() { throw new UnsupportedOperationException(); }
public String toString() { return function.toString(); }
#if #keys(primitive)
public VALUE_GENERIC_TYPE remove( final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public VALUE_GENERIC_TYPE get( final KEY_GENERIC_TYPE k ) { return function.get( k ); }
public boolean containsKey( final Object ok ) { return function.containsKey( ok ); }
#endif
#if #keys(reference) || #values(reference)
public VALUE_GENERIC_TYPE REMOVE_VALUE( final Object k ) { throw new UnsupportedOperationException(); }
public VALUE_GENERIC_TYPE GET_VALUE( final Object k ) { return function.GET_VALUE( k ); }
#endif
}
/** Returns an unmodifiable type-specific function backed by the given type-specific function.
*
* @param f the function to be wrapped in an unmodifiable function.
* @return an unmodifiable view of the specified function.
* @see java.util.Collections#unmodifiableMap(java.util.Map)
*/
public static KEY_VALUE_GENERIC FUNCTION KEY_VALUE_GENERIC unmodifiable( final FUNCTION KEY_VALUE_GENERIC f ) { return new UnmodifiableFunction KEY_VALUE_GENERIC( f ); }
}
fastutil-7.0.2/drv/Hash.drv 0000644 0000000 0000000 00000002633 12502261336 014371 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import it.unimi.dsi.fastutil.Hash;
/** A type-specific {@link Hash} interface.
*
* @see Hash
*/
public interface HASH {
/** A type-specific hash strategy.
*
* @see it.unimi.dsi.fastutil.Hash.Strategy
*/
public interface Strategy {
/** Returns the hash code of the specified element with respect to this hash strategy.
*
* @param e an element.
* @return the hash code of the given element with respect to this hash strategy.
*/
public int hashCode( KEY_TYPE e );
/** Returns true if the given elements are equal with respect to this hash strategy.
*
* @param a an element.
* @param b another element.
* @return true if the two specified elements are equal with respect to this hash strategy.
*/
public boolean equals( KEY_TYPE a, KEY_TYPE b );
}
}
fastutil-7.0.2/drv/HeapIndirectDoublePriorityQueue.drv 0000644 0000000 0000000 00000060731 12502261336 021752 0 ustar root wheel /*
* Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
#if #keyclass(Object)
import java.util.Comparator;
import it.unimi.dsi.fastutil.IndirectDoublePriorityQueue;
#endif
/** A type-specific heap-based indirect double priority queue.
*
* null
, indicating that natural comparison should take place. Of course,
* it makes little sense having them equal.
*/
public class HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE KEY_GENERIC extends HEAP_INDIRECT_PRIORITY_QUEUE KEY_GENERIC implements INDIRECT_DOUBLE_PRIORITY_QUEUE KEY_GENERIC {
/** The secondary indirect queue. */
protected HEAP_INDIRECT_PRIORITY_QUEUE KEY_GENERIC secondaryQueue;
/** Creates a new empty queue with a given capacity.
*
* @param refArray the reference array.
* @param capacity the initial capacity of this queue.
* @param c the primary comparator used in this queue, or null
for the natural order.
* @param d the secondary comparator used in this queue, or null
for the natural order.
*/
public HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity, KEY_COMPARATOR KEY_SUPER_GENERIC c, KEY_COMPARATOR KEY_SUPER_GENERIC d ) {
super( refArray, capacity, c );
secondaryQueue = new HEAP_INDIRECT_PRIORITY_QUEUE KEY_GENERIC( refArray, capacity, d );
}
/** Creates a new empty queue with a given capacity.
*
* c
.
*
* @param refArray the reference array.
* @param capacity the initial capacity of this queue.
* @param c the primary comparator used in this queue, or null
for the natural order.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
super( refArray, capacity, c );
secondaryQueue = new HEAP_INDIRECT_PRIORITY_QUEUE KEY_GENERIC( refArray, capacity, c == null ? COMPARATORS.OPPOSITE_COMPARATOR : COMPARATORS.oppositeComparator( c ) );
}
/** Creates a new empty queue with a given capacity and natural order as primary comparator.
*
* null
for the natural order.
* @param d the secondary comparator used in this queue, or null
for the natural order.
*/
public HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, KEY_COMPARATOR KEY_SUPER_GENERIC c, KEY_COMPARATOR KEY_SUPER_GENERIC d ) {
this( refArray, refArray.length, c, d );
}
/** Creates a new empty queue with capacity equal to the length of the reference array.
*
* c
.
*
* @param refArray the reference array.
* @param c the primary comparator used in this queue, or null
for the natural order.
*/
public HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, refArray.length, c );
}
/** Creates a new empty queue with capacity equal to the length of the reference array and natural order as primary comparator.
*
* size
element of the array will be rearranged so to form a heap, and
* moreover the array will be cloned and wrapped in a secondary queue (this is
* more efficient than enqueing the elements of a
one by one).
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param size the number of elements to be included in the queue.
* @param c the primary comparator used in this queue, or null
for the natural order.
* @param d the secondary comparator used in this queue, or null
for the natural order.
*/
public HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size, final KEY_COMPARATOR KEY_SUPER_GENERIC c, final KEY_COMPARATOR KEY_SUPER_GENERIC d ) {
super( refArray, a, size, c );
this.secondaryQueue = new HEAP_INDIRECT_PRIORITY_QUEUE KEY_GENERIC( refArray, a.clone(), size, d );
}
/** Wraps a given array in a queue using the given comparators.
*
* a
one by one).
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param c the primary comparator used in this queue, or null
for the natural order.
* @param d the secondary comparator used in this queue, or null
for the natural order.
*/
public HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, final KEY_COMPARATOR KEY_SUPER_GENERIC c, final KEY_COMPARATOR KEY_SUPER_GENERIC d ) {
this( refArray, a, a.length, c, d );
}
/** Wraps a given array in a queue using a given comparator.
*
* size
element of the array will be rearranged so to form a heap, and
* moreover the array will be cloned and wrapped in a secondary queue (this is
* more efficient than enqueing the elements of a
one by one).
*
* c
.
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param size the number of elements to be included in the queue.
* @param c the primary comparator used in this queue, or null
for the natural order.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, a, size, c, c == null ? COMPARATORS.OPPOSITE_COMPARATOR : COMPARATORS.oppositeComparator( c ) );
}
/** Wraps a given array in a queue using a given comparator.
*
* a
one by one).
*
* c
.
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param c the primary comparator used in this queue, or null
for the natural order.
*/
public HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, a, a.length, c );
}
/** Wraps a given array in a queue using the natural order.
*
* size
element of the array will be rearranged so to form a heap, and
* moreover the array will be cloned and wrapped in a secondary queue (this is
* more efficient than enqueing the elements of a
one by one).
*
* refArray
.
* @param size the number of elements to be included in the queue.
*/
public HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size ) {
this( refArray, a, size, null );
}
/** Wraps a given array in a queue using the natural order.
*
* a
one by one).
*
* refArray
.
*/
public HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a ) {
this( refArray, a, a.length );
}
public void enqueue( int x ) {
secondaryQueue.enqueue( x );
super.enqueue( x );
}
public int dequeue() {
final int result = super.dequeue();
secondaryQueue.remove( result );
return result;
}
public int secondaryFirst() {
return secondaryQueue.first();
}
public int secondaryLast() { throw new UnsupportedOperationException(); }
public void changed() {
secondaryQueue.changed( heap[ 0 ] );
super.changed();
}
public void changed( final int index ) {
secondaryQueue.changed( index );
super.changed( index );
}
public void allChanged() {
secondaryQueue.allChanged();
super.allChanged();
}
public void clear() {
super.clear();
secondaryQueue.clear();
}
public boolean remove( final int index ) {
secondaryQueue.remove( index );
return super.remove( index );
}
public int secondaryFront( final int[] a ) {
return secondaryQueue.front( a );
}
/** Trims the underlying queues so they have exactly {@link #size()} elements.
*/
public void trim() {
super.trim();
secondaryQueue.trim();
}
/** Returns the secondary comparator of this queue.
*
* @return the secondary comparator of this queue.
* @see #secondaryFirst()
*/
public KEY_COMPARATOR KEY_SUPER_GENERIC secondaryComparator() { return secondaryQueue.comparator(); }
#ifdef TEST
/** The original class, now just used for testing. */
private static class TestQueue {
/** The reference array */
private KEY_TYPE refArray[];
/** Its length */
private int N;
/** The number of elements in the heaps */
private int n;
/** The two comparators */
private KEY_COMPARATOR primaryComp, secondaryComp;
/** Two indirect heaps are used, called primary
and secondary
. Each of them contains
a permutation of n
among the indices 0, 1, ..., N
-1 in such a way that the corresponding
objects be sorted with respect to the two comparators.
We also need an array inSec[]
so that inSec[k]
is the index of secondary
containing k
.
*/
private int primary[], secondary[], inSec[];
/** Builds a double indirect priority queue.
* @param refArray The reference array.
* @param primaryComp The primary comparator.
* @param secondaryComp The secondary comparator.
*/
public TestQueue( KEY_TYPE refArray[], KEY_COMPARATOR primaryComp, KEY_COMPARATOR secondaryComp ) {
this.refArray = refArray;
this.N = refArray.length;
assert this.N != 0;
this.n = 0;
this.primaryComp = primaryComp;
this.secondaryComp = secondaryComp;
this.primary = new int[N];
this.secondary = new int[N];
this.inSec = new int[N];
java.util.Arrays.fill( inSec, -1 );
}
/** Adds an index to the queue. Notice that the index should not be already present in the queue.
* @param i The index to be added
*/
public void add( int i ) {
if ( i < 0 || i >= refArray.length ) throw new IndexOutOfBoundsException();
if ( inSec[ i ] >= 0 ) throw new IllegalArgumentException();
primary[n] = i;
secondary[n] = i; inSec[i] = n;
n++;
swimPrimary( n-1 );
swimSecondary( n-1 );
}
/** Heapify the primary heap.
* @param i The index of the heap to be heapified.
*/
private void heapifyPrimary( int i ) {
int dep = primary[i];
int child;
while ( ( child = 2*i+1 ) < n ) {
if ( child+1 < n && primaryComp.compare( refArray[primary[child+1]], refArray[primary[child]] ) < 0 ) child++;
if ( primaryComp.compare( refArray[dep], refArray[primary[child]] ) <= 0 ) break;
primary[i] = primary[child];
i = child;
}
primary[i] = dep;
}
/** Heapify the secondary heap.
* @param i The index of the heap to be heapified.
*/
private void heapifySecondary( int i ) {
int dep = secondary[i];
int child;
while ( ( child = 2*i+1 ) < n ) {
if ( child+1 < n && secondaryComp.compare( refArray[secondary[child+1]], refArray[secondary[child]] ) < 0 ) child++;
if ( secondaryComp.compare( refArray[dep], refArray[secondary[child]] ) <= 0 ) break;
secondary[i] = secondary[child]; inSec[secondary[i]] = i;
i = child;
}
secondary[i] = dep; inSec[secondary[i]] = i;
}
/** Swim and heapify the primary heap.
* @param i The index to be moved.
*/
private void swimPrimary( int i ) {
int dep = primary[i];
int parent;
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( primaryComp.compare( refArray[primary[parent]], refArray[dep] ) <= 0 ) break;
primary[i] = primary[parent];
i = parent;
}
primary[i] = dep;
heapifyPrimary( i );
}
/** Swim and heapify the secondary heap.
* @param i The index to be moved.
*/
private void swimSecondary( int i ) {
int dep = secondary[i];
int parent;
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( secondaryComp.compare( refArray[secondary[parent]], refArray[dep] ) <= 0 ) break;
secondary[i] = secondary[parent]; inSec[secondary[i]] = i;
i = parent;
}
secondary[i] = dep; inSec[secondary[i]] = i;
heapifySecondary( i );
}
/** Returns the minimum element with respect to the primary comparator.
@return the minimum element.
*/
public int top() {
if ( n == 0 ) throw new java.util.NoSuchElementException();
return primary[0];
}
/** Returns the minimum element with respect to the secondary comparator.
@return the minimum element.
*/
public int secTop() {
if ( n == 0 ) throw new java.util.NoSuchElementException();
return secondary[0];
}
/** Removes the minimum element with respect to the primary comparator.
* @return the removed element.
*/
public void remove() {
if ( n == 0 ) throw new java.util.NoSuchElementException();
int result = primary[0];
int ins = inSec[result];
inSec[ result ] = -1;
// Copy a leaf
primary[0] = primary[n-1];
if ( ins == n-1 ) {
n--;
heapifyPrimary( 0 );
return;
}
secondary[ins] = secondary[n-1];
inSec[secondary[ins]] = ins;
// Heapify
n--;
heapifyPrimary( 0 );
swimSecondary( ins );
}
public void clear() {
while( size() != 0 ) remove();
}
/** Signals that the minimum element with respect to the comparator has changed.
*/
public void change() {
int ins = inSec[primary[0]];
heapifyPrimary( 0 );
swimSecondary( ins );
}
/** Returns the number of elements in the queue.
* @return the size of the queue
*/
public int size() {
return n;
}
public String toString() {
String s = "[";
for ( int i = 0; i < n; i++ )
s += refArray[primary[i]]+", ";
return s+ "]";
}
}
private static long seed = System.currentTimeMillis();
private static java.util.Random r = new java.util.Random( seed );
private static KEY_TYPE genKey() {
#if #keyclass(Byte) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#elif #keyclass(Object)
return Integer.toBinaryString( r.nextInt() );
#else
return new java.io.Serializable() {};
#endif
}
private static java.text.NumberFormat format = new java.text.DecimalFormat( "#,###.00" );
private static java.text.FieldPosition p = new java.text.FieldPosition( 0 );
private static String format( double d ) {
StringBuffer s = new StringBuffer();
return format.format( d, s, p ).toString();
}
private static void speedTest( int n, boolean comp ) {
System.out.println( "There are presently no speed tests for this class." );
}
private static void fatal( String msg ) {
System.out.println( msg );
System.exit( 1 );
}
private static void ensure( boolean cond, String msg ) {
if ( cond ) return;
fatal( msg );
}
private static boolean heapEqual( int[] a, int[] b, int sizea, int sizeb ) {
if ( sizea != sizeb ) return false;
while( sizea-- != 0 ) if ( a[sizea] != b[sizea] ) return false;
return true;
}
private static boolean invEqual( int inva[], int[] invb ) {
int i = inva.length;
while( i-- != 0 ) if ( inva[ i ] != invb[ i ] ) return false;
return true;
}
protected static void test( int n ) {
long ms;
Exception mThrowsIllegal, tThrowsIllegal, mThrowsOutOfBounds, tThrowsOutOfBounds, mThrowsNoElement, tThrowsNoElement;
int rm = 0, rt = 0;
KEY_TYPE[] refArray = new KEY_TYPE[ n ];
for( int i = 0; i < n; i++ ) refArray[ i ] = genKey();
HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE m = new HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUE( refArray );
TestQueue t = new TestQueue( refArray, COMPARATORS.NATURAL_COMPARATOR, COMPARATORS.OPPOSITE_COMPARATOR );
/* We add pairs to t. */
for( int i = 0; i < n / 2; i++ ) {
t.add( i );
m.enqueue( i );
}
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in primary heap after creation (" + m + ", " + t + ")" );
ensure( heapEqual( m.secondaryQueue.heap, t.secondary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in secondary heap after creation (" + m + ", " + t + ")" );
ensure( invEqual( m.secondaryQueue.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after creation (" + java.util.Arrays.toString( m.secondaryQueue.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
/* Now we add and remove random data in m and t, checking that the result is the same. */
for(int i=0; i<2*n; i++ ) {
if ( r.nextDouble() < 0.01 ) {
t.clear();
m.clear();
for( int j = 0; j < n / 2; j++ ) {
t.add( j );
m.enqueue( j );
}
}
int T = r.nextInt( 2 * n );
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
m.enqueue( T );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
try {
t.add( T );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): enqueue() divergence in IndexOutOfBoundsException for " + T + " (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): enqueue() divergence in IllegalArgumentException for " + T + " (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in primary heap after enqueue (" + m + ", " + t + ")" );
ensure( heapEqual( m.secondaryQueue.heap, t.secondary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in secondary heap after enqueue (" + m + ", " + t + ")" );
ensure( invEqual( m.secondaryQueue.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after enqueue (" + java.util.Arrays.toString( m.secondaryQueue.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
if ( m.size() != 0 ) {
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after enqueue (" + m.first() + ", " + t.top() + ")");
ensure( m.secondaryFirst() == t.secTop(), "Error (" + seed + "): m and t differ in secondary first element after enqueue (" + m.secondaryFirst() + ", " + t.secTop() + ")");
}
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
rm = m.dequeue();
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { mThrowsNoElement = e; }
try {
rt = t.top();
t.remove();
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { tThrowsNoElement = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): dequeue() divergence in IndexOutOfBoundsException (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): dequeue() divergence in IllegalArgumentException (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( ( mThrowsNoElement == null ) == ( tThrowsNoElement == null ), "Error (" + seed + "): dequeue() divergence in java.util.NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
if ( mThrowsOutOfBounds == null ) ensure( rt == rm , "Error (" + seed + "): divergence in dequeue() between t and m (" + rt + ", " + rm + ")" );
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in primary heap after dequeue (" + m + ", " + t + ")" );
ensure( heapEqual( m.secondaryQueue.heap, t.secondary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in secondary heap after dequeue (" + m + ", " + t + ")" );
ensure( invEqual( m.secondaryQueue.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after dequeue (" + java.util.Arrays.toString( m.secondaryQueue.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
if ( m.size() != 0 ) {
refArray[ m.first() ] = genKey();
m.changed();
t.change();
ensure( m.size() == t.size(), "Error (" + seed + "): m and t differ in size after change (" + m.size() + ", " + t.size() + ")");
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after change (" + m.first() + ", " + t.top() + ")");
ensure( m.secondaryFirst() == t.secTop(), "Error (" + seed + "): m and t differ in secondary first element after change (" + m.secondaryFirst() + ", " + t.secTop() + ")");
}
}
/* Now we check that m actually holds the same data. */
m.clear();
ensure( m.isEmpty(), "Error (" + seed + "): m is not empty after clear()" );
System.out.println("Test OK");
}
public static void main( String args[] ) {
int n = Integer.parseInt(args[1]);
if ( args.length > 2 ) r = new java.util.Random( seed = Long.parseLong( args[ 2 ] ) );
try {
if ("speedTest".equals(args[0]) || "speedComp".equals(args[0])) speedTest( n, "speedComp".equals(args[0]) );
else if ( "test".equals( args[0] ) ) test(n);
} catch( Throwable e ) {
e.printStackTrace( System.err );
System.err.println( "seed: " + seed );
}
}
#endif
}
fastutil-7.0.2/drv/HeapIndirectPriorityQueue.drv 0000644 0000000 0000000 00000060766 12502267264 020635 0 ustar root wheel /*
* Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
#if #keyclass(Object)
import java.util.Comparator;
#endif
import it.unimi.dsi.fastutil.ints.IntArrays;
import java.util.Arrays;
import java.util.NoSuchElementException;
/** A type-specific heap-based indirect priority queue.
*
* null
for the natural order.
*/
public HEAP_INDIRECT_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
super( refArray, capacity, c );
if ( capacity > 0 ) this.heap = new int[ capacity ];
this.c = c;
this.inv = new int[ refArray.length ];
Arrays.fill( inv, -1 );
}
/** Creates a new empty queue with a given capacity and using the natural order.
*
* @param refArray the reference array.
* @param capacity the initial capacity of this queue.
*/
public HEAP_INDIRECT_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity ) {
this( refArray, capacity, null );
}
/** Creates a new empty queue with capacity equal to the length of the reference array and a given comparator.
*
* @param refArray the reference array.
* @param c the comparator used in this queue, or null
for the natural order.
*/
public HEAP_INDIRECT_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, refArray.length, c );
}
/** Creates a new empty queue with capacity equal to the length of the reference array and using the natural order.
* @param refArray the reference array.
*/
public HEAP_INDIRECT_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray ) {
this( refArray, refArray.length, null );
}
/** Wraps a given array in a queue using a given comparator.
*
* size
element of the array will be rearranged so to form a heap (this is
* more efficient than enqueing the elements of a
one by one).
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param size the number of elements to be included in the queue.
* @param c the comparator used in this queue, or null
for the natural order.
*/
public HEAP_INDIRECT_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, final int size, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, 0, c );
this.heap = a;
this.size = size;
int i = size;
while( i-- != 0 ) {
if ( inv[ a[ i ] ] != -1 ) throw new IllegalArgumentException( "Index " + a[ i ] + " appears twice in the heap" );
inv[ a[ i ] ] = i;
}
INDIRECT_HEAPS.makeHeap( refArray, a, inv, size, c );
}
/** Wraps a given array in a queue using a given comparator.
*
* a
one by one).
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param c the comparator used in this queue, or null
for the natural order.
*/
public HEAP_INDIRECT_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, a, a.length, c );
}
/** Wraps a given array in a queue using the natural order.
*
* size
element of the array will be rearranged so to form a heap (this is
* more efficient than enqueing the elements of a
one by one).
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param size the number of elements to be included in the queue.
*/
public HEAP_INDIRECT_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size ) {
this( refArray, a, size, null );
}
/** Wraps a given array in a queue using the natural order.
*
* a
one by one).
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
*/
public HEAP_INDIRECT_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a ) {
this( refArray, a, a.length );
}
public void enqueue( final int x ) {
if ( inv[ x ] >= 0 ) throw new IllegalArgumentException( "Index " + x + " belongs to the queue" );
if ( size == heap.length ) heap = IntArrays.grow( heap, size + 1 );
inv[ heap[ size ] = x ] = size++;
INDIRECT_HEAPS.upHeap( refArray, heap, inv, size, size - 1, c );
}
public boolean contains( final int index ) {
return inv[ index ] >= 0;
}
public int dequeue() {
if ( size == 0 ) throw new NoSuchElementException();
final int result = heap[ 0 ];
if ( --size != 0 ) inv[ heap[ 0 ] = heap[ size ] ] = 0;
inv[ result ] = -1;
if ( size != 0 ) INDIRECT_HEAPS.downHeap( refArray, heap, inv, size, 0, c );
return result;
}
public void changed() {
INDIRECT_HEAPS.downHeap( refArray, heap, inv, size, 0, c );
}
public void changed( final int index ) {
final int pos = inv[ index ];
if ( pos < 0 ) throw new IllegalArgumentException( "Index " + index + " does not belong to the queue" );
final int newPos = INDIRECT_HEAPS.upHeap( refArray, heap, inv, size, pos, c );
INDIRECT_HEAPS.downHeap( refArray, heap, inv, size, newPos, c );
}
/** Rebuilds this heap in a bottom-up fashion.
*/
public void allChanged() {
INDIRECT_HEAPS.makeHeap( refArray, heap, inv, size, c );
}
public boolean remove( final int index ) {
final int result = inv[ index ];
if ( result < 0 ) return false;
inv[ index ] = -1;
if ( result < --size ) {
inv[ heap[ result ] = heap[ size ] ] = result;
final int newPos = INDIRECT_HEAPS.upHeap( refArray, heap, inv, size, result, c );
INDIRECT_HEAPS.downHeap( refArray, heap, inv, size, newPos, c );
}
return true;
}
public void clear() {
size = 0;
Arrays.fill( inv, -1 );
}
#ifdef TEST
/** The original class, now just used for testing. */
private static class TestQueue {
/** The reference array */
private KEY_TYPE refArray[];
/** Its length */
private int N;
/** The number of elements in the heaps */
private int n;
/** The two comparators */
private KEY_COMPARATOR primaryComp, secondaryComp;
/** Two indirect heaps are used, called primary
and secondary
. Each of them contains
a permutation of n
among the indices 0, 1, ..., N
-1 in such a way that the corresponding
objects be sorted with respect to the two comparators.
We also need an array inSec[]
so that inSec[k]
is the index of secondary
containing k
.
*/
private int primary[], secondary[], inSec[];
/** Builds a double indirect priority queue.
* @param refArray The reference array.
* @param primaryComp The primary comparator.
* @param secondaryComp The secondary comparator.
*/
public TestQueue( KEY_TYPE refArray[], KEY_COMPARATOR primaryComp, KEY_COMPARATOR secondaryComp ) {
this.refArray = refArray;
this.N = refArray.length;
assert this.N != 0;
this.n = 0;
this.primaryComp = primaryComp;
this.secondaryComp = secondaryComp;
this.primary = new int[N];
this.secondary = new int[N];
this.inSec = new int[N];
java.util.Arrays.fill( inSec, -1 );
}
/** Adds an index to the queue. Notice that the index should not be already present in the queue.
* @param i The index to be added
*/
public void add( int i ) {
if ( i < 0 || i >= refArray.length ) throw new IndexOutOfBoundsException();
if ( inSec[ i ] >= 0 ) throw new IllegalArgumentException();
primary[n] = i;
secondary[n] = i; inSec[i] = n;
n++;
swimPrimary( n-1 );
swimSecondary( n-1 );
}
/** Heapify the primary heap.
* @param i The index of the heap to be heapified.
*/
private void heapifyPrimary( int i ) {
int dep = primary[i];
int child;
while ( ( child = 2*i+1 ) < n ) {
if ( child+1 < n && primaryComp.compare( refArray[primary[child+1]], refArray[primary[child]] ) < 0 ) child++;
if ( primaryComp.compare( refArray[dep], refArray[primary[child]] ) <= 0 ) break;
primary[i] = primary[child];
i = child;
}
primary[i] = dep;
}
/** Heapify the secondary heap.
* @param i The index of the heap to be heapified.
*/
private void heapifySecondary( int i ) {
int dep = secondary[i];
int child;
while ( ( child = 2*i+1 ) < n ) {
if ( child+1 < n && secondaryComp.compare( refArray[secondary[child+1]], refArray[secondary[child]] ) < 0 ) child++;
if ( secondaryComp.compare( refArray[dep], refArray[secondary[child]] ) <= 0 ) break;
secondary[i] = secondary[child]; inSec[secondary[i]] = i;
i = child;
}
secondary[i] = dep; inSec[secondary[i]] = i;
}
/** Swim and heapify the primary heap.
* @param i The index to be moved.
*/
private void swimPrimary( int i ) {
int dep = primary[i];
int parent;
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( primaryComp.compare( refArray[primary[parent]], refArray[dep] ) <= 0 ) break;
primary[i] = primary[parent];
i = parent;
}
primary[i] = dep;
heapifyPrimary( i );
}
/** Swim and heapify the secondary heap.
* @param i The index to be moved.
*/
private void swimSecondary( int i ) {
int dep = secondary[i];
int parent;
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( secondaryComp.compare( refArray[secondary[parent]], refArray[dep] ) <= 0 ) break;
secondary[i] = secondary[parent]; inSec[secondary[i]] = i;
i = parent;
}
secondary[i] = dep; inSec[secondary[i]] = i;
heapifySecondary( i );
}
/** Returns the minimum element with respect to the primary comparator.
@return the minimum element.
*/
public int top() {
if ( n == 0 ) throw new java.util.NoSuchElementException();
return primary[0];
}
/** Returns the minimum element with respect to the secondary comparator.
@return the minimum element.
*/
public int secTop() {
if ( n == 0 ) throw new java.util.NoSuchElementException();
return secondary[0];
}
/** Removes the minimum element with respect to the primary comparator.
* @return the removed element.
*/
public boolean remove() {
if ( n == 0 ) throw new java.util.NoSuchElementException();
if ( inSec[primary[0]] == -1 ) return false;
int result = primary[0];
int ins = inSec[result];
inSec[ result ] = -1;
// Copy a leaf
primary[0] = primary[n-1];
if ( ins == n-1 ) {
n--;
heapifyPrimary( 0 );
return true;
}
secondary[ins] = secondary[n-1];
inSec[secondary[ins]] = ins;
// Heapify
n--;
heapifyPrimary( 0 );
swimSecondary( ins );
return true;
}
public void clear() {
while( size() != 0 ) remove();
}
public void remove( int index ) {
if ( index >= refArray.length ) throw new IndexOutOfBoundsException();
if ( inSec[index] == -1 ) return;
int ins = inSec[index];
inSec[ index ] = -1;
// Copy a leaf
primary[ins] = primary[n-1];
if ( ins == n-1 ) {
n--;
swimPrimary( ins );
return;
}
secondary[ins] = secondary[n-1];
inSec[secondary[ins]] = ins;
// Heapify
n--;
swimPrimary( ins );
swimSecondary( ins );
}
/** Signals that the minimum element with respect to the comparator has changed.
*/
public void change() {
if ( n == 0 ) throw new java.util.NoSuchElementException();
if ( inSec[primary[0]] == -1 ) throw new IllegalArgumentException();
int ins = inSec[primary[0]];
heapifyPrimary( 0 );
swimSecondary( ins );
}
public void change(int index) {
if ( index >= refArray.length ) throw new IndexOutOfBoundsException();
if ( inSec[index] == -1 ) throw new IllegalArgumentException();
if ( n == 0 ) throw new java.util.NoSuchElementException();
int ins = inSec[ index ];
swimPrimary( ins );
swimSecondary( ins );
}
/** Returns the number of elements in the queue.
* @return the size of the queue
*/
public int size() {
return n;
}
public String toString() {
String s = "[";
for ( int i = 0; i < n; i++ )
s += refArray[primary[i]]+", ";
return s+ "]";
}
}
private static long seed = System.currentTimeMillis();
private static java.util.Random r = new java.util.Random( seed );
private static KEY_TYPE genKey() {
#if #keyclass(Byte) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#elif #keyclass(Object)
return Integer.toBinaryString( r.nextInt() );
#else
return new java.io.Serializable() {};
#endif
}
private static java.text.NumberFormat format = new java.text.DecimalFormat( "#,###.00" );
private static java.text.FieldPosition p = new java.text.FieldPosition( 0 );
private static String format( double d ) {
StringBuffer s = new StringBuffer();
return format.format( d, s, p ).toString();
}
private static void speedTest( int n, boolean comp ) {
System.out.println( "There are presently no speed tests for this class." );
}
private static void fatal( String msg ) {
System.out.println( msg );
System.exit( 1 );
}
private static void ensure( boolean cond, String msg ) {
if ( cond ) return;
fatal( msg );
}
private static boolean heapEqual( int[] a, int[] b, int sizea, int sizeb ) {
if ( sizea != sizeb ) return false;
while( sizea-- != 0 ) if ( a[sizea] != b[sizea] ) return false;
return true;
}
private static boolean invEqual( int inva[], int[] invb ) {
int i = inva.length;
while( i-- != 0 ) if ( inva[ i ] != invb[ i ] ) return false;
return true;
}
protected static void test( int n ) {
long ms;
Exception mThrowsIllegal, tThrowsIllegal, mThrowsOutOfBounds, tThrowsOutOfBounds, mThrowsNoElement, tThrowsNoElement;
int rm = 0, rt = 0;
KEY_TYPE[] refArray = new KEY_TYPE[ n ];
for( int i = 0; i < n; i++ ) refArray[ i ] = genKey();
HEAP_INDIRECT_PRIORITY_QUEUE m = new HEAP_INDIRECT_PRIORITY_QUEUE( refArray, COMPARATORS.NATURAL_COMPARATOR );
TestQueue t = new TestQueue( refArray, COMPARATORS.NATURAL_COMPARATOR, COMPARATORS.NATURAL_COMPARATOR );
/* We add pairs to t. */
for( int i = 0; i < n / 2; i++ ) {
t.add( i );
m.enqueue( i );
}
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ after creation (" + m + ", " + t + ")" );
ensure( invEqual( m.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after creation (" + java.util.Arrays.toString( m.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
/* Now we add and remove random data in m and t, checking that the result is the same. */
for(int i=0; i<2*n; i++ ) {
if ( r.nextDouble() < 0.01 ) {
t.clear();
m.clear();
for( int j = 0; j < n / 2; j++ ) {
t.add( j );
m.enqueue( j );
}
}
int T = r.nextInt( 2 * n );
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
m.enqueue( T );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
try {
t.add( T );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): enqueue() divergence in IndexOutOfBoundsException for " + T + " (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): enqueue() divergence in IllegalArgumentException for " + T + " (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ after enqueue (" + m + ", " + t + ")" );
ensure( invEqual( m.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after enqueue (" + java.util.Arrays.toString( m.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
if ( m.size() != 0 ) {
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after enqueue (" + m.first() + ", " + t.top() + ")");
}
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
rm = m.dequeue();
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { mThrowsNoElement = e; }
try {
rt = t.top();
t.remove();
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { tThrowsNoElement = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): dequeue() divergence in IndexOutOfBoundsException (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): dequeue() divergence in IllegalArgumentException (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( ( mThrowsNoElement == null ) == ( tThrowsNoElement == null ), "Error (" + seed + "): dequeue() divergence in java.util.NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
if ( mThrowsOutOfBounds == null ) ensure( rt == rm , "Error (" + seed + "): divergence in dequeue() between t and m (" + rt + ", " + rm + ")" );
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ after dequeue (" + m + ", " + t + ")" );
ensure( invEqual( m.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after dequeue (" + java.util.Arrays.toString( m.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
if ( m.size() != 0 ) {
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after dequeue (" + m.first() + ", " + t.top() + ")");
}
int pos = r.nextInt( n * 2 );
try {
m.remove( pos );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { mThrowsNoElement = e; }
try {
t.remove( pos );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { tThrowsNoElement = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): remove(int) divergence in IndexOutOfBoundsException (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): remove(int) divergence in IllegalArgumentException (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( ( mThrowsNoElement == null ) == ( tThrowsNoElement == null ), "Error (" + seed + "): remove(int) divergence in java.util.NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
if ( mThrowsOutOfBounds == null ) ensure( rt == rm , "Error (" + seed + "): divergence in remove(int) between t and m (" + rt + ", " + rm + ")" );
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ after remove(int) (" + m + ", " + t + ")" );
ensure( invEqual( m.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after remove(int) (" + java.util.Arrays.toString( m.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
if ( m.size() != 0 ) {
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after remove(int) (" + m.first() + ", " + t.top() + ")");
}
pos = r.nextInt( n * 2 );
try {
m.changed( pos );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { mThrowsNoElement = e; }
try {
t.change( pos );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { tThrowsNoElement = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): change(int) divergence in IndexOutOfBoundsException (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): change(int) divergence in IllegalArgumentException (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( ( mThrowsNoElement == null ) == ( tThrowsNoElement == null ), "Error (" + seed + "): change(int) divergence in java.util.NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
if ( mThrowsOutOfBounds == null ) ensure( rt == rm , "Error (" + seed + "): divergence in change(int) between t and m (" + rt + ", " + rm + ")" );
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ after change(int) (" + m + ", " + t + ")" );
ensure( invEqual( m.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after change(int) (" + java.util.Arrays.toString( m.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
if ( m.size() != 0 ) {
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after change(int) (" + m.first() + ", " + t.top() + ")");
}
if ( m.size() != 0 ) {
refArray[ m.first() ] = genKey();
m.changed();
t.change();
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ after change (" + m + ", " + t + ")" );
ensure( invEqual( m.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after change (" + java.util.Arrays.toString( m.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
if ( m.size() != 0 ) {
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after change (" + m.first() + ", " + t.top() + ")");
}
}
}
/* Now we check that m actually holds the same data. */
m.clear();
ensure( m.isEmpty(), "Error (" + seed + "): m is not empty after clear()" );
System.out.println("Test OK");
}
public static void main( String args[] ) {
int n = Integer.parseInt(args[1]);
if ( args.length > 2 ) r = new java.util.Random( seed = Long.parseLong( args[ 2 ] ) );
try {
if ("speedTest".equals(args[0]) || "speedComp".equals(args[0])) speedTest( n, "speedComp".equals(args[0]) );
else if ( "test".equals( args[0] ) ) test(n);
} catch( Throwable e ) {
e.printStackTrace( System.err );
System.err.println( "seed: " + seed );
}
}
#endif
}
fastutil-7.0.2/drv/HeapPriorityQueue.drv 0000644 0000000 0000000 00000031752 12502267243 017141 0 ustar root wheel /*
* Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
#if #keyclass(Object)
import java.util.Arrays;
import java.util.Comparator;
import it.unimi.dsi.fastutil.AbstractPriorityQueue;
#endif
import java.util.NoSuchElementException;
/** A type-specific heap-based priority queue.
*
* null
for the natural order.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public HEAP_PRIORITY_QUEUE( int capacity, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
if ( capacity > 0 ) this.heap = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ capacity ];
this.c = c;
}
/** Creates a new empty queue with a given capacity and using the natural order.
*
* @param capacity the initial capacity of this queue.
*/
public HEAP_PRIORITY_QUEUE( int capacity ) {
this( capacity, null );
}
/** Creates a new empty queue with a given comparator.
*
* @param c the comparator used in this queue, or null
for the natural order.
*/
public HEAP_PRIORITY_QUEUE( KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( 0, c );
}
/** Creates a new empty queue using the natural order.
*/
public HEAP_PRIORITY_QUEUE() {
this( 0, null );
}
/** Wraps a given array in a queue using a given comparator.
*
* size
element of the array will be rearranged so to form a heap (this is
* more efficient than enqueing the elements of a
one by one).
*
* @param a an array.
* @param size the number of elements to be included in the queue.
* @param c the comparator used in this queue, or null
for the natural order.
*/
public HEAP_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] a, int size, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( c );
this.heap = a;
this.size = size;
HEAPS.makeHeap( a, size, c );
}
/** Wraps a given array in a queue using a given comparator.
*
* a
one by one).
*
* @param a an array.
* @param c the comparator used in this queue, or null
for the natural order.
*/
public HEAP_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] a, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( a, a.length, c );
}
/** Wraps a given array in a queue using the natural order.
*
* size
element of the array will be rearranged so to form a heap (this is
* more efficient than enqueing the elements of a
one by one).
*
* @param a an array.
* @param size the number of elements to be included in the queue.
*/
public HEAP_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] a, int size ) {
this( a, size, null );
}
/** Wraps a given array in a queue using the natural order.
*
* a
one by one).
*
* @param a an array.
*/
public HEAP_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] a ) {
this( a, a.length );
}
public void enqueue( KEY_GENERIC_TYPE x ) {
if ( size == heap.length ) heap = ARRAYS.grow( heap, size + 1 );
heap[ size++ ] = x;
HEAPS.upHeap( heap, size, size - 1, c );
}
public KEY_GENERIC_TYPE DEQUEUE() {
if ( size == 0 ) throw new NoSuchElementException();
final KEY_GENERIC_TYPE result = heap[ 0 ];
heap[ 0 ] = heap[ --size ];
#if #keyclass(Object)
heap[ size ] = null;
#endif
if ( size != 0 ) HEAPS.downHeap( heap, size, 0, c );
return result;
}
public KEY_GENERIC_TYPE FIRST() {
if ( size == 0 ) throw new NoSuchElementException();
return heap[ 0 ];
}
public void changed() {
HEAPS.downHeap( heap, size, 0, c );
}
public int size() { return size; }
public void clear() {
#if #keyclass(Object)
Arrays.fill( heap, 0, size, null );
#endif
size = 0;
}
/** Trims the underlying heap array so that it has exactly {@link #size()} elements.
*/
public void trim() {
heap = ARRAYS.trim( heap, size );
}
public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() { return c; }
#ifdef TEST
private static long seed = System.currentTimeMillis();
private static java.util.Random r = new java.util.Random( seed );
private static KEY_TYPE genKey() {
#if #keyclass(Byte) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#elif #keyclass(Object)
return Integer.toBinaryString( r.nextInt() );
#else
return new java.io.Serializable() {};
#endif
}
private static java.text.NumberFormat format = new java.text.DecimalFormat( "#,###.00" );
private static java.text.FieldPosition p = new java.text.FieldPosition( 0 );
private static String format( double d ) {
StringBuffer s = new StringBuffer();
return format.format( d, s, p ).toString();
}
private static void speedTest( int n, boolean comp ) {
System.out.println( "There are presently no speed tests for this class." );
}
private static void fatal( String msg ) {
System.out.println( msg );
System.exit( 1 );
}
private static void ensure( boolean cond, String msg ) {
if ( cond ) return;
fatal( msg );
}
private static boolean heapEqual( KEY_TYPE[] a, KEY_TYPE[] b, int sizea, int sizeb ) {
if ( sizea != sizeb ) return false;
KEY_TYPE[] aa = (KEY_TYPE[])a.clone();
KEY_TYPE[] bb = (KEY_TYPE[])b.clone();
java.util.Arrays.sort( aa, 0, sizea );
java.util.Arrays.sort( bb, 0, sizeb );
while( sizea-- != 0 ) if ( ! KEY_EQUALS( aa[sizea], bb[sizea] ) ) return false;
return true;
}
private static KEY_TYPE k[];
protected static void test( int n ) {
long ms;
Exception mThrowsIllegal, tThrowsIllegal, mThrowsOutOfBounds, tThrowsOutOfBounds, mThrowsNoElement, tThrowsNoElement;
KEY_TYPE rm = KEY_NULL, rt = KEY_NULL;
k = new KEY_TYPE[ n ];
for( int i = 0; i < n; i++ ) k[i] = genKey();
HEAP_PRIORITY_QUEUE m = new HEAP_PRIORITY_QUEUE( COMPARATORS.NATURAL_COMPARATOR );
ARRAY_PRIORITY_QUEUE t = new ARRAY_PRIORITY_QUEUE( COMPARATORS.NATURAL_COMPARATOR );
/* We add pairs to t. */
for( int i = 0; i < n / 2; i++ ) {
t.enqueue( k[ i ] );
m.enqueue( k[ i ] );
}
ensure( heapEqual( m.heap, t.array, m.size(), t.size() ), "Error (" + seed + "): m and t differ after creation (" + m + ", " + t + ")" );
if ( m.size() != 0 ) {
ensure( KEY_EQUALS(m.FIRST(), t.FIRST()), "Error (" + seed + "): m and t differ in first element after creation (" + m.FIRST() + ", " + t.FIRST() + ")");
}
/* Now we add and remove random data in m and t, checking that the result is the same. */
for(int i=0; i<2*n; i++ ) {
if ( r.nextDouble() < 0.01 ) {
t.clear();
m.clear();
for( int j = 0; j < n / 2; j++ ) {
t.enqueue( k[ j ] );
m.enqueue( k[ j ] );
}
}
KEY_TYPE T = genKey();
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
m.enqueue( T );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
try {
t.enqueue( T );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): enqueue() divergence in IndexOutOfBoundsException for " + T + " (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): enqueue() divergence in IllegalArgumentException for " + T + " (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( heapEqual( m.heap, t.array, m.size(), t.size() ), "Error (" + seed + "): m and t differ after enqueue (" + m + ", " + t + ")" );
if ( m.size() != 0 ) {
ensure( KEY_EQUALS(m.FIRST(), t.FIRST()), "Error (" + seed + "): m and t differ in first element after enqueue (" + m.FIRST() + ", " + t.FIRST() + ")");
}
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
rm = m.DEQUEUE();
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
catch ( NoSuchElementException e ) { mThrowsNoElement = e; }
try {
rt = t.DEQUEUE();
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
catch ( NoSuchElementException e ) { tThrowsNoElement = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): dequeue() divergence in IndexOutOfBoundsException (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): dequeue() divergence in IllegalArgumentException (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( ( mThrowsNoElement == null ) == ( tThrowsNoElement == null ), "Error (" + seed + "): dequeue() divergence in NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
if ( mThrowsOutOfBounds == null ) ensure( rt == rm , "Error (" + seed + "): divergence in dequeue() between t and m (" + rt + ", " + rm + ")" );
ensure( heapEqual( m.heap, t.array, m.size(), t.size() ), "Error (" + seed + "): m and t differ after dequeue (" + m + ", " + t + ")");
if ( m.size() != 0 ) {
ensure( KEY_EQUALS(m.FIRST(), t.FIRST()), "Error (" + seed + "): m and t differ in first element after dequeue (" + m.FIRST() + ", " + t.FIRST() + ")");
}
HEAP_PRIORITY_QUEUE m2 = new HEAP_PRIORITY_QUEUE( t.array, t.size() );
ARRAY_PRIORITY_QUEUE t2 = new ARRAY_PRIORITY_QUEUE( m.heap, m.size() );
m = m2;
t = t2;
ensure( heapEqual( m.heap, t.array, m.size(), t.size() ), "Error (" + seed + "): m and t differ after wrap (" + m + ", " + t + ")");
if ( m.size() != 0 ) {
ensure( KEY_EQUALS(m.FIRST(), t.FIRST()), "Error (" + seed + "): m and t differ in first element after wrap (" + m.FIRST() + ", " + t.FIRST() + ")");
}
if ( m.size() != 0 && ( ( new OPEN_HASH_SET( m.heap, 0, m.size ) ).size() == m.size() ) ) {
int j = t.size(), M = --j;
#if #keys(primitive)
while( j-- != 0 ) if ( KEY_LESS( t.array[ j ], t.array[ M ] ) ) M = j;
#else
while( j-- != 0 ) if ( ((Comparable)t.array[ j ]).compareTo( t.array[ M ] )< 0 ) M = j;
#endif
m.heap[ 0 ] = t.array[ M ] = genKey();
m.changed();
t.changed();
ensure( heapEqual( m.heap, t.array, m.size(), t.size() ), "Error (" + seed + "): m and t differ after change (" + m + ", " + t + ")");
if ( m.size() != 0 ) {
ensure( KEY_EQUALS(m.FIRST(), t.FIRST()), "Error (" + seed + "): m and t differ in first element after change (" + m.FIRST() + ", " + t.FIRST() + ")");
}
}
}
/* Now we check that m actually holds the same data. */
m.clear();
ensure( m.isEmpty(), "Error (" + seed + "): m is not empty after clear()" );
System.out.println("Test OK");
}
public static void main( String args[] ) {
int n = Integer.parseInt(args[1]);
if ( args.length > 2 ) r = new java.util.Random( seed = Long.parseLong( args[ 2 ] ) );
try {
if ("speedTest".equals(args[0]) || "speedComp".equals(args[0])) speedTest( n, "speedComp".equals(args[0]) );
else if ( "test".equals( args[0] ) ) test(n);
} catch( Throwable e ) {
e.printStackTrace( System.err );
System.err.println( "seed: " + seed );
}
}
#endif
}
fastutil-7.0.2/drv/HeapSemiIndirectPriorityQueue.drv 0000644 0000000 0000000 00000046756 12502261336 021450 0 ustar root wheel /*
* Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
#if #keyclass(Object)
import java.util.Comparator;
import it.unimi.dsi.fastutil.IndirectPriorityQueue;
#endif
import java.util.NoSuchElementException;
import it.unimi.dsi.fastutil.ints.IntArrays;
import it.unimi.dsi.fastutil.AbstractIndirectPriorityQueue;
/** A type-specific heap-based semi-indirect priority queue.
*
* null
for the natural order.
*/
public HEAP_SEMI_INDIRECT_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
if ( capacity > 0 ) this.heap = new int[ capacity ];
this.refArray = refArray;
this.c = c;
}
/** Creates a new empty queue with given capacity and using the natural order.
*
* @param refArray the reference array.
* @param capacity the initial capacity of this queue.
*/
public HEAP_SEMI_INDIRECT_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity ) {
this( refArray, capacity, null );
}
/** Creates a new empty queue with capacity equal to the length of the reference array and a given comparator.
*
* @param refArray the reference array.
* @param c the comparator used in this queue, or null
for the natural order.
*/
public HEAP_SEMI_INDIRECT_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, refArray.length, c );
}
/** Creates a new empty queue with capacity equal to the length of the reference array and using the natural order.
* @param refArray the reference array.
*/
public HEAP_SEMI_INDIRECT_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray ) {
this( refArray, refArray.length, null );
}
/** Wraps a given array in a queue using a given comparator.
*
* size
element of the array will be rearranged so to form a heap (this is
* more efficient than enqueing the elements of a
one by one).
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param size the number of elements to be included in the queue.
* @param c the comparator used in this queue, or null
for the natural order.
*/
public HEAP_SEMI_INDIRECT_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, 0, c );
this.heap = a;
this.size = size;
SEMI_INDIRECT_HEAPS.makeHeap( refArray, a, size, c );
}
/** Wraps a given array in a queue using a given comparator.
*
* a
one by one).
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param c the comparator used in this queue, or null
for the natural order.
*/
public HEAP_SEMI_INDIRECT_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, a, a.length, c );
}
/** Wraps a given array in a queue using the natural order.
*
* size
element of the array will be rearranged so to form a heap (this is
* more efficient than enqueing the elements of a
one by one).
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param size the number of elements to be included in the queue.
*/
public HEAP_SEMI_INDIRECT_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size ) {
this( refArray, a, size, null );
}
/** Wraps a given array in a queue using the natural order.
*
* a
one by one).
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
*/
public HEAP_SEMI_INDIRECT_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a ) {
this( refArray, a, a.length );
}
/** Ensures that the given index is a valid reference.
*
* @param index an index in the reference array.
* @throws IndexOutOfBoundsException if the given index is negative or larger than the reference array length.
*/
protected void ensureElement( final int index ) {
if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" );
if ( index >= refArray.length ) throw new IndexOutOfBoundsException( "Index (" + index + ") is larger than or equal to reference array size (" + refArray.length + ")" );
}
public void enqueue( int x ) {
ensureElement( x );
if ( size == heap.length ) heap = IntArrays.grow( heap, size + 1 );
heap[ size++ ] = x;
SEMI_INDIRECT_HEAPS.upHeap( refArray, heap, size, size - 1, c );
}
public int dequeue() {
if ( size == 0 ) throw new NoSuchElementException();
final int result = heap[ 0 ];
heap[ 0 ] = heap[ --size ];
if ( size != 0 ) SEMI_INDIRECT_HEAPS.downHeap( refArray, heap, size, 0, c );
return result;
}
public int first() {
if ( size == 0 ) throw new NoSuchElementException();
return heap[ 0 ];
}
/** {@inheritDoc}
*
* primary
and secondary
. Each of them contains
a permutation of n
among the indices 0, 1, ..., N
-1 in such a way that the corresponding
objects be sorted with respect to the two comparators.
We also need an array inSec[]
so that inSec[k]
is the index of secondary
containing k
.
*/
private int primary[], secondary[], inSec[];
/** Builds a double indirect priority queue.
* @param refArray The reference array.
* @param primaryComp The primary comparator.
* @param secondaryComp The secondary comparator.
*/
public TestQueue( KEY_TYPE refArray[], KEY_COMPARATOR primaryComp, KEY_COMPARATOR secondaryComp ) {
this.refArray = refArray;
this.N = refArray.length;
assert this.N != 0;
this.n = 0;
this.primaryComp = primaryComp;
this.secondaryComp = secondaryComp;
this.primary = new int[N];
this.secondary = new int[N];
this.inSec = new int[N];
java.util.Arrays.fill( inSec, -1 );
}
/** Adds an index to the queue. Notice that the index should not be already present in the queue.
* @param i The index to be added
*/
public void add( int i ) {
if ( i < 0 || i >= refArray.length ) throw new IndexOutOfBoundsException();
//if ( inSec[ i ] >= 0 ) throw new IllegalArgumentException();
primary[n] = i;
n++;
swimPrimary( n-1 );
}
/** Heapify the primary heap.
* @param i The index of the heap to be heapified.
*/
private void heapifyPrimary( int i ) {
int dep = primary[i];
int child;
while ( ( child = 2*i+1 ) < n ) {
if ( child+1 < n && primaryComp.compare( refArray[primary[child+1]], refArray[primary[child]] ) < 0 ) child++;
if ( primaryComp.compare( refArray[dep], refArray[primary[child]] ) <= 0 ) break;
primary[i] = primary[child];
i = child;
}
primary[i] = dep;
}
/** Heapify the secondary heap.
* @param i The index of the heap to be heapified.
*/
private void heapifySecondary( int i ) {
int dep = secondary[i];
int child;
while ( ( child = 2*i+1 ) < n ) {
if ( child+1 < n && secondaryComp.compare( refArray[secondary[child+1]], refArray[secondary[child]] ) < 0 ) child++;
if ( secondaryComp.compare( refArray[dep], refArray[secondary[child]] ) <= 0 ) break;
secondary[i] = secondary[child]; inSec[secondary[i]] = i;
i = child;
}
secondary[i] = dep; inSec[secondary[i]] = i;
}
/** Swim and heapify the primary heap.
* @param i The index to be moved.
*/
private void swimPrimary( int i ) {
int dep = primary[i];
int parent;
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( primaryComp.compare( refArray[primary[parent]], refArray[dep] ) <= 0 ) break;
primary[i] = primary[parent];
i = parent;
}
primary[i] = dep;
heapifyPrimary( i );
}
/** Swim and heapify the secondary heap.
* @param i The index to be moved.
*/
private void swimSecondary( int i ) {
int dep = secondary[i];
int parent;
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( secondaryComp.compare( refArray[secondary[parent]], refArray[dep] ) <= 0 ) break;
secondary[i] = secondary[parent]; inSec[secondary[i]] = i;
i = parent;
}
secondary[i] = dep; inSec[secondary[i]] = i;
heapifySecondary( i );
}
/** Returns the minimum element with respect to the primary comparator.
@return the minimum element.
*/
public int top() {
if ( n == 0 ) throw new NoSuchElementException();
return primary[0];
}
/** Returns the minimum element with respect to the secondary comparator.
@return the minimum element.
*/
public int secTop() {
if ( n == 0 ) throw new NoSuchElementException();
return secondary[0];
}
/** Removes the minimum element with respect to the primary comparator.
* @return the removed element.
*/
public void remove() {
if ( n == 0 ) throw new NoSuchElementException();
int result = primary[0];
// Copy a leaf
primary[0] = primary[n-1];
n--;
heapifyPrimary( 0 );
return;
}
public void clear() {
while( size() != 0 ) remove();
}
/** Signals that the minimum element with respect to the comparator has changed.
*/
public void change() {
heapifyPrimary( 0 );
}
/** Returns the number of elements in the queue.
* @return the size of the queue
*/
public int size() {
return n;
}
public String toString() {
String s = "[";
for ( int i = 0; i < n; i++ )
s += refArray[primary[i]]+", ";
return s+ "]";
}
}
private static long seed = System.currentTimeMillis();
private static java.util.Random r = new java.util.Random( seed );
private static KEY_TYPE genKey() {
#if #keyclass(Byte) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#elif #keyclass(Object)
return Integer.toBinaryString( r.nextInt() );
#else
return new java.io.Serializable() {};
#endif
}
private static java.text.NumberFormat format = new java.text.DecimalFormat( "#,###.00" );
private static java.text.FieldPosition p = new java.text.FieldPosition( 0 );
private static String format( double d ) {
StringBuffer s = new StringBuffer();
return format.format( d, s, p ).toString();
}
private static void speedTest( int n, boolean comp ) {
System.out.println( "There are presently no speed tests for this class." );
}
private static void fatal( String msg ) {
System.out.println( msg );
System.exit( 1 );
}
private static void ensure( boolean cond, String msg ) {
if ( cond ) return;
fatal( msg );
}
private static boolean heapEqual( int[] a, int[] b, int sizea, int sizeb ) {
if ( sizea != sizeb ) return false;
while( sizea-- != 0 ) if ( a[sizea] != b[sizea] ) return false;
return true;
}
protected static void test( int n ) {
long ms;
Exception mThrowsIllegal, tThrowsIllegal, mThrowsOutOfBounds, tThrowsOutOfBounds, mThrowsNoElement, tThrowsNoElement;
int rm = 0, rt = 0;
KEY_TYPE[] refArray = new KEY_TYPE[ n ];
for( int i = 0; i < n; i++ ) refArray[ i ] = genKey();
HEAP_SEMI_INDIRECT_PRIORITY_QUEUE m = new HEAP_SEMI_INDIRECT_PRIORITY_QUEUE( refArray, COMPARATORS.NATURAL_COMPARATOR );
TestQueue t = new TestQueue( refArray, COMPARATORS.NATURAL_COMPARATOR, COMPARATORS.OPPOSITE_COMPARATOR );
/* We add pairs to t. */
for( int i = 0; i < n / 2; i++ ) {
t.add( i );
m.enqueue( i );
}
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ after creation (" + m + ", " + t + ")" );
/* Now we add and remove random data in m and t, checking that the result is the same. */
for(int i=0; i<2*n; i++ ) {
if ( r.nextDouble() < 0.01 ) {
t.clear();
m.clear();
for( int j = 0; j < n / 2; j++ ) {
t.add( j );
m.enqueue( j );
}
}
int T = r.nextInt( 2 * n );
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
m.enqueue( T );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
try {
t.add( T );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): enqueue() divergence in IndexOutOfBoundsException for " + T + " (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): enqueue() divergence in IllegalArgumentException for " + T + " (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ after enqueue (" + m + ", " + t + ")" );
if ( m.size() != 0 ) {
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after enqueue (" + m.first() + ", " + t.top() + ")");
}
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
rm = m.dequeue();
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
catch ( NoSuchElementException e ) { mThrowsNoElement = e; }
try {
rt = t.top();
t.remove();
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
catch ( NoSuchElementException e ) { tThrowsNoElement = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): dequeue() divergence in IndexOutOfBoundsException (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): dequeue() divergence in IllegalArgumentException (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( ( mThrowsNoElement == null ) == ( tThrowsNoElement == null ), "Error (" + seed + "): dequeue() divergence in NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
if ( mThrowsOutOfBounds == null ) ensure( rt == rm , "Error (" + seed + "): divergence in dequeue() between t and m (" + rt + ", " + rm + ")" );
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ after dequeue (" + m + ", " + t + ")");
if ( m.size() != 0 ) {
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after dequeue (" + m.first() + ", " + t.top() + ")");
}
if ( m.size() != 0 && ( ( new it.unimi.dsi.fastutil.ints.IntOpenHashSet( m.heap, 0, m.size ) ).size() == m.size() ) ) {
refArray[ m.first() ] = genKey();
m.changed();
t.change();
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ after change (" + m + ", " + t + ")");
if ( m.size() != 0 ) {
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after change (" + m.first() + ", " + t.top() + ")");
}
}
}
/* Now we check that m actually holds the same data. */
m.clear();
ensure( m.isEmpty(), "Error (" + seed + "): m is not empty after clear()" );
System.out.println("Test OK");
}
public static void main( String args[] ) {
int n = Integer.parseInt(args[1]);
if ( args.length > 2 ) r = new java.util.Random( seed = Long.parseLong( args[ 2 ] ) );
try {
if ("speedTest".equals(args[0]) || "speedComp".equals(args[0])) speedTest( n, "speedComp".equals(args[0]) );
else if ( "test".equals( args[0] ) ) test(n);
} catch( Throwable e ) {
e.printStackTrace( System.err );
System.err.println( "seed: " + seed );
}
}
#endif
}
fastutil-7.0.2/drv/HeapSesquiIndirectDoublePriorityQueue.drv 0000644 0000000 0000000 00000062060 12502261336 023141 0 ustar root wheel /*
* Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
#if #keyclass(Object)
import java.util.Comparator;
import it.unimi.dsi.fastutil.IndirectDoublePriorityQueue;
#endif
/** A type-specific heap-based sesqui-indirect double priority queue.
*
* null
, indicating that natural comparison should take place. Of course,
* it makes little sense having them equal.
*/
public class HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE KEY_GENERIC extends HEAP_SEMI_INDIRECT_PRIORITY_QUEUE KEY_GENERIC implements INDIRECT_DOUBLE_PRIORITY_QUEUE KEY_GENERIC {
/** The secondary indirect queue. */
protected HEAP_INDIRECT_PRIORITY_QUEUE KEY_GENERIC secondaryQueue;
/** Creates a new empty queue with a given capacity.
*
* @param refArray the reference array.
* @param capacity the initial capacity of this queue.
* @param c the primary comparator used in this queue, or null
for the natural order.
* @param d the secondary comparator used in this queue, or null
for the natural order.
*/
public HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity, KEY_COMPARATOR KEY_SUPER_GENERIC c, KEY_COMPARATOR KEY_SUPER_GENERIC d ) {
super( refArray, capacity, c );
secondaryQueue = new HEAP_INDIRECT_PRIORITY_QUEUE KEY_GENERIC( refArray, capacity, d );
}
/** Creates a new empty queue with a given capacity.
*
* c
.
*
* @param refArray the reference array.
* @param capacity the initial capacity of this queue.
* @param c the primary comparator used in this queue, or null
for the natural order.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, int capacity, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
super( refArray, capacity, c );
secondaryQueue = new HEAP_INDIRECT_PRIORITY_QUEUE KEY_GENERIC( refArray, capacity, c == null ? COMPARATORS.OPPOSITE_COMPARATOR : COMPARATORS.oppositeComparator( c ) );
}
/** Creates a new empty queue with a given capacity and natural order as primary comparator.
*
* null
for the natural order.
* @param d the secondary comparator used in this queue, or null
for the natural order.
*/
public HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, KEY_COMPARATOR KEY_SUPER_GENERIC c, KEY_COMPARATOR KEY_SUPER_GENERIC d ) {
this( refArray, refArray.length, c, d );
}
/** Creates a new empty queue with capacity equal to the length of the reference array.
*
* c
.
*
* @param refArray the reference array.
* @param c the primary comparator used in this queue, or null
for the natural order.
*/
public HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( KEY_GENERIC_TYPE[] refArray, KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, refArray.length, c );
}
/** Creates a new empty queue with capacity equal to the length of the reference array and natural order as primary comparator.
*
* size
element of the array will be rearranged so to form a heap, and
* moreover the array will be cloned and wrapped in a secondary queue (this is
* more efficient than enqueing the elements of a
one by one).
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param size the number of elements to be included in the queue.
* @param c the primary comparator used in this queue, or null
for the natural order.
* @param d the secondary comparator used in this queue, or null
for the natural order.
*/
public HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size, final KEY_COMPARATOR KEY_SUPER_GENERIC c, final KEY_COMPARATOR KEY_SUPER_GENERIC d ) {
super( refArray, a, size, c );
this.secondaryQueue = new HEAP_INDIRECT_PRIORITY_QUEUE KEY_GENERIC( refArray, a.clone(), size, d );
}
/** Wraps a given array in a queue using the given comparators.
*
* a
one by one).
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param c the primary comparator used in this queue, or null
for the natural order.
* @param d the secondary comparator used in this queue, or null
for the natural order.
*/
public HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, final KEY_COMPARATOR KEY_SUPER_GENERIC c, final KEY_COMPARATOR KEY_SUPER_GENERIC d ) {
this( refArray, a, a.length, c, d );
}
/** Wraps a given array in a queue using a given comparator.
*
* size
element of the array will be rearranged so to form a heap, and
* moreover the array will be cloned and wrapped in a secondary queue (this is
* more efficient than enqueing the elements of a
one by one).
*
* c
.
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param size the number of elements to be included in the queue.
* @param c the primary comparator used in this queue, or null
for the natural order.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, a, size, c, c == null ? COMPARATORS.OPPOSITE_COMPARATOR : COMPARATORS.oppositeComparator( c ) );
}
/** Wraps a given array in a queue using a given comparator.
*
* a
one by one).
*
* c
.
*
* @param refArray the reference array.
* @param a an array of indices into refArray
.
* @param c the primary comparator used in this queue, or null
for the natural order.
*/
public HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
this( refArray, a, a.length, c );
}
/** Wraps a given array in a queue using the natural order.
*
* size
element of the array will be rearranged so to form a heap, and
* moreover the array will be cloned and wrapped in a secondary queue (this is
* more efficient than enqueing the elements of a
one by one).
*
* refArray
.
* @param size the number of elements to be included in the queue.
*/
public HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a, int size ) {
this( refArray, a, size, null );
}
/** Wraps a given array in a queue using the natural order.
*
* a
one by one).
*
* refArray
.
*/
public HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( final KEY_GENERIC_TYPE[] refArray, final int[] a ) {
this( refArray, a, a.length );
}
public void enqueue( int x ) {
secondaryQueue.enqueue( x );
super.enqueue( x );
}
public int dequeue() {
final int result = super.dequeue();
secondaryQueue.remove( result );
return result;
}
public int secondaryFirst() {
return secondaryQueue.first();
}
public int secondaryLast() { throw new UnsupportedOperationException(); }
public int secondaryFront( final int[] a ) {
return secondaryQueue.front( a );
}
public void changed() {
secondaryQueue.changed( heap[ 0 ] );
super.changed();
}
public void allChanged() {
secondaryQueue.allChanged();
super.allChanged();
}
public void clear() {
super.clear();
secondaryQueue.clear();
}
/** Trims the underlying queues so they have exactly {@link #size()} elements.
*/
public void trim() {
super.trim();
secondaryQueue.trim();
}
/** Returns the secondary comparator of this queue.
*
* @return the secondary comparator of this queue.
* @see #secondaryFirst()
*/
public KEY_COMPARATOR KEY_SUPER_GENERIC secondaryComparator() { return secondaryQueue.comparator(); }
#ifdef TEST
/** The original class, now just used for testing. */
private static class TestQueue {
/** The reference array */
private KEY_TYPE refArray[];
/** Its length */
private int N;
/** The number of elements in the heaps */
private int n;
/** The two comparators */
private KEY_COMPARATOR primaryComp, secondaryComp;
/** Two indirect heaps are used, called primary
and secondary
. Each of them contains
a permutation of n
among the indices 0, 1, ..., N
-1 in such a way that the corresponding
objects be sorted with respect to the two comparators.
We also need an array inSec[]
so that inSec[k]
is the index of secondary
containing k
.
*/
private int primary[], secondary[], inSec[];
/** Builds a double indirect priority queue.
* @param refArray The reference array.
* @param primaryComp The primary comparator.
* @param secondaryComp The secondary comparator.
*/
public TestQueue( KEY_TYPE refArray[], KEY_COMPARATOR primaryComp, KEY_COMPARATOR secondaryComp ) {
this.refArray = refArray;
this.N = refArray.length;
assert this.N != 0;
this.n = 0;
this.primaryComp = primaryComp;
this.secondaryComp = secondaryComp;
this.primary = new int[N];
this.secondary = new int[N];
this.inSec = new int[N];
java.util.Arrays.fill( inSec, -1 );
}
/** Adds an index to the queue. Notice that the index should not be already present in the queue.
* @param i The index to be added
*/
public void add( int i ) {
if ( i < 0 || i >= refArray.length ) throw new IndexOutOfBoundsException();
if ( inSec[ i ] >= 0 ) throw new IllegalArgumentException();
primary[n] = i;
secondary[n] = i; inSec[i] = n;
n++;
swimPrimary( n-1 );
swimSecondary( n-1 );
}
/** Heapify the primary heap.
* @param i The index of the heap to be heapified.
*/
private void heapifyPrimary( int i ) {
int dep = primary[i];
int child;
while ( ( child = 2*i+1 ) < n ) {
if ( child+1 < n && primaryComp.compare( refArray[primary[child+1]], refArray[primary[child]] ) < 0 ) child++;
if ( primaryComp.compare( refArray[dep], refArray[primary[child]] ) <= 0 ) break;
primary[i] = primary[child];
i = child;
}
primary[i] = dep;
}
/** Heapify the secondary heap.
* @param i The index of the heap to be heapified.
*/
private void heapifySecondary( int i ) {
int dep = secondary[i];
int child;
while ( ( child = 2*i+1 ) < n ) {
if ( child+1 < n && secondaryComp.compare( refArray[secondary[child+1]], refArray[secondary[child]] ) < 0 ) child++;
if ( secondaryComp.compare( refArray[dep], refArray[secondary[child]] ) <= 0 ) break;
secondary[i] = secondary[child]; inSec[secondary[i]] = i;
i = child;
}
secondary[i] = dep; inSec[secondary[i]] = i;
}
/** Swim and heapify the primary heap.
* @param i The index to be moved.
*/
private void swimPrimary( int i ) {
int dep = primary[i];
int parent;
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( primaryComp.compare( refArray[primary[parent]], refArray[dep] ) <= 0 ) break;
primary[i] = primary[parent];
i = parent;
}
primary[i] = dep;
heapifyPrimary( i );
}
/** Swim and heapify the secondary heap.
* @param i The index to be moved.
*/
private void swimSecondary( int i ) {
int dep = secondary[i];
int parent;
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( secondaryComp.compare( refArray[secondary[parent]], refArray[dep] ) <= 0 ) break;
secondary[i] = secondary[parent]; inSec[secondary[i]] = i;
i = parent;
}
secondary[i] = dep; inSec[secondary[i]] = i;
heapifySecondary( i );
}
/** Returns the minimum element with respect to the primary comparator.
@return the minimum element.
*/
public int top() {
if ( n == 0 ) throw new java.util.NoSuchElementException();
return primary[0];
}
/** Returns the minimum element with respect to the secondary comparator.
@return the minimum element.
*/
public int secTop() {
if ( n == 0 ) throw new java.util.NoSuchElementException();
return secondary[0];
}
/** Removes the minimum element with respect to the primary comparator.
* @return the removed element.
*/
public void remove() {
if ( n == 0 ) throw new java.util.NoSuchElementException();
int result = primary[0];
int ins = inSec[result];
inSec[ result ] = -1;
// Copy a leaf
primary[0] = primary[n-1];
if ( ins == n-1 ) {
n--;
heapifyPrimary( 0 );
return;
}
secondary[ins] = secondary[n-1];
inSec[secondary[ins]] = ins;
// Heapify
n--;
heapifyPrimary( 0 );
swimSecondary( ins );
}
public void clear() {
while( size() != 0 ) remove();
}
public void remove( int index ) {
if ( n == 0 ) throw new java.util.NoSuchElementException();
int result = primary[index];
int ins = inSec[result];
inSec[ result ] = -1;
// Copy a leaf
primary[index] = primary[n-1];
if ( ins == n-1 ) {
n--;
swimPrimary( index );
return;
}
secondary[ins] = secondary[n-1];
inSec[secondary[ins]] = ins;
// Heapify
n--;
swimPrimary( index );
swimSecondary( ins );
}
/** Signals that the minimum element with respect to the comparator has changed.
*/
public void change() {
int ins = inSec[primary[0]];
heapifyPrimary( 0 );
swimSecondary( ins );
}
public void change(int index) {
int ins = inSec[primary[index]];
swimPrimary( index );
swimSecondary( ins );
}
/** Returns the number of elements in the queue.
* @return the size of the queue
*/
public int size() {
return n;
}
public String toString() {
String s = "[";
for ( int i = 0; i < n; i++ )
s += refArray[primary[i]]+", ";
return s+ "]";
}
}
private static long seed = System.currentTimeMillis();
private static java.util.Random r = new java.util.Random( seed );
private static KEY_TYPE genKey() {
#if #keyclass(Byte) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#elif #keyclass(Object)
return Integer.toBinaryString( r.nextInt() );
#else
return new java.io.Serializable() {};
#endif
}
private static java.text.NumberFormat format = new java.text.DecimalFormat( "#,###.00" );
private static java.text.FieldPosition p = new java.text.FieldPosition( 0 );
private static String format( double d ) {
StringBuffer s = new StringBuffer();
return format.format( d, s, p ).toString();
}
private static void speedTest( int n, boolean comp ) {
System.out.println( "There are presently no speed tests for this class." );
}
private static void fatal( String msg ) {
System.out.println( msg );
System.exit( 1 );
}
private static void ensure( boolean cond, String msg ) {
if ( cond ) return;
fatal( msg );
}
private static boolean heapEqual( int[] a, int[] b, int sizea, int sizeb ) {
if ( sizea != sizeb ) return false;
while( sizea-- != 0 ) if ( a[sizea] != b[sizea] ) return false;
return true;
}
private static boolean invEqual( int inva[], int[] invb ) {
int i = inva.length;
while( i-- != 0 ) if ( inva[ i ] != invb[ i ] ) return false;
return true;
}
protected static void test( int n ) {
long ms;
Exception mThrowsIllegal, tThrowsIllegal, mThrowsOutOfBounds, tThrowsOutOfBounds, mThrowsNoElement, tThrowsNoElement;
int rm = 0, rt = 0;
KEY_TYPE[] refArray = new KEY_TYPE[ n ];
for( int i = 0; i < n; i++ ) refArray[ i ] = genKey();
HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE m = new HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUE( refArray );
TestQueue t = new TestQueue( refArray, COMPARATORS.NATURAL_COMPARATOR, COMPARATORS.OPPOSITE_COMPARATOR );
/* We add pairs to t. */
for( int i = 0; i < n / 2; i++ ) {
t.add( i );
m.enqueue( i );
}
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in primary heap after creation (" + m + ", " + t + ")" );
ensure( heapEqual( m.secondaryQueue.heap, t.secondary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in secondary heap after creation (" + m + ", " + t + ")" );
ensure( invEqual( m.secondaryQueue.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after creation (" + java.util.Arrays.toString( m.secondaryQueue.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
/* Now we add and remove random data in m and t, checking that the result is the same. */
for(int i=0; i<2*n; i++ ) {
if ( r.nextDouble() < 0.01 ) {
t.clear();
m.clear();
for( int j = 0; j < n / 2; j++ ) {
t.add( j );
m.enqueue( j );
}
}
int T = r.nextInt( 2 * n );
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
m.enqueue( T );
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
try {
t.add( T );
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): enqueue() divergence in IndexOutOfBoundsException for " + T + " (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): enqueue() divergence in IllegalArgumentException for " + T + " (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in primary heap after enqueue (" + m + ", " + t + ")" );
ensure( heapEqual( m.secondaryQueue.heap, t.secondary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in secondary heap after enqueue (" + m + ", " + t + ")" );
ensure( invEqual( m.secondaryQueue.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after enqueue (" + java.util.Arrays.toString( m.secondaryQueue.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
if ( m.size() != 0 ) {
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after enqueue (" + m.first() + ", " + t.top() + ")");
ensure( m.secondaryFirst() == t.secTop(), "Error (" + seed + "): m and t differ in secondary first element after enqueue (" + m.secondaryFirst() + ", " + t.secTop() + ")");
}
mThrowsNoElement = tThrowsNoElement = mThrowsOutOfBounds = tThrowsOutOfBounds = mThrowsIllegal = tThrowsIllegal = null;
try {
rm = m.dequeue();
}
catch ( IndexOutOfBoundsException e ) { mThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { mThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { mThrowsNoElement = e; }
try {
rt = t.top();
t.remove();
}
catch ( IndexOutOfBoundsException e ) { tThrowsOutOfBounds = e; }
catch ( IllegalArgumentException e ) { tThrowsIllegal = e; }
catch ( java.util.NoSuchElementException e ) { tThrowsNoElement = e; }
ensure( ( mThrowsOutOfBounds == null ) == ( tThrowsOutOfBounds == null ), "Error (" + seed + "): dequeue() divergence in IndexOutOfBoundsException (" + mThrowsOutOfBounds + ", " + tThrowsOutOfBounds + ")" );
ensure( ( mThrowsIllegal == null ) == ( tThrowsIllegal == null ), "Error (" + seed + "): dequeue() divergence in IllegalArgumentException (" + mThrowsIllegal + ", " + tThrowsIllegal + ")" );
ensure( ( mThrowsNoElement == null ) == ( tThrowsNoElement == null ), "Error (" + seed + "): dequeue() divergence in java.util.NoSuchElementException (" + mThrowsNoElement + ", " + tThrowsNoElement + ")" );
if ( mThrowsOutOfBounds == null ) ensure( rt == rm , "Error (" + seed + "): divergence in dequeue() between t and m (" + rt + ", " + rm + ")" );
ensure( heapEqual( m.heap, t.primary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in primary heap after dequeue (" + m + ", " + t + ")" );
ensure( heapEqual( m.secondaryQueue.heap, t.secondary, m.size(), t.size() ), "Error (" + seed + "): m and t differ in secondary heap after dequeue (" + m + ", " + t + ")" );
ensure( invEqual( m.secondaryQueue.inv, t.inSec ), "Error (" + seed + "): m and t differ in inversion arrays after dequeue (" + java.util.Arrays.toString( m.secondaryQueue.inv ) + ", " + java.util.Arrays.toString( t.inSec ) + ")" );
if ( m.size() != 0 ) {
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after dequeue (" + m.first() + ", " + t.top() + ")");
ensure( m.secondaryFirst() == t.secTop(), "Error (" + seed + "): m and t differ in secondary first element after dequeue (" + m.secondaryFirst() + ", " + t.secTop() + ")");
}
if ( m.size() != 0 ) {
refArray[ m.first() ] = genKey();
m.changed();
t.change();
ensure( m.size() == t.size(), "Error (" + seed + "): m and t differ in size after change (" + m.size() + ", " + t.size() + ")");
ensure( m.first() == t.top(), "Error (" + seed + "): m and t differ in first element after change (" + m.first() + ", " + t.top() + ")");
ensure( m.secondaryFirst() == t.secTop(), "Error (" + seed + "): m and t differ in secondary first element after change (" + m.secondaryFirst() + ", " + t.secTop() + ")");
}
}
/* Now we check that m actually holds the same data. */
m.clear();
ensure( m.isEmpty(), "Error (" + seed + "): m is not empty after clear()" );
System.out.println("Test OK");
}
public static void main( String args[] ) {
int n = Integer.parseInt(args[1]);
if ( args.length > 2 ) r = new java.util.Random( seed = Long.parseLong( args[ 2 ] ) );
try {
if ("speedTest".equals(args[0]) || "speedComp".equals(args[0])) speedTest( n, "speedComp".equals(args[0]) );
else if ( "test".equals( args[0] ) ) test(n);
} catch( Throwable e ) {
e.printStackTrace( System.err );
System.err.println( "seed: " + seed );
}
}
#endif
}
fastutil-7.0.2/drv/Heaps.drv 0000644 0000000 0000000 00000007517 12502261336 014554 0 ustar root wheel /*
* Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
#if #keyclass(Object)
import java.util.Comparator;
#endif
/** A class providing static methods and objects that do useful things with heaps.
*
* null
for the natural order.
* @return the new position of the element of index i
.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static KEY_GENERIC int downHeap( final KEY_GENERIC_TYPE[] heap, final int size, int i, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
if ( i >= size ) throw new IllegalArgumentException( "Heap position (" + i + ") is larger than or equal to heap size (" + size + ")" );
final KEY_GENERIC_TYPE e = heap[ i ];
int child;
if ( c == null )
while ( ( child = 2 * i + 1 ) < size ) {
if ( child + 1 < size && KEY_LESS( heap[ child + 1 ], heap[ child ] ) ) child++;
if ( KEY_LESSEQ( e, heap[ child ] ) ) break;
heap[ i ] = heap[ child ];
i = child;
}
else
while ( ( child = 2 * i + 1 ) < size ) {
if ( child + 1 < size && c.compare( heap[ child + 1 ], heap[ child ] ) < 0 ) child++;
if ( c.compare( e, heap[ child ] ) <= 0 ) break;
heap[ i ] = heap[ child ];
i = child;
}
heap[ i ] = e;
return i;
}
/** Moves the given element up in the heap until it reaches the highest possible position.
*
* @param heap the heap (starting at 0).
* @param size the number of elements in the heap.
* @param i the index of the element that must be moved up.
* @param c a type-specific comparator, or null
for the natural order.
* @return the new position of the element of index i
.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static KEY_GENERIC int upHeap( final KEY_GENERIC_TYPE[] heap, final int size, int i, final KEY_COMPARATOR KEY_GENERIC c ) {
if ( i >= size ) throw new IllegalArgumentException( "Heap position (" + i + ") is larger than or equal to heap size (" + size + ")" );
final KEY_GENERIC_TYPE e = heap[ i ];
int parent;
if ( c == null )
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( KEY_LESSEQ( heap[ parent ], e ) ) break;
heap[ i ] = heap[ parent ];
i = parent;
}
else
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( c.compare( heap[ parent ], e ) <= 0 ) break;
heap[ i ] = heap[ parent ];
i = parent;
}
heap[ i ] = e;
return i;
}
/** Makes an array into a heap.
*
* @param heap the heap (starting at 0).
* @param size the number of elements in the heap.
* @param c a type-specific comparator, or null
for the natural order.
*/
public static KEY_GENERIC void makeHeap( final KEY_GENERIC_TYPE[] heap, final int size, final KEY_COMPARATOR KEY_GENERIC c ) {
int i = size / 2;
while( i-- != 0 ) downHeap( heap, size, i, c );
}
}
fastutil-7.0.2/drv/IndirectDoublePriorityQueue.drv 0000644 0000000 0000000 00000002417 12502261336 021151 0 ustar root wheel /*
* Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import it.unimi.dsi.fastutil.IndirectDoublePriorityQueue;
/** A type-specific {@link IndirectDoublePriorityQueue}.
*
* heap[inv[i]]==i
when
* inv[i]>=0
, and inv[heap[i]]==i
for all elements in the heap.
*/
public class INDIRECT_HEAPS {
private INDIRECT_HEAPS() {}
/** Moves the given element down into the indirect heap until it reaches the lowest possible position.
*
* @param refArray the reference array.
* @param heap the indirect heap (starting at 0).
* @param inv the inversion array.
* @param size the number of elements in the heap.
* @param i the index in the heap of the element to be moved down.
* @param c a type-specific comparator, or null
for the natural order.
* @return the new position in the heap of the element of heap index i
.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static KEY_GENERIC int downHeap( final KEY_GENERIC_TYPE[] refArray, final int[] heap, final int[] inv, final int size, int i, final KEY_COMPARATOR KEY_GENERIC c ) {
if ( i >= size ) throw new IllegalArgumentException( "Heap position (" + i + ") is larger than or equal to heap size (" + size + ")" );
final int e = heap[ i ];
final KEY_GENERIC_TYPE E = refArray[ e ];
int child;
if ( c == null )
while ( ( child = 2 * i + 1 ) < size ) {
if ( child + 1 < size && KEY_LESS( refArray[ heap[ child + 1 ] ], refArray[ heap[ child ] ] ) ) child++;
if ( KEY_LESSEQ( E, refArray[ heap[ child ] ] ) ) break;
heap[ i ] = heap[ child ];
inv[ heap[ i ] ] = i;
i = child;
}
else
while ( ( child = 2 * i + 1 ) < size ) {
if ( child + 1 < size && c.compare( refArray[ heap[ child + 1 ] ], refArray[ heap[ child ] ] ) < 0 ) child++;
if ( c.compare( E, refArray[ heap[ child ] ] ) <= 0 ) break;
heap[ i ] = heap[ child ];
inv[ heap[ i ] ] = i;
i = child;
}
heap[ i ] = e;
inv[ e ] = i;
return i;
}
/** Moves the given element up in the indirect heap until it reaches the highest possible position.
*
* Note that in principle after this call the heap property may be violated.
*
* @param refArray the reference array.
* @param heap the indirect heap (starting at 0).
* @param inv the inversion array.
* @param size the number of elements in the heap.
* @param i the index in the heap of the element to be moved up.
* @param c a type-specific comparator, or null
for the natural order.
* @return the new position in the heap of the element of heap index i
.
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static KEY_GENERIC int upHeap( final KEY_GENERIC_TYPE[] refArray, final int[] heap, final int[] inv, final int size, int i, final KEY_COMPARATOR KEY_GENERIC c ) {
if ( i >= size ) throw new IllegalArgumentException( "Heap position (" + i + ") is larger than or equal to heap size (" + size + ")" );
final int e = heap[ i ];
final KEY_GENERIC_TYPE E = refArray[ e ];
int parent;
if ( c == null )
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( KEY_LESSEQ( refArray[ heap[ parent ] ], E ) ) break;
heap[ i ] = heap[ parent ];
inv[ heap[ i ] ] = i;
i = parent;
}
else
while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
if ( c.compare( refArray[ heap[ parent ] ], E ) <= 0 ) break;
heap[ i ] = heap[ parent ];
inv[ heap[ i ] ] = i;
i = parent;
}
heap[ i ] = e;
inv[ e ] = i;
return i;
}
/** Creates an indirect heap in the given array.
*
* @param refArray the reference array.
* @param offset the first element of the reference array to be put in the heap.
* @param length the number of elements to be put in the heap.
* @param heap the array where the heap is to be created.
* @param inv the inversion array.
* @param c a type-specific comparator, or null
for the natural order.
*/
public static KEY_GENERIC void makeHeap( final KEY_GENERIC_TYPE[] refArray, final int offset, final int length, final int[] heap, final int[] inv, final KEY_COMPARATOR KEY_GENERIC c ) {
ARRAYS.ensureOffsetLength( refArray, offset, length );
if ( heap.length < length ) throw new IllegalArgumentException( "The heap length (" + heap.length + ") is smaller than the number of elements (" + length + ")" );
if ( inv.length < refArray.length ) throw new IllegalArgumentException( "The inversion array length (" + heap.length + ") is smaller than the length of the reference array (" + refArray.length + ")" );
Arrays.fill( inv, 0, refArray.length, -1 );
int i = length;
while( i-- != 0 ) inv[ heap[ i ] = offset + i ] = i;
i = length / 2;
while( i-- != 0 ) downHeap( refArray, heap, inv, length, i, c );
}
/** Creates an indirect heap from a given index array.
*
* @param refArray the reference array.
* @param heap an array containing indices into refArray
.
* @param inv the inversion array.
* @param size the number of elements in the heap.
* @param c a type-specific comparator, or null
for the natural order.
*/
public static KEY_GENERIC void makeHeap( final KEY_GENERIC_TYPE[] refArray, final int[] heap, final int[] inv, final int size, final KEY_COMPARATOR KEY_GENERIC c ) {
int i = size / 2;
while( i-- != 0 ) downHeap( refArray, heap, inv, size, i, c );
}
}
fastutil-7.0.2/drv/IndirectPriorityQueue.drv 0000644 0000000 0000000 00000002276 12502261336 020021 0 ustar root wheel /*
* Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import it.unimi.dsi.fastutil.IndirectPriorityQueue;
/** A type-specific {@link IndirectPriorityQueue}.
*
* for
statements with primitive-type
* loop variables; however, what is (unfortunately) really happening is that at each iteration an
* unboxing (and, in the case of fastutil
type-specific data structures, a boxing) will be performed. Watch out.
*
* @see Iterable
*/
public interface KEY_ITERABLE KEY_GENERIC extends Iterablen
times (possibly stopping
* if {@link #hasNext()} becomes false).
*
* @param n the number of elements to skip.
* @return the number of elements actually skipped.
* @see Iterator#next()
*/
int skip( int n );
}
fastutil-7.0.2/drv/Iterators.drv 0000644 0000000 0000000 00000072631 12502304576 015473 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.NoSuchElementException;
/** A class providing static methods and objects that do useful things with type-specific iterators.
*
* @see Iterator
*/
public class ITERATORS {
private ITERATORS() {}
/** A class returning no elements and a type-specific iterator interface.
*
* element
.
*/
public static KEY_GENERIC KEY_LIST_ITERATOR KEY_GENERIC singleton( final KEY_GENERIC_TYPE element ) {
return new SingletonIterator KEY_GENERIC( element );
}
/** A class to wrap arrays in iterators. */
private static class ArrayIterator KEY_GENERIC extends KEY_ABSTRACT_LIST_ITERATOR KEY_GENERIC {
private final KEY_GENERIC_TYPE[] array;
private final int offset, length;
private int curr;
public ArrayIterator( final KEY_GENERIC_TYPE[] array, final int offset, final int length ) {
this.array = array;
this.offset = offset;
this.length = length;
}
public boolean hasNext() { return curr < length; }
public boolean hasPrevious() { return curr > 0; }
public KEY_GENERIC_TYPE NEXT_KEY() {
if ( ! hasNext() ) throw new NoSuchElementException();
return array[ offset + curr++ ];
}
public KEY_GENERIC_TYPE PREV_KEY() {
if ( ! hasPrevious() ) throw new NoSuchElementException();
return array[ offset + --curr ];
}
public int skip( int n ) {
if ( n <= length - curr ) {
curr += n;
return n;
}
n = length - curr;
curr = length;
return n;
}
public int back( int n ) {
if ( n <= curr ) {
curr -= n;
return n;
}
n = curr;
curr = 0;
return n;
}
public int nextIndex() {
return curr;
}
public int previousIndex() {
return curr - 1;
}
}
/** Wraps the given part of an array into a type-specific list iterator.
*
* length
times, returning consecutive elements of the given
* array starting from the one with index offset
.
*
* @param array an array to wrap into a type-specific list iterator.
* @param offset the first element of the array to be returned.
* @param length the number of elements to return.
* @return an iterator that will return length
elements of array
starting at position offset
.
*/
public static KEY_GENERIC KEY_LIST_ITERATOR KEY_GENERIC wrap( final KEY_GENERIC_TYPE[] array, final int offset, final int length ) {
ARRAYS.ensureOffsetLength( array, offset, length );
return new ArrayIterator KEY_GENERIC( array, offset, length );
}
/** Wraps the given array into a type-specific list iterator.
*
* array
.
*/
public static KEY_GENERIC KEY_LIST_ITERATOR KEY_GENERIC wrap( final KEY_GENERIC_TYPE[] array ) {
return new ArrayIterator KEY_GENERIC( array, 0, array.length );
}
/** Unwraps an iterator into an array starting at a given offset for a given number of elements.
*
* length
, in the given array starting at offset
.
* The number of actually unwrapped elements is returned (it may be less than max
if
* the iterator emits less than max
elements).
*
* @param i a type-specific iterator.
* @param array an array to contain the output of the iterator.
* @param offset the first element of the array to be returned.
* @param max the maximum number of elements to unwrap.
* @return the number of elements unwrapped.
*/
public static KEY_GENERIC int unwrap( final STD_KEY_ITERATOR KEY_EXTENDS_GENERIC i, final KEY_GENERIC_TYPE array[], int offset, final int max ) {
if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" );
if ( offset < 0 || offset + max > array.length ) throw new IllegalArgumentException();
int j = max;
while( j-- != 0 && i.hasNext() ) array[ offset++ ] = i.NEXT_KEY();
return max - j - 1;
}
/** Unwraps an iterator into an array.
*
* max
elements
* will be returned.
*
* @param i a type-specific iterator.
* @param max the maximum number of elements to be unwrapped.
* @return an array containing the elements returned by the iterator (at most max
).
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public static KEY_GENERIC KEY_GENERIC_TYPE[] unwrap( final STD_KEY_ITERATOR KEY_EXTENDS_GENERIC i, int max ) {
if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" );
KEY_GENERIC_TYPE array[] = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ 16 ];
int j = 0;
while( max-- != 0 && i.hasNext() ) {
if ( j == array.length ) array = ARRAYS.grow( array, j + 1 );
array[ j++ ] = i.NEXT_KEY();
}
return ARRAYS.trim( array, j );
}
/** Unwraps an iterator, returning an array.
*
* max
, in the given type-specific collection.
* The number of actually unwrapped elements is returned (it may be less than max
if
* the iterator emits less than max
elements).
*
* @param i a type-specific iterator.
* @param c a type-specific collection array to contain the output of the iterator.
* @param max the maximum number of elements to unwrap.
* @return the number of elements unwrapped. Note that
* this is the number of elements returned by the iterator, which is not necessarily the number
* of elements that have been added to the collection (because of duplicates).
*/
public static KEY_GENERIC int unwrap( final STD_KEY_ITERATOR KEY_GENERIC i, final COLLECTION KEY_SUPER_GENERIC c, final int max ) {
if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" );
int j = max;
while( j-- != 0 && i.hasNext() ) c.add( i.NEXT_KEY() );
return max - j - 1;
}
/** Unwraps an iterator into a type-specific collection.
*
* max
).
*
* @param i a type-specific iterator.
* @param s a type-specific collection.
* @param max the maximum number of elements to be poured.
* @return the number of elements poured. Note that
* this is the number of elements returned by the iterator, which is not necessarily the number
* of elements that have been added to the collection (because of duplicates).
*/
public static KEY_GENERIC int pour( final STD_KEY_ITERATOR KEY_GENERIC i, final COLLECTION KEY_SUPER_GENERIC s, final int max ) {
if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" );
int j = max;
while( j-- != 0 && i.hasNext() ) s.add( i.NEXT_KEY() );
return max - j - 1;
}
/** Pours an iterator into a type-specific collection.
*
* max
). Iteration
* on the returned list is guaranteed to produce the elements in the same order
* in which they appeared in the iterator.
*
*
* @param i a type-specific iterator.
* @param max the maximum number of elements to be poured.
* @return a type-specific list containing the returned elements, up to max
.
*/
public static KEY_GENERIC LIST KEY_GENERIC pour( final STD_KEY_ITERATOR KEY_GENERIC i, int max ) {
final ARRAY_LIST KEY_GENERIC l = new ARRAY_LIST KEY_GENERIC();
pour( i, l, max );
l.trim();
return l;
}
/** Pours an iterator, returning a type-specific list.
*
* i
: changes to one of the iterators
* will affect the other, too.
*
* i
is already type-specific, it will returned and no new object
* will be generated.
*
* @param i an iterator.
* @return a type-specific iterator backed by i
.
*/
#if #keys(primitive)
@SuppressWarnings({"unchecked","rawtypes"})
#endif
public static KEY_GENERIC KEY_ITERATOR KEY_GENERIC AS_KEY_ITERATOR( final Iterator KEY_GENERIC i ) {
if ( i instanceof KEY_ITERATOR ) return (KEY_ITERATOR KEY_GENERIC)i;
return new IteratorWrapper KEY_GENERIC( i );
}
private static class ListIteratorWrapper KEY_GENERIC extends KEY_ABSTRACT_LIST_ITERATOR KEY_GENERIC {
final ListIteratori
: changes to one of the iterators
* will affect the other, too.
*
* i
is already type-specific, it will returned and no new object
* will be generated.
*
* @param i a list iterator.
* @return a type-specific list iterator backed by i
.
*/
#if #keys(primitive)
@SuppressWarnings({"unchecked","rawtypes"})
#endif
public static KEY_GENERIC KEY_LIST_ITERATOR KEY_GENERIC AS_KEY_ITERATOR( final ListIterator KEY_GENERIC i ) {
if ( i instanceof KEY_LIST_ITERATOR ) return (KEY_LIST_ITERATOR KEY_GENERIC)i;
return new ListIteratorWrapper KEY_GENERIC( i );
}
#if #keyclass(Integer) || #keyclass(Byte) || #keyclass(Short) || #keyclass(Character) || #keyclass(Long)
#if #keyclass(Long)
private static class IntervalIterator extends KEY_ABSTRACT_BIDI_ITERATOR {
#else
private static class IntervalIterator extends KEY_ABSTRACT_LIST_ITERATOR {
#endif
private final KEY_TYPE from, to;
KEY_TYPE curr;
public IntervalIterator( final KEY_TYPE from, final KEY_TYPE to ) {
this.from = this.curr = from;
this.to = to;
}
public boolean hasNext() { return curr < to; }
public boolean hasPrevious() { return curr > from; }
public KEY_TYPE NEXT_KEY() {
if ( ! hasNext() ) throw new NoSuchElementException();
return curr++;
}
public KEY_TYPE PREV_KEY() {
if ( ! hasPrevious() ) throw new NoSuchElementException();
return --curr;
}
#if ! #keyclass(Long)
public int nextIndex() { return curr - from; }
public int previousIndex() { return curr - from - 1; }
#endif
public int skip( int n ) {
if ( curr + n <= to ) {
curr += n;
return n;
}
#if ! #keyclass(Long)
n = to - curr;
#else
n = (int)( to - curr );
#endif
curr = to;
return n;
}
public int back( int n ) {
if ( curr - n >= from ) {
curr -= n;
return n;
}
#if ! #keyclass(Long)
n = curr - from ;
#else
n = (int)( curr - from );
#endif
curr = from;
return n;
}
}
#if #keyclass(Long)
/** Creates a type-specific bidirectional iterator over an interval.
*
* from
, from+1
,…, to-1
.
*
* from
to to
.
*/
public static KEY_BIDI_ITERATOR fromTo( final KEY_TYPE from, final KEY_TYPE to ) {
return new IntervalIterator( from, to );
}
#else
/** Creates a type-specific list iterator over an interval.
*
* from
, from+1
,…, to-1
.
*
* @param from the starting element (inclusive).
* @param to the ending element (exclusive).
* @return a type-specific list iterator enumerating the elements from from
to to
.
*/
public static KEY_LIST_ITERATOR fromTo( final KEY_TYPE from, final KEY_TYPE to ) {
return new IntervalIterator( from, to );
}
#endif
#endif
private static class IteratorConcatenator KEY_GENERIC extends KEY_ABSTRACT_ITERATOR KEY_GENERIC {
final KEY_ITERATOR KEY_EXTENDS_GENERIC a[];
int offset, length, lastOffset = -1;
public IteratorConcatenator( final KEY_ITERATOR KEY_EXTENDS_GENERIC a[], int offset, int length ) {
this.a = a;
this.offset = offset;
this.length = length;
advance();
}
private void advance() {
while( length != 0 ) {
if ( a[ offset ].hasNext() ) break;
length--;
offset++;
}
return;
}
public boolean hasNext() {
return length > 0;
}
public KEY_GENERIC_TYPE NEXT_KEY() {
if ( ! hasNext() ) throw new NoSuchElementException();
KEY_GENERIC_TYPE next = a[ lastOffset = offset ].NEXT_KEY();
advance();
return next;
}
public void remove() {
if ( lastOffset == -1 ) throw new IllegalStateException();
a[ lastOffset ].remove();
}
public int skip( int n ) {
lastOffset = -1;
int skipped = 0;
while( skipped < n && length != 0 ) {
skipped += a[ offset ].skip( n - skipped );
if ( a[ offset ].hasNext() ) break;
length--;
offset++;
}
return skipped;
}
}
/** Concatenates all iterators contained in an array.
*
* a[ offset ]
, then those returned
* by a[ offset + 1 ]
, and so on up to
* a[ offset + length - 1 ]
.
*
* @param a an array of iterators.
* @param offset the index of the first iterator to concatenate.
* @param length the number of iterators to concatenate.
* @return an iterator obtained by concatenation of length
elements of a
starting at offset
.
*/
public static KEY_GENERIC KEY_ITERATOR KEY_GENERIC concat( final KEY_ITERATOR KEY_EXTENDS_GENERIC a[], final int offset, final int length ) {
return new IteratorConcatenator KEY_GENERIC( a, offset, length );
}
/** An unmodifiable wrapper class for iterators. */
public static class UnmodifiableIterator KEY_GENERIC extends KEY_ABSTRACT_ITERATOR KEY_GENERIC {
final protected KEY_ITERATOR KEY_GENERIC i;
public UnmodifiableIterator( final KEY_ITERATOR KEY_GENERIC i ) {
this.i = i;
}
public boolean hasNext() { return i.hasNext(); }
public KEY_GENERIC_TYPE NEXT_KEY() { return i.NEXT_KEY(); }
#if #keys(primitive)
public KEY_GENERIC_CLASS next() { return i.next(); }
#endif
}
/** Returns an unmodifiable iterator backed by the specified iterator.
*
* @param i the iterator to be wrapped in an unmodifiable iterator.
* @return an unmodifiable view of the specified iterator.
*/
public static KEY_GENERIC KEY_ITERATOR KEY_GENERIC unmodifiable( final KEY_ITERATOR KEY_GENERIC i ) { return new UnmodifiableIterator KEY_GENERIC( i ); }
/** An unmodifiable wrapper class for bidirectional iterators. */
public static class UnmodifiableBidirectionalIterator KEY_GENERIC extends KEY_ABSTRACT_BIDI_ITERATOR KEY_GENERIC {
final protected KEY_BIDI_ITERATOR KEY_GENERIC i;
public UnmodifiableBidirectionalIterator( final KEY_BIDI_ITERATOR KEY_GENERIC i ) {
this.i = i;
}
public boolean hasNext() { return i.hasNext(); }
public boolean hasPrevious() { return i.hasPrevious(); }
public KEY_GENERIC_TYPE NEXT_KEY() { return i.NEXT_KEY(); }
public KEY_GENERIC_TYPE PREV_KEY() { return i.PREV_KEY(); }
#if #keys(primitive)
public KEY_GENERIC_CLASS next() { return i.next(); }
public KEY_GENERIC_CLASS previous() { return i.previous(); }
#endif
}
/** Returns an unmodifiable bidirectional iterator backed by the specified bidirectional iterator.
*
* @param i the bidirectional iterator to be wrapped in an unmodifiable bidirectional iterator.
* @return an unmodifiable view of the specified bidirectional iterator.
*/
public static KEY_GENERIC KEY_BIDI_ITERATOR KEY_GENERIC unmodifiable( final KEY_BIDI_ITERATOR KEY_GENERIC i ) { return new UnmodifiableBidirectionalIterator KEY_GENERIC( i ); }
/** An unmodifiable wrapper class for list iterators. */
public static class UnmodifiableListIterator KEY_GENERIC extends KEY_ABSTRACT_LIST_ITERATOR KEY_GENERIC {
final protected KEY_LIST_ITERATOR KEY_GENERIC i;
public UnmodifiableListIterator( final KEY_LIST_ITERATOR KEY_GENERIC i ) {
this.i = i;
}
public boolean hasNext() { return i.hasNext(); }
public boolean hasPrevious() { return i.hasPrevious(); }
public KEY_GENERIC_TYPE NEXT_KEY() { return i.NEXT_KEY(); }
public KEY_GENERIC_TYPE PREV_KEY() { return i.PREV_KEY(); }
public int nextIndex() { return i.nextIndex(); }
public int previousIndex() { return i.previousIndex(); }
#if #keys(primitive)
public KEY_GENERIC_CLASS next() { return i.next(); }
public KEY_GENERIC_CLASS previous() { return i.previous(); }
#endif
}
/** Returns an unmodifiable list iterator backed by the specified list iterator.
*
* @param i the list iterator to be wrapped in an unmodifiable list iterator.
* @return an unmodifiable view of the specified list iterator.
*/
public static KEY_GENERIC KEY_LIST_ITERATOR KEY_GENERIC unmodifiable( final KEY_LIST_ITERATOR KEY_GENERIC i ) { return new UnmodifiableListIterator KEY_GENERIC( i ); }
#if #keyclass(Short) || #keyclass(Integer) || #keyclass(Long) || #keyclass(Float) || #keyclass(Double)
/** A wrapper promoting the results of a ByteIterator. */
protected static class ByteIteratorWrapper implements KEY_ITERATOR {
final it.unimi.dsi.fastutil.bytes.ByteIterator iterator;
public ByteIteratorWrapper( final it.unimi.dsi.fastutil.bytes.ByteIterator iterator ) {
this.iterator = iterator;
}
public boolean hasNext() { return iterator.hasNext(); }
public KEY_GENERIC_CLASS next() { return KEY_GENERIC_CLASS.valueOf( iterator.nextByte() ); }
public KEY_TYPE NEXT_KEY() { return iterator.nextByte(); }
public void remove() { iterator.remove(); }
public int skip( final int n ) { return iterator.skip( n ); }
}
/** Returns an iterator backed by the specified byte iterator.
* @return an iterator backed by the specified byte iterator.
*/
public static KEY_ITERATOR wrap( final it.unimi.dsi.fastutil.bytes.ByteIterator iterator ) {
return new ByteIteratorWrapper( iterator );
}
#endif
#if #keyclass(Integer) || #keyclass(Long) || #keyclass(Float) || #keyclass(Double)
/** A wrapper promoting the results of a ShortIterator. */
protected static class ShortIteratorWrapper implements KEY_ITERATOR {
final it.unimi.dsi.fastutil.shorts.ShortIterator iterator;
public ShortIteratorWrapper( final it.unimi.dsi.fastutil.shorts.ShortIterator iterator ) {
this.iterator = iterator;
}
public boolean hasNext() { return iterator.hasNext(); }
public KEY_GENERIC_CLASS next() { return KEY_GENERIC_CLASS.valueOf( iterator.nextShort() ); }
public KEY_TYPE NEXT_KEY() { return iterator.nextShort(); }
public void remove() { iterator.remove(); }
public int skip( final int n ) { return iterator.skip( n ); }
}
/** Returns an iterator backed by the specified short iterator.
* @return an iterator backed by the specified short iterator.
*/
public static KEY_ITERATOR wrap( final it.unimi.dsi.fastutil.shorts.ShortIterator iterator ) {
return new ShortIteratorWrapper( iterator );
}
#endif
#if #keyclass(Long) || #keyclass(Double)
/** A wrapper promoting the results of an IntIterator. */
protected static class IntIteratorWrapper implements KEY_ITERATOR {
final it.unimi.dsi.fastutil.ints.IntIterator iterator;
public IntIteratorWrapper( final it.unimi.dsi.fastutil.ints.IntIterator iterator ) {
this.iterator = iterator;
}
public boolean hasNext() { return iterator.hasNext(); }
public KEY_GENERIC_CLASS next() { return KEY_GENERIC_CLASS.valueOf( iterator.nextInt() ); }
public KEY_TYPE NEXT_KEY() { return iterator.nextInt(); }
public void remove() { iterator.remove(); }
public int skip( final int n ) { return iterator.skip( n ); }
}
/** Returns an iterator backed by the specified integer iterator.
* @return an iterator backed by the specified integer iterator.
*/
public static KEY_ITERATOR wrap( final it.unimi.dsi.fastutil.ints.IntIterator iterator ) {
return new IntIteratorWrapper( iterator );
}
#endif
#if #keyclass(Double)
/** A wrapper promoting the results of a FloatIterator. */
protected static class FloatIteratorWrapper implements KEY_ITERATOR {
final it.unimi.dsi.fastutil.floats.FloatIterator iterator;
public FloatIteratorWrapper( final it.unimi.dsi.fastutil.floats.FloatIterator iterator ) {
this.iterator = iterator;
}
public boolean hasNext() { return iterator.hasNext(); }
public KEY_GENERIC_CLASS next() { return KEY_GENERIC_CLASS.valueOf( iterator.nextFloat() ); }
public KEY_TYPE NEXT_KEY() { return iterator.nextFloat(); }
public void remove() { iterator.remove(); }
public int skip( final int n ) { return iterator.skip( n ); }
}
/** Returns an iterator backed by the specified float iterator.
* @return an iterator backed by the specified float iterator.
*/
public static KEY_ITERATOR wrap( final it.unimi.dsi.fastutil.floats.FloatIterator iterator ) {
return new FloatIteratorWrapper( iterator );
}
#endif
}
fastutil-7.0.2/drv/LinkedOpenCustomDoubleHashMap.drv 0000755 0000000 0000000 00000000000 12502263136 025326 2OpenDoubleHashMap.drv ustar root wheel fastutil-7.0.2/drv/LinkedOpenCustomDoubleHashSet.drv 0000755 0000000 0000000 00000000000 12502263136 025362 2OpenDoubleHashSet.drv ustar root wheel fastutil-7.0.2/drv/LinkedOpenCustomHashMap.drv 0000755 0000000 0000000 00000000000 12502263136 023040 2OpenHashMap.drv ustar root wheel fastutil-7.0.2/drv/LinkedOpenCustomHashSet.drv 0000755 0000000 0000000 00000000000 12502263136 023074 2OpenHashSet.drv ustar root wheel fastutil-7.0.2/drv/LinkedOpenDoubleHashMap.drv 0000755 0000000 0000000 00000000000 12502263136 024133 2OpenDoubleHashMap.drv ustar root wheel fastutil-7.0.2/drv/LinkedOpenDoubleHashSet.drv 0000755 0000000 0000000 00000000000 12502263136 024167 2OpenDoubleHashSet.drv ustar root wheel fastutil-7.0.2/drv/LinkedOpenHashMap.drv 0000755 0000000 0000000 00000000000 12502263136 021645 2OpenHashMap.drv ustar root wheel fastutil-7.0.2/drv/LinkedOpenHashSet.drv 0000755 0000000 0000000 00000000000 12502263136 021701 2OpenHashSet.drv ustar root wheel fastutil-7.0.2/drv/List.drv 0000644 0000000 0000000 00000015175 12502261336 014426 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import java.util.List;
#if ! #keyclass(Reference)
/** A type-specific {@link List}; provides some additional methods that use polymorphism to avoid (un)boxing.
*
* >, COLLECTION KEY_GENERIC {
#else
/** A type-specific {@link List}; provides some additional methods that use polymorphism to avoid (un)boxing.
*
*
fastutil
5, replaced by {@link #listIterator()}.
*/
@Deprecated
KEY_LIST_ITERATOR KEY_GENERIC KEY_LIST_ITERATOR_METHOD();
/** Returns a type-specific list iterator on the list starting at a given index.
*
* @see #listIterator(int)
* @deprecated As of fastutil
5, replaced by {@link #listIterator(int)}.
*/
@Deprecated
KEY_LIST_ITERATOR KEY_GENERIC KEY_LIST_ITERATOR_METHOD( int index );
/** Returns a type-specific list iterator on the list.
*
* @see List#listIterator()
*/
KEY_LIST_ITERATOR KEY_GENERIC listIterator();
/** Returns a type-specific list iterator on the list starting at a given index.
*
* @see List#listIterator(int)
*/
KEY_LIST_ITERATOR KEY_GENERIC listIterator( int index );
/** Returns a type-specific view of the portion of this list from the index from
, inclusive, to the index to
, exclusive.
* @see List#subList(int,int)
* @deprecated As of fastutil
5, replaced by {@link #subList(int,int)}.
*/
@Deprecated
LIST KEY_GENERIC SUBLIST_METHOD( int from, int to );
/** Returns a type-specific view of the portion of this list from the index from
, inclusive, to the index to
, exclusive.
*
* null
/false
.
*
* @param size the new size.
*/
void size( int size );
/** Copies (hopefully quickly) elements of this type-specific list into the given array.
*
* @param from the start index (inclusive).
* @param a the destination array.
* @param offset the offset into the destination array where to store the first element copied.
* @param length the number of elements to be copied.
*/
void getElements( int from, KEY_TYPE a[], int offset, int length );
/** Removes (hopefully quickly) elements of this type-specific list.
*
* @param from the start index (inclusive).
* @param to the end index (exclusive).
*/
void removeElements( int from, int to );
/** Add (hopefully quickly) elements to this type-specific list.
*
* @param index the index at which to add elements.
* @param a the array containing the elements.
*/
void addElements( int index, KEY_GENERIC_TYPE a[] );
/** Add (hopefully quickly) elements to this type-specific list.
*
* @param index the index at which to add elements.
* @param a the array containing the elements.
* @param offset the offset of the first element to add.
* @param length the number of elements to add.
*/
void addElements( int index, KEY_GENERIC_TYPE a[], int offset, int length );
#if #keys(primitive)
/**
* @see List#add(Object)
*/
boolean add( KEY_TYPE key );
/**
* @see List#add(int,Object)
*/
void add( int index, KEY_TYPE key );
/**
* @see List#add(int,Object)
*/
boolean addAll( int index, COLLECTION c );
/**
* @see List#add(int,Object)
*/
boolean addAll( int index, LIST c );
/**
* @see List#add(int,Object)
*/
boolean addAll( LIST c );
/**
* @see List#get(int)
*/
KEY_TYPE GET_KEY( int index );
/**
* @see List#indexOf(Object)
*/
int indexOf( KEY_TYPE k );
/**
* @see List#lastIndexOf(Object)
*/
int lastIndexOf( KEY_TYPE k );
/**
* @see List#remove(int)
*/
KEY_TYPE REMOVE_KEY( int index );
/**
* @see List#set(int,Object)
*/
KEY_TYPE set( int index, KEY_TYPE k );
#endif
}
fastutil-7.0.2/drv/ListIterator.drv 0000644 0000000 0000000 00000002506 12502261336 016132 0 ustar root wheel /*
* Copyright (C) 2002-2014 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package PACKAGE;
import java.util.ListIterator;
/** A type-specific bidirectional iterator that is also a {@link ListIterator}.
*
* l
.
*/
public static KEY_GENERIC LIST KEY_GENERIC shuffle( final LIST KEY_GENERIC l, final Random random ) {
for( int i = l.size(); i-- != 0; ) {
final int p = random.nextInt( i + 1 );
final KEY_GENERIC_TYPE t = l.GET_KEY( i );
l.set( i, l.GET_KEY( p ) );
l.set( p, t );
}
return l;
}
/** An immutable class representing an empty type-specific list.
*
* element
.
*/
public static KEY_GENERIC LIST KEY_GENERIC singleton( final KEY_GENERIC_TYPE element ) { return new Singleton KEY_GENERIC( element ); }
#if ! #keys(reference)
/** Returns a type-specific immutable list containing only the specified element. The returned list is serializable and cloneable.
*
* @param element the only element of the returned list.
* @return a type-specific immutable list containing just element
.
*/
public static KEY_GENERIC LIST KEY_GENERIC singleton( final Object element ) { return new Singleton KEY_GENERIC( KEY_OBJ2TYPE( element ) ); }
#endif
/** A synchronized wrapper class for lists. */
public static class SynchronizedList KEY_GENERIC extends COLLECTIONS.SynchronizedCollection KEY_GENERIC implements LIST KEY_GENERIC, java.io.Serializable {
private static final long serialVersionUID = -7046029254386353129L;
protected final LIST KEY_GENERIC list; // Due to the large number of methods that are not in COLLECTION, this is worth caching.
protected SynchronizedList( final LIST KEY_GENERIC l, final Object sync ) {
super( l, sync );
this.list = l;
}
protected SynchronizedList( final LIST KEY_GENERIC l ) {
super( l );
this.list = l;
}
public KEY_GENERIC_TYPE GET_KEY( final int i ) { synchronized( sync ) { return list.GET_KEY( i ); } }
public KEY_GENERIC_TYPE set( final int i, final KEY_GENERIC_TYPE k ) { synchronized( sync ) { return list.set( i, k ); } }
public void add( final int i, final KEY_GENERIC_TYPE k ) { synchronized( sync ) { list.add( i, k ); } }
public KEY_GENERIC_TYPE REMOVE_KEY( final int i ) { synchronized( sync ) { return list.REMOVE_KEY( i ); } }
public int indexOf( final KEY_TYPE k ) { synchronized( sync ) { return list.indexOf( k ); } }
public int lastIndexOf( final KEY_TYPE k ) { synchronized( sync ) { return list.lastIndexOf( k ); } }
public boolean addAll( final int index, final Collection extends KEY_GENERIC_CLASS> c ) { synchronized( sync ) { return list.addAll( index, c ); } }
public void getElements( final int from, final KEY_TYPE a[], final int offset, final int length ) { synchronized( sync ) { list.getElements( from, a, offset, length ); } }
public void removeElements( final int from, final int to ) { synchronized( sync ) { list.removeElements( from, to ); } }
public void addElements( int index, final KEY_GENERIC_TYPE a[], int offset, int length ) { synchronized( sync ) { list.addElements( index, a, offset, length ); } }
public void addElements( int index, final KEY_GENERIC_TYPE a[] ) { synchronized( sync ) { list.addElements( index, a ); } }
public void size( final int size ) { synchronized( sync ) { list.size( size ); } }
public KEY_LIST_ITERATOR KEY_GENERIC iterator() { return list.listIterator(); }
public KEY_LIST_ITERATOR KEY_GENERIC listIterator() { return list.listIterator(); }
public KEY_LIST_ITERATOR KEY_GENERIC listIterator( final int i ) { return list.listIterator( i ); }
@Deprecated
public KEY_LIST_ITERATOR KEY_GENERIC KEY_LIST_ITERATOR_METHOD() { return listIterator(); }
@Deprecated
public KEY_LIST_ITERATOR KEY_GENERIC KEY_LIST_ITERATOR_METHOD( final int i ) { return listIterator( i ); }
public LIST KEY_GENERIC subList( final int from, final int to ) { synchronized( sync ) { return synchronize( list.subList( from, to ), sync ); } }
@Deprecated
public LIST KEY_GENERIC SUBLIST_METHOD( final int from, final int to ) { return subList( from, to ); }
public boolean equals( final Object o ) { synchronized( sync ) { return collection.equals( o ); } }
public int hashCode() { synchronized( sync ) { return collection.hashCode(); } }
#if ! #keyclass(Reference)
public int compareTo( final List extends KEY_GENERIC_CLASS> o ) { synchronized( sync ) { return list.compareTo( o ); } }
#endif
#if #keys(primitive)
public boolean addAll( final int index, final COLLECTION c ) { synchronized( sync ) { return list.addAll( index, c ); } }
public boolean addAll( final int index, LIST l ) { synchronized( sync ) { return list.addAll( index, l ); } }
public boolean addAll( LIST l ) { synchronized( sync ) { return list.addAll( l ); } }
public KEY_GENERIC_CLASS get( final int i ) { synchronized( sync ) { return list.get( i ); } }
public void add( final int i, KEY_GENERIC_CLASS k ) { synchronized( sync ) { list.add( i, k ); } }
public KEY_GENERIC_CLASS set( final int index, KEY_GENERIC_CLASS k ) { synchronized( sync ) { return list.set( index, k ); } }
public KEY_GENERIC_CLASS remove( final int i ) { synchronized( sync ) { return list.remove( i ); } }
public int indexOf( final Object o ) { synchronized( sync ) { return list.indexOf( o ); } }
public int lastIndexOf( final Object o ) { synchronized( sync ) { return list.lastIndexOf( o ); } }
#endif
}
/** Returns a synchronized type-specific list backed by the given type-specific list.
*
* @param l the list to be wrapped in a synchronized list.
* @return a synchronized view of the specified list.
* @see java.util.Collections#synchronizedList(List)
*/
public static KEY_GENERIC LIST KEY_GENERIC synchronize( final LIST KEY_GENERIC l ) { return new SynchronizedList KEY_GENERIC( l ); }
/** Returns a synchronized type-specific list backed by the given type-specific list, using an assigned object to synchronize.
*
* @param l the list to be wrapped in a synchronized list.
* @param sync an object that will be used to synchronize the access to the list.
* @return a synchronized view of the specified list.
* @see java.util.Collections#synchronizedList(List)
*/
public static KEY_GENERIC LIST KEY_GENERIC synchronize( final LIST KEY_GENERIC l, final Object sync ) { return new SynchronizedList KEY_GENERIC( l, sync ); }
/** An unmodifiable wrapper class for lists. */
public static class UnmodifiableList KEY_GENERIC extends COLLECTIONS.UnmodifiableCollection KEY_GENERIC implements LIST KEY_GENERIC, java.io.Serializable {
private static final long serialVersionUID = -7046029254386353129L;
protected final LIST KEY_GENERIC list; // Due to the large number of methods that are not in COLLECTION, this is worth caching.
protected UnmodifiableList( final LIST KEY_GENERIC l ) {
super( l );
this.list = l;
}
public KEY_GENERIC_TYPE GET_KEY( final int i ) { return list.GET_KEY( i ); }
public KEY_GENERIC_TYPE set( final int i, final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public void add( final int i, final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_TYPE REMOVE_KEY( final int i ) { throw new UnsupportedOperationException(); }
public int indexOf( final KEY_TYPE k ) { return list.indexOf( k ); }
public int lastIndexOf( final KEY_TYPE k ) { return list.lastIndexOf( k ); }
public boolean addAll( final int index, final Collection extends KEY_GENERIC_CLASS> c ) { throw new UnsupportedOperationException(); }
public void getElements( final int from, final KEY_TYPE a[], final int offset, final int length ) { list.getElements( from, a, offset, length ); }
public void removeElements( final int from, final int to ) { throw new UnsupportedOperationException(); }
public void addElements( int index, final KEY_GENERIC_TYPE a[], int offset, int length ) { throw new UnsupportedOperationException(); }
public void addElements( int index, final KEY_GENERIC_TYPE a[] ) { throw new UnsupportedOperationException(); }
public void size( final int size ) { list.size( size ); }
public KEY_LIST_ITERATOR KEY_GENERIC iterator() { return listIterator(); }
public KEY_LIST_ITERATOR KEY_GENERIC listIterator() { return ITERATORS.unmodifiable( list.listIterator() ); }
public KEY_LIST_ITERATOR KEY_GENERIC listIterator( final int i ) { return ITERATORS.unmodifiable( list.listIterator( i ) ); }
@Deprecated
public KEY_LIST_ITERATOR KEY_GENERIC KEY_LIST_ITERATOR_METHOD() { return listIterator(); }
@Deprecated
public KEY_LIST_ITERATOR KEY_GENERIC KEY_LIST_ITERATOR_METHOD( final int i ) { return listIterator( i ); }
public LIST KEY_GENERIC subList( final int from, final int to ) { return unmodifiable( list.subList( from, to ) ); }
@Deprecated
public LIST KEY_GENERIC SUBLIST_METHOD( final int from, final int to ) { return subList( from, to ); }
public boolean equals( final Object o ) { return collection.equals( o ); }
public int hashCode() { return collection.hashCode(); }
#if ! #keyclass(Reference)
public int compareTo( final List extends KEY_GENERIC_CLASS> o ) { return list.compareTo( o ); }
#endif
#if #keys(primitive)
public boolean addAll( final int index, final COLLECTION c ) { throw new UnsupportedOperationException(); }
public boolean addAll( final LIST l ) { throw new UnsupportedOperationException(); }
public boolean addAll( final int index, final LIST l ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_CLASS get( final int i ) { return list.get( i ); }
public void add( final int i, KEY_GENERIC_CLASS k ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_CLASS set( final int index, KEY_GENERIC_CLASS k ) { throw new UnsupportedOperationException(); }
public KEY_GENERIC_CLASS remove( final int i ) { throw new UnsupportedOperationException(); }
public int indexOf( final Object o ) { return list.indexOf( o ); }
public int lastIndexOf( final Object o ) { return list.lastIndexOf( o ); }
#endif
}
/** Returns an unmodifiable type-specific list backed by the given type-specific list.
*
* @param l the list to be wrapped in an unmodifiable list.
* @return an unmodifiable view of the specified list.
* @see java.util.Collections#unmodifiableList(List)
*/
public static KEY_GENERIC LIST KEY_GENERIC unmodifiable( final LIST KEY_GENERIC l ) { return new UnmodifiableList KEY_GENERIC( l ); }
#ifdef TEST
private static KEY_TYPE genKey() {
#if #keyclass(Byte ) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#elif #keyclass(Object)
return Integer.toBinaryString( r.nextInt() );
#else
return new java.io.Serializable() {};
#endif
}
private static void testLists( KEY_TYPE k, LIST m, List t, int level ) {
int n = 100;
int c;
long ms;
boolean mThrowsIllegal, tThrowsIllegal, mThrowsNoElement, tThrowsNoElement, mThrowsIndex, tThrowsIndex, mThrowsUnsupp, tThrowsUnsupp;
boolean rt = false, rm = false;
Object Rt = null, Rm = null;
if ( level == 0 ) return;
/* Now we check that m and t are equal. */
if ( !m.equals( t ) || ! t.equals( m ) ) System.err.println("m: " + m + " t: " + t);
ensure( m.equals( t ), "Error (" + level + ", " + seed + "): ! m.equals( t ) at start" );
ensure( t.equals( m ), "Error (" + level + ", " + seed + "): ! t.equals( m ) at start" );
/* Now we check that m actually holds that data. */
for(java.util.Iterator i=t.iterator(); i.hasNext(); ) {
ensure( m.contains( i.next() ), "Error (" + level + ", " + seed + "): m and t differ on an entry after insertion (iterating on t)" );
}
/* Now we check that m actually holds that data, but iterating on m. */
for(java.util.Iterator i=m.listIterator(); i.hasNext(); ) {
ensure( t.contains( i.next() ), "Error (" + level + ", " + seed + "): m and t differ on an entry after insertion (iterating on m)" );
}
/* Now we check that inquiries about random data give the same answer in m and t. For
m we use the polymorphic method. */
for(int i=0; ifastutil
* maps might return {@linkplain #entrySet() entry set} objects of type FastEntrySet
: in this case, {@link #fastIterator() fastIterator()}
* will return an iterator that is guaranteed not to create a large number of objects, possibly
* by returning always the same entry (of course, mutated).
*/
public interface FastEntrySet KEY_VALUE_GENERIC extends ObjectSet<key,value>
.
*/
public static KEY_VALUE_GENERIC MAP KEY_VALUE_GENERIC singleton( final KEY_GENERIC_TYPE key, VALUE_GENERIC_TYPE value ) {
return new Singleton KEY_VALUE_GENERIC( key, value );
}
#if #keys(primitive) || #values(primitive)
/** Returns a type-specific immutable map containing only the specified pair. The returned map is serializable and cloneable.
*
* <key,value>
.
*/
public static KEY_VALUE_GENERIC MAP KEY_VALUE_GENERIC singleton( final KEY_GENERIC_CLASS key, final VALUE_GENERIC_CLASS value ) {
return new Singleton KEY_VALUE_GENERIC( KEY_CLASS2TYPE( key ), VALUE_CLASS2TYPE( value ) );
}
#endif
/** A synchronized wrapper class for maps. */
public static class SynchronizedMap KEY_VALUE_GENERIC extends FUNCTIONS.SynchronizedFunction KEY_VALUE_GENERIC implements MAP KEY_VALUE_GENERIC, java.io.Serializable {
private static final long serialVersionUID = -7046029254386353129L;
protected final MAP KEY_VALUE_GENERIC map;
protected transient volatile ObjectSetnull
.
*
* {@link Hash#PRIMES}[{@link #p}+growthFactor
. */
protected transient int growthFactor = Hash.DEFAULT_GROWTH_FACTOR;
#ifdef Linked
/** The index of the first entry in iteration order. It is valid iff {@link #count} is nonzero; otherwise, it contains -1. */
protected transient int first = -1;
/** The index of the last entry in iteration order. It is valid iff {@link #count} is nonzero; otherwise, it contains -1. */
protected transient int last = -1;
/** For each entry, the next and the previous entry in iteration order
exclusive-or'd together. It is valid only on {@link Hash#OCCUPIED}
entries. The first and the last entry contain the actual successor and
predecessor, respectively, exclusived-or'd with -1. */
protected transient int link[];
#endif
#ifdef Custom
/** The hash strategy of this custom map. */
protected Strategy KEY_GENERIC strategy;
#endif
private static final long serialVersionUID = -7046029254386353129L;
private static final boolean ASSERTS = ASSERTS_VALUE;
#ifdef Custom
/** Creates a new hash map.
*
* The actual table size is the least available prime greater than n
/f
.
*
* @param n the expected number of elements in the hash map.
* @param f the load factor.
* @param strategy the strategy.
* @see Hash#PRIMES
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public OPEN_DOUBLE_HASH_MAP( final int n, final float f, final Strategy KEY_GENERIC strategy ) {
this.strategy = strategy;
#else
/** Creates a new hash map.
*
* The actual table size is the least available prime greater than n
/f
.
*
* @param n the expected number of elements in the hash map.
* @param f the load factor.
* @see Hash#PRIMES
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public OPEN_DOUBLE_HASH_MAP( final int n, final float f ) {
#endif
if ( f <= 0 || f > 1 ) throw new IllegalArgumentException( "Load factor must be greater than 0 and smaller than or equal to 1" );
if ( n < 0 ) throw new IllegalArgumentException( "Hash table size must be nonnegative" );
int l = Arrays.binarySearch( PRIMES, (int)( n / f ) + 1 );
if ( l < 0 ) l = -l - 1;
free = PRIMES[ p = l ];
this.f = f;
this.maxFill = (int)( free * f );
key = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ free ];
value = VALUE_GENERIC_ARRAY_CAST new VALUE_TYPE[ free ];
state = new byte[ free ];
#ifdef Linked
link = new int[ free ];
#endif
}
#ifdef Custom
/** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
*
* @param n the expected number of elements in the hash map.
* @param strategy the strategy.
*/
public OPEN_DOUBLE_HASH_MAP( final int n, final Strategy KEY_GENERIC strategy ) {
this( n, DEFAULT_LOAD_FACTOR, strategy );
}
#else
/** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
*
* @param n the expected number of elements in the hash map.
*/
public OPEN_DOUBLE_HASH_MAP( final int n ) {
this( n, DEFAULT_LOAD_FACTOR );
}
#endif
#ifdef Custom
/** Creates a new hash map with {@link Hash#DEFAULT_INITIAL_SIZE} entries
* and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
* @param strategy the strategy.
*/
public OPEN_DOUBLE_HASH_MAP( final Strategy KEY_GENERIC strategy ) {
this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR, strategy );
}
#else
/** Creates a new hash map with {@link Hash#DEFAULT_INITIAL_SIZE} entries
* and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
*/
public OPEN_DOUBLE_HASH_MAP() {
this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR );
}
#endif
#ifdef Custom
/** Creates a new hash map copying a given one.
*
* @param m a {@link Map} to be copied into the new hash map.
* @param f the load factor.
* @param strategy the strategy.
*/
public OPEN_DOUBLE_HASH_MAP( final Map extends KEY_GENERIC_CLASS, ? extends VALUE_GENERIC_CLASS> m, final float f, final Strategy KEY_GENERIC strategy ) {
this( m.size(), f, strategy );
putAll( m );
}
#else
/** Creates a new hash map copying a given one.
*
* @param m a {@link Map} to be copied into the new hash map.
* @param f the load factor.
*/
public OPEN_DOUBLE_HASH_MAP( final Map extends KEY_GENERIC_CLASS, ? extends VALUE_GENERIC_CLASS> m, final float f ) {
this( m.size(), f );
putAll( m );
}
#endif
#ifdef Custom
/** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given one.
*
* @param m a {@link Map} to be copied into the new hash map.
* @param strategy the strategy.
*/
public OPEN_DOUBLE_HASH_MAP( final Map extends KEY_GENERIC_CLASS, ? extends VALUE_GENERIC_CLASS> m, final Strategy KEY_GENERIC strategy ) {
this( m, DEFAULT_LOAD_FACTOR, strategy );
}
#else
/** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given one.
*
* @param m a {@link Map} to be copied into the new hash map.
*/
public OPEN_DOUBLE_HASH_MAP( final Map extends KEY_GENERIC_CLASS, ? extends VALUE_GENERIC_CLASS> m ) {
this( m, DEFAULT_LOAD_FACTOR );
}
#endif
#ifdef Custom
/** Creates a new hash map copying a given type-specific one.
*
* @param m a type-specific map to be copied into the new hash map.
* @param f the load factor.
* @param strategy the strategy.
*/
public OPEN_DOUBLE_HASH_MAP( final MAP KEY_VALUE_GENERIC m, final float f, final Strategy KEY_GENERIC strategy ) {
this( m.size(), f, strategy );
putAll( m );
}
#else
/** Creates a new hash map copying a given type-specific one.
*
* @param m a type-specific map to be copied into the new hash map.
* @param f the load factor.
*/
public OPEN_DOUBLE_HASH_MAP( final MAP KEY_VALUE_GENERIC m, final float f ) {
this( m.size(), f );
putAll( m );
}
#endif
#ifdef Custom
/** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given type-specific one.
*
* @param m a type-specific map to be copied into the new hash map.
* @param strategy the strategy.
*/
public OPEN_DOUBLE_HASH_MAP( final MAP KEY_VALUE_GENERIC m, final Strategy KEY_GENERIC strategy ) {
this( m, DEFAULT_LOAD_FACTOR, strategy );
}
#else
/** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given type-specific one.
*
* @param m a type-specific map to be copied into the new hash map.
*/
public OPEN_DOUBLE_HASH_MAP( final MAP KEY_VALUE_GENERIC m ) {
this( m, DEFAULT_LOAD_FACTOR );
}
#endif
#ifdef Custom
/** Creates a new hash map using the elements of two parallel arrays.
*
* @param k the array of keys of the new hash map.
* @param v the array of corresponding values in the new hash map.
* @param f the load factor.
* @param strategy the strategy.
* @throws IllegalArgumentException if k
and v
have different lengths.
*/
public OPEN_DOUBLE_HASH_MAP( final KEY_GENERIC_TYPE[] k, final VALUE_GENERIC_TYPE v[], final float f, final Strategy KEY_GENERIC strategy ) {
this( k.length, f, strategy );
if ( k.length != v.length ) throw new IllegalArgumentException( "The key array and the value array have different lengths (" + k.length + " and " + v.length + ")" );
for( int i = 0; i < k.length; i++ ) this.put( k[ i ], v[ i ] );
}
#else
/** Creates a new hash map using the elements of two parallel arrays.
*
* @param k the array of keys of the new hash map.
* @param v the array of corresponding values in the new hash map.
* @param f the load factor.
* @throws IllegalArgumentException if k
and v
have different lengths.
*/
public OPEN_DOUBLE_HASH_MAP( final KEY_GENERIC_TYPE[] k, final VALUE_GENERIC_TYPE v[], final float f ) {
this( k.length, f );
if ( k.length != v.length ) throw new IllegalArgumentException( "The key array and the value array have different lengths (" + k.length + " and " + v.length + ")" );
for( int i = 0; i < k.length; i++ ) this.put( k[ i ], v[ i ] );
}
#endif
#ifdef Custom
/** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using the elements of two parallel arrays.
*
* @param k the array of keys of the new hash map.
* @param v the array of corresponding values in the new hash map.
* @param strategy the strategy.
* @throws IllegalArgumentException if k
and v
have different lengths.
*/
public OPEN_DOUBLE_HASH_MAP( final KEY_GENERIC_TYPE[] k, final VALUE_GENERIC_TYPE v[], final Strategy KEY_GENERIC strategy ) {
this( k, v, DEFAULT_LOAD_FACTOR, strategy );
}
#else
/** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using the elements of two parallel arrays.
*
* @param k the array of keys of the new hash map.
* @param v the array of corresponding values in the new hash map.
* @throws IllegalArgumentException if k
and v
have different lengths.
*/
public OPEN_DOUBLE_HASH_MAP( final KEY_GENERIC_TYPE[] k, final VALUE_GENERIC_TYPE v[] ) {
this( k, v, DEFAULT_LOAD_FACTOR );
}
#endif
#ifdef Custom
/** Returns the hashing strategy.
*
* @return the hashing strategy of this custom hash set.
*/
public Strategy KEY_GENERIC strategy() {
return strategy;
}
#endif
/** Sets the growth factor. Subsequent enlargements will increase the table
* size roughly by a multiplicative factor of 2p/16.
*
* @param growthFactor the new growth factor; it must be positive.
*/
public void growthFactor( int growthFactor ) {
if ( growthFactor <= 0 ) throw new IllegalArgumentException( "Illegal growth factor " + growthFactor );
this.growthFactor = growthFactor;
}
/** Gets the growth factor.
*
* @return the growth factor of this set.
* @see #growthFactor(int)
*/
public int growthFactor() {
return growthFactor;
}
/*
* The following methods implements some basic building blocks used by
* all accessors. They are (and should be maintained) identical to those used in HashSet.drv.
*/
/** Searches for a key, keeping track of a possible insertion point.
*
* @param k the key.
* @return the index of the correct insertion point, if the key is not found; otherwise,
* -i-1, where i is the index of the entry containing the key.
*/
protected final int findInsertionPoint( final KEY_GENERIC_TYPE k ) {
final KEY_GENERIC_TYPE key[] = this.key;
final byte state[] = this.state;
final int n = key.length;
// First of all, we make the key into a positive integer.
#if #keyclass(Object)
final int h, k2i = ( h = KEY2INTHASH( k ) ) & 0x7FFFFFFF;
#else
final int k2i = KEY2INTHASH(k) & 0x7FFFFFFF;
#endif
// The primary hash, a.k.a. starting point.
int h1 = k2i % n;
if ( state[ h1 ] == OCCUPIED && ! KEY_EQUALS( key[ h1 ], k ) ) {
// The secondary hash.
final int h2 = ( k2i % ( n - 2 ) ) + 1;
do {
h1 += h2;
if ( h1 >= n || h1 < 0 ) h1 -= n;
} while( state[ h1 ] == OCCUPIED && ! KEY_EQUALS( key[ h1 ], k ) ); // There's always a FREE entry.
}
if (state[ h1 ] == FREE) return h1;
if (state[ h1 ] == OCCUPIED) return -h1-1; // Necessarily, KEY_EQUALS( key[ h1 ], k ).
/* Tables without deletions will never use code beyond this point. */
final int i = h1; // Remember first available bucket for later.
/** See the comments in the documentation of the interface Hash. */
if ( ASSERTS ) assert state[ h1 ] == REMOVED;
if ( ! KEY_EQUALS( key[ h1 ], k ) ) {
// The secondary hash.
final int h2 = ( k2i % ( n - 2 ) ) + 1;
do {
h1 += h2;
if ( h1 >= n || h1 < 0 ) h1 -= n;
} while( state[ h1 ] != FREE && ! KEY_EQUALS( key[ h1 ], k ) );
}
return state[ h1 ] == OCCUPIED ? -h1-1 : i; // In the first case, necessarily, KEY_EQUALS( key[ h1 ], k ).
}
/** Searches for a key.
*
* @param k the key.
* @return the index of the entry containing the key, or -1 if the key wasn't found.
*/
protected final int findKey( final KEY_GENERIC_TYPE k ) {
final KEY_GENERIC_TYPE key[] = this.key;
final byte state[] = this.state;
final int n = key.length;
// First of all, we make the key into a positive integer.
#if #keyclass(Object)
final int h, k2i = ( h = KEY2INTHASH( k ) ) & 0x7FFFFFFF;
#else
final int k2i = KEY2INTHASH(k) & 0x7FFFFFFF;
#endif
// The primary hash, a.k.a. starting point.
int h1 = k2i % n;
/** See the comments in the documentation of the interface Hash. */
if ( state[ h1 ] != FREE && ! KEY_EQUALS( key[ h1 ], k ) ) {
// The secondary hash.
final int h2 = ( k2i % ( n - 2 ) ) + 1;
do {
h1 += h2;
if ( h1 >= n || h1 < 0 ) h1 -= n;
} while( state[ h1 ] != FREE && ! KEY_EQUALS( key[ h1 ], k ) ); // There's always a FREE entry.
}
return state[ h1 ] == OCCUPIED ? h1 : -1; // In the first case, necessarily, KEY_EQUALS( key[ h1 ], k ).
}
public VALUE_GENERIC_TYPE put(final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE v) {
final int i = findInsertionPoint( k );
if (i < 0) {
final VALUE_GENERIC_TYPE oldValue = value[-i-1];
value[-i-1] = v;
return oldValue;
}
if ( state[i] == FREE ) free--;
state[i] = OCCUPIED;
key[i] = k;
value[i] = v;
#ifdef Linked
if ( count == 0 ) {
first = last = i;
link[ i ] = 0;
}
else {
link[ last ] ^= i ^ -1;
link[ i ] = last ^ -1;
last = i;
}
#endif
if ( ++count >= maxFill ) {
int newP = Math.min( p + growthFactor, PRIMES.length - 1 );
// Just to be sure that size changes when p is very small.
while( PRIMES[ newP ] == PRIMES[ p ] ) newP++;
rehash( newP ); // Table too filled, let's rehash
}
if ( free == 0 ) rehash( p );
if ( ASSERTS ) checkTable();
return defRetValue;
}
#if #values(primitive) || #keys(primitive)
public VALUE_GENERIC_CLASS put(final KEY_GENERIC_CLASS ok, final VALUE_GENERIC_CLASS ov) {
final VALUE_GENERIC_TYPE v = VALUE_CLASS2TYPE(ov);
final KEY_GENERIC_TYPE k = KEY_CLASS2TYPE(ok);
final int i = findInsertionPoint( k );
if (i < 0) {
final VALUE_GENERIC_TYPE oldValue = value[-i-1];
value[-i-1] = v;
return VALUE2OBJ(oldValue);
}
if ( state[i] == FREE ) free--;
state[i] = OCCUPIED;
key[i] = k;
value[i] = v;
#ifdef Linked
if ( count == 0 ) {
first = last = i;
link[ i ] = 0;
}
else {
link[ last ] ^= i ^ -1;
link[ i ] = last ^ -1;
last = i;
}
#endif
if ( ++count >= maxFill ) rehash( Math.min(p+16, PRIMES.length-1) ); // Table too filled, let's rehash
if ( free == 0 ) rehash( p );
if ( ASSERTS ) checkTable();
return OBJECT_DEFAULT_RETURN_VALUE;
}
#endif
public boolean containsValue( final VALUE_TYPE v ) {
final VALUE_GENERIC_TYPE value[] = this.value;
final byte state[] = this.state;
int i = 0, j = count;
while(j-- != 0) {
while(state[ i ] != OCCUPIED ) i++;
if ( VALUE_EQUALS(value[ i ], v ) ) return true;
i++;
}
return false;
}
/* Removes all elements from this map.
*
* null
if no previous entry exists). */
int prev = -1;
/** The entry that will be returned by the next call to {@link java.util.ListIterator#next()} (or null
if no next entry exists). */
int next = -1;
/** The last entry that was returned (or -1 if we did not iterate or used {@link java.util.Iterator#remove()}). */
int curr = -1;
/** The current index (in the sense of a {@link java.util.ListIterator}). Note that this value is not meaningful when this iterator has been created using the nonempty constructor.*/
int index = 0;
MapIterator() {
next = first;
}
MapIterator( final KEY_GENERIC_TYPE from ) {
if ( KEY_EQUALS( key[ last ], from ) ) {
prev = last;
index = count;
}
else {
if ( ! OPEN_DOUBLE_HASH_MAP.this.containsKey( from ) ) throw new IllegalArgumentException( "The key " + from + " does not belong to this set." );
next = first;
int e;
do e = nextEntry(); while( ! KEY_EQUALS( key[ e ], from ) );
curr = -1;
}
}
public boolean hasNext() { return next != -1; }
public boolean hasPrevious() { return prev != -1; }
public int nextIndex() {
return index;
}
public int previousIndex() {
return index - 1;
}
public int nextEntry() {
if ( ! hasNext() ) return size();
curr = next;
next = link[ curr ] ^ prev;
prev = curr;
index++;
return curr;
}
public int previousEntry() {
if ( ! hasPrevious() ) return -1;
curr = prev;
prev = link[ curr ] ^ next;
next = curr;
index--;
return curr;
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
public void remove() {
if ( curr == -1 ) throw new IllegalStateException();
state[ curr ] = REMOVED;
#if #keys(reference)
key[ curr ] = KEY_GENERIC_CAST HashCommon.REMOVED;
#endif
#if #values(reference)
value[ curr ] = null;
#endif
if ( curr == prev ) {
/* If the last operation was a next(), we are removing an entry that preceeds
the current index, and thus we must decrement it. */
index--;
prev = link[ curr ] ^ next;
}
else next = link[ curr ] ^ prev; // curr == next
count--;
/* Now we manually fix the pointers. Because of our knowledge of next
and prev, this is going to be faster than calling fixPointers(). */
if ( prev == -1 ) first = next;
else link[ prev ] ^= curr ^ next;
if ( next == -1 ) last = prev;
else link[ next ] ^= curr ^ prev;
curr = -1;
}
public int skip( final int n ) {
int i = n;
while( i-- != 0 && hasNext() ) nextEntry();
return n - i - 1;
}
public int back( final int n ) {
int i = n;
while( i-- != 0 && hasPrevious() ) previousEntry();
return n - i - 1;
}
}
private class EntryIterator extends MapIterator implements ObjectListIteratortrue
if there was enough memory to rehash the map, false
otherwise.
* @see #trim()
*/
public boolean rehash() {
try {
rehash(p);
}
catch(OutOfMemoryError cantDoIt) { return false; }
return true;
}
/** Rehashes the map, making the table as small as possible.
*
* max(n,{@link #size()})
entries, still satisfying the load factor. If the current
* table size is smaller than or equal to N, this method does
* nothing. Otherwise, it rehashes this map in a table of size
* N.
*
* equals()
is not overriden, it is important
* that the value returned by this method is the same value as
* the one returned by the overriden method.
*
* @return a hash code for this map.
*/
public int hashCode() {
int h = 0, t, i = 0, j = count;
while( j-- != 0 ) {
while( state[ i ] != OCCUPIED ) i++;
t = 0;
#if #keys(reference)
if ( this != key[ i ] )
#endif
t = KEY2JAVAHASH( key[ i ] );
#if #values(reference)
if ( this != value[ i ] )
#endif
t ^= VALUE2JAVAHASH( value[ i ] );
h += t;
i++;
}
return h;
}
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
final KEY_GENERIC_TYPE key[] = this.key;
final VALUE_GENERIC_TYPE value[] = this.value;
final MapIterator i = new MapIterator();
int e, j = count;
s.defaultWriteObject();
while( j-- != 0 ) {
e = i.nextEntry();
s.WRITE_KEY( key[ e ] );
s.WRITE_VALUE( value[ e ] );
}
}
SUPPRESS_WARNINGS_KEY_UNCHECKED
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
// We restore the default growth factor.
growthFactor = Hash.DEFAULT_GROWTH_FACTOR;
// Note that we DO NOT USE the stored p. See CHANGES.
p = Arrays.binarySearch( PRIMES, (int)( count / f ) + 1 );
if ( p < 0 ) p = -p - 1;
final int n = PRIMES[ p ];
maxFill = (int)( n * f );
free = n - count;;
final KEY_GENERIC_TYPE key[] = this.key = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ n ];
final VALUE_GENERIC_TYPE value[] = this.value = VALUE_GENERIC_ARRAY_CAST new VALUE_TYPE[ n ];
final byte state[] = this.state = new byte[ n ];
#ifdef Linked
final int link[] = this.link = new int[ n ];
int prev = -1;
first = last = -1;
#endif
int i, k2i, h1, h2;
KEY_GENERIC_TYPE k;
VALUE_GENERIC_TYPE v;
i = count;
while( i-- != 0 ) {
k = KEY_GENERIC_CAST s.READ_KEY();
v = VALUE_GENERIC_CAST s.READ_VALUE();
k2i = KEY2INTHASH( k ) & 0x7FFFFFFF;
h1 = k2i % n;
if ( state[ h1 ] != FREE ) {
h2 = ( k2i % ( n - 2 ) ) + 1;
do {
h1 += h2;
if ( h1 >= n || h1 < 0 ) h1 -= n;
} while( state[ h1 ] != FREE );
}
state[ h1 ] = OCCUPIED;
key[ h1 ] = k;
value[ h1 ] = v;
#ifdef Linked
if ( first != -1 ) {
link[ prev ] ^= h1;
link[ h1 ] = prev;
prev = h1;
}
else {
prev = first = h1;
link[ h1 ] = -1;
}
#endif
}
#ifdef Linked
last = prev;
if ( prev != -1 ) link[ prev ] ^= -1;
#endif
if ( ASSERTS ) checkTable();
}
#ifdef ASSERTS_CODE
private void checkTable() {
int n = state.length;
while( n-- != 0 )
if ( state[ n ] == OCCUPIED && ! containsKey( key[ n ] ) )
throw new AssertionError( "Hash table has key " + key[ n ] + " marked as occupied, but the key does not belong to the table" );
#ifdef Linked
KEY_BIDI_ITERATOR KEY_GENERIC i = keySet().iterator();
KEY_TYPE k;
n = size();
while( n-- != 0 )
if ( ! containsKey( k = i.NEXT_KEY() ) )
throw new AssertionError( "Linked hash table forward enumerates key " + k + ", but the key does not belong to the table" );
if ( i.hasNext() ) throw new AssertionError( "Forward iterator not exhausted" );
n = size();
if ( n > 0 ) {
i = keySet().iterator( LAST_KEY() );
while( n-- != 0 )
if ( ! containsKey( k = i.PREV_KEY() ) )
throw new AssertionError( "Linked hash table backward enumerates key " + k + ", but the key does not belong to the table" );
if ( i.hasPrevious() ) throw new AssertionError( "Previous iterator not exhausted" );
}
#endif
}
#else
private void checkTable() {}
#endif
#ifdef TEST
private static long seed = System.currentTimeMillis();
private static java.util.Random r = new java.util.Random( seed );
private static KEY_TYPE genKey() {
#if #keyclass(Byte) || #keyclass(Short) || #keyclass(Character)
return (KEY_TYPE)(r.nextInt());
#elif #keys(primitive)
return r.NEXT_KEY();
#elif !#keyclass(Reference)
#ifdef Custom
int i = r.nextInt( 3 );
byte a[] = new byte[ i ];
while( i-- != 0 ) a[ i ] = (byte)r.nextInt();
return a;
#else
return Integer.toBinaryString( r.nextInt() );
#endif
#else
return new java.io.Serializable() {};
#endif
}
private static VALUE_TYPE genValue() {
#if #valueclass(Byte) || #valueclass(Short) || #valueclass(Character)
return (VALUE_TYPE)(r.nextInt());
#elif #values(primitive)
return r.NEXT_VALUE();
#elif !#valueclass(Reference)
return Integer.toBinaryString( r.nextInt() );
#else
return new java.io.Serializable() {};
#endif
}
private static final class ArrayComparator implements java.util.Comparator {
public int compare( Object a, Object b ) {
byte[] aa = (byte[])a;
byte[] bb = (byte[])b;
int length = Math.min( aa.length, bb.length );
for( int i = 0; i < length; i++ ) {
if ( aa[ i ] < bb[ i ] ) return -1;
if ( aa[ i ] > bb[ i ] ) return 1;
}
return aa.length == bb.length ? 0 : ( aa.length < bb.length ? -1 : 1 );
}
}
private static final class MockMap extends java.util.TreeMap {
private java.util.List list = new java.util.ArrayList();
public MockMap( java.util.Comparator c ) { super( c ); }
public Object put( Object k, Object v ) {
if ( ! containsKey( k ) ) list.add( k );
return super.put( k, v );
}
public void putAll( Map m ) {
java.util.Iterator i = m.entrySet().iterator();
while( i.hasNext() ) {
Map.Entry e = (Map.Entry)i.next();
put( e.getKey(), e.getValue() );
}
}
public Object remove( Object k ) {
if ( containsKey( k ) ) {
int i = list.size();
while( i-- != 0 ) if ( comparator().compare( list.get( i ), k ) == 0 ) {
list.remove( i );
break;
}
}
return super.remove( k );
}
private void justRemove( Object k ) { super.remove( k ); }
private java.util.Set justEntrySet() { return super.entrySet(); }
private java.util.Set justKeySet() { return super.keySet(); }
public java.util.Set keySet() {
return new java.util.AbstractSet() {
final java.util.Set keySet = justKeySet();
public boolean contains( Object k ) { return keySet.contains( k ); }
public int size() { return keySet.size(); }
public java.util.Iterator iterator() {
return new java.util.Iterator() {
final java.util.Iterator iterator = list.iterator();
Object curr;
public Object next() { return curr = iterator.next(); }
public boolean hasNext() { return iterator.hasNext(); }
public void remove() {
justRemove( curr );
iterator.remove();
}
};
}
};
}
public java.util.Set entrySet() {
return new java.util.AbstractSet() {
final java.util.Set entrySet = justEntrySet();
public boolean contains( Object k ) { return entrySet.contains( k ); }
public int size() { return entrySet.size(); }
public java.util.Iterator iterator() {
return new java.util.Iterator() {
final java.util.Iterator iterator = list.iterator();
Object curr;
public Object next() {
curr = iterator.next();
#if #valueclass(Reference)
#if #keyclass(Reference)
return new ABSTRACT_MAP.BasicEntry( (Object)curr, (Object)get(curr) ) {
#else
return new ABSTRACT_MAP.BasicEntry( (KEY_CLASS)curr, (Object)get(curr) ) {
#endif
#else
#if #keyclass(Reference)
return new ABSTRACT_MAP.BasicEntry( (Object)curr, (VALUE_CLASS)get(curr) ) {
#else
return new ABSTRACT_MAP.BasicEntry( (KEY_CLASS)curr, (VALUE_CLASS)get(curr) ) {
#endif
#endif
public VALUE_TYPE setValue( VALUE_TYPE v ) {
return VALUE_OBJ2TYPE(put( getKey(), VALUE2OBJ(v) ));
}
};
}
public boolean hasNext() { return iterator.hasNext(); }
public void remove() {
justRemove( ((Map.Entry)curr).getKey() );
iterator.remove();
}
};
}
};
}
}
private static java.text.NumberFormat format = new java.text.DecimalFormat( "#,###.00" );
private static java.text.FieldPosition fp = new java.text.FieldPosition( 0 );
private static String format( double d ) {
StringBuffer s = new StringBuffer();
return format.format( d, s, fp ).toString();
}
private static void speedTest( int n, float f, boolean comp ) {
#ifndef Custom
int i, j;
OPEN_DOUBLE_HASH_MAP m;
#ifdef Linked
java.util.LinkedHashMap t;
#else
java.util.HashMap t;
#endif
KEY_TYPE k[] = new KEY_TYPE[n];
KEY_TYPE nk[] = new KEY_TYPE[n];
VALUE_TYPE v[] = new VALUE_TYPE[n];
long ms;
for( i = 0; i < n; i++ ) {
k[i] = genKey();
nk[i] = genKey();
v[i] = genValue();
}
double totPut = 0, totYes = 0, totNo = 0, totIter = 0, totRemYes = 0, totRemNo = 0, d;
if ( comp ) { for( j = 0; j < 20; j++ ) {
#ifdef Linked
t = new java.util.LinkedHashMap( 16 );
#else
t = new java.util.HashMap( 16 );
#endif
/* We put pairs to t. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) t.put( KEY2OBJ( k[i] ), VALUE2OBJ( v[i] ) );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totPut += d;
System.out.print("Put: " + format( d ) +" K/s " );
/* We check for pairs in t. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) t.containsKey( KEY2OBJ( k[i] ) );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totYes += d;
System.out.print("Yes: " + format( d ) +" K/s " );
/* We check for pairs not in t. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) t.containsKey( KEY2OBJ( nk[i] ) );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totNo += d;
System.out.print("No: " + format( d ) +" K/s " );
/* We iterate on t. */
ms = System.currentTimeMillis();
for( java.util.Iterator it = t.entrySet().iterator(); it.hasNext(); it.next() );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totIter += d;
System.out.print("Iter: " + format( d ) +" K/s " );
/* We delete pairs not in t. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) t.remove( KEY2OBJ( nk[i] ) );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totRemNo += d;
System.out.print("RemNo: " + format( d ) +" K/s " );
/* We delete pairs in t. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) t.remove( KEY2OBJ( k[i] ) );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totRemYes += d;
System.out.print("RemYes: " + format( d ) +" K/s " );
System.out.println();
}
System.out.println();
System.out.println( "java.util Put: " + format( totPut/(j-3) ) + " K/s Yes: " + format( totYes/(j-3) ) + " K/s No: " + format( totNo/(j-3) ) + " K/s Iter: " + format( totIter/(j-3) ) + " K/s RemNo: " + format( totRemNo/(j-3) ) + " K/s RemYes: " + format( totRemYes/(j-3) ) + "K/s" );
System.out.println();
totPut = totYes = totNo = totIter = totRemYes = totRemNo = 0;
}
for( j = 0; j < 20; j++ ) {
m = new OPEN_DOUBLE_HASH_MAP( 16, f );
/* We put pairs to m. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) m.put( k[i], v[i] );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totPut += d;
System.out.print("Put: " + format( d ) +" K/s " );
/* We check for pairs in m. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) m.containsKey( k[i] );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totYes += d;
System.out.print("Yes: " + format( d ) +" K/s " );
/* We check for pairs not in m. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) m.containsKey( nk[i] );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totNo += d;
System.out.print("No: " + format( d ) +" K/s " );
/* We iterate on m. */
ms = System.currentTimeMillis();
for( java.util.Iterator it = m.entrySet().iterator(); it.hasNext(); it.next() );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totIter += d;
System.out.print("Iter: " + format( d ) +" K/s " );
/* We delete pairs not in m. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) m.remove( nk[i] );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totRemNo += d;
System.out.print("RemNo: " + format( d ) +" K/s " );
/* We delete pairs in m. */
ms = System.currentTimeMillis();
for( i = 0; i < n; i++ ) m.remove( k[i] );
d = 1.0 * n / (System.currentTimeMillis() - ms );
if ( j > 2 ) totRemYes += d;
System.out.print("RemYes: " + format( d ) +" K/s " );
System.out.println();
}
System.out.println();
System.out.println( "fastutil Put: " + format( totPut/(j-3) ) + " K/s Yes: " + format( totYes/(j-3) ) + " K/s No: " + format( totNo/(j-3) ) + " K/s Iter: " + format( totIter/(j-3) ) + " K/s RemNo: " + format( totRemNo/(j-3) ) + " K/s RemYes: " + format( totRemYes/(j-3) ) + " K/s" );
System.out.println();
#endif
}
private static boolean valEquals(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
private static void fatal( String msg ) {
System.out.println( msg );
System.exit( 1 );
}
private static void ensure( boolean cond, String msg ) {
if ( cond ) return;
fatal( msg );
}
protected static void test( int n, float f ) {
#ifdef Custom
OPEN_DOUBLE_HASH_MAP m = new OPEN_DOUBLE_HASH_MAP(Hash.DEFAULT_INITIAL_SIZE, f, it.unimi.dsi.fastutil.bytes.ByteArrays.HASH_STRATEGY);
#else
OPEN_DOUBLE_HASH_MAP m = new OPEN_DOUBLE_HASH_MAP(Hash.DEFAULT_INITIAL_SIZE, f);
#endif
#ifdef Linked
#ifdef Custom
Map t = new MockMap( new ArrayComparator() );
#else
Map t = new java.util.LinkedHashMap();
#endif
#else
#ifdef Custom
Map t = new java.util.TreeMap(new ArrayComparator());
#else
Map t = new java.util.HashMap();
#endif
#endif
/* First of all, we fill t with random data. */
for(int i=0; inull
.
*
* {@link Hash#PRIMES}[{@link #p}+growthFactor
. */
protected transient int growthFactor = Hash.DEFAULT_GROWTH_FACTOR;
#ifdef Linked
/** The index of the first entry in iteration order. It is valid iff {@link #count} is nonzero; otherwise, it contains -1. */
protected transient int first = -1;
/** The index of the last entry in iteration order. It is valid iff {@link #count} is nonzero; otherwise, it contains -1. */
protected transient int last = -1;
/** For each entry, the next and the previous entry in iteration order
exclusive-or'd together. It is valid only on {@link Hash#OCCUPIED}
entries. The first and the last entry contain the actual successor and
predecessor, respectively, exclusived-or'd with -1. */
protected transient int link[];
#endif
#ifdef Custom
/** The hash strategy of this custom set. */
protected Strategyn
/f
.
*
* @param n the expected number of elements in the hash set.
* @param f the load factor.
* @param strategy the strategy.
* @see Hash#PRIMES
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public OPEN_DOUBLE_HASH_SET( final int n, final float f, final Strategyn
/f
.
*
* @param n the expected number of elements in the hash set.
* @param f the load factor.
* @see Hash#PRIMES
*/
SUPPRESS_WARNINGS_KEY_UNCHECKED
public OPEN_DOUBLE_HASH_SET( final int n, final float f ) {
#endif
if ( f <= 0 || f > 1 ) throw new IllegalArgumentException( "Load factor must be greater than 0 and smaller than or equal to 1" );
if ( n < 0 ) throw new IllegalArgumentException( "Hash table size must be nonnegative" );
int l = Arrays.binarySearch( PRIMES, (int)( n / f ) + 1 );
if ( l < 0 ) l = -l - 1;
free = PRIMES[ p = l ];
this.f = f;
this.maxFill = (int)( free * f );
key = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ free ];
state = new byte[ free ];
#ifdef Linked
link = new int[ free ];
#endif
}
#ifdef Custom
/** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
*
* @param n the expected number of elements in the hash set.
* @param strategy the strategy.
*/
public OPEN_DOUBLE_HASH_SET( final int n, final Strategy