[libfastutil-java] 01/15: Imported Upstream version 7.0.11

Tony Mancill tmancill at moszumanska.debian.org
Sun Jul 10 22:05:29 UTC 2016


This is an automated email from the git hooks/post-receive script.

tmancill pushed a commit to branch experimental
in repository libfastutil-java.

commit b3425b59e01cd93b119d2da28a5d2467136d415d
Author: tony mancill <tmancill at debian.org>
Date:   Sun Jul 10 14:48:18 2016 -0700

    Imported Upstream version 7.0.11
---
 CHANGES                                            |   62 +
 README => README.md                                |   28 +-
 build.properties                                   |    4 +-
 build.xml                                          |   46 +-
 drv/AVLTreeMap.drv                                 |  310 ++-
 drv/AVLTreeSet.drv                                 |   11 +-
 drv/AbstractBidirectionalIterator.drv              |    2 +-
 drv/AbstractBigList.drv                            |   78 +-
 drv/AbstractBigListIterator.drv                    |    4 +-
 drv/AbstractCollection.drv                         |    9 +-
 drv/AbstractComparator.drv                         |    5 +-
 drv/AbstractFunction.drv                           |   41 +-
 drv/AbstractIterator.drv                           |    6 +-
 drv/AbstractList.drv                               |   29 +-
 drv/AbstractListIterator.drv                       |    2 +-
 drv/AbstractMap.drv                                |   29 +-
 drv/AbstractPriorityQueue.drv                      |   21 +-
 drv/AbstractSet.drv                                |    2 +-
 drv/AbstractSortedMap.drv                          |   22 +-
 drv/AbstractSortedSet.drv                          |   22 +-
 drv/AbstractStack.drv                              |    2 +-
 drv/ArrayFIFOQueue.drv                             |    6 +-
 drv/ArrayFrontCodedList.drv                        |    2 +-
 drv/ArrayIndirectDoublePriorityQueue.drv           |  635 -----
 drv/ArrayIndirectPriorityQueue.drv                 |    2 +-
 drv/ArrayList.drv                                  |   53 +-
 drv/ArrayMap.drv                                   |   72 +-
 drv/ArrayPriorityQueue.drv                         |   24 +-
 drv/ArraySet.drv                                   |   24 +-
 drv/Arrays.drv                                     |  179 +-
 drv/BidirectionalIterator.drv                      |    2 +-
 drv/BigArrayBigList.drv                            |   87 +-
 drv/BigArrays.drv                                  |   22 +-
 drv/BigList.drv                                    |    2 +-
 drv/BigListIterator.drv                            |    2 +-
 drv/BigListIterators.drv                           |    8 +-
 drv/BigLists.drv                                   |   30 +-
 drv/BinIO.drv                                      |    2 +-
 drv/BinIOFragment.drv                              |    2 +-
 drv/Collection.drv                                 |    2 +-
 drv/Collections.drv                                |    2 +-
 drv/Comparator.drv                                 |    2 +-
 drv/Comparators.drv                                |   76 +-
 drv/Function.drv                                   |    2 +-
 drv/Functions.drv                                  |   44 +-
 drv/Hash.drv                                       |    2 +-
 drv/HeapIndirectDoublePriorityQueue.drv            |  654 -----
 drv/HeapIndirectPriorityQueue.drv                  |    2 +-
 drv/HeapPriorityQueue.drv                          |  122 +-
 drv/HeapSemiIndirectPriorityQueue.drv              |    2 +-
 drv/HeapSesquiIndirectDoublePriorityQueue.drv      |  667 -----
 drv/Heaps.drv                                      |   46 +-
 drv/IndirectDoublePriorityQueue.drv                |   37 -
 drv/IndirectHeaps.drv                              |   47 +-
 drv/IndirectPriorityQueue.drv                      |    2 +-
 drv/Iterable.drv                                   |    2 +-
 drv/Iterator.drv                                   |    2 +-
 drv/Iterators.drv                                  |   22 +-
 drv/LinkedOpenCustomDoubleHashMap.drv              |    1 -
 drv/LinkedOpenCustomDoubleHashSet.drv              |    1 -
 drv/LinkedOpenDoubleHashMap.drv                    |    1 -
 drv/LinkedOpenDoubleHashSet.drv                    |    1 -
 drv/List.drv                                       |    2 +-
 drv/ListIterator.drv                               |    2 +-
 drv/Lists.drv                                      |   22 +-
 drv/Map.drv                                        |   20 +-
 drv/Maps.drv                                       |   97 +-
 drv/OpenCustomDoubleHashMap.drv                    |    1 -
 drv/OpenCustomDoubleHashSet.drv                    |    1 -
 drv/OpenDoubleHashMap.drv                          | 2606 --------------------
 drv/OpenDoubleHashSet.drv                          | 1986 ---------------
 drv/OpenHashBigSet.drv                             |   44 +-
 drv/OpenHashMap.drv                                |  144 +-
 drv/OpenHashSet.drv                                |  133 +-
 drv/PriorityQueue.drv                              |    2 +-
 drv/PriorityQueues.drv                             |    2 +-
 drv/RBTreeMap.drv                                  |  143 +-
 drv/RBTreeSet.drv                                  |   11 +-
 drv/SemiIndirectHeaps.drv                          |   49 +-
 drv/Set.drv                                        |    2 +-
 drv/Sets.drv                                       |   18 +-
 drv/SortedMap.drv                                  |    2 +-
 drv/SortedMaps.drv                                 |   47 +-
 drv/SortedSet.drv                                  |    2 +-
 drv/SortedSets.drv                                 |   32 +-
 drv/Stack.drv                                      |    2 +-
 drv/StripedOpenHashMap.drv                         |    2 +-
 drv/TextIO.drv                                     |    2 +-
 drv/TextIOFragment.drv                             |    2 +-
 gencsource.sh                                      |   27 +-
 makefile                                           |   89 +-
 pom.xml                                            |    2 +-
 .../fastutil/AbstractIndirectPriorityQueue.java    |    2 +-
 .../unimi/dsi/fastutil/AbstractPriorityQueue.java  |    2 +-
 src/it/unimi/dsi/fastutil/AbstractStack.java       |    2 +-
 src/it/unimi/dsi/fastutil/Arrays.java              |  185 +-
 .../unimi/dsi/fastutil/BidirectionalIterator.java  |    2 +-
 src/it/unimi/dsi/fastutil/BigArrays.java           |  640 +++--
 src/it/unimi/dsi/fastutil/BigList.java             |    2 +-
 src/it/unimi/dsi/fastutil/BigListIterator.java     |    2 +-
 src/it/unimi/dsi/fastutil/BigSwapper.java          |    2 +-
 src/it/unimi/dsi/fastutil/Function.java            |    2 +-
 src/it/unimi/dsi/fastutil/Hash.java                |    6 +-
 src/it/unimi/dsi/fastutil/HashCommon.java          |   11 +-
 .../unimi/dsi/fastutil/IndirectPriorityQueue.java  |    2 +-
 .../unimi/dsi/fastutil/IndirectPriorityQueues.java |    2 +-
 src/it/unimi/dsi/fastutil/Maps.java                |    2 +-
 src/it/unimi/dsi/fastutil/PriorityQueue.java       |    2 +-
 src/it/unimi/dsi/fastutil/PriorityQueues.java      |    2 +-
 src/it/unimi/dsi/fastutil/Size64.java              |    2 +-
 src/it/unimi/dsi/fastutil/Stack.java               |    2 +-
 src/it/unimi/dsi/fastutil/Swapper.java             |    2 +-
 .../dsi/fastutil/io/FastBufferedInputStream.java   |    2 +-
 .../dsi/fastutil/io/FastBufferedOutputStream.java  |    2 +-
 .../dsi/fastutil/io/FastByteArrayInputStream.java  |    2 +-
 .../dsi/fastutil/io/FastByteArrayOutputStream.java |    2 +-
 .../fastutil/io/FastMultiByteArrayInputStream.java |    2 +-
 .../io/InspectableFileCachedInputStream.java       |    2 +-
 .../dsi/fastutil/io/MeasurableInputStream.java     |    2 +-
 .../dsi/fastutil/io/MeasurableOutputStream.java    |    2 +-
 src/it/unimi/dsi/fastutil/io/MeasurableStream.java |    2 +-
 .../dsi/fastutil/io/RepositionableStream.java      |    2 +-
 src/overview.html                                  |    4 +-
 src/stylesheet.css                                 |  482 ----
 test/it/unimi/dsi/fastutil/ArraysTest.java         |  164 +-
 test/it/unimi/dsi/fastutil/BigArraysTest.java      |    8 +
 .../dsi/fastutil/doubles/DoubleBigArraysTest.java  |    4 +-
 .../dsi/fastutil/ints/Int2IntAVLTreeMapTest.java   |   25 +
 .../dsi/fastutil/ints/Int2IntArrayMapTest.java     |   76 +
 .../ints/Int2IntLinkedOpenHashMapTest.java         |   49 +-
 .../ints/Int2IntOpenCustomHashMapTest.java         |   27 +
 .../dsi/fastutil/ints/Int2IntOpenHashMapTest.java  |   26 +-
 .../dsi/fastutil/ints/Int2IntRBTreeMapTest.java    |   25 +
 .../dsi/fastutil/ints/IntArrayFIFOQueueTest.java   |    3 +-
 .../ints/IntArrayIndirectPriorityQueueTest.java    |   21 +-
 .../unimi/dsi/fastutil/ints/IntArrayListTest.java  |   44 +
 .../fastutil/ints/IntArrayPriorityQueueTest.java   |   22 +
 .../unimi/dsi/fastutil/ints/IntArraySetTest.java   |   36 +-
 test/it/unimi/dsi/fastutil/ints/IntArraysTest.java |    8 +
 .../dsi/fastutil/ints/IntBigArrayBigListTest.java  |   56 +
 .../unimi/dsi/fastutil/ints/IntBigArraysTest.java  |    4 +-
 .../fastutil/ints/IntHeapPriorityQueueTest.java    |   29 +
 .../ints/IntHeapSemiIndirectPriorityQueueTest.java |    2 +
 .../ints/IntLinkedOpenCustomHashSetTest.java       |   47 +
 .../fastutil/ints/IntOpenCustomHashSetTest.java    |   78 +-
 .../dsi/fastutil/ints/IntOpenHashSetTest.java      |   44 +-
 .../fastutil/ints/IntSemiIndirectHeapsTest.java    |    2 +
 .../unimi/dsi/fastutil/longs/LongArraysTest.java   |    1 -
 .../objects/AbstractObject2IntFunctionTest.java    |    1 +
 .../objects/Object2IntOpenHashMapTest.java         |    2 +-
 .../objects/Object2ObjectArrayMapTest.java         |  140 ++
 .../dsi/fastutil/objects/ObjectAVLTreeSetTest.java |   56 +
 .../dsi/fastutil/objects/ObjectArrayListTest.java  |   19 +
 .../objects/ObjectArrayPriorityQueueTest.java      |  171 ++
 .../ObjectArraySetTest.java}                       |   56 +-
 .../objects/ObjectBigArrayBigListTest.java         |   21 +
 .../dsi/fastutil/objects/ObjectBigArraysTest.java  |    4 +-
 .../objects/ObjectHeapPriorityQueueTest.java       |   30 +
 .../objects/ObjectOpenCustomHashSetTest.java       |   33 +
 .../fastutil/objects/ObjectOpenHashBigSetTest.java |   14 +-
 .../fastutil/objects/ObjectOpenHashSetTest.java    |   16 +-
 .../dsi/fastutil/objects/ObjectRBTreeSetTest.java  |   56 +
 162 files changed, 3693 insertions(+), 8229 deletions(-)

diff --git a/CHANGES b/CHANGES
index 24ef0f9..26641d0 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,65 @@
+7.0.11
+
+- Several small glitches that were making fastutil's classes behave
+  differently from those of java.util have been fixed. Thanks to Balázs
+  Attila-Mihály or reporting these bug (obtained by massive testing using
+  Guava's battery of unit tests).
+
+7.0.10
+
+- The infinite-loop bug was affecting trim(int) besides trim(). Thanks
+  to Igor Kabiljo for reporting this bug.
+
+- With the help of Erich Schubert, all methods with a type-specific,
+  more efficient counterpart have been deprecated.
+
+7.0.9
+
+- A subtle infinite-loop bug in hash-based structures (happening with load
+  factor 1 and tiny structures) has been fixed. Thanks to  Tuomas Välimäki
+  and Jarkko Mönkkönen for reporting this bug.
+
+- Now tree-based map have an addTo() method analogous to that of
+  hash-based maps. Thanks to Almog Gavra for implementing the method.
+
+7.0.8
+
+- Non-indirect priority queues are now serializable.
+
+- Fixed implementation of structures based on a custom hash: keys
+  strategy-equal to zero zero would not be managed correctly. Thanks to
+  Shawn Cao for reporting this bug.
+
+- Natural/opposite/abstract comparators are now serializable.
+
+7.0.7
+
+- Now we check whether ranges of parallel sorting algorithms
+  are too small *before* creating the thread pool.
+
+- Merged Erich Schubert's fix for Object{AVL,RB}TreeSet.get().
+
+7.0.6
+
+- Faster priority queues: better variable caching, deleted
+  a spurious check, tests for parameters turned into assertions.
+
+- New collection-based constructors for heap-based priority queues.
+
+- Reviewed ObjectArrays.newArray() so that there is a fast track
+  for reallocation of arrays of type Object[].
+
+7.0.4
+
+- Fixed old-standing bug: iterators in linked maps would
+  return bogus data on entrySet().next()/entrySet().previous()
+  when no element is available instead of throwing an exception.
+
+7.0.3
+
+- Fixed wrong generation of custom-hash classes with primitive
+  keys. Thanks to Michael Henke for reporting this bug.
+
 7.0.2
 
 - Now we shutdown() correctly ForkJoinPool's.
diff --git a/README b/README.md
similarity index 52%
rename from README
rename to README.md
index 3eb7665..18bb301 100644
--- a/README
+++ b/README.md
@@ -1,8 +1,12 @@
-Welcome to fastutil, a collection of type-specific Java classes that
-extend the Java Collections Framework by providing several containers,
-such as maps, sets, lists and prority queues, implementing the interfaces
-of the java.util package; it provides also big (64-bit) arrays, sets and
-lists, and fast, practical I/O classes for binary and text files.
+Welcome to fastutil.
+--------------------
+
+[fastutil](http://fastutil.di.unimi.it/) is a collection of type-specific
+Java classes that extend the Java Collections Framework by providing
+several containers, such as maps, sets, lists and prority queues,
+implementing the interfaces of the java.util package; it provides also big
+(64-bit) arrays, sets and lists, and fast, practical I/O classes for
+binary and text files.
 
 fastutil provides a huge collection of specialized classes generated
 starting from a parameterized version; the classes are much more compact
@@ -12,21 +16,19 @@ documentation for more information.
 The compiled code is contained in the jar file, and should be installed
 where you keep Java extensions. Note that the jar file is huge, due to the
 large number of classes: if you plan to ship your own jar with some
-fastutil classes included, you should look at AutoJar to extract
-automatically the necessary classes.
+fastutil classes included, you should look at AutoJar or similar tools to
+extract automatically the necessary classes.
 
 You have to "make sources" to get the actual Java sources; finally, "ant
 jar" and "ant javadoc" will generate the jar file and the API
-documentation. Note that you need ant (http://jakarta.apache.org/ant/).
-The target "oldsources" generates the old code for priority queues and
-hash sets/maps, and the ant task "jar-oldsources" includes what is
-necessary in the jar file.
+documentation.
 
 The Java sources are generated using a C preprocessor. The gencsource.sh
 script reads in a driver file, that is, a Java source that uses some
 preprocessor-defined symbols and some conditional compilation, and
 produces a (fake) C source, which includes the driver code and some
-#define that customize the environment.
+definitions that customize the environment.
 
 
-                                          seba (vigna at acm.org)
+* seba (<mailto:sebastiano.vigna at unimi.it>)
+* <mailto:fastutil at googlegroups.com>
diff --git a/build.properties b/build.properties
index 183b044..2c28ec8 100644
--- a/build.properties
+++ b/build.properties
@@ -3,7 +3,7 @@ javadoc.base=/usr/share/javadoc
 
 build.sysclasspath=ignore
 
-version=7.0.2
+version=7.0.11
 
 dist=dist
 src=src
@@ -16,5 +16,5 @@ docs=docs
 build=build
 instrumented=instrumented
 
-remote.j2se.apiurl=http://download.oracle.com/javase/6/docs/api/
+remote.j2se.apiurl=http://docs.oracle.com/javase/7/docs/api/
 local.j2se.apiurl=file://${javadoc.base}/java
diff --git a/build.xml b/build.xml
index cf7ba20..e25d8b4 100644
--- a/build.xml
+++ b/build.xml
@@ -52,7 +52,9 @@
 
 		<!-- build the sources artifact -->
 		<jar jarfile="${maven-sources-jar}">
-			<fileset dir="." includes="README,CHANGES,LICENSE-2.0,build.xml,ivy.xml,pom.xml,fastutil.bnd,build.properties,makefile,${drv}/*.drv,gencsource.sh,${src}/it/unimi/dsi/fastutil/**/*.java,${src}/it/unimi/dsi/fastutil/**/*.html,${test}/**/*.java"/>
+			<fileset dir="." includes="README.md,CHANGES,LICENSE-2.0,build.xml,ivy.xml,pom.xml,fastutil.bnd,build.properties,makefile,${drv}/*.drv,gencsource.sh"/>
+			<fileset dir="src" includes="it/unimi/dsi/fastutil/**/*.java,it/unimi/dsi/fastutil/**/*.html"/>
+			<fileset dir="test" includes="**/*.java"/>
 		</jar>
 	</target>
 
@@ -114,13 +116,6 @@
 
 	<property name="j2se.apiurl" value="http://java.sun.com/j2se/5.0/docs/api/"/>
 
-	<path id="emma.lib" >
-		<pathelement location="${jar.base}/emma.jar" />
-		<pathelement location="${jar.base}/emma_ant.jar" />
-	</path>
-
-	<taskdef resource="emma_ant.properties" classpathref="emma.lib" />
-
 	<target name="init">
 		<mkdir dir="${build}"/>
 		<mkdir dir="${dist}/lib"/>
@@ -182,7 +177,6 @@
 			 public="on"
 			 source="${source}"
 			 windowtitle="fastutil ${version}"
-			 stylesheetfile="${src}/stylesheet.css"
 			 additionalparam="-breakiterator"
 			 maxmemory="800M"
 			 >
@@ -190,21 +184,17 @@
 		</javadoc>
 	</target>
 
-	<target name="junit" depends="instrument" description="Runs JUnit tests">
-
+	<target name="junit" depends="compile-tests" description="Runs JUnit tests">
 		<junit printsummary="yes" fork="yes" haltonfailure="off"  haltonerror="off">
-			<classpath location="${instrumented}/classes"/>
+			<classpath location="${build}"/>
 			<classpath location="${src}"/>
-			<classpath location="${jar.base}/emma.jar"/>
 			<jvmarg value="-Xmx1G" />
-			<jvmarg value="-Demma.coverage.out.file=${coverage}/coverage.emma" />
-			<jvmarg value="-Demma.coverage.out.merge=true" />
 
 			<formatter type="xml"/>
 			<formatter type="plain"/>
 
 			<batchtest fork="yes" todir="${reports}">
-				<fileset dir="${instrumented}/classes">
+				<fileset dir="${build}">
 					<include name="**/*Test.class"/>
 				</fileset>
 			</batchtest>
@@ -216,37 +206,13 @@
 			</fileset>
 			<report todir="reports/html"/>
 		</junitreport>
-
-		<emma>
-			<report sourcepath="${src}" >
-				<fileset file="${coverage}/*a"/>
-				<html outfile="coverage.html" />
-				<xml outfile="${coverage}/coverage.xml" />
-			</report>
-		</emma>
 	</target>
 
-	<target name="instrument" depends="compile" description="Generate instrumented classes">
-		<emma>
-			<instr mode="fullcopy"
-				 outdir="${instrumented}"
-				 merge="no"
-				 metadatafile="${coverage}/metadata.emma"
-				 instrpath="${build}"
-			>
-				<filter excludes="*Test*"/>
-			</instr>
-		</emma>
-	</target>
-
-
 	<!-- ************		CLEAN		********************* -->
 	<target name="clean">
 		<delete dir="${build}"/>
 		<delete dir="${dist}"/>
 		<delete dir="${reports}"/>
-		<delete dir="${coverage}"/>
-		<delete dir="${instrumented}"/>
 		<delete dir="${docs}"/>
 		<delete>
 			<fileset dir="." includes="fastutil-*.jar"/>
diff --git a/drv/AVLTreeMap.drv b/drv/AVLTreeMap.drv
index b3d359c..c2ce100 100644
--- a/drv/AVLTreeMap.drv
+++ b/drv/AVLTreeMap.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -58,13 +58,13 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 	protected transient Entry KEY_VALUE_GENERIC lastEntry;
 
 	/** Cached set of entries. */
-	protected transient volatile ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC> entries;
+	protected transient ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC> entries;
 
 	/** Cached set of keys. */
-	protected transient volatile SORTED_SET KEY_GENERIC keys;
+	protected transient SORTED_SET KEY_GENERIC keys;
 
 	/** Cached collection of values. */
-	protected transient volatile VALUE_COLLECTION VALUE_GENERIC values;
+	protected transient VALUE_COLLECTION VALUE_GENERIC values;
 
 	/** The value of this variable remembers, after a <code>put()</code> 
 	 * or a <code>remove()</code>, whether the <em>domain</em> of the map
@@ -269,27 +269,58 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 		dirPath = new boolean[ 48 ];
 	}
 
+	#if #values(primitive) && !#valueclass(Boolean)
+	/** Adds an increment to value currently associated with a key.
+	*
+	* <P>Note that this method respects the {@linkplain #defaultReturnValue() default return value} semantics: when
+	* called with a key that does not currently appears in the map, the key
+	* will be associated with the default return value plus
+	* the given increment.
+	*
+	* @param k the key.
+	* @param incr the increment.
+	* @return the old value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key.
+	*/
+	public VALUE_GENERIC_TYPE addTo( final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE incr) {
+		Entry KEY_VALUE_GENERIC e = add( k );
+		final VALUE_GENERIC_TYPE oldValue = e.value;
+		e.value += incr;
+		return oldValue;
+	}
+	#endif
 
-	/* 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 ) {
+		Entry KEY_VALUE_GENERIC e = add( k );
+		final VALUE_GENERIC_TYPE oldValue = e.value;
+		e.value = v;
+		return oldValue;
+	}
+
+	/** Returns a node with key k in the balanced tree, creating one with defRetValue if necessary.
+	*
+	* @param k the key
+	* @return a node with key k. If a node with key k already exists, then that node is returned,
+	* 				otherwise a new node with defRetValue is created ensuring that the tree is balanced
+						after creation of the node.
+	*/
+	private Entry KEY_VALUE_GENERIC add( final KEY_GENERIC_TYPE k ) {
+  	/* After execution of this method, modified is true iff a new entry has
+  	been inserted. */
 		modified = false;
 
+		Entry KEY_VALUE_GENERIC e = null;
 		if ( tree == null ) { // The case of the empty tree is treated separately.
 			count++;
-			tree = lastEntry = firstEntry = new Entry KEY_VALUE_GENERIC( k, v );
+			e = tree = lastEntry = firstEntry = new Entry KEY_VALUE_GENERIC( k, defRetValue );
 			modified = true;
 		}
 		else {
-			Entry KEY_VALUE_GENERIC p = tree, q = null, y = tree, z = null, e = null, w = null;
+			Entry KEY_VALUE_GENERIC p = tree, q = null, y = tree, z = 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;
+					return p;
 				}
 					 
 				if ( p.balance() != 0 ) {
@@ -301,7 +332,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 				if ( dirPath[ i++ ] = cmp > 0 ) {
 					if ( p.succ() ) {
 						count++;
-						e = new Entry KEY_VALUE_GENERIC( k, v );
+						e = new Entry KEY_VALUE_GENERIC( k, defRetValue );
 								
 						modified = true; 
 						if ( p.right == null ) lastEntry = e;
@@ -320,7 +351,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 				else {
 					if ( p.pred() ) {
 						count++;
-						e = new Entry KEY_VALUE_GENERIC( k, v );
+						e = new Entry KEY_VALUE_GENERIC( k, defRetValue );
 								
 						modified = true;
 						if ( p.left == null ) firstEntry = e;
@@ -446,7 +477,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 
 				}
 			}
-			else return defRetValue;
+			else return e;
 
 			if ( z == null ) tree = w;
 			else {
@@ -456,7 +487,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 		}
 
 		if ( ASSERTS ) checkTree( tree );
-		return defRetValue;
+		return e;
 	}
 
 	/** Finds the parent of an entry.
@@ -772,6 +803,10 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 	 
 
 #if ! #keyclass(Object) || #values(primitive)
+	/** {@inheritDoc}
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
+	@Override
 	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 );
@@ -781,6 +816,10 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 
 
 #if ! #keyclass(Object) || #values(primitive)
+	/** {@inheritDoc}
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
+	@Override
 	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;
@@ -976,6 +1015,11 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 			return prev;
 		}
 
+#if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
 		public KEY_GENERIC_CLASS getKey() {
 			return KEY2OBJ(key);
 		}
@@ -986,6 +1030,11 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 		}
 #endif
 		  
+#if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead.  */
+		@Deprecated
+#endif
 		public VALUE_GENERIC_CLASS getValue() {
 			return VALUE2OBJ(value);
 		}
@@ -1100,7 +1149,10 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 	}
 
 #if #keyclass(Object) && #values(primitive)
-
+	/** {@inheritDoc}
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
+	@Override
 	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public VALUE_GENERIC_CLASS get( final Object ok ) {
 		final Entry KEY_VALUE_GENERIC e = findKey( KEY_GENERIC_CAST ok );
@@ -1254,6 +1306,9 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 				public boolean contains( final Object o ) {
 					if (!(o instanceof Map.Entry)) return false;
 					final Map.Entry <KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS> e = (Map.Entry <KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS>)o;
+#if #keys(primitive)
+					if ( e.getKey() == null ) return false;
+#endif
 					final Entry KEY_VALUE_GENERIC f = findKey( KEY_CLASS2TYPE( e.getKey() ) );
 					return e.equals( f );
 				}					 
@@ -1262,6 +1317,9 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 				public boolean remove( final Object o ) {
 					if (!(o instanceof Map.Entry)) return false;
 					final Map.Entry <KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS> e = (Map.Entry <KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS>)o;
+#if #keys(primitive)
+					if ( e.getKey() == null ) return false;
+#endif
 					final Entry KEY_VALUE_GENERIC f = findKey( KEY_CLASS2TYPE( e.getKey() ) );
 					if ( f != null ) AVL_TREE_MAP.this.REMOVE_VALUE( f.key );
 					return f != null;
@@ -1412,13 +1470,13 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 		boolean top;
 		/** Cached set of entries. */
 		@SuppressWarnings("hiding")
-		protected transient volatile ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC> entries;
+		protected transient ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC> entries;
 		/** Cached set of keys. */
 		@SuppressWarnings("hiding")
- 		protected transient volatile SORTED_SET KEY_GENERIC keys;
+		protected transient SORTED_SET KEY_GENERIC keys;
 		/** Cached collection of values. */
 		@SuppressWarnings("hiding")
-		protected transient volatile VALUE_COLLECTION VALUE_GENERIC values;
+		protected transient VALUE_COLLECTION VALUE_GENERIC values;
 
 		/** Creates a new submap with given key range.
 		 *
@@ -1568,7 +1626,10 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 		  
 		  
 #if #keyclass(Object) && #values(primitive)
-
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead.  */
+		@Deprecated
+		@Override
 		SUPPRESS_WARNINGS_KEY_UNCHECKED
 		public VALUE_GENERIC_CLASS get( final Object ok ) {
 			final AVL_TREE_MAP.Entry KEY_VALUE_GENERIC e;
@@ -1586,6 +1647,10 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 
 		  
 #if ! #keyclass(Object) || #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead.  */
+		@Deprecated
+		@Override
 		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 );
@@ -1601,6 +1666,10 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 		}
 
 #if ! #keyclass(Object) || #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead.  */
+		@Deprecated
+		@Override
 		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;
@@ -1696,12 +1765,20 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 		}
 	 
 #if !#keyclass(Object)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead.  */
+		@Deprecated
+		@Override
 		public KEY_GENERIC_CLASS firstKey() {
 			AVL_TREE_MAP.Entry KEY_VALUE_GENERIC e = firstEntry();
 			if ( e == null ) throw new NoSuchElementException();
 			return e.getKey();
 		}
 	 
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead.  */
+		@Deprecated
+		@Override
 		public KEY_GENERIC_CLASS lastKey() {
 			AVL_TREE_MAP.Entry KEY_VALUE_GENERIC e = lastEntry();
 			if ( e == null ) throw new NoSuchElementException();
@@ -2045,7 +2122,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 			v[i] = genValue();
 		}
 
-		double totPut = 0, totYes = 0, totNo = 0, totIterFor = 0, totIterBack = 0, totRemYes = 0, d, dd;
+		double totPut = 0, totYes = 0, totNo = 0, totAddTo = 0, totIterFor = 0, totIterBack = 0, totRemYes = 0, d, dd, ddd;
 
 		if ( comp ) { for( j = 0; j < 20; j++ ) {
 
@@ -2082,6 +2159,15 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 			/* And then we put it back. */
 			for( i = 0; i < n/2;  i++ ) t.put( KEY2OBJ( k[i] ), VALUE2OBJ( v[i] )  );
 
+			#if #values(primitive) && !#valueclass(Boolean)
+			/* we perform n/2 addTo() operations with get then put */
+			ms = System.currentTimeMillis();
+			for( i = 0; i < n/2; i++ ) t.put( KEY2OBJ( k[i] ), (VALUE_TYPE) ((VALUE_CLASS) t.get( KEY2OBJ(k[i])) + i) );
+			ddd = System.currentTimeMillis() - ms;
+			if ( j > 2 ) totAddTo += n/ddd;
+			System.out.print("AddTo: " + format( n/ddd ) +" K/s " );
+			#endif
+
 			/* We check for pairs in t. */
 			ms = System.currentTimeMillis();
 			for( i = 0; i < n;  i++ ) t.containsKey( KEY2OBJ( k[i] ) );
@@ -2107,12 +2193,12 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 		}
 
 		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( "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 AddTo: " + format( totAddTo/(j-3) ) + " K/s IterFor: " + format( totIterFor/(j-3) )  + " K/s"  );
 
 		System.out.println();
 
 		t = null;
-		totPut = totYes = totNo = totIterFor = totIterBack = totRemYes = 0;
+		totPut = totYes = totNo = totIterFor = totIterBack = totRemYes = totAddTo = 0;
 
 		}
 
@@ -2151,6 +2237,15 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 			/* And then we put it back. */
 			for( i = 0; i < n/2;  i++ ) m.put( k[i], v[i]  );
 
+			#if #values(primitive) && !#valueclass(Boolean)
+			/* we perform n/2 addTo() operations with get then put */
+			ms = System.currentTimeMillis();
+			for( i = 0; i < n/2; i++ ) m.addTo( k[i], (VALUE_TYPE) i );
+			ddd = System.currentTimeMillis() - ms;
+			if ( j > 2 ) totAddTo += n/ddd;
+			System.out.print("AddTo: " + format( n/ddd ) +" K/s " );
+			#endif
+
 			/* We check for pairs in m. */
 			ms = System.currentTimeMillis();
 			for( i = 0; i < n;  i++ ) m.containsKey( k[i] );
@@ -2186,7 +2281,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 
 
 		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( "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 AddTo: " + format( totAddTo/(j-3) ) + " K/s IterFor: " + format( totIterFor/(j-3) )  + " K/s"  );
 
 		System.out.println();
 
@@ -2207,53 +2302,7 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 		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() +")");
-
-
+	private static void compareMT( SORTED_MAP m, SortedMap t, int level, long seed ) {
 		/* Now we check that m and t are equal. */
 		if ( !m.equals( t ) || ! t.equals( m ) ) System.err.println("m: " + m + " t: " + t);
 
@@ -2303,6 +2352,56 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 			ensure( t.values().contains(o), "Error (" + level + ", " + seed + "): m and t differ on a value (in values()) after insertion (iterating on m)");
 		}
 
+	}
+
+	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() +")");
+
+		compareMT( m, t, level, seed );
+
 		/* Now we check that inquiries about random data give the same answer in m and t. For
 		   m we use the polymorphic method. */
 
@@ -2416,55 +2515,38 @@ public class AVL_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP  KEY_VAL
 			if ( !mThrowsNoElement && !mThrowsIllegal ) ensure( valEquals( rm, rt ), "Error (" + level + ", " + seed + "): divergence in remove() between t and m (" + rt + ", " + rm + ")" );
 		}
 
-		ensure( m.equals(t), "Error (" + level + ", " + seed + "): ! m.equals( t ) after removal" );
-		ensure( t.equals(m), "Error (" + level + ", " + seed + "): ! t.equals( m ) after removal" );
-
-		/* Now we check that m actually holds the same 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 removal (iterating on t)");
-		}
+		compareMT( m, t, level, seed );
 
-		/* 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 removal (iterating on m)" );
-		}
+		#if #values(primitive) && !#valueclass(Boolean)
+		/* Now we check that addTo results in the same values as get/put */
+		if (m instanceof AVL_TREE_MAP) {
+			for (Iterator i=m.entrySet().iterator(); i.hasNext(); ) {
+				Entry e = (Entry)i.next();
+				VALUE_TYPE incr = genValue();
+				((AVL_TREE_MAP) m).addTo( e.key, incr );
+				t.put( e.key, (VALUE_TYPE) ((VALUE_CLASS) t.get(e.key) + incr) );
+			}
+			compareMT( m, t, level, seed );
 
-		/* 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 removal (iterating on t)");
-			ensure( m.keySet().contains(o), "Error (" + level + ", " + seed + "): m and t differ on a key ("+o+", in keySet()) after removal (iterating on t)");
-		}
+			/* Now we make sure that addTo works with a key that did not previously exist (with special default return value )*/
+			KEY_TYPE newKey;
 
-		/* 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 removal (iterating on m)");
-			ensure( t.keySet().contains(o), "Error (" + level + ", " + seed + "): m and t differ on a key (in keySet()) after removal (iterating on m)");
-		}
+			do {
+				newKey = genKey();
+			} while (m.containsKey(newKey));
 
+			VALUE_TYPE newValue, drv;
+			drv = m.defaultReturnValue();
+			newValue = genValue();
+			m.defaultReturnValue( genValue() );
 
-		/* 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 removal (iterating on t)" );
-			ensure( m.values().contains(o), "Error (" + level + ", " + seed + "): m and t differ on a value (in values()) after removal (iterating on t)");
-		}
+			((AVL_TREE_MAP) m).addTo( newKey, newValue );
+			t.put( newKey, (VALUE_TYPE) (newValue + m.defaultReturnValue()) );
 
-		/* 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 removal (iterating on m)");
-			ensure( t.values().contains(o), "Error (" + level + ", " + seed + "): m and t differ on a value (in values()) after removal (iterating on m)");
+			compareMT( m, t, level, seed );
+			m.defaultReturnValue(drv); // set the default value back to the old drv
 		}
+		#endif
 
 		/* Now we check that both maps agree on first/last keys. */
 
diff --git a/drv/AVLTreeSet.drv b/drv/AVLTreeSet.drv
index 39bd7df..0f288a5 100644
--- a/drv/AVLTreeSet.drv
+++ b/drv/AVLTreeSet.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -792,10 +792,11 @@ public class AVL_TREE_SET KEY_GENERIC extends ABSTRACT_SORTED_SET KEY_GENERIC im
 		return findKey( KEY_GENERIC_CAST k ) != null;
 	}
 
-#if #keysclass(Object)
+#if #keyclass(Object)
+	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public K get( final KEY_TYPE k ) {
 		final Entry KEY_GENERIC entry = findKey( KEY_GENERIC_CAST k );
-		return entry == null ? null : entry.getKey();
+		return entry == null ? null : entry.key;
 	}
 #endif
 
@@ -1199,7 +1200,7 @@ public class AVL_TREE_SET KEY_GENERIC extends ABSTRACT_SORTED_SET KEY_GENERIC im
 		public void clear() {
 			final SubsetIterator i = new SubsetIterator();
 			while( i.hasNext() ) {
-				i.next();
+				i.NEXT_KEY();
 				i.remove();
 			}
 		}
@@ -1235,7 +1236,7 @@ public class AVL_TREE_SET KEY_GENERIC extends ABSTRACT_SORTED_SET KEY_GENERIC im
 				
 			while( i.hasNext() ) {
 				n++;
-				i.next();
+				i.NEXT_KEY();
 			}
 				
 			return n;
diff --git a/drv/AbstractBidirectionalIterator.drv b/drv/AbstractBidirectionalIterator.drv
index 6a00e33..8161d9a 100644
--- a/drv/AbstractBidirectionalIterator.drv
+++ b/drv/AbstractBidirectionalIterator.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/AbstractBigList.drv b/drv/AbstractBigList.drv
index c58cff3..8ae7a92 100644
--- a/drv/AbstractBigList.drv
+++ b/drv/AbstractBigList.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2010-2014 Sebastiano Vigna 
+ * Copyright (C) 2010-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -106,6 +106,8 @@ public abstract class ABSTRACT_BIG_LIST KEY_GENERIC extends ABSTRACT_COLLECTION
 	}
 
 	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;
 							
@@ -116,7 +118,6 @@ public abstract class ABSTRACT_BIG_LIST KEY_GENERIC extends ABSTRACT_COLLECTION
 				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;
 				}
@@ -381,57 +382,108 @@ public abstract class ABSTRACT_BIG_LIST KEY_GENERIC extends ABSTRACT_COLLECTION
 		return addAll( size64(), l );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** {@inheritDoc}
+	 *
+	 * Delegates to a more generic method.
+	 *
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public void add( final long index, final KEY_CLASS ok ) {
 		add( index, ok.KEY_VALUE() );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	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. */
+	/** {@inheritDoc}
+	 *
+	 * Delegates to a more generic method.
+	 *
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_CLASS get( final long index ) {
 		return KEY2OBJ( GET_KEY( index ) );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** {@inheritDoc}
+	 *
+	 * Delegates to a more generic method.
+	 *
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public long indexOf( final Object ok ) {
 		return indexOf( KEY_OBJ2TYPE( ok ) );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** {@inheritDoc}
+	 *
+	 * Delegates to a more generic method.
+	 *
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public long lastIndexOf( final Object ok ) {
 		return lastIndexOf( KEY_OBJ2TYPE( ok ) );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/**
+	 * Delegates to a more generic method.
+	 *
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_CLASS remove( final int index ) {
 		return KEY2OBJ( REMOVE_KEY( index ) );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** {@inheritDoc}
+	 *
+	 * Delegates to a more generic method.
+	 *
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_CLASS remove( final long index ) {
 		return KEY2OBJ( REMOVE_KEY( index ) );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** {@inheritDoc}
+	 *
+	 * Delegates to a more generic method.
+	 *
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public void push( KEY_CLASS o ) {
 		push( o.KEY_VALUE() ); 
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** {@inheritDoc}
+	 *
+	 * Delegates to a more generic method.
+	 *
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_CLASS pop() {
 		return KEY_CLASS.valueOf( POP() ); 
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** {@inheritDoc}
+	 *
+	 * Delegates to a more generic method.
+	 *
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_CLASS top() {
 		return KEY_CLASS.valueOf( TOP() ); 
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** {@inheritDoc}
+	 *
+	 * Delegates to a more generic method.
+	 *
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_CLASS peek( int i ) {
 		return KEY_CLASS.valueOf( PEEK( i ) ); 
 	}
diff --git a/drv/AbstractBigListIterator.drv b/drv/AbstractBigListIterator.drv
index 841ce5c..7f29e86 100644
--- a/drv/AbstractBigListIterator.drv
+++ b/drv/AbstractBigListIterator.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -45,7 +45,7 @@ public abstract class KEY_ABSTRACT_BIG_LIST_ITERATOR KEY_GENERIC extends KEY_ABS
 	/** 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
+	/** This method just iterates the type-specific version of {@code next()} for at most
 	 * <code>n</code> times, stopping if {@link #hasNext()} becomes false.*/
 
 	public long skip( final long n ) { 
diff --git a/drv/AbstractCollection.drv b/drv/AbstractCollection.drv
index 3123914..c636005 100644
--- a/drv/AbstractCollection.drv
+++ b/drv/AbstractCollection.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -126,8 +126,10 @@ public abstract class ABSTRACT_COLLECTION KEY_GENERIC extends AbstractCollection
 
 	@SuppressWarnings("unchecked")
 	public <T> T[] toArray( T[] a ) {
-		if ( a.length < size() ) a = (T[])java.lang.reflect.Array.newInstance( a.getClass().getComponentType(), size() );
+		final int size = size();
+		if ( a.length < size ) a = (T[])java.lang.reflect.Array.newInstance( a.getClass().getComponentType(), size );
 		it.unimi.dsi.fastutil.objects.ObjectIterators.unwrap( iterator(), a );
+		if ( size < a.length ) a[ size ] = null;
 		return a;
 	}
 
@@ -163,6 +165,7 @@ public abstract class ABSTRACT_COLLECTION KEY_GENERIC extends AbstractCollection
 
 	/** Delegates to the type-specific <code>rem()</code> method. */
 	public boolean remove( Object ok ) {
+		if ( ok == null ) return false;
 		return rem( KEY_OBJ2TYPE( ok ) );
 	}
 
@@ -173,11 +176,13 @@ public abstract class ABSTRACT_COLLECTION KEY_GENERIC extends AbstractCollection
 
 	/** Delegates to the corresponding type-specific method. */
 	public boolean rem( final Object o ) {
+		if ( o == null ) return false;
 		return rem( KEY_OBJ2TYPE(o) );
 	}
 
 	/** Delegates to the corresponding type-specific method. */
 	public boolean contains( final Object o ) {
+		if ( o == null ) return false;
 		return contains( KEY_OBJ2TYPE(o) );
 	}
 
diff --git a/drv/AbstractComparator.drv b/drv/AbstractComparator.drv
index c1be069..46a5517 100644
--- a/drv/AbstractComparator.drv
+++ b/drv/AbstractComparator.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,7 +27,8 @@ package PACKAGE;
  * @see java.util.Comparator
  */
 
-public abstract class KEY_ABSTRACT_COMPARATOR KEY_GENERIC implements KEY_COMPARATOR KEY_GENERIC {
+public abstract class KEY_ABSTRACT_COMPARATOR KEY_GENERIC implements KEY_COMPARATOR KEY_GENERIC, java.io.Serializable {
+    private static final long serialVersionUID = 0L;
 
 	protected KEY_ABSTRACT_COMPARATOR() {}
 
diff --git a/drv/AbstractFunction.drv b/drv/AbstractFunction.drv
index fc80ffe..a01fc9d 100644
--- a/drv/AbstractFunction.drv
+++ b/drv/AbstractFunction.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -71,27 +71,51 @@ public abstract class ABSTRACT_FUNCTION KEY_VALUE_GENERIC implements FUNCTION KE
 
 #if #keys(primitive)
 	public boolean containsKey( final Object ok ) {
+		if ( ok == null ) return false;
 		return containsKey( KEY_OBJ2TYPE( ok ) );
 	}
 #endif
 
 #if #keys(primitive) || #values(primitive)
                                                                                                                                              
+#if #values(primitive)
+	/** Delegates to the corresponding type-specific method, taking care of returning <code>null</code> on a missing key.
+	 *
+	 * <P>This method must check whether the provided key is in the map using <code>containsKey()</code>. Thus,
+	 * it probes the map <em>twice</em>. Implementors of subclasses should override it with a more efficient method.
+	 *
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
+#else
 	/** Delegates to the corresponding type-specific method, taking care of returning <code>null</code> on a missing key.
 	 *
 	 * <P>This method must check whether the provided key is in the map using <code>containsKey()</code>. Thus,
 	 * it probes the map <em>twice</em>. Implementors of subclasses should override it with a more efficient method.
 	 */
+#endif
 	public VALUE_GENERIC_CLASS get( final Object ok ) {
+#if #keys(primitive)
+		if ( ok == null ) return null;
+#endif
 		final KEY_TYPE k = KEY_OBJ2TYPE( ok );
 		return containsKey( k ) ? VALUE2OBJ( GET_VALUE( k ) ) : null;
 	}
                                                                                                                                              
+#if #keys(primitive) || #values(primitive)
+	/** Delegates to the corresponding type-specific method, taking care of returning <code>null</code> on a missing key. 
+	 *
+	 * <P>This method must check whether the provided key is in the map using <code>containsKey()</code>. Thus,
+	 * it probes the map <em>twice</em>. Implementors of subclasses should override it with a more efficient method.
+	 *
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
+#else
 	/** Delegates to the corresponding type-specific method, taking care of returning <code>null</code> on a missing key. 
 	 *
 	 * <P>This method must check whether the provided key is in the map using <code>containsKey()</code>. Thus,
 	 * it probes the map <em>twice</em>. Implementors of subclasses should override it with a more efficient method.
 	 */
+#endif
 	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 );
@@ -99,16 +123,29 @@ public abstract class ABSTRACT_FUNCTION KEY_VALUE_GENERIC implements FUNCTION KE
 		return containsKey ? VALUE2OBJ( v ) : null;
 	}
                                                                                                                                              
+#if #values(primitive)
+	/** Delegates to the corresponding type-specific method, taking care of returning <code>null</code> on a missing key. 
+	 *
+	 * <P>This method must check whether the provided key is in the map using <code>containsKey()</code>. Thus,
+	 * it probes the map <em>twice</em>. Implementors of subclasses should override it with a more efficient method.
+	 *
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
+#else
 	/** Delegates to the corresponding type-specific method, taking care of returning <code>null</code> on a missing key. 
 	 *
 	 * <P>This method must check whether the provided key is in the map using <code>containsKey()</code>. Thus,
 	 * it probes the map <em>twice</em>. Implementors of subclasses should override it with a more efficient method.
 	 */
+#endif
 	public VALUE_GENERIC_CLASS remove( final Object ok ) {
+#if #keys(primitive)
+		if ( ok == null ) return null;
+#endif
 		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
-}
\ No newline at end of file
+}
diff --git a/drv/AbstractIterator.drv b/drv/AbstractIterator.drv
index ae002e9..b02d7ae 100644
--- a/drv/AbstractIterator.drv
+++ b/drv/AbstractIterator.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -39,7 +39,9 @@ public abstract class KEY_ABSTRACT_ITERATOR KEY_GENERIC implements KEY_ITERATOR
 	/** Delegates to the corresponding generic method. */
 	public KEY_TYPE NEXT_KEY() { return next().KEY_VALUE(); }
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_GENERIC_CLASS next() { return KEY_CLASS.valueOf( NEXT_KEY() ); }
 
 #endif
diff --git a/drv/AbstractList.drv b/drv/AbstractList.drv
index 9544dbb..b31adc0 100644
--- a/drv/AbstractList.drv
+++ b/drv/AbstractList.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -110,6 +110,8 @@ public abstract class ABSTRACT_LIST KEY_GENERIC extends ABSTRACT_COLLECTION KEY_
 	}
 
 	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;
 							
@@ -120,7 +122,6 @@ public abstract class ABSTRACT_LIST KEY_GENERIC extends ABSTRACT_COLLECTION KEY_
 				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;
 				}
@@ -390,12 +391,16 @@ public abstract class ABSTRACT_LIST KEY_GENERIC extends ABSTRACT_COLLECTION KEY_
 		add( index, ok.KEY_VALUE() );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	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. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_CLASS get( final int index ) {
 		return KEY2OBJ( GET_KEY( index ) );
 	}
@@ -410,7 +415,9 @@ public abstract class ABSTRACT_LIST KEY_GENERIC extends ABSTRACT_COLLECTION KEY_
 		return lastIndexOf( KEY_OBJ2TYPE( ok ) );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_CLASS remove( final int index ) {
 		return KEY2OBJ( REMOVE_KEY( index ) );
 	}
@@ -420,17 +427,23 @@ public abstract class ABSTRACT_LIST KEY_GENERIC extends ABSTRACT_COLLECTION KEY_
 		push( o.KEY_VALUE() ); 
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_CLASS pop() {
 		return KEY_CLASS.valueOf( POP() ); 
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_CLASS top() {
 		return KEY_CLASS.valueOf( TOP() ); 
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_CLASS peek( int i ) {
 		return KEY_CLASS.valueOf( PEEK( i ) ); 
 	}
diff --git a/drv/AbstractListIterator.drv b/drv/AbstractListIterator.drv
index 5b93445..f7a9328 100644
--- a/drv/AbstractListIterator.drv
+++ b/drv/AbstractListIterator.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/AbstractMap.drv b/drv/AbstractMap.drv
index 1388f3b..b0a6a24 100644
--- a/drv/AbstractMap.drv
+++ b/drv/AbstractMap.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -52,6 +52,7 @@ public abstract class ABSTRACT_MAP KEY_VALUE_GENERIC extends ABSTRACT_FUNCTION K
 
 #if #values(primitive)
 	public boolean containsValue( Object ov ) {
+		if ( ov == null ) return false;
 		return containsValue( VALUE_OBJ2TYPE( ov ) );
 	}
 #endif
@@ -72,8 +73,10 @@ public abstract class ABSTRACT_MAP KEY_VALUE_GENERIC extends ABSTRACT_FUNCTION K
 	 *
 	 * @param m a map.
 	 */
-#if #keys(primitive) ^ #values(primitive)
-	 @SuppressWarnings("unchecked")
+#if #keys(primitive) && #values(primitive)
+	 @SuppressWarnings("deprecation")
+#elif #keys(primitive) ^ #values(primitive)
+	 @SuppressWarnings({"unchecked","deprecation"})
 #endif
 	public void putAll(Map<? extends KEY_GENERIC_CLASS,? extends VALUE_GENERIC_CLASS> m) {
 		int n = m.size();
@@ -124,6 +127,11 @@ public abstract class ABSTRACT_MAP KEY_VALUE_GENERIC extends ABSTRACT_FUNCTION K
 		  
 #endif
 
+#if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
 		public KEY_GENERIC_CLASS getKey() {
 			return KEY2OBJ(key);
 		}
@@ -134,6 +142,11 @@ public abstract class ABSTRACT_MAP KEY_VALUE_GENERIC extends ABSTRACT_FUNCTION K
 		}
 #endif
 
+#if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
 		public VALUE_GENERIC_CLASS getValue() {
 			return VALUE2OBJ(value);
 		}
@@ -149,7 +162,9 @@ public abstract class ABSTRACT_MAP KEY_VALUE_GENERIC extends ABSTRACT_FUNCTION K
 		}
 		  
 #if #values(primitive)
-		  
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public VALUE_GENERIC_CLASS setValue( final VALUE_GENERIC_CLASS value ) {
 			return VALUE_CLASS.valueOf(setValue(value.VALUE_VALUE()));
 		}
@@ -199,6 +214,9 @@ public abstract class ABSTRACT_MAP KEY_VALUE_GENERIC extends ABSTRACT_FUNCTION K
 					return new KEY_ABSTRACT_ITERATOR KEY_GENERIC() {
 							final ObjectIterator<Map.Entry<KEY_GENERIC_CLASS,VALUE_GENERIC_CLASS>> i = entrySet().iterator();
 
+							/** {@inheritDoc}
+							 * @deprecated Please use the corresponding type-specific method instead. */
+							@Deprecated
 							public KEY_GENERIC_TYPE NEXT_KEY() { return ((MAP.Entry KEY_VALUE_GENERIC)i.next()).ENTRY_GET_KEY(); };
 
 							public boolean hasNext() { return i.hasNext(); }
@@ -232,6 +250,9 @@ public abstract class ABSTRACT_MAP KEY_VALUE_GENERIC extends ABSTRACT_FUNCTION K
 					return new VALUE_ABSTRACT_ITERATOR VALUE_GENERIC() {
 							final ObjectIterator<Map.Entry<KEY_GENERIC_CLASS,VALUE_GENERIC_CLASS>> i = entrySet().iterator();
 
+							/** {@inheritDoc}
+							 * @deprecated Please use the corresponding type-specific method instead. */
+							@Deprecated
 							public VALUE_GENERIC_TYPE NEXT_VALUE() { return ((MAP.Entry KEY_VALUE_GENERIC)i.next()).ENTRY_GET_VALUE(); };
 
 							public boolean hasNext() { return i.hasNext(); }
diff --git a/drv/AbstractPriorityQueue.drv b/drv/AbstractPriorityQueue.drv
index cdb0710..dd92edc 100644
--- a/drv/AbstractPriorityQueue.drv
+++ b/drv/AbstractPriorityQueue.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,18 +23,27 @@ import it.unimi.dsi.fastutil.AbstractPriorityQueue;
  *
  */
 
-public abstract class ABSTRACT_PRIORITY_QUEUE KEY_GENERIC extends AbstractPriorityQueue<KEY_GENERIC_CLASS> implements PRIORITY_QUEUE KEY_GENERIC  {
+public abstract class ABSTRACT_PRIORITY_QUEUE KEY_GENERIC extends AbstractPriorityQueue<KEY_GENERIC_CLASS> implements java.io.Serializable, PRIORITY_QUEUE KEY_GENERIC  {
+	private static final long serialVersionUID = 1L;
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public void enqueue( final KEY_GENERIC_CLASS x ) { enqueue( x.KEY_VALUE() ); }
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_GENERIC_CLASS dequeue() { return KEY2OBJ( DEQUEUE() ); }
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_GENERIC_CLASS first() { return KEY2OBJ( FIRST() ); }
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_GENERIC_CLASS last() { return KEY2OBJ( LAST() ); }
 
 	/** Throws an {@link UnsupportedOperationException}. */
diff --git a/drv/AbstractSet.drv b/drv/AbstractSet.drv
index 7685ebe..008df60 100644
--- a/drv/AbstractSet.drv
+++ b/drv/AbstractSet.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/AbstractSortedMap.drv b/drv/AbstractSortedMap.drv
index 0414e5c..17f4530 100644
--- a/drv/AbstractSortedMap.drv
+++ b/drv/AbstractSortedMap.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -38,27 +38,37 @@ public abstract class ABSTRACT_SORTED_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP
 	protected ABSTRACT_SORTED_MAP() {}
 
 #if #keys(primitive)
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public SORTED_MAP KEY_VALUE_GENERIC headMap( final KEY_GENERIC_CLASS to  ) {
 		return headMap( KEY_CLASS2TYPE( to ) );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public SORTED_MAP KEY_VALUE_GENERIC tailMap( final KEY_GENERIC_CLASS from ) {
 		return tailMap( KEY_CLASS2TYPE( from ) );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	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. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_GENERIC_CLASS firstKey() {
 		return KEY2OBJ( FIRST_KEY() );
 	}
 	 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_GENERIC_CLASS lastKey() {
 		return KEY2OBJ( LAST_KEY() );
 	}
diff --git a/drv/AbstractSortedSet.drv b/drv/AbstractSortedSet.drv
index dfd2517..64f7a00 100644
--- a/drv/AbstractSortedSet.drv
+++ b/drv/AbstractSortedSet.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2003-2014 Sebastiano Vigna 
+ * Copyright (C) 2003-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,27 +24,37 @@ public abstract class ABSTRACT_SORTED_SET KEY_GENERIC extends ABSTRACT_SET KEY_G
 	protected ABSTRACT_SORTED_SET() {}
 
 #if #keys(primitive)
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public SORTED_SET KEY_GENERIC headSet( final KEY_GENERIC_CLASS to  ) {
 		return headSet( to.KEY_VALUE() );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public SORTED_SET KEY_GENERIC tailSet( final KEY_GENERIC_CLASS from ) {
 		return tailSet( from.KEY_VALUE() );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public SORTED_SET KEY_GENERIC subSet( final KEY_GENERIC_CLASS from, final KEY_GENERIC_CLASS to ) {
 		return subSet( from.KEY_VALUE(), to.KEY_VALUE() );
 	}
 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_GENERIC_CLASS first() {
 		return KEY2OBJ( FIRST() );
 	}
 	 
-	/** Delegates to the corresponding type-specific method. */
+	/** Delegates to the corresponding type-specific method.
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public KEY_GENERIC_CLASS last() {
 		return KEY2OBJ( LAST() );
 	}
diff --git a/drv/AbstractStack.drv b/drv/AbstractStack.drv
index d3368d6..fdee589 100644
--- a/drv/AbstractStack.drv
+++ b/drv/AbstractStack.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/ArrayFIFOQueue.drv b/drv/ArrayFIFOQueue.drv
index 0329448..798fc08 100644
--- a/drv/ArrayFIFOQueue.drv
+++ b/drv/ArrayFIFOQueue.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2010-2014 Sebastiano Vigna 
+ * Copyright (C) 2010-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -94,7 +94,7 @@ public class ARRAY_FIFO_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KEY_GE
 		return t;
 	}
 
-	/** Dequeues the {@linkplain #last() last} element from the queue.
+	/** Dequeues the last element from the queue.
 	 *
 	 * @return the dequeued element. 
 	 * @throws NoSuchElementException if the queue is empty.
@@ -142,7 +142,7 @@ public class ARRAY_FIFO_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KEY_GE
 		if ( end == start ) expand();
 	}
 
-	/** Enqueues a new element as the {@linkplain #first() first} element (in dequeuing order) of the queue.
+	/** Enqueues a new element as the first element (in dequeuing order) of the queue.
 	 */
 	public void enqueueFirst( KEY_GENERIC_TYPE x ) {
 		if ( start == 0 ) start = length;
diff --git a/drv/ArrayFrontCodedList.drv b/drv/ArrayFrontCodedList.drv
index 1f318d5..8ec01d1 100644
--- a/drv/ArrayFrontCodedList.drv
+++ b/drv/ArrayFrontCodedList.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/ArrayIndirectDoublePriorityQueue.drv b/drv/ArrayIndirectDoublePriorityQueue.drv
deleted file mode 100644
index 37315b7..0000000
--- a/drv/ArrayIndirectDoublePriorityQueue.drv
+++ /dev/null
@@ -1,635 +0,0 @@
-/*		 
- * 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 array-based indirect double priority queue.
- *
- * <P>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.
- *
- * <P>Either comparator may be <code>null</code>, 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 <code>null</code> for the natural order.
-	 * @param d the secondary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite order of <code>c</code>.
-	 *
-	 * @param refArray the reference array.
-	 * @param capacity the initial capacity of this queue.
-	 * @param c the primary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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 <code>null</code> for the natural order.
-	 * @param d the secondary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite order of <code>c</code>.
-	 *
-	 * @param refArray the reference array.
-	 * @param c the primary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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.
-	 *
-	 * <P>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 <code>refArray</code>.
-	 * @param size the number of elements to be included in the queue.
-	 * @param c the primary comparator used in this queue, or <code>null</code> for the natural order.
-	 * @param d the secondary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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 <code>refArray</code>.
-	 * @param c the primary comparator used in this queue, or <code>null</code> for the natural order.
-	 * @param d the secondary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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 <code>refArray</code>.
-	 * @param size the number of elements to be included in the queue.
-	 * @param c the comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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 <code>refArray</code>.
-	 * @param c the comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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 <code>refArray</code>.
-	 * @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.
-	 *
-	 * <P>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 <code>refArray</code>.
-	 */
-	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 <code>primary</code> and <code>secondary</code>. Each of them contains
-			a permutation of <code>n</code> among the indices 0, 1, ..., <code>N</code>-1 in such a way that the corresponding
-			objects be sorted with respect to the two comparators.
-			We also need an array <code>inSec[]</code> so that <code>inSec[k]</code> is the index of <code>secondary</code> 
-			containing <code>k</code>.
-		*/
-		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
-
-}
diff --git a/drv/ArrayIndirectPriorityQueue.drv b/drv/ArrayIndirectPriorityQueue.drv
index 24aafb1..882e1a7 100644
--- a/drv/ArrayIndirectPriorityQueue.drv
+++ b/drv/ArrayIndirectPriorityQueue.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
diff --git a/drv/ArrayList.drv b/drv/ArrayList.drv
index 6111e8f..2b49a06 100644
--- a/drv/ArrayList.drv
+++ b/drv/ArrayList.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -68,8 +68,10 @@ public class ARRAY_LIST KEY_GENERIC extends ABSTRACT_LIST KEY_GENERIC implements
  * <p>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
+ * {@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.
+ * Moreover, you must take into consideration that assignment to an array
+ * not of type {@code Object[]} is slower due to type checking.
  *
  * <p>This class implements the bulk methods <code>removeElements()</code>,
  * <code>addElements()</code> and <code>getElements()</code> using
@@ -232,7 +234,7 @@ public class ARRAY_LIST KEY_GENERIC extends ABSTRACT_LIST KEY_GENERIC implements
 	 * 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).
 	 * 
-	 * <strong>Warning</strong>: This behaviour may cause (unfathomable) 
+	 * <P><strong>Warning</strong>: This behaviour may cause (unfathomable) 
 	 * run-time errors if a method expects an array
 	 * actually of type <code>K[]</code>, but this methods returns an array
 	 * of type {@link Object Object[]}.
@@ -247,6 +249,10 @@ public class ARRAY_LIST KEY_GENERIC extends ABSTRACT_LIST KEY_GENERIC implements
 
 	/** Wraps a given array into an array list of given size.
 	 *
+	 * <P>Note it is guaranteed
+	 * that the type of the array returned by {@link #elements()} will be the same
+	 * (see the comments in the class documentation).
+	 *
 	 * @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.
@@ -261,6 +267,10 @@ public class ARRAY_LIST KEY_GENERIC extends ABSTRACT_LIST KEY_GENERIC implements
 
 	/** Wraps a given array into an array list.
 	 *
+	 * <P>Note it is guaranteed
+	 * that the type of the array returned by {@link #elements()} will be the same
+	 * (see the comments in the class documentation).
+	 *
 	 * @param a an array to wrap.
 	 * @return a new array list wrapping the given array.
 	 */
@@ -518,6 +528,42 @@ public class ARRAY_LIST KEY_GENERIC extends ABSTRACT_LIST KEY_GENERIC implements
 		return true;
 	}
 
+	@Override
+	public boolean removeAll( final COLLECTION c ) {
+		final KEY_TYPE[] a = this.a;
+		int j = 0;
+		for( int i = 0; i < size; i++ )
+			if ( ! c.contains( a[ i ] ) ) a[ j++ ] = a[ i ];
+		final boolean modified = size != j;
+		size = j;
+		return modified;
+	}
+
+	@Override
+	public boolean removeAll( final Collection<?> c ) {
+		final KEY_TYPE[] a = this.a;
+		int j = 0;
+		for( int i = 0; i < size; i++ )
+			if ( ! c.contains( KEY2OBJ( a[ i ] ) ) ) a[ j++ ] = a[ i ];
+		final boolean modified = size != j;
+		size = j;
+		return modified;
+	}
+
+#else
+
+	@Override
+	public boolean removeAll( final Collection<?> c ) {
+		final KEY_TYPE[] a = this.a;
+		int j = 0;
+		for( int i = 0; i < size; i++ )
+			if ( ! c.contains( a[ i ] ) ) a[ j++ ] = a[ i ];
+		Arrays.fill( a, j, size, null );
+		final boolean modified = size != j;
+		size = j;
+		return modified;
+	}
+
 #endif
 
 	public KEY_LIST_ITERATOR KEY_GENERIC listIterator( final int index ) {
@@ -533,7 +579,6 @@ public class ARRAY_LIST KEY_GENERIC extends ABSTRACT_LIST KEY_GENERIC implements
 				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;
 				}
diff --git a/drv/ArrayMap.drv b/drv/ArrayMap.drv
index 25a63c9..60cd71f 100644
--- a/drv/ArrayMap.drv
+++ b/drv/ArrayMap.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2007-2014 Sebastiano Vigna 
+ * Copyright (C) 2007-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -114,7 +114,7 @@ public class ARRAY_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENERIC
 		@Override
 		public ObjectIterator<MAP.Entry KEY_VALUE_GENERIC> iterator() {
 			return new AbstractObjectIterator<MAP.Entry KEY_VALUE_GENERIC>() {
-				int next = 0;
+				int curr = -1, next = 0;
 				
 				public boolean hasNext() {
 					return next < size;
@@ -123,15 +123,28 @@ public class ARRAY_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENERIC
 				SUPPRESS_WARNINGS_KEY_VALUE_UNCHECKED
 				public Entry KEY_VALUE_GENERIC next() {
 					if ( ! hasNext() ) throw new NoSuchElementException();
-					return new ABSTRACT_MAP.BasicEntry KEY_VALUE_GENERIC( KEY_GENERIC_CAST key[ next ], VALUE_GENERIC_CAST value[ next++ ] );
+					return new ABSTRACT_MAP.BasicEntry KEY_VALUE_GENERIC( KEY_GENERIC_CAST key[ curr = next ], VALUE_GENERIC_CAST value[ next++ ] );
 				}
 				
+				public void remove() {
+					if ( curr == -1 ) throw new IllegalStateException();
+					curr = -1;
+					final int tail = size-- - next--;
+					System.arraycopy( key, next + 1, key, next, tail );
+					System.arraycopy( value, next + 1, value, next, tail );
+#if #keys(reference)
+					key[ size ] = null;
+#endif
+#if #values(reference)
+					value[ size ] = null;
+#endif
+				}
 			};
 		}
 
 		public ObjectIterator<MAP.Entry KEY_VALUE_GENERIC> fastIterator() {
 			return new AbstractObjectIterator<MAP.Entry KEY_VALUE_GENERIC>() {
-				int next = 0;
+				int next = 0, curr = -1;
 				final BasicEntry KEY_VALUE_GENERIC entry = new BasicEntry KEY_VALUE_GENERIC ( KEY_NULL, VALUE_NULL );
 				
 				public boolean hasNext() {
@@ -141,11 +154,24 @@ public class ARRAY_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENERIC
 				SUPPRESS_WARNINGS_KEY_VALUE_UNCHECKED
 				public Entry KEY_VALUE_GENERIC next() {
 					if ( ! hasNext() ) throw new NoSuchElementException();
-					entry.key = KEY_GENERIC_CAST key[ next ];
+					entry.key = KEY_GENERIC_CAST key[ curr = next ];
 					entry.value = VALUE_GENERIC_CAST value[ next++ ];
 					return entry;
 				}
 				
+				public void remove() {
+					if ( curr == -1 ) throw new IllegalStateException();
+					curr = -1;
+					final int tail = size-- - next--;
+					System.arraycopy( key, next + 1, key, next, tail );
+					System.arraycopy( value, next + 1, value, next, tail );
+#if #keys(reference)
+					key[ size ] = null;
+#endif
+#if #values(reference)
+					value[ size ] = null;
+#endif
+				}
 			};
 		}
 
@@ -157,10 +183,38 @@ public class ARRAY_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENERIC
 		public boolean contains( Object o ) {
 			if ( ! ( o instanceof Map.Entry ) ) return false;
 			final Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS> e = (Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS>)o;
+#if #keys(primitive)
+			if ( e.getKey() == null ) return false;
+#endif
 			final KEY_GENERIC_TYPE k = KEY_CLASS2TYPE( e.getKey() );
 			return ARRAY_MAP.this.containsKey( k ) && VALUE_EQUALS( ARRAY_MAP.this.GET_VALUE( k ), VALUE_CLASS2TYPE( e.getValue() ) );
 		}
-		
+
+		@SuppressWarnings("unchecked")
+		@Override
+		public boolean remove( final Object o ) {
+			if ( !( o instanceof Map.Entry ) ) return false;
+			final Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS> e = (Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS>)o;
+#if #keys(primitive)
+			if ( e.getKey() == null ) return false;
+#endif
+			final KEY_GENERIC_TYPE k = KEY_CLASS2TYPE( e.getKey() );
+			final VALUE_GENERIC_TYPE v = VALUE_CLASS2TYPE( e.getValue() );
+
+			final int oldPos = ARRAY_MAP.this.findKey( k );
+			if ( oldPos == -1 || ! VALUE_EQUALS( v, ARRAY_MAP.this.value[ oldPos ] ) ) return false;
+			final int tail = size - oldPos - 1;
+			System.arraycopy( ARRAY_MAP.this.key, oldPos + 1, ARRAY_MAP.this.key, oldPos, tail );
+			System.arraycopy( ARRAY_MAP.this.value, oldPos + 1, ARRAY_MAP.this.value, oldPos, tail );
+			ARRAY_MAP.this.size--;
+#if #keys(reference)
+			ARRAY_MAP.this.key[ size ] = null;
+#endif
+#if #values(reference)
+			ARRAY_MAP.this.value[ size ] = null;
+#endif
+			return true;
+		}
 	}
 
 	public FastEntrySet KEY_VALUE_GENERIC ENTRYSET() {
@@ -255,10 +309,8 @@ public class ARRAY_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENERIC
 		if ( oldPos == -1 ) return defRetValue;
 		final VALUE_GENERIC_TYPE oldValue = VALUE_GENERIC_CAST value[ oldPos ];
 		final int tail = size - oldPos - 1;
-		for( int i = 0; i < tail; i++ ) {
-			key[ oldPos + i ] = key[ oldPos + i + 1 ];
-			value[ oldPos + i ] = value[ oldPos + i + 1 ];
-		}
+		System.arraycopy( key, oldPos + 1, key, oldPos, tail );
+		System.arraycopy( value, oldPos + 1, value, oldPos, tail );
 		size--;
 #if #keys(reference)
 		key[ size ] = null;
diff --git a/drv/ArrayPriorityQueue.drv b/drv/ArrayPriorityQueue.drv
index 57dd69b..7ee9e87 100644
--- a/drv/ArrayPriorityQueue.drv
+++ b/drv/ArrayPriorityQueue.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
@@ -36,11 +36,12 @@ import java.util.NoSuchElementException;
  * when the size of the queue is very small.
  */
 
-public class ARRAY_PRIORITY_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KEY_GENERIC {
+public class ARRAY_PRIORITY_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KEY_GENERIC implements java.io.Serializable {
+	private static final long serialVersionUID = 1L;
 
 	/** The backing array. */
 	SUPPRESS_WARNINGS_KEY_UNCHECKED
-	protected KEY_GENERIC_TYPE array[] = KEY_GENERIC_ARRAY_CAST ARRAYS.EMPTY_ARRAY;
+	protected transient KEY_GENERIC_TYPE array[] = KEY_GENERIC_ARRAY_CAST ARRAYS.EMPTY_ARRAY;
 
 	/** The number of elements in this queue. */
 	protected int size;
@@ -49,10 +50,10 @@ public class ARRAY_PRIORITY_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KE
 	protected KEY_COMPARATOR KEY_SUPER_GENERIC c;
 
 	/** The first index, cached, if {@link #firstIndexValid} is true. */
-	protected int firstIndex;
+	transient protected int firstIndex;
 
 	/** Whether {@link #firstIndex} contains a valid value. */
-	protected boolean firstIndexValid;
+	transient protected boolean firstIndexValid;
 
 	/** Creates a new empty queue with a given capacity and comparator.
 	 *
@@ -208,4 +209,17 @@ public class ARRAY_PRIORITY_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KE
 	}
 
 	public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() { return c; }
+
+	private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
+		s.defaultWriteObject();
+		s.writeInt( array.length );
+		for( int i = 0; i < size; i++ ) s.WRITE_KEY( array[ i ] );
+	}
+
+	SUPPRESS_WARNINGS_KEY_UNCHECKED
+	private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
+		s.defaultReadObject();
+		array = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ s.readInt() ];
+		for( int i = 0; i < size; i++ ) array[ i ] = KEY_GENERIC_CAST s.READ_KEY();
+	}
 }
diff --git a/drv/ArraySet.drv b/drv/ArraySet.drv
index e8840e6..1cfca80 100644
--- a/drv/ArraySet.drv
+++ b/drv/ArraySet.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2007-2014 Sebastiano Vigna 
+ * Copyright (C) 2007-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
 package PACKAGE;
 
 import java.util.Collection;
+import java.util.NoSuchElementException;
 
 /** A simple, brute-force implementation of a set based on a backing array.
  *
@@ -97,7 +98,26 @@ public class ARRAY_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implements j
 	@Override
 	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public KEY_ITERATOR KEY_GENERIC iterator() {
-		return ITERATORS.wrap( KEY_GENERIC_ARRAY_CAST a, 0, size );
+		return new KEY_ABSTRACT_ITERATOR KEY_GENERIC () {
+			int next = 0;
+
+			public boolean hasNext() {
+				return next < size;
+			}
+
+			public KEY_GENERIC_TYPE NEXT_KEY() {
+				if ( ! hasNext() ) throw new NoSuchElementException();
+				return KEY_GENERIC_CAST a[ next++ ];
+			}
+
+			public void remove() {
+				final int tail = size-- - next--;
+				System.arraycopy( a, next + 1, a, next, tail );
+#if #keys(reference)
+				a[ size ] = null;
+#endif
+			}
+		};
 	}
 
 	public boolean contains( final KEY_TYPE k ) {
diff --git a/drv/Arrays.drv b/drv/Arrays.drv
index ebdff45..f42fad9 100644
--- a/drv/Arrays.drv
+++ b/drv/Arrays.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -100,10 +100,11 @@ import java.util.Comparator;
  * arrays much like array lists. This can be very useful when efficiency (or
  * syntactic simplicity) reasons make array lists unsuitable.
  *
- * <P><strong>Warning:</strong> 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 <em>significantly slower</em> than using <code>new</code>. This phenomenon is particularly
+ * <P><strong>Warning:</strong> if your array is not of type {@code Object[]},
+ * {@link #ensureCapacity(Object[],int,int)} and {@link #grow(Object[],int,int)}
+ * will use {@linkplain java.lang.reflect.Array#newInstance(Class,int) reflection}
+ * to preserve your array type. Reflection is <em>significantly slower</em> than using <code>new</code>. 
+ * This phenomenon is particularly
  * evident in the first growth phases of an array reallocated with doubling (or similar) logic.
  *
  * <h2>Sorting</h2>
@@ -147,9 +148,9 @@ public class ARRAYS {
 
 	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	private static <K> K[] newArray( final K[] prototype, final int length ) {
-		final Class<?> componentType = prototype.getClass().getComponentType();
-		if ( length == 0 && componentType == Object.class ) return (K[])EMPTY_ARRAY;
-		return (K[])java.lang.reflect.Array.newInstance( prototype.getClass().getComponentType(), length );
+		final Class<?> klass = prototype.getClass();
+		if ( klass == Object[].class ) return (K[])( length == 0 ? EMPTY_ARRAY : new Object[ length ] );
+		return (K[])java.lang.reflect.Array.newInstance( klass.getComponentType(), length );
 	}
 #endif
 
@@ -656,9 +657,12 @@ public class ARRAYS {
 	 * @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();
+		if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSort( x, from, to, comp );
+		else {
+			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
@@ -874,9 +878,12 @@ public class ARRAYS {
 	 * @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();
+		if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSort( x, from, to );
+		else {
+			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.
@@ -1097,9 +1104,12 @@ public class ARRAYS {
 	 * @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();
+		if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSortIndirect( perm, x, from, to );
+		else {
+			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.
@@ -1139,6 +1149,8 @@ public class ARRAYS {
 	 *
 	 * @param perm a permutation array indexing {@code x} so that it is sorted.
 	 * @param x the sorted array to be stabilized.
+	 * @param from the index of the first element (inclusive) to be stabilized.
+	 * @param to the index of the last element (exclusive) 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;
@@ -1380,6 +1392,7 @@ public class ARRAYS {
 	 * @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 ) {
+		if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSort( x, y, from, to );
 		final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() );
 		pool.invoke( new ForkJoinQuickSort2 KEY_GENERIC( x, y, from, to ) );
 		pool.shutdown();
@@ -1729,24 +1742,22 @@ public class ARRAYS {
 		final int maxLevel = DIGITS_PER_ELEMENT - 1;
 
 		final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( DIGITS_PER_ELEMENT - 1 ) + 1;
+		int stackPos = 0;
 		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;
+		offsetStack[ stackPos ] = from;
+		lengthStack[ stackPos ] = to - from;
+		levelStack[ stackPos++ ] = 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 ];
+		while( stackPos > 0 ) {
+			final int first = offsetStack[ --stackPos ];
+			final int length = lengthStack[ stackPos ];
+			final int level = levelStack[ stackPos ];
 #if #keyclass(Character)
 			final int signMask = 0;
 #else
@@ -1782,9 +1793,9 @@ public class ARRAYS {
 				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;
+						offsetStack[ stackPos ] = i;
+						lengthStack[ stackPos ] = count[ c ];
+						levelStack[ stackPos++ ] = level + 1;
 					}
 				}
 			}
@@ -1963,25 +1974,23 @@ public class ARRAYS {
 		final int maxLevel = DIGITS_PER_ELEMENT - 1;
 
 		final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( DIGITS_PER_ELEMENT - 1 ) + 1;
+		int stackPos = 0;
 		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;
+		offsetStack[ stackPos ] = from;
+		lengthStack[ stackPos ] = to - from;
+		levelStack[ stackPos++ ] = 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 ];
+		while( stackPos > 0 ) {
+			final int first = offsetStack[ --stackPos ];
+			final int length = lengthStack[ stackPos ];
+			final int level = levelStack[ stackPos ];
 #if #keyclass(Character)
 			final int signMask = 0;
 #else
@@ -2006,9 +2015,9 @@ public class ARRAYS {
 					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;
+							offsetStack[ stackPos ] = p;
+							lengthStack[ stackPos ] = count[ i ];
+							levelStack[ stackPos++ ] = level + 1;
 						}
 					}
 					p += count[ i ];
@@ -2035,9 +2044,9 @@ public class ARRAYS {
 					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;
+							offsetStack[ stackPos ] = i;
+							lengthStack[ stackPos ] = count[ c ];
+							levelStack[ stackPos++ ] = level + 1;
 						}
 					}
 				}
@@ -2226,24 +2235,22 @@ public class ARRAYS {
 		final int maxLevel = DIGITS_PER_ELEMENT * layers - 1;
 		
 		final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( layers * DIGITS_PER_ELEMENT - 1 ) + 1;
+		int stackPos = 0;
 		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;
+		offsetStack[ stackPos ] = from;
+		lengthStack[ stackPos ] = to - from;
+		levelStack[ stackPos++ ] = 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 ];
+		while( stackPos > 0 ) {
+			final int first = offsetStack[ --stackPos ];
+			final int length = lengthStack[ stackPos ];
+			final int level = levelStack[ stackPos ];
 #if #keyclass(Character)
 			final int signMask = 0;
 #else
@@ -2289,9 +2296,9 @@ public class ARRAYS {
 				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;
+						offsetStack[ stackPos ] = i;
+						lengthStack[ stackPos ] = count[ c ];
+						levelStack[ stackPos++ ] = level + 1;
 					}
 				}
 			}
@@ -2482,25 +2489,23 @@ public class ARRAYS {
 		final int maxLevel = DIGITS_PER_ELEMENT * layers - 1;
 		
 		final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( layers * DIGITS_PER_ELEMENT - 1 ) + 1;
+		int stackPos = 0;
 		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;
+		offsetStack[ stackPos ] = from;
+		lengthStack[ stackPos ] = to - from;
+		levelStack[ stackPos++ ] = 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 ];
+		while( stackPos > 0 ) {
+			final int first = offsetStack[ --stackPos ];
+			final int length = lengthStack[ stackPos ];
+			final int level = levelStack[ stackPos ];
 #if #keyclass(Character)
 			final int signMask = 0;
 #else
@@ -2527,9 +2532,9 @@ public class ARRAYS {
 					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;
+							offsetStack[ stackPos ] = p;
+							lengthStack[ stackPos ] = count[ i ];
+							levelStack[ stackPos++ ] = level + 1;
 						}
 					}
 					p += count[ i ];
@@ -2557,9 +2562,9 @@ public class ARRAYS {
 					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;
+							offsetStack[ stackPos ] = i;
+							lengthStack[ stackPos ] = count[ c ];
+							levelStack[ stackPos++ ] = level + 1;
 						}
 					}
 				}
@@ -2636,25 +2641,23 @@ public class ARRAYS {
 		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;
+		int stackPos = 0;
 		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;
+		offsetStack[ stackPos ] = from;
+		lengthStack[ stackPos ] = to - from;
+		levelStack[ stackPos++ ] = 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 ];
+		while( stackPos > 0 ) {
+			final int first = offsetStack[ --stackPos ];
+			final int length = lengthStack[ stackPos ];
+			final int level = levelStack[ stackPos ];
 #if #keyclass(Character)
 			final int signMask = 0;
 #else
@@ -2695,9 +2698,9 @@ public class ARRAYS {
 				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;
+						offsetStack[ stackPos ] = i;
+						lengthStack[ stackPos ] = count[ c ];
+						levelStack[ stackPos++ ] = level + 1;
 					}
 				}
 			}
diff --git a/drv/BidirectionalIterator.drv b/drv/BidirectionalIterator.drv
index f81d8a7..e6b34c5 100644
--- a/drv/BidirectionalIterator.drv
+++ b/drv/BidirectionalIterator.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/BigArrayBigList.drv b/drv/BigArrayBigList.drv
index a8d7027..5efd3de 100644
--- a/drv/BigArrayBigList.drv
+++ b/drv/BigArrayBigList.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
 
 package PACKAGE;
 
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.RandomAccess;
 import java.util.NoSuchElementException;
@@ -369,6 +370,84 @@ public class BIG_ARRAY_BIG_LIST KEY_GENERIC extends ABSTRACT_BIG_LIST KEY_GENERI
 		return old;
 	}
 
+#if #keys(primitive)
+	@Override
+	public boolean removeAll( final COLLECTION c ) {
+		KEY_GENERIC_TYPE[] s = null, d = null;
+		int ss = -1, sd = BigArrays.SEGMENT_SIZE, ds = -1, dd = BigArrays.SEGMENT_SIZE;
+		for ( long i = 0; i < size; i++ ) {
+			if ( sd == BigArrays.SEGMENT_SIZE ) {
+				sd = 0;
+				s = a[ ++ss ];
+			}
+			if ( !c.contains( s[ sd ] ) ) {
+				if ( dd == BigArrays.SEGMENT_SIZE ) {
+					d = a[ ++ds ];
+					dd = 0;
+				}
+				d[ dd++ ] = s[ sd ];
+			}
+			sd++;
+		}
+		final long j = BigArrays.index( ds, dd );
+		final boolean modified = size != j;
+		size = j;
+		return modified;
+	}
+
+	@Override
+	public boolean removeAll( final Collection<?> c ) {
+		KEY_GENERIC_TYPE[] s = null, d = null;
+		int ss = -1, sd = BigArrays.SEGMENT_SIZE, ds = -1, dd = BigArrays.SEGMENT_SIZE;
+		for ( long i = 0; i < size; i++ ) {
+			if ( sd == BigArrays.SEGMENT_SIZE ) {
+				sd = 0;
+				s = a[ ++ss ];
+			}
+			if ( !c.contains( KEY2OBJ( s[ sd ] ) ) ) {
+				if ( dd == BigArrays.SEGMENT_SIZE ) {
+					d = a[ ++ds ];
+					dd = 0;
+				}
+				d[ dd++ ] = s[ sd ];
+			}
+			sd++;
+		}
+		final long j = BigArrays.index( ds, dd );
+		final boolean modified = size != j;
+		size = j;
+		return modified;
+	}
+
+#else
+
+	@Override
+	public boolean removeAll( final Collection<?> c ) {
+		KEY_GENERIC_TYPE[] s = null, d = null;
+		int ss = -1, sd = BigArrays.SEGMENT_SIZE, ds = -1, dd = BigArrays.SEGMENT_SIZE;
+		for ( long i = 0; i < size; i++ ) {
+			if ( sd == BigArrays.SEGMENT_SIZE ) {
+				sd = 0;
+				s = a[ ++ss ];
+			}
+			if ( !c.contains( s[ sd ] ) ) {
+				if ( dd == BigArrays.SEGMENT_SIZE ) {
+					d = a[ ++ds ];
+					dd = 0;
+				}
+				d[ dd++ ] = s[ sd ];
+			}
+			sd++;
+		}
+		final long j = BigArrays.index( ds, dd );
+		final boolean modified = size != j;
+		size = j;
+		return modified;
+	}
+
+#endif
+
+
 	public void clear() {
 #if #keys(reference)
 		BIG_ARRAYS.fill( a, 0, size, null );
@@ -468,11 +547,12 @@ public class BIG_ARRAY_BIG_LIST KEY_GENERIC extends ABSTRACT_BIG_LIST KEY_GENERI
 		size += length;
 	}
 
-	public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator( final int index ) {
+	@Override
+	public KEY_BIG_LIST_ITERATOR KEY_GENERIC listIterator( final long index ) {
 		ensureIndex( index );
 
 		return new KEY_ABSTRACT_BIG_LIST_ITERATOR KEY_GENERIC() {
-				int pos = index, last = -1;
+				long pos = index, last = -1;
 
 				public boolean hasNext() { return pos < size; }
 				public boolean hasPrevious() { return pos > 0; }
@@ -481,7 +561,6 @@ public class BIG_ARRAY_BIG_LIST KEY_GENERIC extends ABSTRACT_BIG_LIST KEY_GENERI
 				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;
 				}
diff --git a/drv/BigArrays.drv b/drv/BigArrays.drv
index 65616b2..1883652 100644
--- a/drv/BigArrays.drv
+++ b/drv/BigArrays.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2009-2014 Sebastiano Vigna 
+ * Copyright (C) 2009-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,10 +33,12 @@ import java.util.Random;
 
 import it.unimi.dsi.fastutil.BigArrays;
 import it.unimi.dsi.fastutil.Hash;
+import static it.unimi.dsi.fastutil.BigArrays.ensureLength;
 import static it.unimi.dsi.fastutil.BigArrays.start;
 import static it.unimi.dsi.fastutil.BigArrays.segment;
 import static it.unimi.dsi.fastutil.BigArrays.displacement;
 import static it.unimi.dsi.fastutil.BigArrays.SEGMENT_MASK;
+import static it.unimi.dsi.fastutil.BigArrays.SEGMENT_SHIFT;
 import static it.unimi.dsi.fastutil.BigArrays.SEGMENT_SIZE;
 
 #if #keys(primitive)
@@ -308,7 +310,8 @@ public class BIG_ARRAYS {
 
 	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);
+		ensureLength( length );
+		final int baseLength = (int)((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
 		Object[][] base = (Object[][])java.lang.reflect.Array.newInstance( componentType, baseLength );
 		final int residual = (int)(length & SEGMENT_MASK);
 		if ( residual != 0 ) {
@@ -329,7 +332,8 @@ public class BIG_ARRAYS {
 
 	public static KEY_TYPE[][] newBigArray( final long length ) {
 		if ( length == 0 ) return EMPTY_BIG_ARRAY;
-		final int baseLength = (int)((length + SEGMENT_MASK) / SEGMENT_SIZE);
+		ensureLength( length );
+		final int baseLength = (int)((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
 		KEY_TYPE[][] base = new KEY_TYPE[ baseLength ][];
 		final int residual = (int)(length & SEGMENT_MASK);
 		if ( residual != 0 ) {
@@ -419,8 +423,9 @@ public class BIG_ARRAYS {
 	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 ) {
+			ensureLength( length );
 			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 int baseLength = (int)((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
 			final KEY_GENERIC_TYPE[][] base = Arrays.copyOf( array, baseLength );
 			final Class<?> componentType = array.getClass().getComponentType();
 			final int residual = (int)(length & SEGMENT_MASK);
@@ -453,8 +458,9 @@ public class BIG_ARRAYS {
 	public static KEY_TYPE[][] ensureCapacity( final KEY_TYPE[][] array, final long length, final long preserve ) {
 		final long oldLength = length( array );
 		if ( length > oldLength ) {
+			ensureLength( length );
 			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 int baseLength = (int)((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
 			final KEY_TYPE[][] base = Arrays.copyOf( array, baseLength );
 			final int residual = (int)(length & SEGMENT_MASK);
 			if ( residual != 0 ) {
@@ -535,9 +541,10 @@ public class BIG_ARRAYS {
 	 */
 
 	public static KEY_GENERIC KEY_GENERIC_TYPE[][] trim( final KEY_GENERIC_TYPE[][] array, final long length ) {
+		ensureLength( length );
 		final long oldLength = length( array );
 		if ( length >= oldLength ) return array;
-		final int baseLength = (int)((length + SEGMENT_MASK) / SEGMENT_SIZE);
+		final int baseLength = (int)((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
 		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 );
@@ -561,9 +568,10 @@ public class BIG_ARRAYS {
 	 */
 
 	public static KEY_GENERIC KEY_GENERIC_TYPE[][] trim( final KEY_GENERIC_TYPE[][] array, final long length ) {
+		ensureLength( length );
 		final long oldLength = length( array );
 		if ( length >= oldLength ) return array;
-		final int baseLength = (int)((length + SEGMENT_MASK) / SEGMENT_SIZE);
+		final int baseLength = (int)((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
 		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 );
diff --git a/drv/BigList.drv b/drv/BigList.drv
index 9892b35..d91ef1d 100644
--- a/drv/BigList.drv
+++ b/drv/BigList.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2010-2014 Sebastiano Vigna 
+ * Copyright (C) 2010-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/BigListIterator.drv b/drv/BigListIterator.drv
index 8dd9c30..973b25c 100644
--- a/drv/BigListIterator.drv
+++ b/drv/BigListIterator.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2010-2014 Sebastiano Vigna 
+ * Copyright (C) 2010-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/BigListIterators.drv b/drv/BigListIterators.drv
index 14d7ffd..f62df8d 100644
--- a/drv/BigListIterators.drv
+++ b/drv/BigListIterators.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -124,7 +124,13 @@ public class BIG_LIST_ITERATORS {
 		public long nextIndex() { return i.nextIndex(); }
 		public long previousIndex() { return i.previousIndex(); }
 #if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public KEY_GENERIC_CLASS next() { return i.next(); }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public KEY_GENERIC_CLASS previous() { return i.previous(); }
 #endif
 	}
diff --git a/drv/BigLists.drv b/drv/BigLists.drv
index fed8060..7277035 100644
--- a/drv/BigLists.drv
+++ b/drv/BigLists.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -121,19 +121,28 @@ public class BIG_LISTS {
 
 		private Object readResolve() { return EMPTY_BIG_LIST; }
 		public Object clone() { return EMPTY_BIG_LIST; }
+		public int hashCode() { return 1; }
+		@SuppressWarnings("rawtypes")
+		public boolean equals( Object o ) { return o instanceof BigList && ((BigList)o).isEmpty(); }
+		public String toString() { return "[]"; }
 	}
 
 	/** An empty big list (immutable). It is serializable and cloneable. 
-	 *
-	 * <P>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();
 
-
+#if #keys(reference)
+	/** Return an empty big list (immutable). It is serializable and cloneable.
+	 *
+	 * <P>This method provides a typesafe access to {@link #EMPTY_BIG_LIST}.
+	 * @return an empty big list (immutable).
+	 */
+	@SuppressWarnings("unchecked")
+	public static KEY_GENERIC BIG_LIST KEY_GENERIC emptyList() {
+		return EMPTY_BIG_LIST;
+	}
+#endif
 
 	/** An immutable class representing a type-specific singleton big list. 
 	 *
@@ -200,6 +209,7 @@ public class BIG_LISTS {
 #if #keys(primitive)
 		public boolean rem( final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
 		public boolean addAll( final COLLECTION c ) { throw new UnsupportedOperationException(); }
+		@Override
 		public boolean addAll( final long i, final COLLECTION c ) { throw new UnsupportedOperationException(); }
 #else
 		public boolean remove( Object k ) { throw new UnsupportedOperationException(); }
@@ -409,7 +419,13 @@ public class BIG_LISTS {
 		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 ); }
+#if #keys(primitive)
+		@Override
+#endif
 		public boolean addAll( long index, COLLECTION KEY_GENERIC c ) { return list.addAll( intIndex( index ), c ); }
+#if #keys(primitive)
+		@Override
+#endif
 		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 ); }
diff --git a/drv/BinIO.drv b/drv/BinIO.drv
index 40c6032..56d94cd 100644
--- a/drv/BinIO.drv
+++ b/drv/BinIO.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2005-2014 Sebastiano Vigna 
+ * Copyright (C) 2005-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/BinIOFragment.drv b/drv/BinIOFragment.drv
index da9a9a2..cf1496f 100644
--- a/drv/BinIOFragment.drv
+++ b/drv/BinIOFragment.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2004-2014 Sebastiano Vigna 
+ * Copyright (C) 2004-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/Collection.drv b/drv/Collection.drv
index 9b4c9e2..5fa3b11 100644
--- a/drv/Collection.drv
+++ b/drv/Collection.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/Collections.drv b/drv/Collections.drv
index 7c4d7d1..896b077 100644
--- a/drv/Collections.drv
+++ b/drv/Collections.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/Comparator.drv b/drv/Comparator.drv
index 26e89ac..dd6ca99 100644
--- a/drv/Comparator.drv
+++ b/drv/Comparator.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/Comparators.drv b/drv/Comparators.drv
index 741c6c1..7588326 100644
--- a/drv/Comparators.drv
+++ b/drv/Comparators.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
@@ -29,30 +29,67 @@ public class COMPARATORS {
 	private COMPARATORS() {}
 
 	/** A type-specific comparator mimicking the natural order. */
-
+#if #keys(reference)
 	SUPPRESS_WARNINGS_KEY_UNCHECKED_RAWTYPES
-	public static final KEY_COMPARATOR NATURAL_COMPARATOR = new KEY_ABSTRACT_COMPARATOR() {
-			public final int compare( final KEY_TYPE a, final KEY_TYPE b ) {
-#if #keys(primitive)
-				return KEY_CMP( a, b );
+	protected static class NaturalImplicitComparator implements Comparator, java.io.Serializable {
 #else
-				return ((Comparable)a).compareTo(b);
+	protected static class NaturalImplicitComparator extends KEY_ABSTRACT_COMPARATOR KEY_GENERIC implements java.io.Serializable {
 #endif
-			}
-		};
+		private static final long serialVersionUID = 1L;
 
-	/** A type-specific comparator mimicking the opposite of the natural order. */
+		public final int compare( final KEY_TYPE a, final KEY_TYPE b ) {
+#if #keys(primitive)
+			return KEY_CMP( a, b );
+#else
+			return ((Comparable)a).compareTo(b);
+#endif
+		}
+        private Object readResolve() { return NATURAL_COMPARATOR; }
+	};
+	
+	SUPPRESS_WARNINGS_KEY_RAWTYPES
+	public static final KEY_COMPARATOR NATURAL_COMPARATOR = new NaturalImplicitComparator();
 
+	/** A type-specific comparator mimicking the opposite of the natural order. */	
+#if #keys(reference)
 	SUPPRESS_WARNINGS_KEY_UNCHECKED_RAWTYPES
-	public static final KEY_COMPARATOR OPPOSITE_COMPARATOR = new KEY_ABSTRACT_COMPARATOR() {
-			public final int compare( final KEY_TYPE a, final KEY_TYPE b ) {
+	protected static class OppositeImplicitComparator implements Comparator, java.io.Serializable {
+#else
+	protected static class OppositeImplicitComparator extends KEY_ABSTRACT_COMPARATOR KEY_GENERIC implements java.io.Serializable {
+#endif
+		private static final long serialVersionUID = 1L;
+
+		public final int compare( final KEY_TYPE a, final KEY_TYPE b ) {
 #if #keys(primitive)
-				return - KEY_CMP( a, b );
+			return - KEY_CMP( a, b );
+#else
+			return ((Comparable)b).compareTo(a);
+#endif
+		}
+        private Object readResolve() { return OPPOSITE_COMPARATOR; }
+	};
+
+	SUPPRESS_WARNINGS_KEY_RAWTYPES
+	public static final KEY_COMPARATOR OPPOSITE_COMPARATOR = new OppositeImplicitComparator();
+	
+
+#if #keys(reference)
+	protected static class OppositeComparator KEY_GENERIC implements Comparator KEY_GENERIC, java.io.Serializable {
 #else
-				return ((Comparable)b).compareTo(a);
+	protected static class OppositeComparator KEY_GENERIC extends KEY_ABSTRACT_COMPARATOR KEY_GENERIC implements java.io.Serializable {
 #endif
-			}
-		};
+		private static final long serialVersionUID = 1L;
+
+		private final KEY_COMPARATOR KEY_GENERIC comparator;
+		
+		protected OppositeComparator( final KEY_COMPARATOR KEY_GENERIC c ) {
+			comparator = c;
+		}
+		
+		public final int compare( final KEY_GENERIC_TYPE a, final KEY_GENERIC_TYPE b ) {
+			return comparator.compare( b, a );
+		}
+	};
 
 	/** Returns a comparator representing the opposite order of the given comparator. 
 	 *
@@ -60,11 +97,6 @@ public class COMPARATORS {
 	 * @return a comparator representing the opposite order of <code>c</code>.
 	 */
 	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 );
-				}
-			};
+		return new OppositeComparator KEY_GENERIC ( c );
 	}
 }
diff --git a/drv/Function.drv b/drv/Function.drv
index 6bc6d65..9a95a91 100644
--- a/drv/Function.drv
+++ b/drv/Function.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/Functions.drv b/drv/Functions.drv
index eaef63b..2e01ad9 100644
--- a/drv/Functions.drv
+++ b/drv/Functions.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -48,6 +48,12 @@ public class FUNCTIONS {
 		public void defaultReturnValue( final VALUE_GENERIC_TYPE defRetValue )  { throw new UnsupportedOperationException(); }
 	
 #if #keys(primitive)
+#if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
+		@Override
 		public VALUE_GENERIC_CLASS get( final Object k ) { return null; }
 #endif
 
@@ -158,19 +164,41 @@ public class FUNCTIONS {
 		public String toString() { synchronized( sync ) { return function.toString(); } }
 
 #if #keys(primitive) || #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public VALUE_GENERIC_CLASS put( final KEY_GENERIC_CLASS k, final VALUE_GENERIC_CLASS v ) { synchronized( sync ) { return function.put( k, v ); } }
+#if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
+		@Override
 		public VALUE_GENERIC_CLASS get( final Object k ) { synchronized( sync ) { return function.get( k ); } }
+#if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
+		@Override
 		public VALUE_GENERIC_CLASS remove( final Object k ) { synchronized( sync ) { return function.remove( k ); } }
 #endif
 
 #if #keys(primitive)
+		@Override
 		public VALUE_GENERIC_TYPE remove( final KEY_GENERIC_TYPE k ) { synchronized( sync ) { return function.remove( k ); } }
+
+		@Override
 		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)
+		@Override
 		public VALUE_GENERIC_TYPE REMOVE_VALUE( final Object k ) { synchronized( sync ) { return function.REMOVE_VALUE( k ); } }
+
+		@Override
 		public VALUE_GENERIC_TYPE GET_VALUE( final Object k ) { synchronized( sync ) { return function.GET_VALUE( k ); } }
 #endif
 
@@ -221,13 +249,27 @@ public class FUNCTIONS {
 		public String toString() { return function.toString(); }
 
 #if #keys(primitive)
+#if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
+		@Override
 		public VALUE_GENERIC_TYPE remove( final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
+#if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
+		@Override
 		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)
+		@Override
 		public VALUE_GENERIC_TYPE REMOVE_VALUE( final Object k ) { throw new UnsupportedOperationException(); }
+		@Override
 		public VALUE_GENERIC_TYPE GET_VALUE( final Object k ) { return function.GET_VALUE( k ); }
 #endif
 
diff --git a/drv/Hash.drv b/drv/Hash.drv
index 1d2ffd8..9ceb310 100644
--- a/drv/Hash.drv
+++ b/drv/Hash.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/HeapIndirectDoublePriorityQueue.drv b/drv/HeapIndirectDoublePriorityQueue.drv
deleted file mode 100644
index b58239a..0000000
--- a/drv/HeapIndirectDoublePriorityQueue.drv
+++ /dev/null
@@ -1,654 +0,0 @@
-/*		 
- * 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.
- *
- * <P>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.
- *
- * <P>Either comparator may be <code>null</code>, 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 <code>null</code> for the natural order.
-	 * @param d the secondary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite order of <code>c</code>.
-	 *
-	 * @param refArray the reference array.
-	 * @param capacity the initial capacity of this queue.
-	 * @param c the primary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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 <code>null</code> for the natural order.
-	 * @param d the secondary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite order of <code>c</code>.
-	 *
-	 * @param refArray the reference array.
-	 * @param c the primary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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.
-	 *
-	 * <P>The queue returned by this method will be backed by the given array.
-	 * The first <code>size</code> 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 <code>a</code> one by one).
-	 *
-	 * @param refArray the reference array.
-	 * @param a an array of indices into <code>refArray</code>.
-	 * @param size the number of elements to be included in the queue.
-	 * @param c the primary comparator used in this queue, or <code>null</code> for the natural order.
-	 * @param d the secondary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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 <code>a</code> one by one).
-	 *
-	 * @param refArray the reference array.
-	 * @param a an array of indices into <code>refArray</code>.
-	 * @param c the primary comparator used in this queue, or <code>null</code> for the natural order.
-	 * @param d the secondary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>The queue returned by this method will be backed by the given array.
-	 * The first <code>size</code> 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 <code>a</code> one by one).
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite order of <code>c</code>.
-	 *
-	 * @param refArray the reference array.
-	 * @param a an array of indices into <code>refArray</code>.
-	 * @param size the number of elements to be included in the queue.
-	 * @param c the primary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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 <code>a</code> one by one).
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite order of <code>c</code>.
-	 *
-	 * @param refArray the reference array.
-	 * @param a an array of indices into <code>refArray</code>.
-	 * @param c the primary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>The queue returned by this method will be backed by the given array.
-	 * The first <code>size</code> 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 <code>a</code> one by one).
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite of the natural order.
-	 *
-	 * @param refArray the reference array.
-	 * @param a an array of indices into <code>refArray</code>.
-	 * @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.
-	 *
-	 * <P>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 <code>a</code> one by one).
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite of the natural order.
-	 *
-	 * @param refArray the reference array.
-	 * @param a an array of indices into <code>refArray</code>.
-	 */
-	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 <code>primary</code> and <code>secondary</code>. Each of them contains
-			a permutation of <code>n</code> among the indices 0, 1, ..., <code>N</code>-1 in such a way that the corresponding
-			objects be sorted with respect to the two comparators.
-			We also need an array <code>inSec[]</code> so that <code>inSec[k]</code> is the index of <code>secondary</code> 
-			containing <code>k</code>.
-		*/
-		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
-
-}
diff --git a/drv/HeapIndirectPriorityQueue.drv b/drv/HeapIndirectPriorityQueue.drv
index 0c6a8c0..25eb305 100644
--- a/drv/HeapIndirectPriorityQueue.drv
+++ b/drv/HeapIndirectPriorityQueue.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
diff --git a/drv/HeapPriorityQueue.drv b/drv/HeapPriorityQueue.drv
index f991880..8ca6ee9 100644
--- a/drv/HeapPriorityQueue.drv
+++ b/drv/HeapPriorityQueue.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
@@ -22,8 +22,11 @@ import java.util.Arrays;
 import java.util.Comparator;
 
 import it.unimi.dsi.fastutil.AbstractPriorityQueue;
+#else
+import java.util.Iterator;
 #endif
 
+import java.util.Collection;
 import java.util.NoSuchElementException;
 
 
@@ -33,11 +36,12 @@ import java.util.NoSuchElementException;
  * 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 {
+public class HEAP_PRIORITY_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KEY_GENERIC implements java.io.Serializable {
+	private static final long serialVersionUID = 1L;
 
 	/** The heap array. */
 	SUPPRESS_WARNINGS_KEY_UNCHECKED
-	protected KEY_GENERIC_TYPE[] heap = KEY_GENERIC_ARRAY_CAST ARRAYS.EMPTY_ARRAY;
+	protected transient KEY_GENERIC_TYPE[] heap = KEY_GENERIC_ARRAY_CAST ARRAYS.EMPTY_ARRAY;
 
 	/** The number of elements in this queue. */
 	protected int size;
@@ -135,6 +139,79 @@ public class HEAP_PRIORITY_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KEY
 		this( a, a.length );
 	}
 
+#if #keys(primitive)
+
+	/** Creates a queue using the elements in a type-specific collection using a given comparator.
+	 *
+	 * <P>This constructor is more efficient than enqueing the elements of <code>collection</code> one by one.
+	 *
+	 * @param collection a collection; its elements will be used to initialize the queue.
+	 * @param c the comparator used in this queue, or <code>null</code> for the natural order.
+	 */
+	public HEAP_PRIORITY_QUEUE( final COLLECTION KEY_EXTENDS_GENERIC collection, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
+		this( collection.TO_KEY_ARRAY(), c );
+	}
+
+	/** Creates a queue using the elements in a type-specific collection using the natural order.
+	 *
+	 * <P>This constructor is
+	 * more efficient than enqueing the elements of <code>collection</code> one by one.
+	 *
+	 * @param collection a collection; its elements will be used to initialize the queue.
+	 */
+	public HEAP_PRIORITY_QUEUE( final COLLECTION KEY_EXTENDS_GENERIC collection ) {
+		this( collection, null );
+	}
+	
+	/** Creates a queue using the elements in a collection using a given comparator.
+	 *
+	 * <P>This constructor is more efficient than enqueing the elements of <code>collection</code> one by one.
+	 *
+	 * @param collection a collection; its elements will be used to initialize the queue.
+	 * @param c the comparator used in this queue, or <code>null</code> for the natural order.
+	 */
+	public HEAP_PRIORITY_QUEUE( final Collection<? extends KEY_GENERIC_CLASS> collection, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
+		this( collection.size(), c );
+		final Iterator<? extends KEY_GENERIC_CLASS> iterator = collection.iterator();
+		final int size = collection.size();
+		for( int i = 0 ; i < size; i++ ) heap[ i ] = KEY_OBJ2TYPE( iterator.next() );
+	}
+
+	/** Creates a queue using the elements in a collection using the natural order.
+	 *
+	 * <P>This constructor is
+	 * more efficient than enqueing the elements of <code>collection</code> one by one.
+	 *
+	 * @param collection a collection; its elements will be used to initialize the queue.
+	 */
+	public HEAP_PRIORITY_QUEUE( final Collection<? extends KEY_GENERIC_CLASS> collection ) {
+		this( collection, null );
+	}
+#else
+	/** Creates a queue using the elements in a collection using a given comparator.
+	 *
+	 * <P>This constructor is more efficient than enqueing the elements of <code>collection</code> one by one.
+	 *
+	 * @param collection a collection; its elements will be used to initialize the queue.
+	 * @param c the comparator used in this queue, or <code>null</code> for the natural order.
+	 */
+	SUPPRESS_WARNINGS_KEY_UNCHECKED
+	public HEAP_PRIORITY_QUEUE( final Collection<? extends KEY_GENERIC_CLASS> collection, final KEY_COMPARATOR KEY_SUPER_GENERIC c ) {
+		this( KEY_GENERIC_ARRAY_CAST collection.toArray(), c );
+	}
+
+	/** Creates a queue using the elements in a collection using the natural order.
+	 *
+	 * <P>This constructor is
+	 * more efficient than enqueing the elements of <code>collection</code> one by one.
+	 *
+	 * @param collection a collection; its elements will be used to initialize the queue.
+	 */
+	public HEAP_PRIORITY_QUEUE( final Collection<? extends KEY_GENERIC_CLASS> collection ) {
+		this( collection, null );
+	}
+#endif
+	
 	public void enqueue( KEY_GENERIC_TYPE x ) {
 		if ( size == heap.length ) heap = ARRAYS.grow( heap, size + 1 );
 
@@ -181,6 +258,19 @@ public class HEAP_PRIORITY_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KEY
 
 	public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() { return c; }
 
+	private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
+		s.defaultWriteObject();
+		s.writeInt( heap.length );
+		for( int i = 0; i < size; i++ ) s.WRITE_KEY( heap[ i ] );
+	}
+
+	SUPPRESS_WARNINGS_KEY_UNCHECKED
+	private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
+		s.defaultReadObject();
+		heap = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[ s.readInt() ];
+		for( int i = 0; i < size; i++ ) heap[ i ] = KEY_GENERIC_CAST s.READ_KEY();
+	}
+
 
 #ifdef TEST
 
@@ -314,7 +404,7 @@ public class HEAP_PRIORITY_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KEY
 			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 + ")" );
+			if ( mThrowsOutOfBounds == null ) ensure( KEY_EQUALS(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 + ")");
@@ -323,6 +413,30 @@ public class HEAP_PRIORITY_QUEUE KEY_GENERIC extends ABSTRACT_PRIORITY_QUEUE KEY
 				ensure( KEY_EQUALS(m.FIRST(), t.FIRST()), "Error (" + seed + "): m and t differ in first element after dequeue (" + m.FIRST() + ", " + t.FIRST() + ")");
 			}
 
+			/* Now we save and read m. */
+
+			try {
+				java.io.File ff = new java.io.File("it.unimi.dsi.fastutil.test");
+				java.io.OutputStream os = new java.io.FileOutputStream(ff);
+				java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(os);
+				
+				oos.writeObject(m);
+				oos.close();
+				
+				java.io.InputStream is = new java.io.FileInputStream(ff);
+				java.io.ObjectInputStream ois = new java.io.ObjectInputStream(is);
+					
+				m = (HEAP_PRIORITY_QUEUE)ois.readObject();
+				ois.close();
+				ff.delete();
+			}
+			catch(Exception e) {
+				e.printStackTrace();
+				System.exit( 1 );
+			}
+
+			ensure( heapEqual( m.heap, t.array, m.size(), t.size() ), "Error (" + seed + "): m and t differ after save/read" );
+
 			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;
diff --git a/drv/HeapSemiIndirectPriorityQueue.drv b/drv/HeapSemiIndirectPriorityQueue.drv
index a2aa337..e6f7908 100644
--- a/drv/HeapSemiIndirectPriorityQueue.drv
+++ b/drv/HeapSemiIndirectPriorityQueue.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
diff --git a/drv/HeapSesquiIndirectDoublePriorityQueue.drv b/drv/HeapSesquiIndirectDoublePriorityQueue.drv
deleted file mode 100644
index ff46d08..0000000
--- a/drv/HeapSesquiIndirectDoublePriorityQueue.drv
+++ /dev/null
@@ -1,667 +0,0 @@
-/*		 
- * 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.
- *
- * <P>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.
- *
- * <P>Either comparator may be <code>null</code>, 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 <code>null</code> for the natural order.
-	 * @param d the secondary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite order of <code>c</code>.
-	 *
-	 * @param refArray the reference array.
-	 * @param capacity the initial capacity of this queue.
-	 * @param c the primary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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 <code>null</code> for the natural order.
-	 * @param d the secondary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite order of <code>c</code>.
-	 *
-	 * @param refArray the reference array.
-	 * @param c the primary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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.
-	 *
-	 * <P>The queue returned by this method will be backed by the given array.
-	 * The first <code>size</code> 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 <code>a</code> one by one).
-	 *
-	 * @param refArray the reference array.
-	 * @param a an array of indices into <code>refArray</code>.
-	 * @param size the number of elements to be included in the queue.
-	 * @param c the primary comparator used in this queue, or <code>null</code> for the natural order.
-	 * @param d the secondary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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 <code>a</code> one by one).
-	 *
-	 * @param refArray the reference array.
-	 * @param a an array of indices into <code>refArray</code>.
-	 * @param c the primary comparator used in this queue, or <code>null</code> for the natural order.
-	 * @param d the secondary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>The queue returned by this method will be backed by the given array.
-	 * The first <code>size</code> 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 <code>a</code> one by one).
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite order of <code>c</code>.
-	 *
-	 * @param refArray the reference array.
-	 * @param a an array of indices into <code>refArray</code>.
-	 * @param size the number of elements to be included in the queue.
-	 * @param c the primary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>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 <code>a</code> one by one).
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite order of <code>c</code>.
-	 *
-	 * @param refArray the reference array.
-	 * @param a an array of indices into <code>refArray</code>.
-	 * @param c the primary comparator used in this queue, or <code>null</code> 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.
-	 *
-	 * <P>The queue returned by this method will be backed by the given array.
-	 * The first <code>size</code> 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 <code>a</code> one by one).
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite of the natural order.
-	 *
-	 * @param refArray the reference array.
-	 * @param a an array of indices into <code>refArray</code>.
-	 * @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.
-	 *
-	 * <P>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 <code>a</code> one by one).
-	 *
-	 * <P>This constructor uses as secondary comparator the opposite of the natural order.
-	 *
-	 * @param refArray the reference array.
-	 * @param a an array of indices into <code>refArray</code>.
-	 */
-	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 <code>primary</code> and <code>secondary</code>. Each of them contains
-			a permutation of <code>n</code> among the indices 0, 1, ..., <code>N</code>-1 in such a way that the corresponding
-			objects be sorted with respect to the two comparators.
-			We also need an array <code>inSec[]</code> so that <code>inSec[k]</code> is the index of <code>secondary</code> 
-			containing <code>k</code>.
-		*/
-		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
-
-}
diff --git a/drv/Heaps.drv b/drv/Heaps.drv
index 302df99..cfa6a34 100644
--- a/drv/Heaps.drv
+++ b/drv/Heaps.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
@@ -44,23 +44,27 @@ public class HEAPS {
 
 	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 + ")" );
+		assert i < 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 ];
+			while ( ( child = ( i << 1 ) + 1 ) < size ) {
+				KEY_GENERIC_TYPE t = heap[ child ];
+				final int right = child + 1;
+				if ( right < size && KEY_LESS( heap[ right ], t ) ) t = heap[ child = right ];
+				if ( KEY_LESSEQ( e, t ) ) break;
+				heap[ i ] = t;
 				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 ];
+			while ( ( child = ( i << 1 ) + 1 ) < size ) {
+				KEY_GENERIC_TYPE t = heap[ child ];
+				final int right = child + 1;
+				if ( right < size && c.compare( heap[ right ], t ) < 0 ) t = heap[ child = right ];
+				if ( c.compare( e, t ) <= 0 ) break;
+				heap[ i ] = t;
 				i = child;
 			}
 
@@ -80,21 +84,24 @@ public class HEAPS {
 
 	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 + ")" );
+		assert i < 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 ]; 
+			while ( i != 0 ) {
+				final int parent = ( i - 1 ) >>> 1;
+				final KEY_GENERIC_TYPE t = heap[ parent ];
+				if ( KEY_LESSEQ( t, e ) ) break;
+				heap[ i ] = t;
 				i = parent;
 			}
 		else
-			while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
-				if ( c.compare( heap[ parent ], e ) <= 0 ) break;
-				heap[ i ] = heap[ parent ]; 
+			while ( i != 0 ) {
+				final int parent = ( i - 1 ) >>> 1;
+				final KEY_GENERIC_TYPE t = heap[ parent ];
+				if ( c.compare( t, e ) <= 0 ) break;
+				heap[ i ] = t; 
 				i = parent;
 			}
 
@@ -111,8 +118,7 @@ public class HEAPS {
 	 */
 
 	public static KEY_GENERIC void makeHeap( final KEY_GENERIC_TYPE[] heap, final int size, final KEY_COMPARATOR KEY_GENERIC c ) {
-		int i = size / 2;
+		int i = size >>> 1;
 		while( i-- != 0 ) downHeap( heap, size, i, c );
 	}
-
 }
diff --git a/drv/IndirectDoublePriorityQueue.drv b/drv/IndirectDoublePriorityQueue.drv
deleted file mode 100644
index 38b088a..0000000
--- a/drv/IndirectDoublePriorityQueue.drv
+++ /dev/null
@@ -1,37 +0,0 @@
-/*		 
- * 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}. 
- *
- * <P>Additionally, this interface strengthens {@link #comparator()}.
- */
-
-public interface INDIRECT_DOUBLE_PRIORITY_QUEUE extends INDIRECT_PRIORITY_QUEUE, IndirectDoublePriorityQueue<KEY_CLASS> {
-
-    /** Returns the secondary comparator associated with this queue.
-	 *
-	 * Note that this specification strengthens the one given in {@link IndirectDoublePriorityQueue}.
-	 *
-	 * @return the comparator associated with this queue.
-	 * @see IndirectDoublePriorityQueue#comparator()
-	 */
-	KEY_COMPARATOR secondaryComparator();
-}
diff --git a/drv/IndirectHeaps.drv b/drv/IndirectHeaps.drv
index 017865d..5658784 100644
--- a/drv/IndirectHeaps.drv
+++ b/drv/IndirectHeaps.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
@@ -48,25 +48,29 @@ public class INDIRECT_HEAPS {
 
 	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 + ")" );
+		assert i < 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 ];
+			while ( ( child = ( i << 1 ) + 1 ) < size ) {
+				int t = heap[ child ];
+				final int right = child + 1;
+				if ( right < size && KEY_LESS( refArray[ heap[ right ] ], refArray[ t ] ) ) t = heap[ child = right ];
+				if ( KEY_LESSEQ( E, refArray[ t ] ) ) break;
+				heap[ i ] = t;
 				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 ];
+			while ( ( child = ( i << 1 ) + 1 ) < size ) {
+				int t = heap[ child ];
+				final int right = child + 1;
+				if ( right < size && c.compare( refArray[ heap[ right ] ], refArray[ t ] ) < 0 ) t = heap[ child = right ];
+				if ( c.compare( E, refArray[ t ] ) <= 0 ) break;
+				heap[ i ] = t;
 				inv[ heap[ i ] ] = i;
 				i = child;
 			}
@@ -91,23 +95,26 @@ public class INDIRECT_HEAPS {
 
 	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 + ")" );
+		assert i < 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 ];
+			while ( i != 0 ) {
+				final int parent = ( i - 1 ) >>> 1;
+				final int t = heap[ parent ];
+				if ( KEY_LESSEQ( refArray[ t ], E ) ) break;
+				heap[ i ] = t;
 				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 ]; 
+			while ( i != 0 ) {
+				final int parent = ( i - 1 ) >>> 1;
+				final int t = heap[ parent ];
+				if ( c.compare( refArray[ t ], E ) <= 0 ) break;
+				heap[ i ] = t;
 				inv[ heap[ i ] ] = i;
 				i = parent;
 			}
@@ -138,7 +145,7 @@ public class INDIRECT_HEAPS {
 		int i = length;
 		while( i-- != 0 ) inv[ heap[ i ] = offset + i ] = i;
 
-		i = length / 2;
+		i = length >>> 1;
 		while( i-- != 0 ) downHeap( refArray, heap, inv, length, i, c );
 	}
 
@@ -153,7 +160,7 @@ public class INDIRECT_HEAPS {
 	 */
 
 	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;
+		int i = size >>> 1;
 		while( i-- != 0 ) downHeap( refArray, heap, inv, size, i, c );
 	}
 }
diff --git a/drv/IndirectPriorityQueue.drv b/drv/IndirectPriorityQueue.drv
index 239b55b..56fca05 100644
--- a/drv/IndirectPriorityQueue.drv
+++ b/drv/IndirectPriorityQueue.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
diff --git a/drv/Iterable.drv b/drv/Iterable.drv
index 987aac9..ef2f906 100644
--- a/drv/Iterable.drv
+++ b/drv/Iterable.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/Iterator.drv b/drv/Iterator.drv
index 3b0b873..a8ef6dc 100644
--- a/drv/Iterator.drv
+++ b/drv/Iterator.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/Iterators.drv b/drv/Iterators.drv
index 8646302..09cf943 100644
--- a/drv/Iterators.drv
+++ b/drv/Iterators.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -660,6 +660,10 @@ public class ITERATORS {
 
 		public KEY_GENERIC_TYPE NEXT_KEY() { return i.NEXT_KEY(); }
 #if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public KEY_GENERIC_CLASS next() { return i.next(); }
 #endif
 	}
@@ -688,7 +692,15 @@ public class ITERATORS {
 		public KEY_GENERIC_TYPE NEXT_KEY() { return i.NEXT_KEY(); }
 		public KEY_GENERIC_TYPE PREV_KEY() { return i.PREV_KEY(); }
 #if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public KEY_GENERIC_CLASS next() { return i.next(); }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public KEY_GENERIC_CLASS previous() { return i.previous(); }
 #endif
 	}
@@ -718,7 +730,15 @@ public class ITERATORS {
 		public int nextIndex() { return i.nextIndex(); }
 		public int previousIndex() { return i.previousIndex(); }
 #if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public KEY_GENERIC_CLASS next() { return i.next(); }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public KEY_GENERIC_CLASS previous() { return i.previous(); }
 #endif
 	}
diff --git a/drv/LinkedOpenCustomDoubleHashMap.drv b/drv/LinkedOpenCustomDoubleHashMap.drv
deleted file mode 120000
index 2a96034..0000000
--- a/drv/LinkedOpenCustomDoubleHashMap.drv
+++ /dev/null
@@ -1 +0,0 @@
-OpenDoubleHashMap.drv
\ No newline at end of file
diff --git a/drv/LinkedOpenCustomDoubleHashSet.drv b/drv/LinkedOpenCustomDoubleHashSet.drv
deleted file mode 120000
index 579ba65..0000000
--- a/drv/LinkedOpenCustomDoubleHashSet.drv
+++ /dev/null
@@ -1 +0,0 @@
-OpenDoubleHashSet.drv
\ No newline at end of file
diff --git a/drv/LinkedOpenDoubleHashMap.drv b/drv/LinkedOpenDoubleHashMap.drv
deleted file mode 120000
index 2a96034..0000000
--- a/drv/LinkedOpenDoubleHashMap.drv
+++ /dev/null
@@ -1 +0,0 @@
-OpenDoubleHashMap.drv
\ No newline at end of file
diff --git a/drv/LinkedOpenDoubleHashSet.drv b/drv/LinkedOpenDoubleHashSet.drv
deleted file mode 120000
index 579ba65..0000000
--- a/drv/LinkedOpenDoubleHashSet.drv
+++ /dev/null
@@ -1 +0,0 @@
-OpenDoubleHashSet.drv
\ No newline at end of file
diff --git a/drv/List.drv b/drv/List.drv
index 87a6177..889c8d8 100644
--- a/drv/List.drv
+++ b/drv/List.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/ListIterator.drv b/drv/ListIterator.drv
index f2c0211..68aa2ee 100644
--- a/drv/ListIterator.drv
+++ b/drv/ListIterator.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/Lists.drv b/drv/Lists.drv
index aedb82b..7fe12e7 100644
--- a/drv/Lists.drv
+++ b/drv/Lists.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -131,18 +131,28 @@ public class LISTS {
 
 		private Object readResolve() { return EMPTY_LIST; }
 		public Object clone() { return EMPTY_LIST; }
+		public int hashCode() { return 1; }
+		@SuppressWarnings("rawtypes")
+		public boolean equals( Object o ) { return o instanceof List && ((List)o).isEmpty(); }
+		public String toString() { return "[]"; }
 	}
 
 	/** An empty list (immutable). It is serializable and cloneable. 
-	 *
-	 * <P>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();
 
+#if #keys(reference)
+	/** Return an empty list (immutable). It is serializable and cloneable.
+	 *
+	 * <P>This method provides a typesafe access to {@link #EMPTY_LIST}.
+	 * @return an empty list (immutable).
+	 */
+	@SuppressWarnings("unchecked")
+	public static KEY_GENERIC LIST KEY_GENERIC emptyList() {
+		return EMPTY_LIST;
+	}
+#endif
 
 
 	/** An immutable class representing a type-specific singleton list. 
diff --git a/drv/Map.drv b/drv/Map.drv
index 5e122f3..9c9c307 100644
--- a/drv/Map.drv
+++ b/drv/Map.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -69,7 +69,7 @@ public interface MAP KEY_VALUE_GENERIC extends FUNCTION KEY_VALUE_GENERIC, Map<K
 	 * <p>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
+	 * of type-specific entries (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.
@@ -116,6 +116,14 @@ public interface MAP KEY_VALUE_GENERIC extends FUNCTION KEY_VALUE_GENERIC, Map<K
 	interface Entry KEY_VALUE_GENERIC extends Map.Entry <KEY_GENERIC_CLASS,VALUE_GENERIC_CLASS> {
 		  
 #if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
+		KEY_GENERIC_CLASS getKey();
+#endif
+
+#if #keys(primitive)
 		/**
 		 * @see java.util.Map.Entry#getKey()
 		 */
@@ -123,6 +131,14 @@ public interface MAP KEY_VALUE_GENERIC extends FUNCTION KEY_VALUE_GENERIC, Map<K
 #endif
 
 #if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
+		VALUE_GENERIC_CLASS getValue();
+#endif
+
+#if #values(primitive)
 		/**
 		 * @see java.util.Map.Entry#setValue(Object)
 		 */
diff --git a/drv/Maps.drv b/drv/Maps.drv
index 092980f..129846b 100644
--- a/drv/Maps.drv
+++ b/drv/Maps.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -90,11 +90,22 @@ public class MAPS {
 
 
 
-	/** An empty type-specific map (immutable). It is serializable and cloneable. */
-	 
+	/** An empty type-specific map (immutable). It is serializable and cloneable. 
+	 */
 	SUPPRESS_WARNINGS_KEY_VALUE_RAWTYPES
 	public static final EmptyMap EMPTY_MAP = new EmptyMap();
 
+#if #keys(reference) || #values(reference)
+	/** Return an empty map (immutable). It is serializable and cloneable.
+	 *
+	 * <P>This method provides a typesafe access to {@link #EMPTY_MAP}.
+	 * @return an empty map (immutable).
+	 */
+	@SuppressWarnings("unchecked")
+	public static KEY_VALUE_GENERIC MAP KEY_VALUE_GENERIC emptyMap() {
+		return EMPTY_MAP;
+	}
+#endif
 
 	/** An immutable class representing a type-specific singleton map.	 
 	 *
@@ -106,9 +117,9 @@ public class MAPS {
 	
 		private static final long serialVersionUID = -7046029254386353129L;
 
-		protected transient volatile ObjectSet<MAP.Entry KEY_VALUE_GENERIC> entries;
-		protected transient volatile SET KEY_GENERIC keys;
-		protected transient volatile VALUE_COLLECTION VALUE_GENERIC values;
+		protected transient ObjectSet<MAP.Entry KEY_VALUE_GENERIC> entries;
+		protected transient SET KEY_GENERIC keys;
+		protected transient VALUE_COLLECTION VALUE_GENERIC values;
 
 		protected Singleton( final KEY_GENERIC_TYPE key, final VALUE_GENERIC_TYPE value ) {
 			super( key, value );
@@ -126,7 +137,17 @@ public class MAPS {
 		public VALUE_COLLECTION VALUE_GENERIC values() { if ( values == null ) values = VALUE_SETS.singleton( value ); return values; }
 
 		protected class SingletonEntry implements MAP.Entry KEY_VALUE_GENERIC, Map.Entry<KEY_GENERIC_CLASS,VALUE_GENERIC_CLASS> {
+#if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
 			public KEY_GENERIC_CLASS getKey() { return KEY2OBJ( Singleton.this.key ); }
+#if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
 			public VALUE_GENERIC_CLASS getValue() { return VALUE2OBJ( Singleton.this.value ); }
 
 #if #keys(primitive)
@@ -209,9 +230,9 @@ public class MAPS {
 
 		protected final MAP KEY_VALUE_GENERIC map;
 
-		protected transient volatile ObjectSet<MAP.Entry KEY_VALUE_GENERIC> entries;
-		protected transient volatile SET KEY_GENERIC keys;
-		protected transient volatile VALUE_COLLECTION VALUE_GENERIC values;
+		protected transient ObjectSet<MAP.Entry KEY_VALUE_GENERIC> entries;
+		protected transient SET KEY_GENERIC keys;
+		protected transient VALUE_COLLECTION VALUE_GENERIC values;
 
 		protected SynchronizedMap( final MAP KEY_VALUE_GENERIC m, final Object sync ) {
 			super( m, sync );
@@ -243,21 +264,49 @@ public class MAPS {
 		public String toString() { synchronized( sync ) { return map.toString(); } }
 
 #if #keys(primitive) || #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public VALUE_GENERIC_CLASS put( final KEY_GENERIC_CLASS k, final VALUE_GENERIC_CLASS v ) { synchronized( sync ) { return map.put( k, v ); } }
 #endif
 
 #if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public VALUE_GENERIC_TYPE remove( final KEY_GENERIC_TYPE k ) { synchronized( sync ) { return map.remove( k ); } }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public VALUE_GENERIC_TYPE get( final KEY_GENERIC_TYPE k ) { synchronized( sync ) { return map.get( k ); } }
 		public boolean containsKey( final Object ok ) { synchronized( sync ) { return map.containsKey( ok ); } }
 #endif
 
 #if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public boolean containsValue( final Object ov ) { synchronized( sync ) { return map.containsValue( ov ); } }
 #endif
 
 #if #keys(reference)
+#if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
+		@Override
 		public VALUE_GENERIC_TYPE REMOVE_VALUE( final Object k ) { synchronized( sync ) { return map.REMOVE_VALUE( k ); } }
+#if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
+		@Override
 		public VALUE_GENERIC_TYPE GET_VALUE( final Object k ) { synchronized( sync ) { return map.GET_VALUE( k ); } }
 #endif
 
@@ -296,9 +345,9 @@ public class MAPS {
 
 		protected final MAP KEY_VALUE_GENERIC map;
 
-		protected transient volatile ObjectSet<MAP.Entry KEY_VALUE_GENERIC> entries;
-		protected transient volatile SET KEY_GENERIC keys;
-		protected transient volatile VALUE_COLLECTION VALUE_GENERIC values;
+		protected transient ObjectSet<MAP.Entry KEY_VALUE_GENERIC> entries;
+		protected transient SET KEY_GENERIC keys;
+		protected transient VALUE_COLLECTION VALUE_GENERIC values;
 
 		protected UnmodifiableMap( final MAP KEY_VALUE_GENERIC m ) {
 			super( m );
@@ -325,11 +374,23 @@ public class MAPS {
 		public String toString() { return map.toString(); }
 
 #if #keys(primitive) && #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public VALUE_GENERIC_CLASS put( final KEY_GENERIC_CLASS k, final VALUE_GENERIC_CLASS v ) { throw new UnsupportedOperationException(); }
 #endif
 
 #if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public VALUE_GENERIC_TYPE remove( final KEY_GENERIC_TYPE k ) { throw new UnsupportedOperationException(); }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public VALUE_GENERIC_TYPE get( final KEY_GENERIC_TYPE k ) { return map.get( k ); }
 		public boolean containsKey( final Object ok ) { return map.containsKey( ok ); }
 #endif
@@ -339,7 +400,19 @@ public class MAPS {
 #endif
 
 #if #keys(reference) || #values(reference)
+#if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
+		@Override
 		public VALUE_GENERIC_TYPE REMOVE_VALUE( final Object k ) { throw new UnsupportedOperationException(); }
+#if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
+		@Override
 		public VALUE_GENERIC_TYPE GET_VALUE( final Object k ) { return map.GET_VALUE( k ); }
 #endif
 
diff --git a/drv/OpenCustomDoubleHashMap.drv b/drv/OpenCustomDoubleHashMap.drv
deleted file mode 120000
index 2a96034..0000000
--- a/drv/OpenCustomDoubleHashMap.drv
+++ /dev/null
@@ -1 +0,0 @@
-OpenDoubleHashMap.drv
\ No newline at end of file
diff --git a/drv/OpenCustomDoubleHashSet.drv b/drv/OpenCustomDoubleHashSet.drv
deleted file mode 120000
index 579ba65..0000000
--- a/drv/OpenCustomDoubleHashSet.drv
+++ /dev/null
@@ -1 +0,0 @@
-OpenDoubleHashSet.drv
\ No newline at end of file
diff --git a/drv/OpenDoubleHashMap.drv b/drv/OpenDoubleHashMap.drv
deleted file mode 100644
index 252ac1d..0000000
--- a/drv/OpenDoubleHashMap.drv
+++ /dev/null
@@ -1,2606 +0,0 @@
-/*		 
- * 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.Map;
-import java.util.NoSuchElementException;
-#ifdef Custom
-//import it.unimi.dsi.fastutil.Maps;
-#endif
-
-import it.unimi.dsi.fastutil.Hash;
-import it.unimi.dsi.fastutil.HashCommon;
-import it.unimi.dsi.fastutil.bytes.ByteArrays;
-
-import VALUE_PACKAGE.VALUE_COLLECTION;
-import VALUE_PACKAGE.VALUE_ABSTRACT_COLLECTION;
-
-#if #values(primitive) || #keys(primitive) && #valueclass(Object)
-import VALUE_PACKAGE.VALUE_ITERATOR;
-#endif
-
-#if #keys(reference) || #values(reference)
-import it.unimi.dsi.fastutil.objects.ObjectArrays;
-#endif
-
-
-#ifdef Linked
-
-import java.util.Comparator;
-
-#if #key(reference)
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.SortedSet;
-#endif
-
-#if #values(primitive)
-import VALUE_PACKAGE.VALUE_LIST_ITERATOR;
-#endif
-
-#if #keys(primitive) && #valueclass(Reference)
-import it.unimi.dsi.fastutil.objects.ObjectIterator;
-#endif
-
-import it.unimi.dsi.fastutil.objects.AbstractObjectSortedSet;
-import it.unimi.dsi.fastutil.objects.ObjectListIterator;
-import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator;
-import it.unimi.dsi.fastutil.objects.ObjectSortedSet;
-
-#else
-
-import it.unimi.dsi.fastutil.objects.AbstractObjectSet;
-
-#if #keys(primitive) && ! #valueclass(Object)
-import it.unimi.dsi.fastutil.objects.ObjectIterator;
-#endif
-
-#endif
-
-
-
-#ifdef Linked
-/**  A type-specific linked hash map with with a fast, small-footprint implementation.
- *
- * <P>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 <em>never</em> 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.
- *
- * <P>The enlargement speed is controlled by the <em>growth factor</em>, a
- * positive number. If the growth factor is <var>p</var>, then the table is
- * enlarged each time roughly by a factor 2<sup>p/16</sup>. By default, <var>p</var> 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 <em>not</em> serialized:
- * deserialized tables gets the {@linkplain Hash#DEFAULT_GROWTH_FACTOR default growth factor}).
- *
- * <P>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.
- *
- * <P>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 <code>null</code>.
- *
- * <P>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.
- *
- * <P>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.
- *
- * <P>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 <em>never</em> 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.
- *
- * <P>The enlargement speed is controlled by the <em>growth factor</em>, a
- * positive number. If the growth factor is <var>p</var>, then the table is
- * enlarged each time roughly by a factor 2<sup>p/16</sup>. By default, <var>p</var> 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 <em>not</em> 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.
- *
- * <P>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 <em>never</em> 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.
- *
- * <P>The enlargement speed is controlled by the <em>growth factor</em>, a
- * positive number. If the growth factor is <var>p</var>, then the table is
- * enlarged each time roughly by a factor 2<sup>p/16</sup>. By default, <var>p</var> 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 <em>not</em> 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 <code>{@link Hash#PRIMES}[{@link #p}+growthFactor</code>. */
-	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 <code>n</code>/<code>f</code>.
-	 *
-	 * @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 <code>n</code>/<code>f</code>.
-	 *
-	 * @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 <code>k</code> and <code>v</code> 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 <code>k</code> and <code>v</code> 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 <code>k</code> and <code>v</code> 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 <code>k</code> and <code>v</code> 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 2<sup>p/16</sup>.
-	 * 
-	 * @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,
-	 * <var>-i</var>-1, where <var>i</var> 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.
-	 *
-	 * <P>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<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS> {
-		private int index;
-		
-		MapEntry( final int index ) {
-			this.index = index;
-		}
-		
-		public KEY_GENERIC_CLASS getKey() {
-			return KEY2OBJ( key[ index ] );
-		}
-		  
-#if #keys(primitive)
-		public KEY_TYPE ENTRY_GET_KEY() {
-	   		return key[ index ];
-		}
-#endif
-
-		public VALUE_GENERIC_CLASS getValue() {
-			return VALUE2OBJ( value[ index ] );
-		}
-		  
-#if #values(primitive)
-		public VALUE_GENERIC_TYPE ENTRY_GET_VALUE() {
-			return value[ index ];
-		}
-#endif
-
-		public VALUE_GENERIC_TYPE setValue( final VALUE_GENERIC_TYPE v ) {
-			final VALUE_GENERIC_TYPE oldValue = value[ index ];
-			value[ index ] = v;
-			return oldValue;
-		}
-		  
-#if #values(primitive)
-		  
-		public VALUE_GENERIC_CLASS setValue( final VALUE_GENERIC_CLASS v ) {
-			return VALUE2OBJ( setValue( VALUE_CLASS2TYPE( v ) ) );
-		}
-
-#endif
-
-		SUPPRESS_WARNINGS_KEY_UNCHECKED
-		public boolean equals( final Object o ) {
-			if (!(o instanceof Map.Entry)) return false;
-			Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS> e = (Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS>)o;
-   				
-			return KEY_EQUALS( key[ index ], KEY_CLASS2TYPE( e.getKey() ) ) && VALUE_EQUALS( value[ index ], VALUE_CLASS2TYPE( e.getValue() ) );
-		}
-		  
-		public int hashCode() {
-			return KEY2JAVAHASH( key[ index ] ) ^ VALUE2JAVAHASH( value[ index ] );
-		}
-		 
-			  
-		public String toString() {
-			return key[ index ] + "=>" + value[ index ];
-		}
-	}
-
-
-#ifdef Linked
-
-	/** Modifies the {@link #link} vector so that the given entry is removed.
-	 *
-	 * <P>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.
-	 *
-	 * <P>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 <code>null</code> 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 <code>null</code> 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 ObjectListIterator<MAP.Entry KEY_VALUE_GENERIC> {
-		public EntryIterator() {}
-
-		public EntryIterator( KEY_GENERIC_TYPE from ) {
-			super( from );
-		}
-
-		public MapEntry next() {
-			return new MapEntry( nextEntry() );
-		}
-
-		public MapEntry previous() {
-			return new MapEntry( previousEntry() );
-		}
-
-		public void set( MAP.Entry KEY_VALUE_GENERIC ok ) { throw new UnsupportedOperationException(); }
-		public void add( MAP.Entry KEY_VALUE_GENERIC ok ) { throw new UnsupportedOperationException(); }
-	}
-
-	private class FastEntryIterator extends MapIterator implements ObjectListIterator<MAP.Entry KEY_VALUE_GENERIC> {
-		final BasicEntry KEY_VALUE_GENERIC entry = new BasicEntry KEY_VALUE_GENERIC ( KEY_NULL, VALUE_NULL );
-	
-		public FastEntryIterator() {}
-
-		public FastEntryIterator( KEY_GENERIC_TYPE from ) {
-			super( from );
-		}
-
-		public BasicEntry KEY_VALUE_GENERIC next() {
-			final int e = nextEntry();
-			entry.key = key[ e ];
-			entry.value = value[ e ];
-			return entry;
-		}
-
-		public BasicEntry KEY_VALUE_GENERIC previous() {
-			final int e = previousEntry();
-			entry.key = key[ e ];
-			entry.value = value[ e ];
-			return entry;
-		}
-
-		public void set( MAP.Entry KEY_VALUE_GENERIC ok ) { throw new UnsupportedOperationException(); }
-		public void add( MAP.Entry KEY_VALUE_GENERIC ok ) { throw new UnsupportedOperationException(); }
-	}
-
-#else	 
-
-	/** An iterator over a hash map. */
-
-	private class MapIterator {
-		/** The index of the next entry to be returned. */
-		int pos = 0;
-		/** The index of the last entry that has been returned. */
-		int last = -1;
-		/** A downward counter measuring how many entries have been returned. */
-		int c = count;
-		
-		{ 
-			final byte state[] = OPEN_DOUBLE_HASH_MAP.this.state;
-			final int n = state.length;
-			
-			if ( c != 0 ) while( pos < n && state[ pos ] != OCCUPIED ) pos++;
-		}
-		
-		public boolean hasNext() {
-			return c != 0 && pos < OPEN_DOUBLE_HASH_MAP.this.state.length;
-		}
-		
-		public int nextEntry() {
-			final byte state[] = OPEN_DOUBLE_HASH_MAP.this.state;
-			final int n = state.length;
-			
-			if ( ! hasNext() ) throw new NoSuchElementException();
-			last = pos;
-			if ( --c != 0 ) do pos++; while( pos < n && state[ pos ] != OCCUPIED );
-			
-			return last;
-		}
-
-		SUPPRESS_WARNINGS_KEY_UNCHECKED
-		public void remove() {
-			if (last == -1) throw new IllegalStateException();
-			state[last] = REMOVED;
-#if #keys(reference)
-			key[last] = KEY_GENERIC_CAST HashCommon.REMOVED;
-#endif
-#if #values(reference)
-			value[last] = null;
-#endif
-			
-			count--;
-		}
-
-		public int skip( final int n ) { 
-			int i = n;
-			while( i-- != 0 && hasNext() ) nextEntry(); 
-			return n - i - 1;
-		}
-	}
-
-
-	private class EntryIterator extends MapIterator implements ObjectIterator<MAP.Entry KEY_VALUE_GENERIC> {
-		public MAP.Entry KEY_VALUE_GENERIC next() {
-			return new MapEntry( nextEntry() );
-		}
-	}
-
-	private class FastEntryIterator extends MapIterator implements ObjectIterator<MAP.Entry KEY_VALUE_GENERIC> {
-		final BasicEntry KEY_VALUE_GENERIC entry = new BasicEntry KEY_VALUE_GENERIC ( KEY_NULL, VALUE_NULL );
-		public BasicEntry KEY_VALUE_GENERIC next() {
-			final int e = nextEntry();
-			entry.key = key[ e ];
-			entry.value = value[ e ];
-			return entry;
-		}
-	}
-
-#endif
-
-
-	SUPPRESS_WARNINGS_KEY_UNCHECKED
-	public boolean containsKey( KEY_TYPE k ) {
-		return findKey( KEY_GENERIC_CAST k ) >= 0;
-	}
-	 
-	public int size() {
-		return count;
-	}
-
-	public boolean isEmpty() {
-		return count == 0;
-	}
-
-	SUPPRESS_WARNINGS_KEY_UNCHECKED
-	public VALUE_GENERIC_TYPE GET_VALUE(final KEY_TYPE k) {
-		final int i = findKey( KEY_GENERIC_CAST k);
-
-		return i < 0 ? defRetValue : value[i];
-	}
-
-	SUPPRESS_WARNINGS_KEY_UNCHECKED
-	public VALUE_GENERIC_TYPE REMOVE_VALUE(final KEY_TYPE k) {
-		final int i = findKey( KEY_GENERIC_CAST k );
-		if (i < 0) return defRetValue;
-		
-		state[i] = REMOVED;
-		count--;
-
-#if #keys(reference)
-		key[i] = KEY_GENERIC_CAST HashCommon.REMOVED;
-#endif
-#if #values(reference)
-		final VALUE_GENERIC_TYPE v = value[i];
-		value[i] = null;
-#endif
-
-#ifdef Linked
-		fixPointers( i );
-#endif
-#if #values(reference)
-		return v;
-#else
-		return value[i];
-#endif
-	}
-
-
-#if #keys(primitive)
-
-	public VALUE_GENERIC_CLASS get(final KEY_CLASS ok) {
-		final int i = findKey(KEY_CLASS2TYPE(ok));
-
-		return i < 0 ? OBJECT_DEFAULT_RETURN_VALUE : (VALUE_GENERIC_CLASS)VALUE2OBJ(value[i]);
-	}
-#endif
-
-#if #keys(primitive) || #values(primitive)
-	SUPPRESS_WARNINGS_KEY_UNCHECKED
-	public VALUE_GENERIC_CLASS remove( final Object ok ) {
-		final int i = findKey( KEY_GENERIC_CAST KEY_OBJ2TYPE( ok ) );
-		if (i < 0) return OBJECT_DEFAULT_RETURN_VALUE;
-
-		state[i] = REMOVED;
-		count--;
-
-#if #keys(reference)
-		key[i] = KEY_GENERIC_CAST HashCommon.REMOVED;
-#endif
-
-#if #values(reference)
-		final VALUE_GENERIC_CLASS v = value[i];
-		value[i] = null;
-#endif
-
-#ifdef Linked
-		fixPointers( i );
-#endif
-
-		if ( ASSERTS ) checkTable();
-
-#if #values(reference)
-		return v;
-#else
-		return VALUE2OBJ( value[i] );
-#endif
-	}
-
-
-#endif
-
-
-
-
-#ifdef Linked
-	private final class MapEntrySet extends AbstractObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC> implements FastSortedEntrySet KEY_VALUE_GENERIC {
-
-		public ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC> iterator() {
-			return new EntryIterator();
-		}
-
-		public Comparator<? super MAP.Entry KEY_VALUE_GENERIC> comparator() { return null; }
-		public ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC> subSet( MAP.Entry KEY_VALUE_GENERIC fromElement, MAP.Entry KEY_VALUE_GENERIC toElement) { throw new UnsupportedOperationException(); }
-		public ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC> headSet( MAP.Entry KEY_VALUE_GENERIC toElement ) { throw new UnsupportedOperationException(); }
-		public ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC> tailSet( MAP.Entry KEY_VALUE_GENERIC fromElement ) { throw new UnsupportedOperationException(); }
-
-		public MAP.Entry KEY_VALUE_GENERIC first() { 
-			if ( count == 0 ) throw new NoSuchElementException();
-			return new MapEntry( OPEN_DOUBLE_HASH_MAP.this.first ); 
-		}
-
-		public MAP.Entry KEY_VALUE_GENERIC last() { 
-			if ( count == 0 ) throw new NoSuchElementException();
-			return new MapEntry( OPEN_DOUBLE_HASH_MAP.this.last ); 
-		}
-		
-#else
-	private final class MapEntrySet extends AbstractObjectSet<MAP.Entry KEY_VALUE_GENERIC> implements FastEntrySet KEY_VALUE_GENERIC {
-
-		public ObjectIterator<MAP.Entry KEY_VALUE_GENERIC> iterator() {
-			return new EntryIterator();
-		}
-
-		public ObjectIterator<MAP.Entry KEY_VALUE_GENERIC> fastIterator() {
-			return new FastEntryIterator();
-		}
-#endif					 
-					 
-		SUPPRESS_WARNINGS_KEY_UNCHECKED
-		public boolean contains( final Object o ) {
-			if (!(o instanceof Map.Entry)) return false;
-			final Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS> e = (Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS>)o;
-			final int i = findKey( KEY_CLASS2TYPE( e.getKey() ) );
-			return i >= 0 && VALUE_EQUALS( value[ i ], VALUE_CLASS2TYPE( e.getValue() ) );
-		}
-			 
-		SUPPRESS_WARNINGS_KEY_UNCHECKED
-		public boolean remove( final Object o ) {
-			if (!(o instanceof Map.Entry)) return false;
-			final Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS> e = (Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS>)o;
-			final int i = findKey( KEY_CLASS2TYPE( e.getKey() ) );
-			if ( i >= 0 ) OPEN_DOUBLE_HASH_MAP.this.remove( e.getKey() );
-			return i >= 0;
-		}
-			 
-		public int size() {
-			return count;
-		}
-			 
-		public void clear() {
-			OPEN_DOUBLE_HASH_MAP.this.clear();
-		}
-
-#ifdef Linked
-		public ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC> iterator( final MAP.Entry KEY_VALUE_GENERIC from ) {
-			return new EntryIterator( KEY_CLASS2TYPE( from.getKey() ) );
-		}
-
-		public ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC> fastIterator() {
-			return new FastEntryIterator();
-		}
-				
-		public ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC> fastIterator( final MAP.Entry KEY_VALUE_GENERIC from ) {
-			return new FastEntryIterator( KEY_CLASS2TYPE( from.getKey() ) );
-		}
-				
-#endif
-	}
-
-
-#ifdef Linked
-	public FastSortedEntrySet KEY_VALUE_GENERIC ENTRYSET() {
-		if ( entries == null ) entries = new MapEntrySet();
-#else
-	public FastEntrySet KEY_VALUE_GENERIC ENTRYSET() {
-		if ( entries == null ) entries = new MapEntrySet();
-#endif
-		return entries;
-	}
-
-
-	/** An iterator on keys.
-	 *
-	 * <P>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.
-	 *
-	 * <P>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.
-	 * <P>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 <em>all</em> 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.
-	 *
-	 * <P>If you need to reduce the table siza to fit exactly
-	 * this map, you must use {@link #trim()}.
-	 *
-	 * @return <code>true</code> if there was enough memory to rehash the map, <code>false</code> 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.
-	 * 
-	 * <P>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.
-	 *
-	 * <P>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.
-	 * 
-	 * <P>Let <var>N</var> be the smallest table size that can hold
-	 * <code>max(n,{@link #size()})</code> entries, still satisfying the load factor. If the current
-	 * table size is smaller than or equal to <var>N</var>, this method does
-	 * nothing. Otherwise, it rehashes this map in a table of size
-	 * <var>N</var>.
-	 *
-	 * <P>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.
-	 *
-	 * <P>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. 
-	 *
-	 * <P>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 <code>equals()</code> 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; i<n;  i++ ) t.put( KEY2OBJ(genKey()), VALUE2OBJ(genValue()) );
-		  
-		/* Now we add to m the same data */
-		  
-		m.putAll(t);
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after insertion");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after insertion");
-
-		/* Now we check that m actually holds that data. */
-		  
-		for(java.util.Iterator i=t.entrySet().iterator(); i.hasNext();  ) {
-			java.util.Map.Entry e = (java.util.Map.Entry)i.next();
-			if (!valEquals(e.getValue(), m.get(e.getKey()))) 
-				System.out.println("Error (" + 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(java.util.Iterator i=m.entrySet().iterator(); i.hasNext();  ) {
-			java.util.Map.Entry e = (java.util.Map.Entry)i.next();
-			if (!valEquals(e.getValue(), t.get(e.getKey()))) 
-				System.out.println("Error (" + 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(java.util.Iterator i=t.keySet().iterator(); i.hasNext();  ) {
-			Object o = i.next();
-			if (!m.containsKey(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a key ("+o+") after insertion (iterating on t)");
-				System.exit( 1 );
-			}
-			if (!m.keySet().contains(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a key ("+o+", in keySet()) after insertion (iterating on t)");
-				System.exit( 1 );
-			}
-		}
-
-		/* Now we check that m actually holds the same keys, but iterating on m. */
-		  
-		for(java.util.Iterator i=m.keySet().iterator(); i.hasNext();  ) {
-			Object o = i.next();
-			if (!t.containsKey(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a key after insertion (iterating on m)");
-				System.exit( 1 );
-			}
-			if (!t.keySet().contains(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a key (in keySet()) after insertion (iterating on m)");
-				System.exit( 1 );
-			}
-		}
-
-
-		/* Now we check that m actually hold the same values. */
-		  
-		for(java.util.Iterator i=t.values().iterator(); i.hasNext();  ) {
-			Object o = i.next();
-			if (!m.containsValue(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a value after insertion (iterating on t)");
-				System.exit( 1 );
-			}
-			if (!m.values().contains(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a value (in values()) after insertion (iterating on t)");
-				System.exit( 1 );
-			}
-		}
-
-		/* Now we check that m actually hold the same values, but iterating on m. */
-		  
-		for(java.util.Iterator i=m.values().iterator(); i.hasNext();  ) {
-			Object o = i.next();
-			if (!t.containsValue(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a value after insertion (iterating on m)");
-				System.exit( 1 );
-			}
-			if (!t.values().contains(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a value (in values()) after insertion (iterating on m)");
-				System.exit( 1 );
-			}
-		}
-
-		/* 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<n;  i++ ) {
-			KEY_TYPE T = genKey();
-			if (m.containsKey(KEY2OBJ(T)) != t.containsKey(KEY2OBJ(T))) {
-				System.out.println("Error (" + seed + "): divergence in keys between t and m (polymorphic method)");
-				System.exit( 1 );
-			}
-
-#if ( #keys(reference) ) && ! ( #values(reference) )
-			if ((m.GET_VALUE(T) != VALUE_NULL) != ((t.get(KEY2OBJ(T)) == null ? VALUE_NULL : VALUE_OBJ2TYPE(t.get(KEY2OBJ(T)))) != VALUE_NULL) || 
-				t.get(KEY2OBJ(T)) != null && 
-				! VALUE2OBJ(m.GET_VALUE(T)).equals(t.get(KEY2OBJ(T)))) 
-#else
-				if ((m.get(T) != VALUE_NULL) != ((t.get(KEY2OBJ(T)) == null ? VALUE_NULL : VALUE_OBJ2TYPE(t.get(KEY2OBJ(T)))) != VALUE_NULL) || 
-					t.get(KEY2OBJ(T)) != null && 
-					! m.get(KEY2OBJ(T)).equals(t.get(KEY2OBJ(T)))) 
-#endif
-					{
-						System.out.println("Error (" + seed + "): divergence between t and m (polymorphic method)");
-						System.exit( 1 );
-					}
-		}
-
-		/* Again, we check that inquiries about random data give the same answer in m and t, but
-		   for m we use the standard method. */
-
-		for(int i=0; i<n;  i++ ) {
-			KEY_TYPE T = genKey();
-			if (!valEquals(m.get(KEY2OBJ(T)), t.get(KEY2OBJ(T)))) {
-				System.out.println("Error (" + seed + "): divergence between t and m (standard method)");
-				System.exit( 1 );
-			}
-		}
-
-		/* Now we put and remove random data in m and t, checking that the result is the same. */
-
-		for(int i=0; i<20*n;  i++ ) {
-			KEY_TYPE T = genKey();
-			VALUE_TYPE U = genValue();
-			if (!valEquals(m.put(KEY2OBJ(T), VALUE2OBJ(U)), t.put(KEY2OBJ(T), VALUE2OBJ(U)))) {
-				System.out.println("Error (" + seed + "): divergence in put() between t and m");
-				System.exit( 1 );
-			}
-			T = genKey();
-			if (!valEquals(m.remove(KEY2OBJ(T)), t.remove(KEY2OBJ(T)))) {
-				System.out.println("Error (" + seed + "): divergence in remove() between t and m");
-				System.exit( 1 );
-			}
-		}
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after removal");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after removal");
-
-
-		/* Now we check that m actually holds the same data. */
-		  
-		for(java.util.Iterator i=t.entrySet().iterator(); i.hasNext();  ) {
-			java.util.Map.Entry e = (java.util.Map.Entry)i.next();
-			if (!valEquals(e.getValue(), m.get(e.getKey()))) {
-				System.out.println("Error (" + seed + "): m and t differ on an entry ("+e+") after removal (iterating on t)");
-				System.exit( 1 );
-			}
-		}
-
-		/* Now we check that m actually holds that data, but iterating on m. */
-		  
-		for(java.util.Iterator i=m.entrySet().iterator(); i.hasNext();  ) {
-			java.util.Map.Entry e = (java.util.Map.Entry)i.next();
-			if (!valEquals(e.getValue(), t.get(e.getKey()))) {
-				System.out.println("Error (" + seed + "): m and t differ on an entry ("+e+") after removal (iterating on m)");
-				System.exit( 1 );
-			}
-		}
-
-		/* Now we check that m actually holds the same keys. */
-		  
-		for(java.util.Iterator i=t.keySet().iterator(); i.hasNext();  ) {
-			Object o = i.next();
-			if (!m.containsKey(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a key ("+o+") after removal (iterating on t)");
-				System.exit( 1 );
-			}
-			if (!m.keySet().contains(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a key ("+o+", in keySet()) after removal (iterating on t)");
-				System.exit( 1 );
-			}
-		}
-
-		/* Now we check that m actually holds the same keys, but iterating on m. */
-		  
-		for(java.util.Iterator i=m.keySet().iterator(); i.hasNext();  ) {
-			Object o = i.next();
-			if (!t.containsKey(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a key after removal (iterating on m)");
-				System.exit( 1 );
-			}
-			if (!t.keySet().contains(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a key (in keySet()) after removal (iterating on m)");
-				System.exit( 1 );
-			}
-		}
-
-
-		/* Now we check that m actually hold the same values. */
-		  
-		for(java.util.Iterator i=t.values().iterator(); i.hasNext();  ) {
-			Object o = i.next();
-			if (!m.containsValue(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a value after removal (iterating on t)");
-				System.exit( 1 );
-			}
-			if (!m.values().contains(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a value (in values()) after removal (iterating on t)");
-				System.exit( 1 );
-			}
-		}
-
-		/* Now we check that m actually hold the same values, but iterating on m. */
-		  
-		for(java.util.Iterator i=m.values().iterator(); i.hasNext();  ) {
-			Object o = i.next();
-			if (!t.containsValue(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a value after removal (iterating on m)");
-				System.exit( 1 );
-			}
-			if (!t.values().contains(o)) {
-				System.out.println("Error (" + seed + "): m and t differ on a value (in values()) after removal (iterating on m)");
-				System.exit( 1 );
-			}
-		}
-
-
-		int h = m.hashCode();
-
-
-		/* Now we save and read m. */
-
-		try {
-			java.io.File ff = new java.io.File("it.unimi.dsi.fastutil.test");
-			java.io.OutputStream os = new java.io.FileOutputStream(ff);
-			java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(os);
-				
-			oos.writeObject(m);
-			oos.close();
-				
-			java.io.InputStream is = new java.io.FileInputStream(ff);
-			java.io.ObjectInputStream ois = new java.io.ObjectInputStream(is);
-				
-			m = (OPEN_DOUBLE_HASH_MAP)ois.readObject();
-			ois.close();
-			ff.delete();
-		}
-		catch(Exception e) {
-			e.printStackTrace();
-			System.exit( 1 );
-		}
-
-
-#if !#keyclass(Reference) && !#valueclass(Reference)
-		if (m.hashCode() != h) System.out.println("Error (" + seed + "): hashCode() changed after save/read");
-
-		/* Now we check that m actually holds that data. */
-		  
-		for(java.util.Iterator i=t.keySet().iterator(); i.hasNext();  ) {
-			Object o = i.next();
-			if (!valEquals(m.get(o),t.get(o))) {
-				System.out.println("Error (" + seed + "): m and t differ on an entry after save/read");
-				System.exit( 1 );
-			}
-		}
-#else
-		m.clear();
-		m.putAll( t );
-#endif
-
-		/* Now we put and remove random data in m and t, checking that the result is the same. */
-
-		for(int i=0; i<20*n;  i++ ) {
-			KEY_TYPE T = genKey();
-			VALUE_TYPE U = genValue();
-			if (!valEquals(m.put(KEY2OBJ(T), VALUE2OBJ(U)), t.put(KEY2OBJ(T), VALUE2OBJ(U)))) {
-				System.out.println("Error (" + seed + "): divergence in put() between t and m after save/read");
-				System.exit( 1 );
-			}
-			T = genKey();
-			if (!valEquals(m.remove(KEY2OBJ(T)), t.remove(KEY2OBJ(T)))) {
-				System.out.println("Error (" + seed + "): divergence in remove() between t and m after save/read");
-				System.exit( 1 );
-			}
-		}
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after post-save/read removal");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after post-save/read removal");
-
-
-
-#ifdef Linked
-
-
-		/* Now we play with iterators. */
-
-		{
-			java.util.ListIterator i, j;
-			Object J;
-			Map.Entry E, F;
-			i = (java.util.ListIterator)m.entrySet().iterator(); 
-			j = new java.util.LinkedList( t.entrySet() ).listIterator(); 
-
-			for( int k = 0; k < 2*n; k++ ) {
-				ensure( i.hasNext() == j.hasNext(), "Error (" + seed + "): divergence in hasNext()" );
-				ensure( i.hasPrevious() == j.hasPrevious(), "Error (" + seed + "): divergence in hasPrevious()" );
-
-				if ( r.nextFloat() < .8 && i.hasNext() ) {
-#ifdef Custom
-					ensure( m.strategy().equals( (E=(java.util.Map.Entry)i.next()).getKey(),  J = (F=(Map.Entry)j.next()).getKey() ), "Error (" + seed + "): divergence in next()" );
-#else
-					ensure( (E=(java.util.Map.Entry)i.next()).getKey().equals( J = (F=(Map.Entry)j.next()).getKey() ), "Error (" + seed + "): divergence in next()" );
-#endif
-
-					if ( r.nextFloat() < 0.3 ) {
-						i.remove();
-						j.remove();
-						t.remove( J );
-					}
-					else if ( r.nextFloat() < 0.3 ) {
-						Object U = VALUE2OBJ(genValue());
-						E.setValue( U );
-                        t.put( F.getKey(), U );
-					}
-				}
-				else if ( r.nextFloat() < .2 && i.hasPrevious() ) {
-#ifdef Custom
-					ensure( m.strategy().equals( (E=(java.util.Map.Entry)i.previous()).getKey(), J = (F=(Map.Entry)j.previous()).getKey() ), "Error (" + seed + "): divergence in previous()" );
-#else
-					ensure( (E=(java.util.Map.Entry)i.previous()).getKey().equals( J = (F=(Map.Entry)j.previous()).getKey() ), "Error (" + seed + "): divergence in previous()" );
-#endif
-
-					if ( r.nextFloat() < 0.3 ) {
-						i.remove();
-						j.remove();
-						t.remove( J );
-					}
-					else if ( r.nextFloat() < 0.3 ) {
-						Object U = VALUE2OBJ(genValue());
-						E.setValue( U );
-                        t.put( F.getKey(), U );
-					}
-				}
-
-				ensure( i.nextIndex() == j.nextIndex(), "Error (" + seed + "): divergence in nextIndex()" );
-				ensure( i.previousIndex() == j.previousIndex(), "Error (" + seed + "): divergence in previousIndex()" );
-
-			}
-
-		}
-		  
-		if ( t.size() > 0 ) {
-			java.util.ListIterator i, j;
-			Object J;
-			j = new java.util.LinkedList( t.keySet() ).listIterator();
-			int e = r.nextInt( t.size() );
-			Object from;
-			do from = j.next(); while( e-- != 0 );
-
-			i = (java.util.ListIterator)((SORTED_SET)m.keySet()).iterator( KEY_OBJ2TYPE( from ) ); 
-
-			for( int k = 0; k < 2*n; k++ ) {
-				ensure( i.hasNext() == j.hasNext(), "Error (" + seed + "): divergence in hasNext() (iterator with starting point " + from + ")" );
-				ensure( i.hasPrevious() == j.hasPrevious(), "Error (" + seed + "): divergence in hasPrevious() (iterator with starting point " + from + ")" );
-
-				if ( r.nextFloat() < .8 && i.hasNext() ) {
-#ifdef Custom
-					ensure( m.strategy().equals( i.next(), J = j.next() ), "Error (" + seed + "): divergence in next() (iterator with starting point " + from + ")" );
-#else
-					ensure( i.next().equals( J = j.next() ), "Error (" + seed + "): divergence in next() (iterator with starting point " + from + ")" );
-#endif
-
-					if ( r.nextFloat() < 0.5 ) {
-						i.remove();
-						j.remove();
-						t.remove( J );
-					}
-				}
-				else if ( r.nextFloat() < .2 && i.hasPrevious() ) {
-#ifdef Custom
-					ensure( m.strategy().equals( i.previous(), J = j.previous() ), "Error (" + seed + "): divergence in previous() (iterator with starting point " + from + ")" );
-#else
-					ensure( i.previous().equals( J = j.previous() ), "Error (" + seed + "): divergence in previous() (iterator with starting point " + from + ")" );
-#endif
-
-					if ( r.nextFloat() < 0.5 ) {
-						i.remove();
-						j.remove();
-						t.remove( J );
-					}
-				}
-
-				ensure( i.nextIndex() == j.nextIndex(), "Error (" + seed + "): divergence in nextIndex() (iterator with starting point " + from + ")" );
-				ensure( i.previousIndex() == j.previousIndex(), "Error (" + seed + "): divergence in previousIndex() (iterator with starting point " + from + ")" );
-
-			}
-
-		}
-		  
-
-
-		/* Now we check that m actually holds that data. */
-		  
-		ensure( m.equals(t), "Error (" + seed + "): ! m.equals( t ) after iteration" );
-		ensure( t.equals(m), "Error (" + seed + "): ! t.equals( m ) after iteration" );
-
-#endif
-
-
-		/* Now we take out of m everything, and check that it is empty. */
-
-		for(java.util.Iterator i=t.keySet().iterator(); i.hasNext(); ) m.remove(i.next()); 
-
-		if (!m.isEmpty())  {
-			System.out.println("Error (" + seed + "): m is not empty (as it should be)");
-			System.exit( 1 );
-		}
-
-#if (#keyclass(Integer) || #keyclass(Long)) && (#valueclass(Integer) || #valueclass(Long))
-		m = new OPEN_DOUBLE_HASH_MAP(n, f);
-		t.clear();
-		int x;
-
-		/* Now we torture-test the hash table. This part is implemented only for integers and longs. */
-
-		int p = m.state.length;
-
-		for(int i=0; i<p; i++) {
-			for (int j=0; j<20; j++) {
-				m.put(i+(r.nextInt() % 10)*p, 1);
-				m.remove(i+(r.nextInt() % 10)*p);
-			}
-
-			for (int j=-10; j<10; j++) m.remove(i+j*p);
-		}
-		  
-		t.putAll(m);
-
-		/* Now all table entries are REMOVED. */
-
-		for(int i=0; i<(p*f)/10; i++) {
-			for (int j=0; j<10; j++) {
-				if (!valEquals(m.put(KEY2OBJ(x = i+(r.nextInt() % 10)*p), VALUE2OBJ(1)), t.put(KEY2OBJ(x), VALUE2OBJ(1))))
-					System.out.println("Error (" + seed + "): m and t differ on an entry during torture-test insertion.");
-			}
-		}
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after torture-test insertion");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after torture-test insertion");
-
-		for(int i=0; i<p/10; i++) {
-			for (int j=0; j<10; j++) {
-				if (!valEquals(m.remove(KEY2OBJ(x = i+(r.nextInt() % 10)*p)), t.remove(KEY2OBJ(x))))
-					System.out.println("Error (" + seed + "): m and t differ on an entry during torture-test removal.");
-			}
-		}
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after torture-test removal");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after torture-test removal");
-
-		if (!m.equals(m.clone())) System.out.println("Error (" + seed + "): !m.equals(m.clone()) after torture-test removal");
-		if (!((OPEN_DOUBLE_HASH_MAP)m.clone()).equals(m)) System.out.println("Error (" + seed + "): !m.clone().equals(m) after torture-test removal");
-
-		m.rehash();
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after rehash()");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after rehash()");
-
-		m.trim();
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after trim()");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after trim()");
-#endif
-
-		System.out.println("Test OK");
-		return;
-	}
-
-
-	public static void main( String args[] ) {
-		float f = Hash.DEFAULT_LOAD_FACTOR;
-		int n  = Integer.parseInt(args[1]);
-		if (args.length>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
-
-}
diff --git a/drv/OpenDoubleHashSet.drv b/drv/OpenDoubleHashSet.drv
deleted file mode 100644
index 0c683d9..0000000
--- a/drv/OpenDoubleHashSet.drv
+++ /dev/null
@@ -1,1986 +0,0 @@
-/*		 
- * 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.
- *
- * <P>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 <em>never</em> 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.
- *
- * <P>The enlargement speed is controlled by the <em>growth factor</em>, a
- * positive number. If the growth factor is <var>p</var>, then the table is
- * enlarged each time roughly by a factor 2<sup>p/16</sup>. By default, <var>p</var> 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 <em>not</em> serialized:
- * deserialized tables gets the {@linkplain Hash#DEFAULT_GROWTH_FACTOR default growth factor}).
- *
- * <P>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.
- *
- * <P>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 <code>null</code>.
- *
- * <P>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.
- *
- * <P>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.
- *
- * <P>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 <em>never</em> 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.
- *
- * <P>The enlargement speed is controlled by the <em>growth factor</em>, a
- * positive number. If the growth factor is <var>p</var>, then the table is
- * enlarged each time roughly by a factor 2<sup>p/16</sup>. By default, <var>p</var> 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 <em>not</em> 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.
- *
- * <P>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 <em>never</em> 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.
- *
- * <P>The enlargement speed is controlled by the <em>growth factor</em>, a
- * positive number. If the growth factor is <var>p</var>, then the table is
- * enlarged each time roughly by a factor 2<sup>p/16</sup>. By default, <var>p</var> 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 <em>not</em> 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 <code>{@link Hash#PRIMES}[{@link #p}+growthFactor</code>. */
-	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 Strategy<K> strategy;
-#endif
-
-    private static final long serialVersionUID = -7046029254386353129L;
-
-	private static final boolean ASSERTS = ASSERTS_VALUE;
-
-#ifdef Custom
-	/** Creates a new hash set.
-	 *
-	 * The actual table size is the least available prime greater than <code>n</code>/<code>f</code>.
-	 *
-	 * @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 Strategy<K> strategy ) {
-		this.strategy = strategy;
-#else
-	/** Creates a new hash set.
-	 *
-	 * The actual table size is the least available prime greater than <code>n</code>/<code>f</code>.
-	 *
-	 * @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<K> strategy ) {
-		this( n, DEFAULT_LOAD_FACTOR, strategy );
-	}
-
-#else
-	/** 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. 
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final int n ) {
-		this( n, DEFAULT_LOAD_FACTOR );
-	}
-
-#endif
-
-
-#ifdef Custom
-	/** Creates a new hash set with {@link Hash#DEFAULT_INITIAL_SIZE} elements
-	 * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
-	 * @param strategy the strategy.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final Strategy<K> strategy ) {
-	this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR, strategy );
-	}
-#else
-	/** Creates a new hash set with {@link Hash#DEFAULT_INITIAL_SIZE} elements
-	 * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET() {
-		this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR );
-	} 
-#endif
-
-
-#ifdef Custom
-	/** Creates a new hash set copying a given collection.
-	 *
-	 * @param c a {@link Collection} to be copied into the new hash set. 
-	 * @param f the load factor.
-	 * @param strategy the strategy.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final Collection<? extends KEY_GENERIC_CLASS> c, final float f, final Strategy<K> strategy ) {
-	this( c.size(), f, strategy );
-		addAll( c );
-	}
-#else
-	/** Creates a new hash set copying a given collection.
-	 *
-	 * @param c a {@link Collection} to be copied into the new hash set. 
-	 * @param f the load factor.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final Collection<? extends KEY_GENERIC_CLASS> c, final float f ) {
-		this( c.size(), f );
-		addAll( c );
-	}
-#endif
-
-
-
-#ifdef Custom
-	/** Creates a new hash set  with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor 
-	 * copying a given collection.
-	 *
-	 * @param c a {@link Collection} to be copied into the new hash set. 
-	 * @param strategy the strategy.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final Collection<? extends KEY_GENERIC_CLASS> c, final Strategy<K> strategy ) {
-		this( c, DEFAULT_LOAD_FACTOR, strategy );
-	}
-
-#else
-	/** Creates a new hash set  with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor 
-	 * copying a given collection.
-	 *
-	 * @param c a {@link Collection} to be copied into the new hash set. 
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final Collection<? extends KEY_GENERIC_CLASS> c ) {
-		this( c, DEFAULT_LOAD_FACTOR );
-	}
-#endif
-
-
-#ifdef Custom
-	/** Creates a new hash set copying a given type-specific collection.
-	 *
-	 * @param c a type-specific collection to be copied into the new hash set. 
-	 * @param f the load factor.
-	 * @param strategy the strategy.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final COLLECTION KEY_EXTENDS_GENERIC c, final float f, Strategy<K> strategy ) {
-	this( c.size(), f, strategy );
-		addAll( c );
-	}
-#else
-	/** Creates a new hash set copying a given type-specific collection.
-	 *
-	 * @param c a type-specific collection to be copied into the new hash set. 
-	 * @param f the load factor.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final COLLECTION KEY_EXTENDS_GENERIC c, final float f ) {
-		this( c.size(), f );
-		addAll( c );
-	}
-#endif
-
-
-#ifdef Custom
-	/** Creates a new hash set  with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor 
-	 * copying a given type-specific collection.
-	 *
-	 * @param c a type-specific collection to be copied into the new hash set. 
-	 * @param strategy the strategy.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final COLLECTION KEY_EXTENDS_GENERIC c, final Strategy<K> strategy ) {
-		this( c, DEFAULT_LOAD_FACTOR, strategy );
-	}
-#else
-	/** Creates a new hash set  with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor 
-	 * copying a given type-specific collection.
-	 *
-	 * @param c a type-specific collection to be copied into the new hash set. 
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final COLLECTION KEY_EXTENDS_GENERIC c ) {
-		this( c, DEFAULT_LOAD_FACTOR );
-	}
-#endif
-
-
-#ifdef Custom
-	/** Creates a new hash set using elements provided by a type-specific iterator.
-	 *
-	 * @param i a type-specific iterator whose elements will fill the set.
-	 * @param f the load factor.
-	 * @param strategy the strategy.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final KEY_ITERATOR KEY_GENERIC i, final float f, final Strategy<K> strategy ) {
-		this( DEFAULT_INITIAL_SIZE, f, strategy );
-		while( i.hasNext() ) add( i.NEXT_KEY() );
-	}
-#else
-	/** Creates a new hash set using elements provided by a type-specific iterator.
-	 *
-	 * @param i a type-specific iterator whose elements will fill the set.
-	 * @param f the load factor.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final KEY_ITERATOR KEY_GENERIC i, final float f ) {
-		this( DEFAULT_INITIAL_SIZE, f );
-		while( i.hasNext() ) add( i.NEXT_KEY() );
-	}
-#endif
-
-#ifdef Custom
-	/** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by a type-specific iterator.
-	 *
-	 * @param i a type-specific iterator whose elements will fill the set.
-	 * @param strategy the strategy.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final KEY_ITERATOR KEY_GENERIC i, final Strategy<K> strategy ) {
-		this( i, DEFAULT_LOAD_FACTOR, strategy );
-	}
-#else
-	/** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by a type-specific iterator.
-	 *
-	 * @param i a type-specific iterator whose elements will fill the set.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final KEY_ITERATOR KEY_GENERIC i ) {
-		this( i, DEFAULT_LOAD_FACTOR );
-	}
-#endif
-
-
-
-#if #keys(primitive)
-
-#ifdef Custom
-	/** Creates a new hash set using elements provided by an iterator.
-	 *
-	 * @param i an iterator whose elements will fill the set.
-	 * @param f the load factor.
-	 * @param strategy the strategy.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final Iterator<?> i, final float f, final Strategy<K> strategy ) {
-		this( ITERATORS.AS_KEY_ITERATOR( i ), f, strategy );
-	}
-#else
-	/** Creates a new hash set using elements provided by an iterator.
-	 *
-	 * @param i an iterator whose elements will fill the set.
-	 * @param f the load factor.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final Iterator<?> i, final float f ) {
-		this( ITERATORS.AS_KEY_ITERATOR( i ), f );
-	}
-#endif
-
-#ifdef Custom
-	/** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by an iterator.
-	 *
-	 * @param i an iterator whose elements will fill the set.
-	 * @param strategy the strategy.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final Iterator i, final Strategy<K> strategy ) {
-		this( ITERATORS.AS_KEY_ITERATOR( i, strategy ) );
-	}
-#else
-	/** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by an iterator.
-	 *
-	 * @param i an iterator whose elements will fill the set.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final Iterator<?> i ) {
-		this( ITERATORS.AS_KEY_ITERATOR( i ) );
-	}
-#endif
-
-#endif
-
-
-
-#ifdef Custom
-	/** Creates a new hash set and fills it with the elements of a given array.
-	 *
-	 * @param a an array whose elements will be used to fill the set.
-	 * @param offset the first element to use.
-	 * @param length the number of elements to use.
-	 * @param f the load factor.
-	 * @param strategy the strategy.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final KEY_GENERIC_TYPE[] a, final int offset, final int length, final float f, final Strategy<K> strategy ) {
-	this( length < 0 ? 0 : length, f, strategy );
-		ARRAYS.ensureOffsetLength( a, offset, length );
-		for( int i = 0; i < length; i++ ) add( a[ offset + i ] );
-	}
-#else
-	/** Creates a new hash set and fills it with the elements of a given array.
-	 *
-	 * @param a an array whose elements will be used to fill the set.
-	 * @param offset the first element to use.
-	 * @param length the number of elements to use.
-	 * @param f the load factor.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final KEY_GENERIC_TYPE[] a, final int offset, final int length, final float f ) {
-		this( length < 0 ? 0 : length, f );
-		ARRAYS.ensureOffsetLength( a, offset, length );
-		for( int i = 0; i < length; i++ ) add( a[ offset + i ] );
-	}
-#endif
-
-#ifdef Custom
-	/** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor and fills it with the elements of a given array.
-	 *
-	 * @param a an array whose elements will be used to fill the set.
-	 * @param offset the first element to use.
-	 * @param length the number of elements to use.
-	 * @param strategy the strategy.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final KEY_GENERIC_TYPE[] a, final int offset, final int length, final Strategy<K> strategy ) {
-		this( a, offset, length, DEFAULT_LOAD_FACTOR, strategy );
-	}
-#else
-	/** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor and fills it with the elements of a given array.
-	 *
-	 * @param a an array whose elements will be used to fill the set.
-	 * @param offset the first element to use.
-	 * @param length the number of elements to use.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final KEY_GENERIC_TYPE[] a, final int offset, final int length ) {
-		this( a, offset, length, DEFAULT_LOAD_FACTOR );
-	}
-#endif
-
-#ifdef Custom
-	/** Creates a new hash set copying the elements of an array.
-	 *
-	 * @param a an array to be copied into the new hash set. 
-	 * @param f the load factor.
-	 * @param strategy the strategy.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final KEY_GENERIC_TYPE[] a, final float f, final Strategy<K> strategy ) {
-		this( a, 0, a.length, f, strategy );
-	}
-#else
-	/** Creates a new hash set copying the elements of an array.
-	 *
-	 * @param a an array to be copied into the new hash set. 
-	 * @param f the load factor.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final KEY_GENERIC_TYPE[] a, final float f ) {
-		this( a, 0, a.length, f );
-	}
-#endif
-
-#ifdef Custom
-	/** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor 
-	 * copying the elements of an array.
-	 *
-	 * @param a an array to be copied into the new hash set. 
-	 * @param strategy the strategy.
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final KEY_GENERIC_TYPE[] a, final Strategy<K> strategy ) {
-		this( a, DEFAULT_LOAD_FACTOR, strategy );
-	}
-#else
-	/** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor 
-	 * copying the elements of an array.
-	 *
-	 * @param a an array to be copied into the new hash set. 
-	 */
-	 
-	public OPEN_DOUBLE_HASH_SET( final KEY_GENERIC_TYPE[] a ) {
-		this( a, DEFAULT_LOAD_FACTOR );
-	}
-#endif
-
-
-#ifdef Custom
-	/** Returns the hashing strategy.
-	 *
-	 * @return the hashing strategy of this custom hash set.
-	 */
-
-	public Strategy<K> strategy() {
-		return strategy;
-	}
-#endif
-
-	/** Sets the growth factor. Subsequent enlargements will increase the table
-	 * size roughly by a multiplicative factor of 2<sup>p/16</sup>.
-	 * 
-	 * @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 HashMap.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,
-	 * <var>-i</var>-1, where <var>i</var> 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 boolean add( final KEY_GENERIC_TYPE k ) {
-		final int i = findInsertionPoint( k );
-		if ( i < 0 ) return false;
-
-		if ( state[ i ] == FREE ) free--;
-		state[ i ] = OCCUPIED;
-		key[ i ] = k;
-
-#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 true;
-	}
-
-	SUPPRESS_WARNINGS_KEY_UNCHECKED
-	public boolean remove( final KEY_TYPE k ) {
-		final int i = findKey( KEY_GENERIC_CAST k );
-		if ( i < 0 ) return false;
-		state[ i ] = REMOVED;
-		count--;
-
-#if #keys(reference)
-		key[ i ] = KEY_GENERIC_CAST HashCommon.REMOVED;
-#endif
-
-#ifdef Linked
-		fixPointers( i );
-#endif
-
-		if ( ASSERTS ) checkTable();
-		return true;
-	}
-	 
-	SUPPRESS_WARNINGS_KEY_UNCHECKED
-	public boolean contains( final KEY_TYPE k ) {
-		return findKey( KEY_GENERIC_CAST k ) >= 0;
-	}
-
-
-	/* Removes all elements from this set.
-	 *
-	 * <P>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.
-	 *
-	 * <P>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.
-	 *
-	 * <P>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 <code>null</code> 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 <code>null</code> if no next entry exists). */
-		int next = -1;
-		/** The last entry that was returned (or -1 if we did not iterate or used {@link #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 {@link SetIterator} has been created using the nonempty constructor.*/
-		int index = 0;
-
-		SetIterator() {
-			next = first;
-		}
-
-		SetIterator( KEY_GENERIC_TYPE from ) {
-			if ( KEY_EQUALS( key[ last ], from ) ) {
-				prev = last;
-				index = count;
-			}
-			else {
-				if ( ! contains( from ) ) throw new IllegalArgumentException( "The key " + from + " does not belong to this set." );
-				next = first;
-				KEY_GENERIC_TYPE k;
-				do k = NEXT_KEY(); while( ! KEY_EQUALS( k, from ) );
-				curr = -1;
-			}
-		}
-					 
-		public boolean hasNext() { return next != -1; }
-		public boolean hasPrevious() { return prev != -1; }
-					 
-		public KEY_GENERIC_TYPE NEXT_KEY() {
-			if ( ! hasNext() ) throw new NoSuchElementException();
-
-			curr = next;
-			next = link[ curr ] ^ prev;
-			prev = curr;
-
-			index++;
-
-			return key[ curr ];
-		}
-
-		public KEY_GENERIC_TYPE PREV_KEY() {
-			if ( ! hasPrevious() ) throw new NoSuchElementException();
-
-			curr = prev;
-			prev = link[ curr ] ^ next;
-			next = curr;
-
-			index--;
-
-			return key[ curr ];
-		}
-
-		public int nextIndex() {
-			return index;
-		}
-
-		public int previousIndex() {
-			return index - 1;
-		}
-
-		
-		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 ( 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;
-		}
-	}
-
-
-	/** Returns a type-specific list iterator on the elements in this set, starting from a given element of the set.
-	 *
-	 * <P>This method provides an iterator positioned immediately after the
-	 * given element. That is, the next call to <code>previous()</code> will
-	 * return <code>from</code>, whereas the next call to <code>next()</code>
-	 * will return the element immediately after <code>from</code>. This
-	 * allows to call <code>iterator(last())</code> and obtain an iterator starting
-	 * from the end of the iteration order.
-	 *
-	 * <P>Because of the way linking is implemented, generating an iterator using this method
-	 * requires constant time only if the argument is <code>last()</code>. In all other cases,
-	 * a linear search for the given element will be necessary.
-	 *
-	 * <P>Note that this method returns a bidirectional iterator, which, however, can be safely cast to 
-	 * a type-specific list iterator.
-	 *
-	 * @param from an element to start from.
-	 * @return a type-specific list iterator starting at the given element.
-	 * @throws IllegalArgumentException if <code>from</code> does not belong to the set.
-	 */
-	public KEY_BIDI_ITERATOR KEY_GENERIC iterator( KEY_GENERIC_TYPE from ) {
-		return new SetIterator( from );
-	}
-
-	public KEY_BIDI_ITERATOR KEY_GENERIC iterator() {
-		return new SetIterator();
-	}
-
-#else	 
-
-	/** An iterator over a hash set. */
-
-	private class SetIterator extends KEY_ABSTRACT_ITERATOR KEY_GENERIC {
-		/** The index of the next entry to be returned. */
-		int pos = 0;
-		/** The index of the last entry that has been returned. */
-		int last = -1;
-		/** A downward counter measuring how many entries have been returned. */
-		int c = count;
-		
-		{ 
-			final byte state[] = OPEN_DOUBLE_HASH_SET.this.state;
-			final int n = state.length;
-			
-			if ( c != 0 ) while( pos < n && state[pos] != OCCUPIED ) pos++;
-		}
-		
-		public boolean hasNext() {
-			return c != 0 && pos < OPEN_DOUBLE_HASH_SET.this.state.length;
-		}
-		
-		public KEY_GENERIC_TYPE NEXT_KEY() {
-			KEY_GENERIC_TYPE retVal;
-			final byte state[] = OPEN_DOUBLE_HASH_SET.this.state;
-			final int n = state.length;
-			
-			if ( ! hasNext() ) throw new NoSuchElementException();
-			retVal = key[ last = pos ];
-			if ( --c != 0 ) do pos++; while( pos < n && state[ pos ] != OCCUPIED );
-			
-			return retVal;
-		}
-		
-		SUPPRESS_WARNINGS_KEY_UNCHECKED
-		public void remove() {
-			if ( last == -1 || state[ last ] != OCCUPIED ) throw new IllegalStateException();
-			state[last] = REMOVED;
-#if #keys(reference)
-			key[ last ] = KEY_GENERIC_CAST HashCommon.REMOVED;
-#endif
-			count--;
-		}
-	}
-
-	public KEY_ITERATOR KEY_GENERIC iterator() {
-		return new SetIterator();
-	}
-
-#endif
-
-
-
-	/** Rehashes this set without changing the table size.
-	 *
-	 * <P>This method should be called when the set underwent numerous
-	 * deletions and insertions.  In this case, free entries become rare, and
-	 * unsuccessful searches require probing <em>all</em> 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.
-	 *
-	 * <P>If you need to reduce the table siza to fit exactly
-	 * this set, you must use {@link #trim()}.
-	 *
-	 * @return true if there was enough memory to rehash the set, false otherwise.
-	 * @see #trim()
-	 */
-
-	public boolean rehash() {
-		try {
-			rehash( p );
-		}
-		catch( OutOfMemoryError cantDoIt ) { return false; }
-		return true;
-	}
-
-
-	/** Rehashes this set, making the table as small as possible.
-	 * 
-	 * <P>This method rehashes the table to the smallest size satisfying the
-	 * load factor. It can be used when the set will not be changed anymore, so
-	 * to optimize access speed (by collecting deleted entries) and size.
-	 *
-	 * <P>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 set.
-	 * @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 set if the table is too large.
-	 * 
-	 * <P>Let <var>N</var> be the smallest table size that can hold
-	 * <code>max(n,{@link #size()})</code> entries, still satisfying the load factor. If the current
-	 * table size is smaller than or equal to <var>N</var>, this method does
-	 * nothing. Otherwise, it rehashes this set in a table of size
-	 * <var>N</var>.
-	 *
-	 * <P>This method is useful when reusing sets.  {@linkplain #clear() Clearing a
-	 * set} leaves the table size untouched. If you are reusing a set
-	 * 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 sets.
-	 *
-	 * @param n the threshold for the trimming.
-	 * @return true if there was enough memory to trim the set.
-	 * @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 set.
-	 *
-	 * <P>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
-
-		//System.err.println("Rehashing to size " +  PRIMES[newP] + "...");
-
-		KEY_GENERIC_TYPE k;
-
-		final int newN = PRIMES[ newP ];
-		final KEY_GENERIC_TYPE key[] = this.key, newKey[] = KEY_GENERIC_ARRAY_CAST new KEY_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 ];
-			k2i = KEY2INTHASH( k ) & 0x7FFFFFFF;
-
-			h1 = k2i % newN;
-
-			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;
-
-#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.state = newState;
-#ifdef Linked
-		this.link = newLink;
-		this.last = newPrev;
-		if ( newPrev != -1 ) newLink[ newPrev ] ^= -1; 
-#endif
-	}
-
-	public int size() {
-		return count;
-	}
-
-	public boolean isEmpty() {
-		return count == 0;
-	}
-
-
-
-	/** Returns a deep copy of this set. 
-	 *
-	 * <P>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 OPEN_DOUBLE_HASH_SET KEY_GENERIC clone() {
-		OPEN_DOUBLE_HASH_SET KEY_GENERIC c;
-		try {
-			c = (OPEN_DOUBLE_HASH_SET KEY_GENERIC)super.clone();
-		}
-		catch(CloneNotSupportedException cantHappen) {
-			throw new InternalError();
-		}
-		c.key = key.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 set.
-	 *
-	 * This method overrides the generic method provided by the superclass. 
-	 * Since <code>equals()</code> 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 set.
-	 */
-
-
-	public int hashCode() {
-		int h = 0, i = 0, j = count;
-		while( j-- != 0 ) {
-			while( state[ i ] != OCCUPIED ) i++;
-#if #keys(reference)
-			if ( this != key[ i ] )
-#endif
-				h += KEY2JAVAHASH( key[ i ] );
-			i++;
-		}
-		return h;
-	}
-
-
-	private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
-		final KEY_ITERATOR KEY_GENERIC i = iterator();
-		int j = count;
-		s.defaultWriteObject();
-		while( j-- != 0 ) s.WRITE_KEY( i.NEXT_KEY() );
-	}
-
-
-	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 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;
-
-		i = count;
-		while( i-- != 0 ) {
-
-			k = KEY_GENERIC_CAST s.READ_KEY();
-			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;
-
-#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 && ! contains( 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 = iterator();
-		KEY_GENERIC_TYPE k;
-		n = size();
-		while( n-- != 0 ) 
-			if ( ! contains( 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 = iterator( LAST() );
-			while( n-- != 0 ) 
-				if ( ! contains( 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(Object)
-#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 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 MockSet extends java.util.TreeSet {
-		private java.util.List list = new java.util.ArrayList();
-
-		public MockSet( java.util.Comparator c ) { super( c ); }
-
-		public boolean add( Object k ) {
-			if ( ! contains( k ) ) list.add( k );
-			return super.add( k );
-		}
-
-		public boolean addAll( Collection c ) {
-			java.util.Iterator i = c.iterator();
-			boolean result = false;
-			while( i.hasNext() ) result |= add( i.next() );
-			return result;
-		}
-
-		public boolean removeAll( Collection c ) {
-			java.util.Iterator i = c.iterator();
-			boolean result = false;
-			while( i.hasNext() ) result |= remove( i.next() );
-			return result;
-		}
-
-		public boolean remove( Object k ) {
-			if ( contains( 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 ); }
-
-		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(); 
-					}
-				};
-		}
-	}
-
-	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_SET m;
-#ifdef Linked
-		java.util.LinkedHashSet t;
-#else
-		java.util.HashSet t;
-#endif
-
-		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, totIter = 0, totRemYes = 0, totRemNo = 0, d;
-
-		if ( comp ) { for( j = 0; j < 20; j++ ) {
-
-#ifdef Linked
-			t = new java.util.LinkedHashSet( 16 );
-#else
-			t = new java.util.HashSet( 16 );
-#endif
-
-			/* We add pairs to t. */
-			ms = System.currentTimeMillis();
-			for( i = 0; i < n;  i++ ) t.add( KEY2OBJ( k[i] ) );
-			d = 1.0 * n / (System.currentTimeMillis() - ms );
-			if ( j > 2 ) totAdd += d; 				
-			System.out.print("Add: " + format( d ) +" K/s " );
-
-			/* 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( java.util.Iterator it = t.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 Add: " + format( totAdd/(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();
-
-		totAdd = totYes = totNo = totIter = totRemYes = totRemNo = 0;
-		}
-
-		for( j = 0; j < 20; j++ ) {
-
-			m = new OPEN_DOUBLE_HASH_SET( 16, f );
-
-			/* We add pairs to m. */
-			ms = System.currentTimeMillis();
-			for( i = 0; i < n;  i++ ) m.add( k[i] );
-			d = 1.0 * n / (System.currentTimeMillis() - ms );
-			if ( j > 2 ) totAdd += d; 				
-			System.out.print("Add: " + format( d ) +" K/s " );
-
-			/* 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. */
-			ms = System.currentTimeMillis();
-			for( KEY_ITERATOR it = (KEY_ITERATOR)m.iterator(); it.hasNext(); it.NEXT_KEY() );
-			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  Add: " + format( totAdd/(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 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 void test( int n, float f ) {
-		int c;
-#ifdef Custom
-		OPEN_DOUBLE_HASH_SET m = new OPEN_DOUBLE_HASH_SET(Hash.DEFAULT_INITIAL_SIZE, f, it.unimi.dsi.fastutil.bytes.ByteArrays.HASH_STRATEGY);
-#else
-		OPEN_DOUBLE_HASH_SET m = new OPEN_DOUBLE_HASH_SET(Hash.DEFAULT_INITIAL_SIZE, f);
-#endif
-#ifdef Linked
-#ifdef Custom
-		java.util.Set t = new MockSet(new ArrayComparator());
-#else
-		java.util.Set t = new java.util.LinkedHashSet();
-#endif
-#else
-#ifdef Custom
-		java.util.Set t = new java.util.TreeSet(new ArrayComparator());
-#else 
-		java.util.Set t = new java.util.HashSet();
-#endif
-#endif
-
-		/* First of all, we fill t with random data. */
-
-		for(int i=0; i<n;  i++ ) t.add(KEY2OBJ(genKey()));
-		  
-		/* Now we add to m the same data */
-		  
-		m.addAll(t); 
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after insertion");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after insertion");
-
-		/* Now we check that m actually holds that data. */
-		  
-		for(java.util.Iterator i=t.iterator(); i.hasNext();  ) {
-			Object e = i.next();
-			if (!m.contains(e)) {
-				System.out.println("Error (" + seed + "): m and t differ on a key ("+e+") after insertion (iterating on t)");
-				System.exit( 1 );
-			}
-		}
-
-		/* Now we check that m actually holds that data, but iterating on m. */
-		  
-		for(java.util.Iterator i=m.iterator(); i.hasNext();  ) {
-			Object e = i.next();
-			if (!t.contains(e)) {
-				System.out.println("Error (" + seed + "): m and t differ on a key ("+e+") after insertion (iterating on m)");
-				System.exit( 1 );
-			}
-		}
-
-		/* 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<n;  i++ ) {
-			KEY_TYPE T = genKey();
-			if (m.contains(T) != t.contains(KEY2OBJ(T))) {
-				System.out.println("Error (" + seed + "): divergence in keys between t and m (polymorphic method)");
-				System.exit( 1 );
-			}
-		}
-
-		/* Again, we check that inquiries about random data give the same answer in m and t, but
-		   for m we use the standard method. */
-
-		for(int i=0; i<n;  i++ ) {
-			KEY_TYPE T = genKey();
-			if (m.contains(KEY2OBJ(T)) != t.contains(KEY2OBJ(T))) {
-				System.out.println("Error (" + seed + "): divergence between t and m (standard method)");
-				System.exit( 1 );
-			}
-		}
-
-
-		/* Now we put and remove random data in m and t, checking that the result is the same. */
-
-		for(int i=0; i<20*n;  i++ ) {
-			KEY_TYPE T = genKey();
-			if (m.add(KEY2OBJ(T)) != t.add(KEY2OBJ(T))) {
-				System.out.println("Error (" + seed + "): divergence in add() between t and m");
-				System.exit( 1 );
-			}
-			T = genKey();
-			if (m.remove(KEY2OBJ(T)) != t.remove(KEY2OBJ(T))) {
-				System.out.println("Error (" + seed + "): divergence in remove() between t and m");
-				System.exit( 1 );
-			}
-		}
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after removal");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after removal");
-
-		/* Now we check that m actually holds that data. */
-		  
-		for(java.util.Iterator i=t.iterator(); i.hasNext();  ) {
-			Object e = i.next();
-			if (!m.contains(e)) {
-				System.out.println("Error (" + seed + "): m and t differ on a key ("+e+") after removal (iterating on t)");
-				System.exit( 1 );
-			}
-		}
-
-		/* Now we check that m actually holds that data, but iterating on m. */
-		  
-		for(java.util.Iterator i=m.iterator(); i.hasNext();  ) {
-			Object e = i.next();
-			if (!t.contains(e)) {
-				System.out.println("Error (" + seed + "): m and t differ on a key ("+e+") after removal (iterating on m)");
-				System.exit( 1 );
-			}
-		}
-
-		/* Now we make m into an array, make it again a set and check it is OK. */
-		KEY_TYPE a[] = m.TO_KEY_ARRAY();
-		  
-#ifdef Custom
-		if (!new OPEN_DOUBLE_HASH_SET(a, m.strategy()).equals(m))
-			System.out.println("Error (" + seed + "): toArray() output (or array-based constructor) is not OK");
-#else
-		if (!new OPEN_DOUBLE_HASH_SET(a).equals(m))
-			System.out.println("Error (" + seed + "): toArray() output (or array-based constructor) is not OK");
-#endif
-
-		/* Now we check cloning. */
-
-		ensure( m.equals( ((OPEN_DOUBLE_HASH_SET)m).clone() ), "Error (" + seed + "): m does not equal m.clone()" );
-		ensure( ((OPEN_DOUBLE_HASH_SET)m).clone().equals( m ), "Error (" + seed + "): m.clone() does not equal m" );
-
-		int h = m.hashCode();
-
-		/* Now we save and read m. */
-
-		try {
-			java.io.File ff = new java.io.File("it.unimi.dsi.fastutil.test");
-			java.io.OutputStream os = new java.io.FileOutputStream(ff);
-			java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(os);
-				
-			oos.writeObject(m);
-			oos.close();
-				
-			java.io.InputStream is = new java.io.FileInputStream(ff);
-			java.io.ObjectInputStream ois = new java.io.ObjectInputStream(is);
-				
-			m = (OPEN_DOUBLE_HASH_SET)ois.readObject();
-			ois.close();
-			ff.delete();
-		}
-		catch(Exception e) {
-			e.printStackTrace();
-			System.exit( 1 );
-		}
-
-#if !#keyclass(Reference)
-		if (m.hashCode() != h) System.out.println("Error (" + seed + "): hashCode() changed after save/read");
-
-		/* Now we check that m actually holds that data, but iterating on m. */
-		  
-		for(java.util.Iterator i=m.iterator(); i.hasNext();  ) {
-			Object e = i.next();
-			if (!t.contains(e)) {
-				System.out.println("Error (" + seed + "): m and t differ on a key ("+e+") after save/read");
-				System.exit( 1 );
-			}
-		}
-#else
-		m.clear();
-		m.addAll( t );
-#endif
-
-		/* Now we put and remove random data in m and t, checking that the result is the same. */
-
-		for(int i=0; i<20*n;  i++ ) {
-			KEY_TYPE T = genKey();
-			if (m.add(KEY2OBJ(T)) != t.add(KEY2OBJ(T))) {
-				System.out.println("Error (" + seed + "): divergence in add() between t and m after save/read");
-				System.exit( 1 );
-			}
-			T = genKey();
-			if (m.remove(KEY2OBJ(T)) != t.remove(KEY2OBJ(T))) {
-				System.out.println("Error (" + seed + "): divergence in remove() between t and m after save/read");
-				System.exit( 1 );
-			}
-		}
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after post-save/read removal");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after post-save/read removal");
-
-
-#ifdef Linked
-
-				 
-		/* Now we play with iterators, but only in the linked case. */
-
-		{
-			java.util.ListIterator i, j;
-			Object I, J;
-			i = (java.util.ListIterator)m.iterator(); 
-			j = new java.util.LinkedList( t ).listIterator(); 
-
-			for( int k = 0; k < 2*n; k++ ) {
-				ensure( i.hasNext() == j.hasNext(), "Error (" + seed + "): divergence in hasNext()" );
-				ensure( i.hasPrevious() == j.hasPrevious(), "Error (" + seed + "): divergence in hasPrevious()" );
-
-				if ( r.nextFloat() < .8 && i.hasNext() ) {
-#ifdef Custom
-					ensure( m.strategy().equals( i.next(), J = j.next() ), "Error (" + seed + "): divergence in next()" );
-#else
-					ensure( i.next().equals( J = j.next() ), "Error (" + seed + "): divergence in next()" );
-#endif
-					if ( r.nextFloat() < 0.5 ) {
-						i.remove();
-						j.remove();
-						t.remove( J );
-					}
-				}
-				else if ( r.nextFloat() < .2 && i.hasPrevious() ) {
-#ifdef Custom
-					ensure( m.strategy().equals( i.previous(), J = j.previous() ), "Error (" + seed + "): divergence in previous()" );
-#else
-					ensure( i.previous().equals( J = j.previous() ), "Error (" + seed + "): divergence in previous()" );
-#endif
-					if ( r.nextFloat() < 0.5 ) {
-						i.remove();
-						j.remove();
-						t.remove( J );
-					}
-				}
-
-				ensure( i.nextIndex() == j.nextIndex(), "Error (" + seed + "): divergence in nextIndex()" );
-				ensure( i.previousIndex() == j.previousIndex(), "Error (" + seed + "): divergence in previousIndex()" );
-
-			}
-
-		}
-
-		if ( t.size() > 0 ) {
-			java.util.ListIterator i, j;
-			Object J;
-			j = new java.util.LinkedList( t ).listIterator(); 
-			int e = r.nextInt( t.size() );
-			Object from;
-			do from = j.next(); while( e-- != 0 );
-
-			i = (java.util.ListIterator)m.iterator( KEY_OBJ2TYPE( from ) ); 
-
-			for( int k = 0; k < 2*n; k++ ) {
-				ensure( i.hasNext() == j.hasNext(), "Error (" + seed + "): divergence in hasNext() (iterator with starting point " + from + ")" );
-				ensure( i.hasPrevious() == j.hasPrevious(), "Error (" + seed + "): divergence in hasPrevious() (iterator with starting point " + from + ")" );
-
-				if ( r.nextFloat() < .8 && i.hasNext() ) {
-#ifdef Custom
-					ensure( m.strategy().equals( i.next(), J = j.next() ), "Error (" + seed + "): divergence in next() (iterator with starting point " + from + ")" );
-#else
-					ensure( i.next().equals( J = j.next() ), "Error (" + seed + "): divergence in next() (iterator with starting point " + from + ")" );
-#endif
-
-					if ( r.nextFloat() < 0.5 ) {
-						i.remove();
-						j.remove();
-						t.remove( J );
-					}
-				}
-				else if ( r.nextFloat() < .2 && i.hasPrevious() ) {
-#ifdef Custom
-					ensure( m.strategy().equals( i.previous(), J = j.previous() ), "Error (" + seed + "): divergence in previous() (iterator with starting point " + from + ")" );
-#else
-					ensure( i.previous().equals( J = j.previous() ), "Error (" + seed + "): divergence in previous() (iterator with starting point " + from + ")" );
-#endif
-
-					if ( r.nextFloat() < 0.5 ) {
-						i.remove();
-						j.remove();
-						t.remove( J );
-					}
-				}
-
-				ensure( i.nextIndex() == j.nextIndex(), "Error (" + seed + "): divergence in nextIndex() (iterator with starting point " + from + ")" );
-				ensure( i.previousIndex() == j.previousIndex(), "Error (" + seed + "): divergence in previousIndex() (iterator with starting point " + from + ")" );
-
-			}
-
-		}
-
-		/* Now we check that m actually holds that data. */
-		  
-		ensure( m.equals(t), "Error (" + seed + "): ! m.equals( t ) after iteration" );
-		ensure( t.equals(m), "Error (" + seed + "): ! t.equals( m ) after iteration" );
-
-
-
-#endif
-
-		/* Now we take out of m everything, and check that it is empty. */
-
-		for(java.util.Iterator i=m.iterator(); i.hasNext(); ) { i.next(); i.remove();} 
-
-		if (!m.isEmpty())  {
-			System.out.println("Error (" + seed + "): m is not empty (as it should be)");
-			System.exit( 1 );
-		}
-
-#if #keyclass(Integer) || #keyclass(Long)
-		m = new OPEN_DOUBLE_HASH_SET(n, f);
-		t.clear();
-		int x;
-
-		/* Now we torture-test the hash table. This part is implemented only for integers and longs. */
-
-		int p = m.state.length;
-
-		for(int i=0; i<p; i++) {
-			for (int j=0; j<20; j++) {
-				m.add(i+(r.nextInt() % 10)*p);
-				m.remove(i+(r.nextInt() % 10)*p);
-			}
-
-			for (int j=-10; j<10; j++) m.remove(i+j*p);
-		}
-		  
-		t.addAll(m);
-
-		/* Now all table entries are REMOVED. */
- 
-		int k = 0;
-		for(int i=0; i<(p*f)/10; i++) {
-			for (int j=0; j<10; j++) {
-				k++;
-				x = i+(r.nextInt() % 10)*p;
-				if (m.add(x) != t.add(KEY2OBJ(x)))
-					System.out.println("Error (" + seed + "): m and t differ on a key during torture-test insertion.");
-			}
-		}
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after torture-test insertion");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after torture-test insertion");
-
-		for(int i=0; i<(p*f)/10; i++) {
-			for (int j=0; j<10; j++) {
-				x = i+(r.nextInt() % 10)*p;
-				if (m.remove(x) != t.remove(KEY2OBJ(x)))
-					System.out.println("Error (" + seed + "): m and t differ on a key during torture-test removal.");
-			}
-		}
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after torture-test removal");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after torture-test removal");
-
-		if (!m.equals(m.clone())) System.out.println("Error (" + seed + "): !m.equals(m.clone()) after torture-test removal");
-		if (!((OPEN_DOUBLE_HASH_SET)m.clone()).equals(m)) System.out.println("Error (" + seed + "): !m.clone().equals(m) after torture-test removal");
-
-		m.rehash();
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after rehash()");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after rehash()");
-
-		m.trim();
-
-		if (!m.equals(t)) System.out.println("Error (" + seed + "): !m.equals(t) after trim()");
-		if (!t.equals(m)) System.out.println("Error (" + seed + "): !t.equals(m) after trim()");
-#endif
-
-		System.out.println("Test OK");
-		return;
-	}
-
-
-	public static void main( String args[] ) {
-		float f = Hash.DEFAULT_LOAD_FACTOR;
-		int n  = Integer.parseInt(args[1]);
-		if (args.length>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
-
-}
diff --git a/drv/OpenHashBigSet.drv b/drv/OpenHashBigSet.drv
index b4b8ef1..5809048 100644
--- a/drv/OpenHashBigSet.drv
+++ b/drv/OpenHashBigSet.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -319,6 +319,46 @@ public class OPEN_HASH_BIG_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC impl
 		return true;
 	}
 
+#if #keyclass(Object)
+	/** Add a random element if not present, get the existing value if already present.
+	 *
+	 * This is equivalent to (but faster than) doing a:
+	 * <pre>
+	 * K exist = set.get(k);
+	 * if (exist == null) {
+	 *   set.add(k);
+	 *   exist = k;
+	 * }
+	 * </pre>
+	 */
+	public KEY_GENERIC_TYPE addOrGet( final KEY_GENERIC_TYPE k ) {
+		int displ, base;
+
+		if ( KEY_IS_NULL( k ) ) {
+			if ( containsNull ) return null;
+			containsNull = true;
+		}
+		else {
+			KEY_GENERIC_TYPE curr;
+			final KEY_GENERIC_TYPE[][] key = this.key;
+			final long h = KEY2LONGHASH( k );
+
+			// The starting point.
+			if ( ! KEY_IS_NULL( curr = key[ base = (int)( ( h & mask ) >>> BigArrays.SEGMENT_SHIFT ) ][ displ = (int)( h & segmentMask ) ] ) ) {
+				if ( KEY_EQUALS_NOT_NULL( curr, k ) ) return curr;
+				while( ! KEY_IS_NULL( curr = key[ base = ( base + ( ( displ = ( displ + 1 ) & segmentMask ) == 0 ? 1 : 0 ) ) & baseMask ][ displ ] ) )
+					if ( KEY_EQUALS_NOT_NULL( curr, k ) ) return curr;
+			}
+
+			key[ base ][ displ ] = k;
+		}
+
+		if ( size++ >= maxFill ) rehash( 2 * n );
+		if ( ASSERTS ) checkTable();
+		return k;
+	}
+#endif
+
 	/** Shifts left entries with the specified hash code, starting at the specified position,
 	 * and empties the resulting free entry.
 	 *
@@ -575,7 +615,7 @@ public class OPEN_HASH_BIG_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC impl
 
 	public boolean trim() {
 		final long l = bigArraySize( size, f );
-		if ( l >= n ) return true;
+		if ( l >= n || size > maxFill( l, f ) ) return true;
 		try {
 			rehash( l );
 		}
diff --git a/drv/OpenHashMap.drv b/drv/OpenHashMap.drv
index 875751b..08d723d 100644
--- a/drv/OpenHashMap.drv
+++ b/drv/OpenHashMap.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -92,7 +92,7 @@ import it.unimi.dsi.fastutil.objects.ObjectIterator;
  *
  * <P>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
+ * in iteration order with {@code 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 <code>null</code>.
@@ -213,20 +213,20 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 	 
 #ifdef Linked
 	/** Cached set of entries. */
-	protected transient volatile FastSortedEntrySet KEY_VALUE_GENERIC entries;
+	protected transient FastSortedEntrySet KEY_VALUE_GENERIC entries;
 
 	/** Cached set of keys. */
-	protected transient volatile SORTED_SET KEY_GENERIC keys;
+	protected transient SORTED_SET KEY_GENERIC keys;
 #else
 	/** Cached set of entries. */
-	protected transient volatile FastEntrySet KEY_VALUE_GENERIC entries;
+	protected transient FastEntrySet KEY_VALUE_GENERIC entries;
 
 	/** Cached set of keys. */
-	protected transient volatile SET KEY_GENERIC keys;
+	protected transient SET KEY_GENERIC keys;
 #endif
 
 	/** Cached collection of values. */
-	protected transient volatile VALUE_COLLECTION VALUE_GENERIC values;
+	protected transient VALUE_COLLECTION VALUE_GENERIC values;
 
 
 #ifdef Custom
@@ -489,7 +489,7 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 	private VALUE_GENERIC_TYPE removeEntry( final int pos ) {
 		final VALUE_GENERIC_TYPE oldValue = value[ pos ];
 #if #values(reference)
-		value[ pos ] = VALUE_NULL;
+		value[ pos ] = null;
 #endif
 		size--;
 #ifdef Linked
@@ -503,9 +503,12 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 
 	private VALUE_GENERIC_TYPE removeNullEntry() {
 		containsNullKey = false;
+#if #keys(reference)
+		key[ n ] = null;
+#endif
 		final VALUE_GENERIC_TYPE oldValue = value[ n ];
 #if #values(reference)
-		value[ n ] = VALUE_NULL;
+		value[ n ] = null;
 #endif
 		size--;
 #ifdef Linked
@@ -526,7 +529,7 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 	private int insert(final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE v) {
 		int pos;
 
-		if ( KEY_IS_NULL( k ) ) {
+		if ( KEY_EQUALS_NULL( k ) ) {
 			if ( containsNullKey ) return n;
 			containsNullKey = true;
 			pos = n;
@@ -541,10 +544,9 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 				while( ! KEY_IS_NULL( curr = key[ pos = ( pos + 1 ) & mask ] ) ) 
 					if ( KEY_EQUALS_NOT_NULL( curr, k ) ) return pos;
 			}
-		
-			key[ pos ] = k;
 		}
 
+		key[ pos ] = k;
 		value[ pos ] = v;
 #ifdef Linked
 		if ( size == 0 ) {
@@ -575,6 +577,10 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 
 
 #if #values(primitive) || #keys(primitive)
+	/** {@inheritDoc}
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
+	@Override
 	public VALUE_GENERIC_CLASS put( final KEY_GENERIC_CLASS ok, final VALUE_GENERIC_CLASS ov ) {
 		final VALUE_GENERIC_TYPE v = VALUE_CLASS2TYPE( ov );
 
@@ -613,7 +619,7 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 	public VALUE_GENERIC_TYPE addTo(final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE incr) {
 		int pos;
 	
-		if ( KEY_IS_NULL( k ) ) {
+		if ( KEY_EQUALS_NULL( k ) ) {
 			if ( containsNullKey ) return addToValue( n, incr );
 			pos = n;
 			containsNullKey = true;
@@ -628,9 +634,10 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 				while( ! KEY_IS_NULL( curr = key[ pos = ( pos + 1 ) & mask ] ) ) 
 					if ( KEY_EQUALS_NOT_NULL( curr, k ) ) return addToValue( pos, incr );
 			}
-			key[ pos ] = k;		  
 		}
 
+		key[ pos ] = k;
+
 #if #valueclass(Byte) || #valueclass(Short) || #valueclass(Char)		
 		value[ pos ] = (VALUE_TYPE)(defRetValue + incr);
 #else
@@ -693,9 +700,9 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 	}
 
 
-	SUPPRESS_WARNINGS_CUSTOM_KEY_UNCHECKED
+	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public VALUE_GENERIC_TYPE REMOVE_VALUE( final KEY_TYPE k ) {
-		if ( KEY_IS_NULL( k ) ) {
+		if ( KEY_EQUALS_NULL( KEY_GENERIC_CAST k ) ) {
 			if ( containsNullKey ) return removeNullEntry();
 			return defRetValue;
 		}
@@ -715,10 +722,14 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 
 
 #if #keys(primitive) || #values(primitive)
+	/** {@inheritDoc}
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
+	@Override
 	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public VALUE_GENERIC_CLASS remove( final Object ok ) {
 		final KEY_GENERIC_TYPE k = KEY_GENERIC_CAST KEY_OBJ2TYPE( ok );
-		if ( KEY_IS_NULL( k ) ) {
+		if ( KEY_EQUALS_NULL( k ) ) {
 			if ( containsNullKey ) return VALUE2OBJ( removeNullEntry() );
 			return OBJECT_DEFAULT_RETURN_VALUE;
 		}
@@ -763,8 +774,11 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 		final VALUE_GENERIC_TYPE v = value[ pos ];
 		if ( pos == n ) {
 			containsNullKey = false;
+#if #keys(reference)
+			key[ n ] = null;
+#endif
 #if #values(reference)
-			value[ n ] = VALUE_NULL;
+			value[ n ] = null;
 #endif
 		}
 		else shiftKeys( pos );
@@ -789,8 +803,11 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 		final VALUE_GENERIC_TYPE v = value[ pos ];
 		if ( pos == n ) {
 			containsNullKey = false;
+#if #keys(reference)
+			key[ n ] = null;
+#endif
 #if #values(reference)
-			value[ n ] = VALUE_NULL;
+			value[ n ] = null;
 #endif
 		}
 		else shiftKeys( pos );
@@ -842,7 +859,7 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 	 * @return the corresponding value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key.
 	 */
 	public VALUE_GENERIC_TYPE getAndMoveToFirst( final KEY_GENERIC_TYPE k ) {
-		if ( KEY_IS_NULL( k ) ) {
+		if ( KEY_EQUALS_NULL( k ) ) {
 			if ( containsNullKey ) {
 				moveIndexToFirst( n );
 				return value[ n ];
@@ -878,7 +895,7 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 	 * @return the corresponding value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key.
 	 */
 	public VALUE_GENERIC_TYPE getAndMoveToLast( final KEY_GENERIC_TYPE k ) {
-		if ( KEY_IS_NULL( k ) ) {
+		if ( KEY_EQUALS_NULL( k ) ) {
 			if ( containsNullKey ) {
 				moveIndexToLast( n );
 				return value[ n ];
@@ -917,7 +934,7 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 	public VALUE_GENERIC_TYPE putAndMoveToFirst( final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE v ) {
 		int pos;
 
-		if ( KEY_IS_NULL( k ) ) {
+		if ( KEY_EQUALS_NULL( k ) ) {
 			if ( containsNullKey ) {
 				moveIndexToFirst( n );
 				return setValue( n, v );
@@ -941,9 +958,9 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 						return setValue( pos, v );
 					}
 			}
-			key[ pos ] = k;
 		}
 		  
+		key[ pos ] = k;
 		value[ pos ] = v;
 		
 		if ( size == 0 ) {
@@ -971,7 +988,7 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 	public VALUE_GENERIC_TYPE putAndMoveToLast( final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE v ) {
 		int pos;
 
-		if ( KEY_IS_NULL( k ) ) {
+		if ( KEY_EQUALS_NULL( k ) ) {
 			if ( containsNullKey ) {
 				moveIndexToLast( n );
 				return setValue( n, v );
@@ -995,9 +1012,9 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 						return setValue( pos, v );
 					}
 			}
-			key[ pos ] = k;
 		}
 		  
+		key[ pos ] = k;
 		value[ pos ] = v;
 				
 		if ( size == 0 ) {
@@ -1019,10 +1036,12 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 #endif
 
 #if #keys(primitive)
-
+	/** @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
 	public VALUE_GENERIC_CLASS get( final KEY_CLASS ok ) {
+		if ( ok == null ) return null;
 		final KEY_GENERIC_TYPE k = KEY_CLASS2TYPE( ok );
-		if ( KEY_IS_NULL( k ) ) return containsNullKey ? VALUE2OBJ( value[ n ] ) : OBJECT_DEFAULT_RETURN_VALUE;
+		if ( KEY_EQUALS_NULL( k ) ) return containsNullKey ? VALUE2OBJ( value[ n ] ) : OBJECT_DEFAULT_RETURN_VALUE;
 
 		KEY_GENERIC_TYPE curr;
 		final KEY_GENERIC_TYPE[] key = this.key;
@@ -1038,12 +1057,11 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 			if ( KEY_EQUALS_NOT_NULL( k, curr ) ) return VALUE2OBJ( value[ pos ] );
 		}
 	}
-
 #endif
 
-	SUPPRESS_WARNINGS_CUSTOM_KEY_UNCHECKED
+	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public VALUE_GENERIC_TYPE GET_VALUE( final KEY_TYPE k ) {
-		if ( KEY_IS_NULL( k ) ) return containsNullKey ? value[ n ] : defRetValue;
+		if ( KEY_EQUALS_NULL( KEY_GENERIC_CAST k ) ) return containsNullKey ? value[ n ] : defRetValue;
 
 		KEY_GENERIC_TYPE curr;
 		final KEY_GENERIC_TYPE[] key = this.key;
@@ -1059,9 +1077,9 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 		}
 	}
 
-	SUPPRESS_WARNINGS_CUSTOM_KEY_UNCHECKED
+	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public boolean containsKey( final KEY_TYPE k ) {
-		if ( KEY_IS_NULL( k ) ) return containsNullKey;
+		if ( KEY_EQUALS_NULL( KEY_GENERIC_CAST k ) ) return containsNullKey;
 
 		KEY_GENERIC_TYPE curr;
 		final KEY_GENERIC_TYPE[] key = this.key;
@@ -1152,6 +1170,11 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 		
 		MapEntry() {}
 		
+#if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
 		public KEY_GENERIC_CLASS getKey() {
 			return KEY2OBJ( key[ index ] );
 		}
@@ -1162,6 +1185,11 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 		}
 #endif
 
+#if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
 		public VALUE_GENERIC_CLASS getValue() {
 			return VALUE2OBJ( value[ index ] );
 		}
@@ -1321,7 +1349,7 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 		}
 
 		private MapIterator( final KEY_GENERIC_TYPE from ) {
-			if ( KEY_IS_NULL( from ) ) {
+			if ( KEY_EQUALS_NULL( from ) ) {
 				if ( OPEN_HASH_MAP.this.containsNullKey ) {
 					next = GET_NEXT( link[ n ] );
 					prev = n;
@@ -1385,7 +1413,7 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 
 					 
 		public int nextEntry() {
-			if ( ! hasNext() ) return size();
+			if ( ! hasNext() ) throw new NoSuchElementException();
 
 			curr = next;
 			next = GET_NEXT(link[ curr ]);
@@ -1397,7 +1425,7 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 		}
 
 		public int previousEntry() {
-			if ( ! hasPrevious() ) return -1;
+			if ( ! hasPrevious() ) throw new NoSuchElementException();
 
 			curr = prev;
 			prev = GET_PREV(link[ curr ]);
@@ -1436,8 +1464,11 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 
 			if ( pos == n ) {
 				OPEN_HASH_MAP.this.containsNullKey = false;
+#if #keys(reference)
+				key[ n ] = null;
+#endif
 #if #values(reference)
-				value[ n ] = VALUE_NULL;
+				value[ n ] = null;
 #endif
 			}
 			else {
@@ -1619,8 +1650,11 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 			if ( last == -1 ) throw new IllegalStateException();
 			if ( last == n ) {
 				containsNullKey = false;
+#if #keys(reference)
+				key[ n ] = null;
+#endif
 #if #values(reference)
-				value[ n ] = VALUE_NULL;
+				value[ n ] = null;
 #endif
 			}
 			else if ( pos >= 0 ) shiftKeys( last );
@@ -1714,10 +1748,12 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 		public boolean contains( final Object o ) {
 			if ( !( o instanceof Map.Entry ) ) return false;
 			final Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS> e = (Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS>)o;
-
+#if #keys(primitive)
+			if ( e.getKey() == null ) return false;
+#endif
 			final KEY_GENERIC_TYPE k = KEY_CLASS2TYPE( e.getKey() );
 			
-			if ( KEY_IS_NULL( k ) ) return ( OPEN_HASH_MAP.this.containsNullKey && VALUE_EQUALS( value[ n ], VALUE_CLASS2TYPE( e.getValue() ) ) );
+			if ( KEY_EQUALS_NULL( k ) ) return ( OPEN_HASH_MAP.this.containsNullKey && VALUE_EQUALS( value[ n ], VALUE_CLASS2TYPE( e.getValue() ) ) );
 
 			KEY_GENERIC_TYPE curr;
 			final KEY_GENERIC_TYPE[] key = OPEN_HASH_MAP.this.key;
@@ -1737,11 +1773,13 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 		public boolean remove( final Object o ) {
 			if ( !( o instanceof Map.Entry ) ) return false;
 			final Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS> e = (Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS>)o;
-
+#if #keys(primitive)
+			if ( e.getKey() == null ) return false;
+#endif
 			final KEY_GENERIC_TYPE k = KEY_CLASS2TYPE( e.getKey() );
 			final VALUE_GENERIC_TYPE v = VALUE_CLASS2TYPE( e.getValue() );
 
-			if ( KEY_IS_NULL( k ) ) {
+			if ( KEY_EQUALS_NULL( k ) ) {
 				if ( containsNullKey && VALUE_EQUALS( value[ n ], v ) ) {
 					removeNullEntry();
 					return true;
@@ -1784,7 +1822,11 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 
 #ifdef Linked
 		public ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC> iterator( final MAP.Entry KEY_VALUE_GENERIC from ) {
+#if #keys(primitive)
+			return new EntryIterator( from.ENTRY_GET_KEY() );
+#else
 			return new EntryIterator( KEY_CLASS2TYPE( from.getKey() ) );
+#endif
 		}
 
 		public ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC> fastIterator() {
@@ -1792,7 +1834,11 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 		}
 				
 		public ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC> fastIterator( final MAP.Entry KEY_VALUE_GENERIC from ) {
+#if #keys(primitive)
+			return new FastEntryIterator( from.ENTRY_GET_KEY() );
+#else
 			return new FastEntryIterator( KEY_CLASS2TYPE( from.getKey() ) );
+#endif
 		}
 				
 #endif
@@ -1934,6 +1980,10 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 		public ValueIterator() { super(); }
 		public VALUE_GENERIC_TYPE NEXT_VALUE() { return value[ nextEntry() ]; }
 #if ! #values(reference)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public VALUE_GENERIC_CLASS next() { return VALUE2OBJ( value[ nextEntry() ] ); }
 #endif
 	}
@@ -1994,7 +2044,7 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 
 	public boolean trim() {
 		final int l = arraySize( size, f );
-		if ( l >= n ) return true;
+		if ( l >= n || size > maxFill( l, f ) ) return true;
 		try {
 			rehash( l );
 		}
@@ -2024,7 +2074,7 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 
 	public boolean trim( final int n ) {
 		final int l = HashCommon.nextPowerOfTwo( (int)Math.ceil( n / f ) );
-		if ( this.n <= l ) return true;
+		if ( l >= n || size > maxFill( l, f ) ) return true;
 		try {
 			rehash( l );
 		}
@@ -2058,13 +2108,13 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 		first = -1;
 
 		for( int j = size; j-- != 0; ) {
-			if ( KEY_IS_NULL( key[ i ] ) ) pos = newN;
+			if ( KEY_EQUALS_NULL( key[ i ] ) ) pos = newN;
 			else {
 				pos = KEY2INTHASH( key[ i ] ) & mask;
 				while ( ! KEY_IS_NULL( newKey[ pos ] ) ) pos = ( pos + 1 ) & mask;
-				newKey[ pos ] = key[ i ];
 			}
 
+			newKey[ pos ] = key[ i ];
 			newValue[ pos ] = value[ i ];
 
 			if ( prev != -1 ) {
@@ -2220,16 +2270,16 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 			k = KEY_GENERIC_CAST s.READ_KEY();
 			v = VALUE_GENERIC_CAST s.READ_VALUE();
 
-			if ( KEY_IS_NULL( k ) ) {
+			if ( KEY_EQUALS_NULL( k ) ) {
 				pos = n;
 				containsNullKey = true;
 			}
 			else {
 				pos = KEY2INTHASH( k ) & mask;
 				while ( ! KEY_IS_NULL( key[ pos ] ) ) pos = ( pos + 1 ) & mask;
-				key[ pos ] = k;
 			}
 
+			key[ pos ] = k;
 			value[ pos ] = v;
 			
 #ifdef Linked
diff --git a/drv/OpenHashSet.drv b/drv/OpenHashSet.drv
index 2e4d53d..ee8b656 100644
--- a/drv/OpenHashSet.drv
+++ b/drv/OpenHashSet.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -55,7 +55,7 @@ import java.util.Comparator;
  *
  * <P>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
+ * in iteration order with {@code 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 <code>null</code>.
@@ -153,7 +153,7 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 	protected transient long[] link;
 #endif
 
-	/** The current table size. */
+	/** The current table size. Note that an additional element is allocated for storing the null key. */
 	protected transient int n;
 
 	/** Threshold after which we rehash. It must be the table size times {@link #f}. */
@@ -598,12 +598,15 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 	public boolean add( final KEY_GENERIC_TYPE k ) {
 		int pos;
 
-		if ( KEY_IS_NULL( k ) ) {
+		if ( KEY_EQUALS_NULL( k ) ) {
 			if ( containsNull ) return false;
 #ifdef Linked
 			pos = n;
 #endif
 			containsNull = true;
+#ifdef Custom
+			key[ n ] = k;
+#endif
 		}
 		else {
 			KEY_GENERIC_TYPE curr;
@@ -636,6 +639,63 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 		return true;
 	}
 
+#if #keyclass(Object)
+	/** Add a random element if not present, get the existing value if already present.
+	 *
+	 * This is equivalent to (but faster than) doing a:
+	 * <pre>
+	 * K exist = set.get(k);
+	 * if (exist == null) {
+	 *   set.add(k);
+	 *   exist = k;
+	 * }
+	 * </pre>
+	 */
+	public KEY_GENERIC_TYPE addOrGet( final KEY_GENERIC_TYPE k ) {
+		int pos;
+
+		if ( KEY_EQUALS_NULL( k ) ) {
+			if ( containsNull ) return key [ n ];
+#ifdef Linked
+			pos = n;
+#endif
+			containsNull = true;
+#ifdef Custom
+			key [ n ] = k;
+#endif
+		}
+		else {
+			KEY_GENERIC_TYPE curr;
+			final KEY_GENERIC_TYPE[] key = this.key;
+
+			// The starting point.
+			if ( ! KEY_IS_NULL( curr = key[ pos = KEY2INTHASH( k ) & mask ] ) ) {
+				if ( KEY_EQUALS_NOT_NULL( curr, k ) ) return curr;
+				while( ! KEY_IS_NULL( curr = key[ pos = ( pos + 1 ) & mask ] ) ) 
+					if ( KEY_EQUALS_NOT_NULL( curr, k ) ) return curr;
+			}
+			key[ pos ] = k;
+		}
+
+#ifdef Linked
+		if ( size == 0 ) {
+			first = last = pos;
+			// Special case of SET_UPPER_LOWER(link[ pos ], -1, -1);
+			link[ pos ] = -1L;
+		}
+		else {
+			SET_NEXT( link[ last ], pos );
+			SET_UPPER_LOWER( link[ pos ], last, -1 );
+			last = pos;
+		}
+#endif
+
+		if ( size++ >= maxFill ) rehash( arraySize( size + 1, f ) );
+		if ( ASSERTS ) checkTable();
+		return k;
+	}
+#endif
+
 	/** Shifts left entries with the specified hash code, starting at the specified position,
 	 * and empties the resulting free entry.
 	 *
@@ -679,6 +739,7 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 
 	private boolean removeNullEntry() {
 		containsNull = false;
+		key[ n ] = KEY_NULL;
 		size--;
 #ifdef Linked
 		fixPointers( n );
@@ -687,9 +748,9 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 		return true;	
 	}
 
-	SUPPRESS_WARNINGS_CUSTOM_KEY_UNCHECKED
+	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public boolean remove( final KEY_TYPE k ) {
-		if ( KEY_IS_NULL( k ) ) {
+		if ( KEY_EQUALS_NULL( KEY_GENERIC_CAST k ) ) {
 			if ( containsNull ) return removeNullEntry();
 			return false;
 		}
@@ -708,9 +769,9 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 		}
 	}
 
-	SUPPRESS_WARNINGS_CUSTOM_KEY_UNCHECKED
+	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public boolean contains( final KEY_TYPE k ) {
-		if ( KEY_IS_NULL( k ) ) return containsNull;
+		if ( KEY_EQUALS_NULL( KEY_GENERIC_CAST k ) ) return containsNull;
 
 		KEY_GENERIC_TYPE curr;
 		final KEY_GENERIC_TYPE[] key = this.key;
@@ -730,9 +791,9 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 	/** Returns the element of this set that is equal to the given key, or <code>null</code>.
 	 * @return the element of this set that is equal to the given key, or <code>null</code>.
 	 */
-	SUPPRESS_WARNINGS_CUSTOM_KEY_UNCHECKED
+	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public K get( final Object k ) {
-		if ( k == null ) return null; // This is correct independently of the value of containsNull
+		if ( KEY_EQUALS_NULL( KEY_GENERIC_CAST k ) ) return key[ n ]; // This is correct independently of the value of containsNull and of the map being custom
 
 		KEY_GENERIC_TYPE curr;
 		final KEY_GENERIC_TYPE[] key = this.key;
@@ -766,7 +827,10 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 		}
 		final KEY_GENERIC_TYPE k = key[ pos ];
 		size--;
-		if ( KEY_IS_NULL( k ) ) containsNull = false;
+		if ( KEY_EQUALS_NULL( k ) ) {
+			containsNull = false;
+			key[ n ] = KEY_NULL;
+		}
 		else shiftKeys( pos );
 		if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 );
 		return k;
@@ -787,7 +851,10 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 		}
 		final KEY_GENERIC_TYPE k = key[ pos ];
 		size--;
-		if ( KEY_IS_NULL( k ) ) containsNull = false;
+		if ( KEY_EQUALS_NULL( k ) ) {
+			containsNull = false;
+			key[ n ] = KEY_NULL;
+		}
 		else shiftKeys( pos );
 		if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 );
 		return k;
@@ -839,7 +906,7 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 	public boolean addAndMoveToFirst( final KEY_GENERIC_TYPE k ) {
 		int pos;
 		
-		if ( KEY_IS_NULL( k ) ) {
+		if ( KEY_EQUALS_NULL( k ) ) {
 			if ( containsNull ) {
 				moveIndexToFirst( n );
 				return false;
@@ -860,11 +927,11 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 				}
 			
 				pos = ( pos + 1 ) & mask;
-			}
-		  
-			key[ pos ] = k;
+			}		  
 		}
 		
+		key[ pos ] = k;
+
 		if ( size == 0 ) {
 			first = last = pos;
 			// Special case of SET_UPPER_LOWER( link[ pos ], -1, -1 );
@@ -889,7 +956,7 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 	public boolean addAndMoveToLast( final KEY_GENERIC_TYPE k ) {
 		int pos;
 	
-		if ( KEY_IS_NULL( k ) ) {
+		if ( KEY_EQUALS_NULL( k ) ) {
 			if ( containsNull ) {
 				moveIndexToLast( n );
 				return false;
@@ -911,9 +978,9 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 			
 				pos = ( pos + 1 ) & mask;
 			}
-		  
-			key[ pos ] = k;
 		}
+
+		key[ pos ] = k;
 		
 		if ( size == 0 ) {
 			first = last = pos;
@@ -1098,7 +1165,7 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 		}
 
 		SetIterator( KEY_GENERIC_TYPE from ) {
-			if ( KEY_IS_NULL( from ) ) {
+			if ( KEY_EQUALS_NULL( from ) ) {
 				if ( OPEN_HASH_SET.this.containsNull ) {
 					next = GET_NEXT( link[ n ] );
 					prev = n;
@@ -1212,7 +1279,10 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 			int last, slot, pos = curr;
 			curr = -1;
 
-			if ( pos == n ) OPEN_HASH_SET.this.containsNull = false;
+			if ( pos == n ) {
+				OPEN_HASH_SET.this.containsNull = false;
+				OPEN_HASH_SET.this.key[ n ] = KEY_NULL;
+			}
 			else {
 				KEY_GENERIC_TYPE curr;
 				final KEY_GENERIC_TYPE[] key = OPEN_HASH_SET.this.key;
@@ -1283,7 +1353,7 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 			if ( mustReturnNull ) {
 				mustReturnNull = false;
 				last = n;
-				return KEY_NULL;
+				return key[ n ];
 			}
 			final KEY_GENERIC_TYPE key[] = OPEN_HASH_SET.this.key;
 			for(;;) {
@@ -1332,7 +1402,10 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 	
 		public void remove() {
 			if ( last == -1 ) throw new IllegalStateException();
-			if ( last == n ) OPEN_HASH_SET.this.containsNull = false;
+			if ( last == n ) {
+				OPEN_HASH_SET.this.containsNull = false;
+				OPEN_HASH_SET.this.key[ n ] = KEY_NULL;
+			}
 			else if ( pos >= 0 ) shiftKeys( last );
 			else {
 				// We're removing wrapped entries.
@@ -1391,7 +1464,7 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 
 	public boolean trim() {
 		final int l = arraySize( size, f );
-		if ( l >= n ) return true;
+		if ( l >= n || size > maxFill( l, f ) ) return true;
 		try {
 			rehash( l );
 		}
@@ -1421,7 +1494,7 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 
 	public boolean trim( final int n ) {
 		final int l = HashCommon.nextPowerOfTwo( (int)Math.ceil( n / f ) );
-		if ( this.n <= l ) return true;
+		if ( l >= n || size > maxFill( l, f ) ) return true;
 		try {
 			rehash( l );
 		}
@@ -1453,13 +1526,14 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 		first = -1;
 
 		for( int j = size; j-- != 0; ) {
-			if ( KEY_IS_NULL( key[ i ] ) ) pos = newN;
+			if ( KEY_EQUALS_NULL( key[ i ] ) ) pos = newN;
 			else {
 				pos = KEY2INTHASH( key[ i ] ) & mask;
 				while ( ! KEY_IS_NULL( newKey[ pos ] ) ) pos = ( pos + 1 ) & mask;
-				newKey[ pos ] = key[ i ];
 			}
 
+			newKey[ pos ] = key[ i ];
+
 			if ( prev != -1 ) {
 				SET_NEXT( newLink[ newPrev ], pos );
 				SET_PREV( newLink[ pos ], newPrev );
@@ -1582,16 +1656,17 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 
 			k = KEY_GENERIC_CAST s.READ_KEY();
 
-			if ( KEY_IS_NULL( k ) ) {
+			if ( KEY_EQUALS_NULL( k ) ) {
 				pos = n;
 				containsNull = true;
 			}
 			else {
 				if ( ! KEY_IS_NULL( key[ pos = KEY2INTHASH( k ) & mask ] ) )
 					while ( ! KEY_IS_NULL( key[ pos = ( pos + 1 ) & mask ] ) );
-				key[ pos ] = k;
 			}
 
+			key[ pos ] = k;
+
 #ifdef Linked
 			if ( first != -1 ) {
 				SET_NEXT( link[ prev ], pos );
diff --git a/drv/PriorityQueue.drv b/drv/PriorityQueue.drv
index e59a6b3..5adb4a5 100644
--- a/drv/PriorityQueue.drv
+++ b/drv/PriorityQueue.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
diff --git a/drv/PriorityQueues.drv b/drv/PriorityQueues.drv
index 7f251d6..a103ab2 100644
--- a/drv/PriorityQueues.drv
+++ b/drv/PriorityQueues.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2003-2014 Sebastiano Vigna 
+ * Copyright (C) 2003-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/RBTreeMap.drv b/drv/RBTreeMap.drv
index 65902d7..c9ef92b 100644
--- a/drv/RBTreeMap.drv
+++ b/drv/RBTreeMap.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -60,13 +60,13 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 	protected transient Entry KEY_VALUE_GENERIC lastEntry;
 
 	/** Cached set of entries. */
-	protected transient volatile ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC> entries;
+	protected transient ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC> entries;
 
 	/** Cached set of keys. */
-	protected transient volatile SORTED_SET KEY_GENERIC keys;
+	protected transient SORTED_SET KEY_GENERIC keys;
 
 	/** Cached collection of values. */
-	protected transient volatile VALUE_COLLECTION VALUE_GENERIC values;
+	protected transient VALUE_COLLECTION VALUE_GENERIC values;
 
 	/** The value of this variable remembers, after a <code>put()</code> 
 	 * or a <code>remove()</code>, whether the <em>domain</em> of the map
@@ -274,28 +274,61 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 		nodePath = new Entry[ 64 ];
 	}
 
-	/* After execution of this method, modified is true iff a new entry has
-	been inserted. */
-	 
+	#if #values(primitive) && !#valueclass(Boolean)
+	/** Adds an increment to value currently associated with a key.
+	*
+	* <P>Note that this method respects the {@linkplain #defaultReturnValue() default return value} semantics: when
+	* called with a key that does not currently appears in the map, the key
+	* will be associated with the default return value plus
+	* the given increment.
+	*
+	* @param k the key.
+	* @param incr the increment.
+	* @return the old value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key.
+	*/
+	public VALUE_GENERIC_TYPE addTo( final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE incr) {
+		Entry KEY_VALUE_GENERIC e = add( k );
+		final VALUE_GENERIC_TYPE oldValue = e.value;
+		e.value += incr;
+		return oldValue;
+	}
+	#endif
+
 	public VALUE_GENERIC_TYPE put( final KEY_GENERIC_TYPE k, final VALUE_GENERIC_TYPE v ) {
+		Entry KEY_VALUE_GENERIC e = add( k );
+		final VALUE_GENERIC_TYPE oldValue = e.value;
+		e.value = v;
+		return oldValue;
+	}
+
+	 	/** Returns a node with key k in the balanced tree, creating one with defRetValue if necessary.
+	*
+	* @param k the key
+	* @return a node with key k. If a node with key k already exists, then that node is returned,
+	* 				otherwise a new node with defRetValue is created ensuring that the tree is balanced
+						after creation of the node.
+	*/
+	private Entry KEY_VALUE_GENERIC add( final KEY_GENERIC_TYPE k ) {
+    /* After execution of this method, modified is true iff a new entry has
+    been inserted. */
 		modified = false;
 		int maxDepth = 0;
 
+		Entry KEY_VALUE_GENERIC e;
+
 		if ( tree == null ) { // The case of the empty tree is treated separately.
 			count++;
-			tree = lastEntry = firstEntry = new Entry KEY_VALUE_GENERIC( k, v );
+			e = tree = lastEntry = firstEntry = new Entry KEY_VALUE_GENERIC( k, defRetValue );
 		}
 		else {
-			Entry KEY_VALUE_GENERIC p = tree, e;
+			Entry KEY_VALUE_GENERIC p = tree;
 			int cmp, i = 0;
 
 			while( true ) {
 				if ( ( cmp = compare( k, p.key ) ) == 0 ) {
-					final VALUE_GENERIC_TYPE oldValue = p.value;
-					p.value = v;
 					// We clean up the node path, or we could have stale references later.
 					while( i-- != 0 ) nodePath[ i ] = null;
-					return oldValue;
+					return p;
 				}
 					 
 				nodePath[ i ] = p;
@@ -303,7 +336,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 				if ( dirPath[ i++ ] = cmp > 0 ) {
 					if ( p.succ() ) {
 						count++;
-						e = new Entry KEY_VALUE_GENERIC( k, v );
+						e = new Entry KEY_VALUE_GENERIC( k, defRetValue ); 
 								
 						if ( p.right == null ) lastEntry = e;
 								
@@ -320,7 +353,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 				else {
 					if ( p.pred() ) {
 						count++;
-						e = new Entry KEY_VALUE_GENERIC( k, v );
+						e = new Entry KEY_VALUE_GENERIC( k, defRetValue );
 								
 						if ( p.left == null ) firstEntry = e;
 								
@@ -441,7 +474,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 			checkNodePath();
 			checkTree( tree, 0, -1 );
 		}
-		return defRetValue;
+		return e;
 	}
 
 	 
@@ -723,6 +756,10 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 
 
 #if ! #keyclass(Object) || #values(primitive)
+	/** {@inheritDoc}
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
+	@Override
 	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 );
@@ -730,6 +767,10 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 #endif
 
 #if ! #keyclass(Object) || #values(primitive)
+	/** {@inheritDoc}
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
+	@Override
 	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;
@@ -917,6 +958,11 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 			return prev;
 		}
 
+#if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
 		public KEY_GENERIC_CLASS getKey() {
 			return KEY2OBJ(key);
 		}
@@ -927,6 +973,11 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 		}
 #endif
 		  
+#if #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+#endif
 		public VALUE_GENERIC_CLASS getValue() {
 			return VALUE2OBJ(value);
 		}
@@ -1038,7 +1089,10 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 	}
 
 #if #keyclass(Object) && #values(primitive)
-
+	/** {@inheritDoc}
+	 * @deprecated Please use the corresponding type-specific method instead. */
+	@Deprecated
+	@Override
 	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public VALUE_GENERIC_CLASS get( final Object ok ) {
 		final Entry KEY_VALUE_GENERIC e = findKey( KEY_GENERIC_CAST ok );
@@ -1192,6 +1246,9 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 				public boolean contains( final Object o ) {
 					if (!(o instanceof Map.Entry)) return false;
 					final Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS> e = (Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS>)o;
+#if #keys(primitive)
+					if ( e.getKey() == null ) return false;
+#endif
 					final Entry KEY_VALUE_GENERIC f = findKey( KEY_CLASS2TYPE( e.getKey() ) );
 					return e.equals( f );
 				}					 
@@ -1200,6 +1257,9 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 				public boolean remove( final Object o ) {
 					if (!(o instanceof Map.Entry)) return false;
 					final Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS> e = (Map.Entry<KEY_GENERIC_CLASS, VALUE_GENERIC_CLASS>)o;
+#if #keys(primitive)
+					if ( e.getKey() == null ) return false;
+#endif
 					final Entry KEY_VALUE_GENERIC f = findKey( KEY_CLASS2TYPE( e.getKey() ) );
 					if ( f != null ) RB_TREE_MAP.this.REMOVE_VALUE( f.key );
 					return f != null;
@@ -1351,13 +1411,13 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 		boolean top;
 		/** Cached set of entries. */
 		@SuppressWarnings("hiding")
-		protected transient volatile ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC> entries;
+		protected transient ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC> entries;
 		/** Cached set of keys. */
 		@SuppressWarnings("hiding")
-		protected transient volatile SORTED_SET KEY_GENERIC keys;
+		protected transient SORTED_SET KEY_GENERIC keys;
 		/** Cached collection of values. */
 		@SuppressWarnings("hiding")
-		protected transient volatile VALUE_COLLECTION VALUE_GENERIC values;
+		protected transient VALUE_COLLECTION VALUE_GENERIC values;
 		  
 		/** Creates a new submap with given key range.
 		 *
@@ -1501,7 +1561,10 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 		  
 		  
 #if #keyclass(Object) && #values(primitive)
-
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		SUPPRESS_WARNINGS_KEY_UNCHECKED
 		public VALUE_GENERIC_CLASS get( final Object ok ) {
 			final RB_TREE_MAP.Entry KEY_VALUE_GENERIC e;
@@ -1519,6 +1582,10 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 
 		  
 #if ! #keyclass(Object) || #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		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 );
@@ -1534,6 +1601,10 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 		}
 
 #if ! #keyclass(Object) || #values(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		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;
@@ -1629,12 +1700,20 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 		}
 	 
 #if !#keyclass(Object)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public KEY_GENERIC_CLASS firstKey() {
 			RB_TREE_MAP.Entry KEY_VALUE_GENERIC e = firstEntry();
 			if ( e == null ) throw new NoSuchElementException();
 			return e.getKey();
 		}
 	 
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
+		@Override
 		public KEY_GENERIC_CLASS lastKey() {
 			RB_TREE_MAP.Entry KEY_VALUE_GENERIC e = lastEntry();
 			if ( e == null ) throw new NoSuchElementException();
@@ -1988,7 +2067,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 			v[i] = genValue();
 		}
 
-		double totPut = 0, totYes = 0, totNo = 0, totIterFor = 0, totIterBack = 0, totRemYes = 0, d, dd;
+		double totPut = 0, totYes = 0, totNo = 0, totAddTo = 0, totIterFor = 0, totIterBack = 0, totRemYes = 0, d, dd, ddd;
 
 		if ( comp ) { for( j = 0; j < 20; j++ ) {
 
@@ -2026,6 +2105,15 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 			/* And then we put it back. */
 			for( i = 0; i < n/2;  i++ ) t.put( KEY2OBJ( k[i] ), VALUE2OBJ( v[i] )  );
 
+			#if #values(primitive) && !#valueclass(Boolean)
+      /* we perform n/2 addTo() operations with get then put */
+      ms = System.currentTimeMillis();
+      for( i = 0; i < n/2; i++ ) t.put( KEY2OBJ( k[i] ), (VALUE_TYPE) ((VALUE_CLASS) t.get( KEY2OBJ(k[i])) + i) );
+      ddd = System.currentTimeMillis() - ms;
+      if ( j > 2 ) totAddTo += n/ddd;
+      System.out.print("AddTo: " + format( n/ddd ) +" K/s " );
+      #endif
+
 			/* We check for pairs in t. */
 			ms = System.currentTimeMillis();
 			for( i = 0; i < n;  i++ ) t.containsKey( KEY2OBJ( k[i] ) );
@@ -2051,7 +2139,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 		}
 
 		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( "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 AddTo: " + format( totAddTo/(j-3) ) + " K/s IterFor: " + format( totIterFor/(j-3) )  + " K/s"  );
 
 		System.out.println();
 
@@ -2096,6 +2184,15 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 			/* And then we put it back. */
 			for( i = 0; i < n/2;  i++ ) m.put( k[i], v[i]  );
 
+			#if #values(primitive) && !#valueclass(Boolean)
+      /* we perform n/2 addTo() operations with get then put */
+      ms = System.currentTimeMillis();
+      for( i = 0; i < n/2; i++ ) m.addTo( k[i], (VALUE_TYPE) i );
+      ddd = System.currentTimeMillis() - ms;
+      if ( j > 2 ) totAddTo += n/ddd;
+      System.out.print("AddTo: " + format( n/ddd ) +" K/s " );
+      #endif
+
 			/* We check for pairs in m. */
 			ms = System.currentTimeMillis();
 			for( i = 0; i < n;  i++ ) m.containsKey( k[i] );
@@ -2130,7 +2227,7 @@ public class RB_TREE_MAP KEY_VALUE_GENERIC extends ABSTRACT_SORTED_MAP KEY_VALUE
 
 
 		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( "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 AddTo: " + format( totAddTo/(j-3) ) + " K/s IterFor: " + format( totIterFor/(j-3) )  + " K/s"  );
 
 		System.out.println();
 
diff --git a/drv/RBTreeSet.drv b/drv/RBTreeSet.drv
index 93b4388..16309f5 100644
--- a/drv/RBTreeSet.drv
+++ b/drv/RBTreeSet.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -743,10 +743,11 @@ public class RB_TREE_SET KEY_GENERIC extends ABSTRACT_SORTED_SET KEY_GENERIC imp
 		return findKey( KEY_GENERIC_CAST k ) != null;
 	}
 
-#if #keysclass(Object)
+#if #keyclass(Object)
+	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public K get( final KEY_TYPE k ) {
 		final Entry KEY_GENERIC entry = findKey( KEY_GENERIC_CAST k );
-		return entry == null ? null : entry.getKey();
+		return entry == null ? null : entry.key;
 	}
 #endif
 
@@ -1140,7 +1141,7 @@ public class RB_TREE_SET KEY_GENERIC extends ABSTRACT_SORTED_SET KEY_GENERIC imp
 		public void clear() {
 			final SubsetIterator i = new SubsetIterator();
 			while( i.hasNext() ) {
-				i.next();
+				i.NEXT_KEY();
 				i.remove();
 			}
 		}
@@ -1176,7 +1177,7 @@ public class RB_TREE_SET KEY_GENERIC extends ABSTRACT_SORTED_SET KEY_GENERIC imp
 				
 			while( i.hasNext() ) {
 				n++;
-				i.next();
+				i.NEXT_KEY();
 			}
 				
 			return n;
diff --git a/drv/SemiIndirectHeaps.drv b/drv/SemiIndirectHeaps.drv
index 05d93b2..f3633ac 100644
--- a/drv/SemiIndirectHeaps.drv
+++ b/drv/SemiIndirectHeaps.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
@@ -47,24 +47,28 @@ public class SEMI_INDIRECT_HEAPS {
 
 	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public static KEY_GENERIC int downHeap( final KEY_GENERIC_TYPE[] refArray, final int[] 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 + ")" );
+		assert i < 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 ];
+			while ( ( child = ( i << 1 ) + 1 ) < size ) {
+				int t = heap[ child ];
+				final int right = child + 1;
+				if ( right < size && KEY_LESS( refArray[ heap[ right ] ], refArray[ t ] ) ) t = heap[ child = right ];
+				if ( KEY_LESSEQ( E, refArray[ t ] ) ) break;
+				heap[ i ] = t;
 				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 ];
+			while ( ( child = ( i << 1 ) + 1 ) < size ) {
+				int t = heap[ child ];
+				final int right = child + 1;
+				if ( right < size && c.compare( refArray[ heap[ right ] ], refArray[ t ] ) < 0 ) t = heap[ child = right ];
+				if ( c.compare( E, refArray[ t ] ) <= 0 ) break;
+				heap[ i ] = t;
 				i = child;
 			}
 
@@ -85,22 +89,25 @@ public class SEMI_INDIRECT_HEAPS {
 
 	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public static KEY_GENERIC int upHeap( final KEY_GENERIC_TYPE[] refArray, final int[] 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 + ")" );
+		assert i < size;
 
 		final int e = heap[ i ];
-		int parent;
 		final KEY_GENERIC_TYPE E = refArray[ e ];
 
 		if ( c == null )
-			while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
-				if ( KEY_LESSEQ( refArray[ heap[ parent ] ], E ) ) break;
-				heap[ i ] = heap[ parent ]; 
+			while ( i != 0 ) {
+				final int parent = ( i - 1 ) >>> 1;
+				final int t = heap[ parent ];
+				if ( KEY_LESSEQ( refArray[ t ], E ) ) break;
+				heap[ i ] = t; 
 				i = parent;
 			}
 		else
-			while ( i != 0 && ( parent = ( i - 1 ) / 2 ) >= 0 ) {
-				if ( c.compare( refArray[ heap[ parent ] ], E ) <= 0 ) break;
-				heap[ i ] = heap[ parent ]; 
+			while ( i != 0 ) {
+				final int parent = ( i - 1 ) >>> 1;
+				final int t = heap[ parent ];
+				if ( c.compare( refArray[ t ], E ) <= 0 ) break;
+				heap[ i ] = t; 
 				i = parent;
 			}
 
@@ -125,7 +132,7 @@ public class SEMI_INDIRECT_HEAPS {
 		int i = length;
 		while( i-- != 0 ) heap[ i ] = offset + i;
 
-		i = length / 2;
+		i = length >>> 1;
 		while( i-- != 0 ) downHeap( refArray, heap, length, i, c );
 	}
 
@@ -139,7 +146,7 @@ public class SEMI_INDIRECT_HEAPS {
 	 */
 
 	public static KEY_GENERIC int[] makeHeap( final KEY_GENERIC_TYPE[] refArray, final int offset, final int length, final KEY_COMPARATOR KEY_GENERIC c ) {
-		int[] heap = length <= 0 ? IntArrays.EMPTY_ARRAY : new int[ length ];
+		final int[] heap = length <= 0 ? IntArrays.EMPTY_ARRAY : new int[ length ];
 		makeHeap( refArray, offset, length, heap, c );
 		return heap;
 	}
@@ -155,7 +162,7 @@ public class SEMI_INDIRECT_HEAPS {
 	 */
 
 	public static KEY_GENERIC void makeHeap( final KEY_GENERIC_TYPE[] refArray, final int[] heap, final int size, final KEY_COMPARATOR KEY_GENERIC c ) {
-		int i = size / 2;
+		int i = size >>> 1;
 		while( i-- != 0 ) downHeap( refArray, heap, size, i, c );
 	}
 
diff --git a/drv/Set.drv b/drv/Set.drv
index f8a9280..ce4f56e 100644
--- a/drv/Set.drv
+++ b/drv/Set.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/Sets.drv b/drv/Sets.drv
index cb60fe1..af52d5e 100644
--- a/drv/Sets.drv
+++ b/drv/Sets.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -42,18 +42,28 @@ public class SETS {
 
 		public boolean remove( KEY_TYPE ok ) { throw new UnsupportedOperationException(); }
 		public Object clone() { return EMPTY_SET; }
+		@SuppressWarnings("rawtypes")
+		public boolean equals( final Object o ) { return o instanceof Set && ((Set)o).isEmpty(); }
         private Object readResolve() { return EMPTY_SET; }
 	}
 
 
 	/** An empty set (immutable). It is serializable and cloneable.
-	 *
-	 * <P>The class of this objects represent an abstract empty set
-	 * that is a subset of a (sorted) type-specific set.
 	 */
 	SUPPRESS_WARNINGS_KEY_RAWTYPES
 	public static final EmptySet EMPTY_SET = new EmptySet();
 
+#if #keys(reference)
+	/** Return an empty set (immutable). It is serializable and cloneable.
+	 *
+	 * <P>This method provides a typesafe access to {@link #EMPTY_SET}.
+	 * @return an empty set (immutable).
+	 */
+	@SuppressWarnings("unchecked")
+	public static KEY_GENERIC SET KEY_GENERIC emptySet() {
+		return EMPTY_SET;
+	}
+#endif
 
 
 	/** An immutable class representing a type-specific singleton set.
diff --git a/drv/SortedMap.drv b/drv/SortedMap.drv
index 8de8cfd..158c333 100644
--- a/drv/SortedMap.drv
+++ b/drv/SortedMap.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/SortedMaps.drv b/drv/SortedMaps.drv
index 4b3151f..d78e157 100644
--- a/drv/SortedMaps.drv
+++ b/drv/SortedMaps.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -83,11 +83,26 @@ public class SORTED_MAPS {
 		public KEY_GENERIC_TYPE LAST_KEY() { throw new NoSuchElementException(); }
 
 #if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public SORTED_MAP KEY_VALUE_GENERIC headMap( KEY_GENERIC_CLASS oto ) { return headMap( KEY_CLASS2TYPE( oto ) ); }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public SORTED_MAP KEY_VALUE_GENERIC tailMap( KEY_GENERIC_CLASS ofrom ) { return tailMap( KEY_CLASS2TYPE( ofrom ) ); }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public SORTED_MAP KEY_VALUE_GENERIC subMap( KEY_GENERIC_CLASS ofrom, KEY_GENERIC_CLASS oto ) { return subMap( KEY_CLASS2TYPE( ofrom ), KEY_CLASS2TYPE( oto ) ); }
 
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public KEY_GENERIC_CLASS firstKey() { return KEY2OBJ( FIRST_KEY() ); }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public KEY_GENERIC_CLASS lastKey() { return KEY2OBJ( LAST_KEY() ); }
 #endif
 
@@ -95,11 +110,22 @@ public class SORTED_MAPS {
 
 
 
-	/** An empty type-specific sorted map (immutable). It is serializable and cloneable. */
-	 
+	/** An empty sorted map (immutable). It is serializable and cloneable. 
+	 */
 	SUPPRESS_WARNINGS_KEY_VALUE_RAWTYPES
 	public static final EmptySortedMap EMPTY_MAP = new EmptySortedMap();
 
+#if #keys(reference) || #values(reference)
+	/** Return an empty sorted map (immutable). It is serializable and cloneable.
+	 *
+	 * <P>This method provides a typesafe access to {@link #EMPTY_MAP}.
+	 * @return an empty sorted map (immutable).
+	 */
+	@SuppressWarnings("unchecked")
+	public static KEY_VALUE_GENERIC SORTED_MAP KEY_VALUE_GENERIC emptyMap() {
+		return EMPTY_MAP;
+	}
+#endif
 
 	/** An immutable class representing a type-specific singleton sorted map. 
 	 *
@@ -149,11 +175,26 @@ public class SORTED_MAPS {
 		public KEY_GENERIC_TYPE LAST_KEY() { return key; }
 
 #if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public SORTED_MAP KEY_VALUE_GENERIC headMap( KEY_GENERIC_CLASS oto ) { return headMap( KEY_CLASS2TYPE( oto ) ); }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public SORTED_MAP KEY_VALUE_GENERIC tailMap( KEY_GENERIC_CLASS ofrom ) { return tailMap( KEY_CLASS2TYPE( ofrom ) ); }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public SORTED_MAP KEY_VALUE_GENERIC subMap( KEY_GENERIC_CLASS ofrom, KEY_GENERIC_CLASS oto ) { return subMap( KEY_CLASS2TYPE( ofrom ), KEY_CLASS2TYPE( oto ) ); }
 
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public KEY_GENERIC_CLASS firstKey() { return KEY2OBJ( FIRST_KEY() ); }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public KEY_GENERIC_CLASS lastKey() { return KEY2OBJ( LAST_KEY() ); }
 #endif
 	}
diff --git a/drv/SortedSet.drv b/drv/SortedSet.drv
index 25fe858..082d12a 100644
--- a/drv/SortedSet.drv
+++ b/drv/SortedSet.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/SortedSets.drv b/drv/SortedSets.drv
index 7eaf914..efb6561 100644
--- a/drv/SortedSets.drv
+++ b/drv/SortedSets.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -83,13 +83,22 @@ public class SORTED_SETS {
 
 	/** An empty sorted set (immutable). It is serializable and cloneable.
 	 *
-	 * <P>The class of this objects represent an abstract empty set
-	 * that is a subset of a (sorted) type-specific set.
 	 */
-
 	SUPPRESS_WARNINGS_KEY_RAWTYPES
 	public static final EmptySet EMPTY_SET = new EmptySet();
 
+#if #keys(reference)
+	/** Return an empty sorted set (immutable). It is serializable and cloneable.
+	 *
+	 * <P>This method provides a typesafe access to {@link #EMPTY_SET}.
+	 * @return an empty sorted set (immutable).
+	 */
+	@SuppressWarnings("unchecked")
+	public static KEY_GENERIC SET KEY_GENERIC emptySet() {
+		return EMPTY_SET;
+	}
+#endif
+
 	/** A class representing a singleton sorted set.
 	 *
 	 * <P>This class may be useful to implement your own in case you subclass
@@ -142,12 +151,27 @@ public class SORTED_SETS {
 		public KEY_GENERIC_TYPE LAST() { return element; }
 
 #if #keys(primitive)
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public KEY_CLASS first() { return KEY2OBJ( element ); }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public KEY_CLASS last() { return KEY2OBJ( element ); }
 
 
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public SORTED_SET KEY_GENERIC subSet( final KEY_CLASS from, final KEY_CLASS to ) { return subSet( KEY_CLASS2TYPE( from ), KEY_CLASS2TYPE( to ) ); }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public SORTED_SET KEY_GENERIC headSet( final KEY_CLASS to ) { return headSet( KEY_CLASS2TYPE( to ) ); }
+		/** {@inheritDoc}
+		 * @deprecated Please use the corresponding type-specific method instead. */
+		@Deprecated
 		public SORTED_SET KEY_GENERIC tailSet( final KEY_CLASS from ) { return tailSet( KEY_CLASS2TYPE( from ) ); }
 #endif
 	}
diff --git a/drv/Stack.drv b/drv/Stack.drv
index 8bed3e8..dd7e79a 100644
--- a/drv/Stack.drv
+++ b/drv/Stack.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/StripedOpenHashMap.drv b/drv/StripedOpenHashMap.drv
index 7eeef21..5eeac3f 100644
--- a/drv/StripedOpenHashMap.drv
+++ b/drv/StripedOpenHashMap.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/TextIO.drv b/drv/TextIO.drv
index db1383a..5d88454 100644
--- a/drv/TextIO.drv
+++ b/drv/TextIO.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2005-2014 Sebastiano Vigna 
+ * Copyright (C) 2005-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/drv/TextIOFragment.drv b/drv/TextIOFragment.drv
index 44155dc..adda3ff 100644
--- a/drv/TextIOFragment.drv
+++ b/drv/TextIOFragment.drv
@@ -1,5 +1,5 @@
 /*		 
- * Copyright (C) 2004-2014 Sebastiano Vigna 
+ * Copyright (C) 2004-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/gencsource.sh b/gencsource.sh
index 149cf95..2974c6a 100755
--- a/gencsource.sh
+++ b/gencsource.sh
@@ -151,7 +151,7 @@ $(if [[ "${CLASS[$v]}" != "" ]]; then\
 "#define SUPPRESS_WARNINGS_KEY_UNCHECKED @SuppressWarnings(\"unchecked\")\n"\
 "#define SUPPRESS_WARNINGS_KEY_RAWTYPES @SuppressWarnings(\"rawtypes\")\n"\
 "#define SUPPRESS_WARNINGS_KEY_UNCHECKED_RAWTYPES @SuppressWarnings({\"unchecked\",\"rawtypes\"})\n"\
-"#if defined(Custom) && #keyclass(Object)\n"\
+"#if defined(Custom)\n"\
 "#define SUPPRESS_WARNINGS_CUSTOM_KEY_UNCHECKED @SuppressWarnings(\"unchecked\")\n"\
 "#else\n"\
 "#define SUPPRESS_WARNINGS_CUSTOM_KEY_UNCHECKED\n"\
@@ -467,17 +467,10 @@ $(if [[ "${CLASS[$v]}" != "" ]]; then\
 \
 \
 "#define KEY_EQUALS_NOT_NULL_CAST(x,y) KEY_EQUALS_NOT_NULL(x,y)\n"\
-"#define KEY2INTHASH_CAST(x) KEY2INTHASH(x)\n"\
+"#define KEY2INTHASH_CAST(x) KEY2INTHASH(x)\n\n"\
 "#if #keyclass(Object)\n"\
-"#ifdef Custom\n"\
-"#define KEY_EQUALS(x,y) ( strategy.equals( (x), (y) ) )\n"\
-"#define KEY_EQUALS_NOT_NULL(x,y) ( strategy.equals( (x), (y) ) )\n"\
-"#undef KEY_EQUALS_NOT_NULL_CAST\n"\
-"#define KEY_EQUALS_NOT_NULL_CAST(x,y) ( strategy.equals( " KEY_GENERIC_CAST "(x), (y) ) )\n"\
-"#else\n"\
 "#define KEY_EQUALS(x,y) ( (x) == null ? (y) == null : (x).equals(y) )\n"\
 "#define KEY_EQUALS_NOT_NULL(x,y) ( (x).equals(y) )\n"\
-"#endif\n"\
 "#define KEY_IS_NULL(x) ( (x) == null )\n"\
 "#elif #keyclass(Float)\n"\
 "#define KEY_EQUALS(x,y) ( Float.floatToIntBits(x) == Float.floatToIntBits(y) )\n"\
@@ -493,6 +486,18 @@ $(if [[ "${CLASS[$v]}" != "" ]]; then\
 "#define KEY_IS_NULL(x) ( (x) == KEY_NULL )\n"\
 "#endif\n\n"\
 \
+"#ifdef Custom\n"\
+"#undef KEY_EQUALS\n"\
+"#define KEY_EQUALS(x,y) ( strategy.equals( (x), (y) ) )\n"\
+"#undef KEY_EQUALS_NOT_NULL\n"\
+"#define KEY_EQUALS_NOT_NULL(x,y) ( strategy.equals( (x), (y) ) )\n"\
+"#undef KEY_EQUALS_NOT_NULL_CAST\n"\
+"#define KEY_EQUALS_NOT_NULL_CAST(x,y) ( strategy.equals( " KEY_GENERIC_CAST "(x), (y) ) )\n"\
+"#define KEY_EQUALS_NULL(x) ( strategy.equals( (x), KEY_NULL ) )\n"\
+"#else\n"\
+"#define KEY_EQUALS_NULL(x) KEY_IS_NULL(x)\n"\
+"#endif\n\n"\
+\
 "#if #valueclass(Object)\n"\
 "#define VALUE_EQUALS(x,y) ( (x) == null ? (y) == null : (x).equals(y) )\n"\
 "#else\n"\
@@ -512,19 +517,17 @@ $(if [[ "${CLASS[$v]}" != "" ]]; then\
 "#define KEY_CLASS2TYPE(x) (x)\n"\
 "#define KEY2OBJ(x) (x)\n"\
 \
-"#if #keyclass(Object)\n"\
 "#ifdef Custom\n"\
 "#define KEY2JAVAHASH_NOT_NULL(x) ( strategy.hashCode(x) )\n"\
 "#define KEY2INTHASH(x) ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(x) ) )\n"\
 "#undef KEY2INTHASH_CAST\n"\
 "#define KEY2INTHASH_CAST(x) ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode( " KEY_GENERIC_CAST " x) ) )\n"\
 "#define KEY2LONGHASH(x) ( it.unimi.dsi.fastutil.HashCommon.mix( (long)( strategy.hashCode(x)) ) ) )\n"\
-"#else\n"\
+"#elif #keyclass(Object)\n"\
 "#define KEY2JAVAHASH_NOT_NULL(x) ( (x).hashCode() )\n"\
 "#define KEY2JAVAHASH(x) ( (x) == null ? 0 : (x).hashCode() )\n"\
 "#define KEY2INTHASH(x) ( it.unimi.dsi.fastutil.HashCommon.mix( (x).hashCode() ) )\n"\
 "#define KEY2LONGHASH(x) ( it.unimi.dsi.fastutil.HashCommon.mix( (long)( (x).hashCode() ) ) )\n"\
-"#endif\n"\
 "#else\n"\
 "#define KEY2JAVAHASH_NOT_NULL(x) ( System.identityHashCode(x) )\n"\
 "#define KEY2INTHASH(x) ( it.unimi.dsi.fastutil.HashCommon.mix( System.identityHashCode(x) ) )\n"\
diff --git a/makefile b/makefile
index 5851c26..955797f 100644
--- a/makefile
+++ b/makefile
@@ -70,26 +70,25 @@ source:
 		fastutil-$(version)/build.properties \
 		fastutil-$(version)/gencsource.sh \
 		fastutil-$(version)/CHANGES \
-		fastutil-$(version)/README \
+		fastutil-$(version)/README.md \
 		fastutil-$(version)/LICENSE-2.0 \
 		fastutil-$(version)/makefile \
 		$(foreach f, $(SOURCES), fastutil-$(version)/$(f)) \
 		fastutil-$(version)/$(SOURCEDIR)/{boolean,byte,char,short,int,long,float,double,object}s/package.html \
 		fastutil-$(version)/$(SOURCEDIR)/io/package.html \
 		fastutil-$(version)/src/overview.html \
-		fastutil-$(version)/src/stylesheet.css \
 		$$(find fastutil-$(version)/test -iname \*.java)
 	rm fastutil-$(version)
 
 binary:
-	make -s clean sources format
+	make -s clean sources format GCC=$(GCC)
 	ant clean osgi javadoc
 	-rm -f fastutil-$(version)
 	ln -s . fastutil-$(version)
 	cp dist/lib/fastutil-$(version).jar .
 	$(TAR) zcvf fastutil-$(version)-bin.tar.gz --owner=0 --group=0 \
 		fastutil-$(version)/CHANGES \
-		fastutil-$(version)/README \
+		fastutil-$(version)/README.md \
 		fastutil-$(version)/LICENSE-2.0 \
 		fastutil-$(version)/docs \
 		fastutil-$(version)/fastutil-$(version).jar
@@ -541,73 +540,8 @@ $(GEN_SRCDIR)/$(PKG_PATH)/io/TextIO.c: drv/TextIO.drv $(TEXTIO_FRAGMENTS)
 
 CSOURCES += $(GEN_SRCDIR)/$(PKG_PATH)/io/TextIO.c
 
-#
-# Old sources, generated only with the old target
-#
-
-OPEN_DOUBLE_HASH_SETS := $(foreach k,$(TYPE), $(GEN_SRCDIR)/$(PKG_PATH)/$(PACKAGE_$(k))/$(k)OpenDoubleHashSet.c)
-$(OPEN_DOUBLE_HASH_SETS): drv/OpenDoubleHashSet.drv; ./gencsource.sh $< $@ >$@
-
-OLDCSOURCES += $(OPEN_DOUBLE_HASH_SETS)
-
-LINKED_OPEN_DOUBLE_HASH_SETS := $(foreach k,$(TYPE_NOBOOL), $(GEN_SRCDIR)/$(PKG_PATH)/$(PACKAGE_$(k))/$(k)LinkedOpenDoubleHashSet.c)
-$(LINKED_OPEN_DOUBLE_HASH_SETS): drv/LinkedOpenDoubleHashSet.drv; ./gencsource.sh $< $@ >$@
-
-OLDCSOURCES += $(LINKED_OPEN_DOUBLE_HASH_SETS)
-
-OPEN_DOUBLE_CUSTOM_HASH_SETS := $(GEN_SRCDIR)/$(PKG_PATH)/objects/ObjectOpenCustomDoubleHashSet.c
-$(OPEN_DOUBLE_CUSTOM_HASH_SETS): drv/OpenCustomDoubleHashSet.drv; ./gencsource.sh $< $@ >$@
-
-OLDCSOURCES += $(OPEN_DOUBLE_CUSTOM_HASH_SETS)
-
-LINKED_OPEN_DOUBLE_CUSTOM_HASH_SETS := $(GEN_SRCDIR)/$(PKG_PATH)/objects/ObjectLinkedOpenCustomDoubleHashSet.c
-$(LINKED_OPEN_DOUBLE_CUSTOM_HASH_SETS): drv/LinkedOpenCustomDoubleHashSet.drv; ./gencsource.sh $< $@ >$@
-
-OLDCSOURCES += $(LINKED_OPEN_CUSTOM_DOUBLE_HASH_SETS)
-
-OPEN_DOUBLE_HASH_MAPS := $(foreach k,$(TYPE_NOBOOL), $(foreach v,$(TYPE), $(GEN_SRCDIR)/$(PKG_PATH)/$(PACKAGE_$(k))/$(k)2$(v)OpenDoubleHashMap.c))
-$(OPEN_DOUBLE_HASH_MAPS): drv/OpenDoubleHashMap.drv; ./gencsource.sh $< $@ >$@
-
-OLDCSOURCES += $(OPEN_DOUBLE_HASH_MAPS)
-
-LINKED_OPEN_DOUBLE_HASH_MAPS := $(foreach k,$(TYPE_NOBOOL), $(foreach v,$(TYPE), $(GEN_SRCDIR)/$(PKG_PATH)/$(PACKAGE_$(k))/$(k)2$(v)LinkedOpenDoubleHashMap.c))
-$(LINKED_OPEN_DOUBLE_HASH_MAPS): drv/LinkedOpenDoubleHashMap.drv; ./gencsource.sh $< $@ >$@
-
-OLDCSOURCES += $(LINKED_OPEN_DOUBLE_HASH_MAPS)
-
-OPEN_CUSTOM_DOUBLE_HASH_MAPS := $(foreach v,$(TYPE), $(GEN_SRCDIR)/$(PKG_PATH)/objects/Object2$(v)OpenCustomDoubleHashMap.c)
-$(OPEN_CUSTOM_DOUBLE_HASH_MAPS): drv/OpenCustomDoubleHashMap.drv; ./gencsource.sh $< $@ >$@
-
-OLDCSOURCES += $(OPEN_CUSTOM_DOUBLE_HASH_MAPS)
-
-LINKED_OPEN_CUSTOM_DOUBLE_HASH_MAPS := $(foreach v,$(TYPE), $(GEN_SRCDIR)/$(PKG_PATH)/objects/Object2$(v)LinkedOpenCustomDoubleHashMap.c)
-$(LINKED_OPEN_CUSTOM_DOUBLE_HASH_MAPS): drv/LinkedOpenCustomDoubleHashMap.drv; ./gencsource.sh $< $@ >$@
-
-OLDCSOURCES += $(LINKED_OPEN_CUSTOM_DOUBLE_HASH_MAPS)
-
-INDIRECT_DOUBLE_PRIORITY_QUEUES := $(foreach k,$(TYPE_NOBOOL_NOOBJ), $(GEN_SRCDIR)/$(PKG_PATH)/$(PACKAGE_$(k))/$(k)IndirectDoublePriorityQueue.c)
-$(INDIRECT_DOUBLE_PRIORITY_QUEUES): drv/IndirectDoublePriorityQueue.drv; ./gencsource.sh $< $@ >$@
-
-OLDCSOURCES += $(INDIRECT_DOUBLE_PRIORITY_QUEUES)
-
-HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUES := $(foreach k, $(TYPE_NOBOOL_NOREF), $(GEN_SRCDIR)/$(PKG_PATH)/$(PACKAGE_$(k))/$(k)HeapSesquiIndirectDoublePriorityQueue.c)
-$(HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUES): drv/HeapSesquiIndirectDoublePriorityQueue.drv; ./gencsource.sh $< $@ >$@
-
-OLDCSOURCES += $(HEAP_SESQUI_INDIRECT_DOUBLE_PRIORITY_QUEUES)
-
-HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUES := $(foreach k, $(TYPE_NOBOOL_NOREF), $(GEN_SRCDIR)/$(PKG_PATH)/$(PACKAGE_$(k))/$(k)HeapIndirectDoublePriorityQueue.c)
-$(HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUES): drv/HeapIndirectDoublePriorityQueue.drv; ./gencsource.sh $< $@ >$@
-
-OLDCSOURCES += $(HEAP_INDIRECT_DOUBLE_PRIORITY_QUEUES)
-
-ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUES := $(foreach k, $(TYPE_NOBOOL_NOREF), $(GEN_SRCDIR)/$(PKG_PATH)/$(PACKAGE_$(k))/$(k)ArrayIndirectDoublePriorityQueue.c)
-$(ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUES): drv/ArrayIndirectDoublePriorityQueue.drv; ./gencsource.sh $< $@ >$@
-
-OLDCSOURCES += $(ARRAY_INDIRECT_DOUBLE_PRIORITY_QUEUES)
-
 
 JSOURCES = $(CSOURCES:.c=.java) # The list of generated Java source files
-OLDJSOURCES = $(OLDCSOURCES:.c=.java) 
 
 
 SOURCES = \
@@ -642,17 +576,14 @@ SOURCES = \
 	$(SOURCEDIR)/io/MeasurableStream.java \
 	$(SOURCEDIR)/io/RepositionableStream.java # These are True Java Sources instead
 
-OLDSOURCES = \
-	$(SOURCEDIR)/IndirectDoublePriorityQueue.java \
-	$(SOURCEDIR)/IndirectDoublePriorityQueues.java \
-	$(SOURCEDIR)/AbstractIndirectDoublePriorityQueue.java
-
 
-# We pass each generated Java source through the preprocessor. TEST compiles in the test code,
+# We pass each generated Java source through the gccpreprocessor. TEST compiles in the test code,
 # whereas ASSERTS compiles in some assertions (whose testing, of course, must be enabled in the JVM).
 
-$(JSOURCES) $(OLDJSOURCES): %.java: %.c
-	gcc -w -I. -ftabstop=4 $(if $(TEST),-DTEST,) $(if $(ASSERTS),-DASSERTS_CODE,) -DASSERTS_VALUE=$(if $(ASSERTS),true,false) -E -C -P $< >$@
+GCC=gcc
+
+$(JSOURCES): %.java: %.c
+	$(GCC) -w -I. -ftabstop=4 $(if $(TEST),-DTEST,) $(if $(ASSERTS),-DASSERTS_CODE,) -DASSERTS_VALUE=$(if $(ASSERTS),true,false) -E -C -P $< >$@
 
 
 clean: 
@@ -666,8 +597,4 @@ clean:
 
 sources: $(JSOURCES)
 
-oldsources: $(OLDJSOURCES)
-
 csources: $(CSOURCES)
-
-oldcsources: $(OLDCSOURCES)
diff --git a/pom.xml b/pom.xml
index de58498..f44181a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
   <artifactId>fastutil</artifactId>
   <packaging>jar</packaging>
   <name>fastutil</name>
-  <version>7.0.1</version>
+  <version>7.0.10</version>
   <description>fastutil extends the Java Collections Framework by providing type-specific maps, sets, lists and priority queues with a small memory footprint and fast access and insertion; provides also big (64-bit) arrays, sets and lists, and fast, practical I/O classes for binary and text files.</description>
   <url>http://fasutil.di.unimi.it/</url>
   <licenses>
diff --git a/src/it/unimi/dsi/fastutil/AbstractIndirectPriorityQueue.java b/src/it/unimi/dsi/fastutil/AbstractIndirectPriorityQueue.java
index d76772a..7138801 100644
--- a/src/it/unimi/dsi/fastutil/AbstractIndirectPriorityQueue.java
+++ b/src/it/unimi/dsi/fastutil/AbstractIndirectPriorityQueue.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
diff --git a/src/it/unimi/dsi/fastutil/AbstractPriorityQueue.java b/src/it/unimi/dsi/fastutil/AbstractPriorityQueue.java
index c98c140..7e819f3 100644
--- a/src/it/unimi/dsi/fastutil/AbstractPriorityQueue.java
+++ b/src/it/unimi/dsi/fastutil/AbstractPriorityQueue.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
diff --git a/src/it/unimi/dsi/fastutil/AbstractStack.java b/src/it/unimi/dsi/fastutil/AbstractStack.java
index 5970fa9..faf3e7c 100644
--- a/src/it/unimi/dsi/fastutil/AbstractStack.java
+++ b/src/it/unimi/dsi/fastutil/AbstractStack.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/Arrays.java b/src/it/unimi/dsi/fastutil/Arrays.java
index 790008e..e57cc0a 100644
--- a/src/it/unimi/dsi/fastutil/Arrays.java
+++ b/src/it/unimi/dsi/fastutil/Arrays.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,10 +16,12 @@ package it.unimi.dsi.fastutil;
  * limitations under the License. 
  */
 
-import java.util.ArrayList;
-
 import it.unimi.dsi.fastutil.ints.IntComparator;
 
+import java.util.ArrayList;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.RecursiveAction;
+
 /** A class providing static methods and objects that do useful things with arrays.
  *
  * <p>In addition to commodity methods, this class contains {@link Swapper}-based implementations
@@ -71,9 +73,6 @@ public class Arrays {
 		if ( offset + length > arrayLength ) throw new ArrayIndexOutOfBoundsException( "Last index (" + ( offset + length ) + ") is greater than array length (" + arrayLength + ")" );
 	}
 
-	private static final int SMALL = 7;
-	private static final int MEDIUM = 40;
-
 	/**
 	 * Transforms two consecutive sorted ranges into a single sorted range. The initial ranges are
 	 * <code>[first..middle)</code> and <code>[middle..last)</code>, and the resulting range is
@@ -193,7 +192,9 @@ public class Arrays {
 				( bc > 0 ? b : ac > 0 ? c : a ) );
 	}
 
-	/** Sorts the specified range of elements using the specified swapper and according to the order induced by the specified
+	 private static final int MERGESORT_NO_REC = 16;
+
+	 /** Sorts the specified range of elements using the specified swapper and according to the order induced by the specified
 	 * comparator using mergesort.
 	 * 
 	 * <p>This sort is guaranteed to be <i>stable</i>: equal elements will not be reordered as a result
@@ -217,7 +218,7 @@ public class Arrays {
 		final int length = to - from;
 
 		// Insertion sort on smallest arrays
-		if ( length < SMALL ) {
+		if ( length < MERGESORT_NO_REC ) {
 			for ( int i = from; i < to; i++ ) {
 				for ( int j = i; j > from && ( c.compare( j - 1, j ) > 0 ); j-- ) {
 					swapper.swap( j, j - 1 );
@@ -239,13 +240,127 @@ public class Arrays {
 		inPlaceMerge( from, mid, to, c, swapper );
 	}
 
+	/** Swaps two sequences of elements using a provided swapper.
+	 *
+	 * @param swapper the swapper.
+	 * @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}.
+	 */
+	protected static void swap( final Swapper swapper, int a, int b, final int n ) {
+		for ( int i = 0; i < n; i++, a++, b++ ) swapper.swap( a, b );
+	}
+
+	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;
+
+	protected static class ForkJoinGenericQuickSort extends RecursiveAction {
+		private static final long serialVersionUID = 1L;
+		private final int from;
+		private final int to;
+		private final IntComparator comp;
+		private final Swapper swapper;
+
+		public ForkJoinGenericQuickSort( final int from, final int to, final IntComparator comp, final Swapper swapper ) {
+			this.from = from;
+			this.to = to;
+			this.comp = comp;
+			this.swapper = swapper;
+		}
+
+		@Override
+		protected void compute() {
+			final int len = to - from;
+			if ( len < PARALLEL_QUICKSORT_NO_FORK ) {
+				quickSort( from, to, comp, swapper );
+				return;
+			}
+			// Choose a partition element, v
+			int m = from + len / 2;
+			int l = from;
+			int n = to - 1;
+			int s = len / 8;
+			l = med3( l, l + s, l + 2 * s, comp );
+			m = med3( m - s, m, m + s, comp );
+			n = med3( n - 2 * s, n - s, n, comp );
+			m = med3( l, m, n, comp );
+			// Establish Invariant: v* (<v)* (>v)* v*
+			int a = from, b = a, c = to - 1, d = c;
+			while ( true ) {
+				int comparison;
+				while ( b <= c && ( ( comparison = comp.compare( b, m ) ) <= 0 ) ) {
+					if ( comparison == 0 ) {
+						// Fix reference to pivot if necessary
+						if ( a == m ) m = b;
+						else if ( b == m ) m = a;
+						swapper.swap( a++, b );
+					}
+					b++;
+				}
+				while ( c >= b && ( ( comparison = comp.compare( c, m ) ) >= 0 ) ) {
+					if ( comparison == 0 ) {
+						// Fix reference to pivot if necessary
+						if ( c == m ) m = d;
+						else if ( d == m ) m = c;
+						swapper.swap( c, d-- );
+					}
+					c--;
+				}
+				if ( b > c ) break;
+				// Fix reference to pivot if necessary
+				if ( b == m ) m = d;
+				else if ( c == m ) m = c;
+				swapper.swap( b++, c-- );
+			}
+
+			// Swap partition elements back to middle
+			s = Math.min( a - from, b - a );
+			swap( swapper, from, b - s, s );
+			s = Math.min( d - c, to - d - 1 );
+			swap( swapper, b, to - s, s );
+
+			// Recursively sort non-partition-elements
+			int t;
+			s = b - a;
+			t = d - c;
+			if ( s > 1 && t > 1 ) invokeAll( new ForkJoinGenericQuickSort( from, from + s, comp, swapper ), new ForkJoinGenericQuickSort( to - t, to, comp, swapper ) );
+			else if ( s > 1 ) invokeAll( new ForkJoinGenericQuickSort( from, from + s, comp, swapper ) );
+			else invokeAll( new ForkJoinGenericQuickSort( to - t, to, comp, swapper ) );
+		}
+	}
+
 	/** Sorts the specified range of elements using the specified swapper and according to the order induced by the specified
-	 * comparator using quicksort. 
+	 * comparator using a parallel quicksort. 
 	 * 
 	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
 	 * McIlroy, “Engineering a Sort Function”, <i>Software: Practice and Experience</i>, 23(11), pages
 	 * 1249−1265, 1993.
 	 * 
+	 * <p>This implementation uses a {@link ForkJoinPool} executor service with {@link Runtime#availableProcessors()} parallel threads.
+	 * 
+	 * @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 order of the generic data.
+	 * @param swapper an object that knows how to swap the elements at any two positions.
+	 * 
+	 */
+	public static void parallelQuickSort( final int from, final int to, final IntComparator comp, final Swapper swapper ) {
+		final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() );
+		pool.invoke( new ForkJoinGenericQuickSort( from, to, comp, swapper ) );
+		pool.shutdown();
+	}
+
+
+	/** Sorts the specified range of elements using the specified swapper and according to the order induced by the specified
+	 * comparator using parallel quicksort. 
+	 * 
+	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
+	 * McIlroy, “Engineering a Sort Function”, <i>Software: Practice and Experience</i>, 23(11), pages
+	 * 1249−1265, 1993.
+	 * 
+	 * <p>This implementation uses a {@link ForkJoinPool} executor service with {@link Runtime#availableProcessors()} parallel threads.
+	 * 
 	 * @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 order of the generic data.
@@ -255,7 +370,7 @@ public class Arrays {
 	public static void quickSort( final int from, final int to, final IntComparator comp, final Swapper swapper ) {
 		final int len = to - from;
 		// Insertion sort on smallest arrays
-		if ( len < SMALL ) {
+		if ( len < QUICKSORT_NO_REC ) {
 			for ( int i = from; i < to; i++ )
 				for ( int j = i; j > from && ( comp.compare( j - 1, j ) > 0 ); j-- ) {
 					swapper.swap( j, j - 1 );
@@ -265,17 +380,15 @@ public class Arrays {
 
 		// Choose a partition element, v
 		int m = from + len / 2; // Small arrays, middle element
-		if ( len > SMALL ) {
-			int l = from;
-			int n = to - 1;
-			if ( len > MEDIUM ) { // Big arrays, pseudomedian of 9
-				int s = len / 8;
-				l = med3( l, l + s, l + 2 * s, comp );
-				m = med3( m - s, m, m + s, comp );
-				n = med3( n - 2 * s, n - s, n, comp );
-			}
-			m = med3( l, m, n, comp ); // Mid-size, med of 3
+		int l = from;
+		int n = to - 1;
+		if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9
+			int s = len / 8;
+			l = med3( l, l + s, l + 2 * s, comp );
+			m = med3( m - s, m, m + s, comp );
+			n = med3( n - 2 * s, n - s, n, comp );
 		}
+		m = med3( l, m, n, comp ); // Mid-size, med of 3
 		// int v = x[m];
 
 		int a = from;
@@ -287,44 +400,38 @@ public class Arrays {
 			int comparison;
 			while ( b <= c && ( ( comparison = comp.compare( b, m ) ) <= 0 ) ) {
 				if ( comparison == 0 ) {
-					if ( a == m ) m = b; // moving target; DELTA to JDK !!!
-					else if ( b == m ) m = a; // moving target; DELTA to JDK !!!
+					// Fix reference to pivot if necessary
+					if ( a == m ) m = b;
+					else if ( b == m ) m = a;
 					swapper.swap( a++, b );
 				}
 				b++;
 			}
 			while ( c >= b && ( ( comparison = comp.compare( c, m ) ) >= 0 ) ) {
 				if ( comparison == 0 ) {
-					if ( c == m ) m = d; // moving target; DELTA to JDK !!!
-					else if ( d == m ) m = c; // moving target; DELTA to JDK !!!
+					// Fix reference to pivot if necessary
+					if ( c == m ) m = d;
+					else if ( d == m ) m = c;
 					swapper.swap( c, d-- );
 				}
 				c--;
 			}
 			if ( b > c ) break;
-			if ( b == m ) m = d; // moving target; DELTA to JDK !!!
-			else if ( c == m ) m = c; // moving target; DELTA to JDK !!!
+			// Fix reference to pivot if necessary
+			if ( b == m ) m = d;
+			else if ( c == m ) m = c;
 			swapper.swap( b++, c-- );
 		}
 
 		// Swap partition elements back to middle
 		int s;
-		int n = to;
 		s = Math.min( a - from, b - a );
-		vecSwap( swapper, from, b - s, s );
-		s = Math.min( d - c, n - d - 1 );
-		vecSwap( swapper, b, n - s, s );
+		swap( swapper, from, b - s, s );
+		s = Math.min( d - c, to - d - 1 );
+		swap( swapper, b, to - s, s );
 
 		// Recursively sort non-partition-elements
 		if ( ( s = b - a ) > 1 ) quickSort( from, from + s, comp, swapper );
-		if ( ( s = d - c ) > 1 ) quickSort( n - s, n, comp, swapper );
-	}
-
-
-	/**
-	 * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
-	 */
-	private static void vecSwap( final Swapper swapper, int from, int l, final int s ) {
-		for ( int i = 0; i < s; i++, from++, l++ ) swapper.swap( from, l );
+		if ( ( s = d - c ) > 1 ) quickSort( to - s, to, comp, swapper );
 	}
 }
diff --git a/src/it/unimi/dsi/fastutil/BidirectionalIterator.java b/src/it/unimi/dsi/fastutil/BidirectionalIterator.java
index f76456e..526d78e 100644
--- a/src/it/unimi/dsi/fastutil/BidirectionalIterator.java
+++ b/src/it/unimi/dsi/fastutil/BidirectionalIterator.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/BigArrays.java b/src/it/unimi/dsi/fastutil/BigArrays.java
index a49a536..fcd3204 100644
--- a/src/it/unimi/dsi/fastutil/BigArrays.java
+++ b/src/it/unimi/dsi/fastutil/BigArrays.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2010-2014 Sebastiano Vigna 
+ * Copyright (C) 2010-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,254 +33,344 @@ import it.unimi.dsi.fastutil.ints.IntBigArrayBigList;
 import it.unimi.dsi.fastutil.ints.IntBigArrays;
 import it.unimi.dsi.fastutil.longs.LongComparator;
 
-/** A class providing static methods and objects that do useful things with big arrays.
+/**
+ * A class providing static methods and objects that do useful things with big
+ * arrays.
  * 
  * <h2>Introducing big arrays</h2>
  * 
- * <p>A <em>big array</em> is an array-of-arrays representation of an array. The length of a big array
- * is bounded by {@link Long#MAX_VALUE} rather than {@link Integer#MAX_VALUE}. The type of a big array
- * is that of an array-of-arrays, so a big array of integers is of type <code>int[][]</code>.
+ * <p>
+ * A <em>big array</em> is an array-of-arrays representation of an array. The
+ * length of a big array is bounded by {@link #SEGMENT_SIZE} *
+ * {@link Integer#MAX_VALUE} = {@value #SEGMENT_SIZE} * (2<sup>31</sup> −
+ * 1) rather than {@link Integer#MAX_VALUE}. The type of a big array is that of
+ * an array-of-arrays, so a big array of integers is of type
+ * <code>int[][]</code>. Note that {@link #SEGMENT_SIZE} has been chosen so that
+ * a single segment is smaller than 2<sup>31</sup> bytes independently of the
+ * data type. It might be enlarged in the future.
  * 
- * <p>If <code>a</code> is a big array, <code>a[0]</code>, <code>a[1]</code>, … are called
- * the <em>segments</em> of the big array. All segments, except possibly for the last one, are of length
- * {@link #SEGMENT_SIZE}. Given an index <code>i</code> into a big array, there is an associated
- * <em>{@linkplain #segment(long) segment}</em> and an associated <em>{@linkplain #displacement(long) displacement}</em>
- * into that segment. Access to single members happens by means of accessors defined in the type-specific
- * versions (see, e.g., {@link IntBigArrays#get(int[][], long)} and {@link IntBigArrays#set(int[][], long, int)}), 
- * but you can also use the methods {@link #segment(long)}/{@link #displacement(long)} to access entries manually.
+ * <p>
+ * If <code>a</code> is a big array, <code>a[0]</code>, <code>a[1]</code>,
+ * … are called the <em>segments</em> of the big array. All segments,
+ * except possibly for the last one, are of length {@link #SEGMENT_SIZE}. Given
+ * an index <code>i</code> into a big array, there is an associated
+ * <em>{@linkplain #segment(long) segment}</em> and an associated
+ * <em>{@linkplain #displacement(long)
+ * displacement}</em> into that segment. Access to single members happens by
+ * means of accessors defined in the type-specific versions (see, e.g.,
+ * {@link IntBigArrays#get(int[][], long)} and
+ * {@link IntBigArrays#set(int[][], long, int)}), but you can also use the
+ * methods {@link #segment(long)}/{@link #displacement(long)} to access entries
+ * manually.
  * 
  * <h2>Scanning big arrays</h2>
  * 
- * <p>You can scan a big array using the following idiomatic form:
+ * <p>
+ * You can scan a big array using the following idiomatic form:
+ * 
  * <pre>
- *   for( int s = 0; s < a.length; s++ ) {
- *      final int[] t = a[ s ];
- *      final int l = t.length;
- *      for( int d = 0; d < l; d++ ) { do something with t[ d ] }
- *   }
+ * for(int s = 0; s < a.length; s++) {
+ *     final int[] t = a[s];
+ *     final int l = t.length;
+ *     for(int d = 0; d < l; d++) {
+ *          do something with t[d]
+ *     }
+ * }
  * </pre>
+ * 
  * or using the (simpler and usually faster) reversed version:
+ * 
  * <pre>
- *   for( int s = a.length; s-- != 0; ) {
- *      final int[] t = a[ s ];  
- *      for( int d = t.length; d-- != 0; ) { do something with t[ d ] }
- *   }
- * </pre>
- * <p>Inside the inner loop, the original index in <code>a</code> can be retrieved using {@link #index(int, int) index(segment, displacement)}.
- * Do <em>not</em> use an additional variable to keep track of the value of the original index, as
- * computing it on the fly is significantly faster. For instance, to inizialise the <var>i</var>-th element of a big array of
- * long integers to the value <var>i</var> you should use
- * <pre>
- *   for( int s = a.length; s-- != 0; ) {
- *      final long[] t = a[ s ];  
- *      for( int d = t.length; d-- != 0; ) t[ d ] = index( s, d );
- *   }
+ * for( int s = a.length; s-- != 0;) {
+ *     final int[] t = a[s];
+ *     for( int d = t.length; d-- != 0;) {
+ *         do something with t[d]
+ *     }
+ * }
  * </pre>
- *  
- * <p>Note that caching is essential in making these loops essentially as fast as those scanning standard arrays (as iterations
- * of the outer loop happen very rarely). Using loops of this kind is extremely faster than using a standard
+ * <p>
+ * Inside the inner loop, the original index in <code>a</code> can be retrieved
+ * using {@link #index(int, int) index(segment, displacement)}. You can also 
+ * use an additional long to keep track of the index.
+ * 
+ * <p>
+ * Note that caching is essential in making these loops essentially as fast as
+ * those scanning standard arrays (as iterations of the outer loop happen very
+ * rarely). Using loops of this kind is extremely faster than using a standard
  * loop and accessors.
  * 
- * <p>In some situations, you might want to iterate over a part of a big array having an offset and a length. In this case, the
- * idiomatic loops are as follows:
+ * <p>
+ * In some situations, you might want to iterate over a part of a big array
+ * having an offset and a length. In this case, the idiomatic loops are as
+ * follows:
+ * 
  * <pre>
- *   for( int s = segment( offset ); s < segment( offset + length + SEGMENT_MASK ); s++ ) {
- *      final int[] t = a[ s ];
- *      final int l = (int)Math.min( t.length, offset + length - start( s ) );
- *      for( int d = (int)Math.max( 0, offset - start( s ) ); d < l; d++ ) { do something with t[ d ] }
- *   }
+ * for(int s = segment(offset); s < segment(offset + length + SEGMENT_MASK); s++) {
+ *     final int[] t = a[s];
+ *     final int l = (int)Math.min(t.length, offset + length - start(s));
+ *     for(int d = (int)Math.max(0, offset - start(s)); d < l; d++) {
+ *         do something with t[d]
+ *     }
+ * }
  * </pre>
+ * 
  * or, in a reversed form,
+ * 
  * <pre>
- *   for( int s = segment( offset + length + SEGMENT_MASK ); s-- != segment( offset ); ) {
- *      final int[] t = a[ s ];
- *      final int b = (int)Math.max( 0, offset - start( s ) );
- *      for( int d = (int)Math.min( t.length, offset + length - start( s ) ); d-- != b ; ) { do something with t[ d ] }
- *   }
+ * for(int s = segment(offset + length + SEGMENT_MASK); s-- != segment(offset);) {
+ *     final int[] t = a[s];
+ *     final int b = (int)Math.max(0, offset - start(s));
+ *     for(int d = (int)Math.min(t.length, offset + length - start(s)); d-- != b ;) {
+ *         do something with t[d]
+ *     }
+ * }
  * </pre>
  * 
  * <h2>Literal big arrays</h2>
  * 
- * <p>A literal big array can be easily created by using the suitable type-specific <code>wrap()</code> method
- * (e.g., {@link IntBigArrays#wrap(int[])}) around a literal standard array. Alternatively, for very small
- * arrays you can just declare a literal array-of-array (e.g., <code>new int[][] { { 1, 2 } }</code>). Be warned,
- * however, that this can lead to creating illegal big arrays if for some reason (e.g., stress testing) {@link #SEGMENT_SIZE}
- * is set to a value smaller than the inner array length. 
+ * <p>
+ * A literal big array can be easily created by using the suitable type-specific
+ * <code>wrap()</code> method (e.g., {@link IntBigArrays#wrap(int[])}) around a
+ * literal standard array. Alternatively, for very small arrays you can just
+ * declare a literal array-of-array (e.g., <code>new int[][] { { 1, 2 } }</code>
+ * ). Be warned, however, that this can lead to creating illegal big arrays if
+ * for some reason (e.g., stress testing) {@link #SEGMENT_SIZE} is set to a
+ * value smaller than the inner array length.
  * 
  * <h2>Big alternatives</h2>
  * 
- * <p>If you find the kind of “bare hands” approach to big arrays not enough object-oriented, please use
- * big lists based on big arrays (.e.g, {@link IntBigArrayBigList}). Big arrays follow the Java tradition of 
- * considering arrays as a “legal alien”—something in-between an object and a primitive type. This
- * approach lacks the consistency of a full object-oriented approach, but provides some significant performance gains.
+ * <p>
+ * If you find the kind of “bare hands” approach to big arrays not
+ * enough object-oriented, please use big lists based on big arrays (.e.g,
+ * {@link IntBigArrayBigList}). Big arrays follow the Java tradition of
+ * considering arrays as a “legal alien”—something in-between
+ * an object and a primitive type. This approach lacks the consistency of a full
+ * object-oriented approach, but provides some significant performance gains.
  *
  * <h2>Additional methods</h2>
  * 
- * <p>In addition to commodity methods, this class contains {@link BigSwapper}-based implementations
- * of {@linkplain #quickSort(long, long, LongComparator, BigSwapper) quicksort} and of
- * a stable, in-place {@linkplain #mergeSort(long, long, LongComparator, BigSwapper) mergesort}. These
- * generic sorting methods can be used to sort any kind of list, but they find their natural
- * usage, for instance, in sorting big arrays in parallel.
+ * <p>
+ * In addition to commodity methods, this class contains {@link BigSwapper}
+ * -based implementations of
+ * {@linkplain #quickSort(long, long, LongComparator, BigSwapper) quicksort} and
+ * of a stable, in-place
+ * {@linkplain #mergeSort(long, long, LongComparator, BigSwapper) mergesort}.
+ * These generic sorting methods can be used to sort any kind of list, but they
+ * find their natural usage, for instance, in sorting big arrays in parallel.
  *
  * @see it.unimi.dsi.fastutil.Arrays
  */
 
 public class BigArrays {
-	/** The shift used to compute the segment associated with an index (equivalently, the logarithm of the segment size). */
+	/**
+	 * The shift used to compute the segment associated with an index
+	 * (equivalently, the logarithm of the segment size).
+	 */
 	public final static int SEGMENT_SHIFT = 27;
-	/** The current size of a segment (2<sup>27</sup>) is the largest size that makes
-	 * the physical memory allocation for a single segment strictly smaller
-	 * than 2<sup>31</sup> bytes. */
+	/**
+	 * The current size of a segment (2<sup>27</sup>) is the largest size that
+	 * makes the physical memory allocation for a single segment strictly
+	 * smaller than 2<sup>31</sup> bytes.
+	 */
 	public final static int SEGMENT_SIZE = 1 << SEGMENT_SHIFT;
 	/** The mask used to compute the displacement associated to an index. */
 	public final static int SEGMENT_MASK = SEGMENT_SIZE - 1;
-	
-	protected BigArrays() {}
-	
-	/** Computes the segment associated with a given index.
+
+	protected BigArrays() {
+	}
+
+	/**
+	 * Computes the segment associated with a given index.
 	 * 
-	 * @param index an index into a big array.
+	 * @param index
+	 *            an index into a big array.
 	 * @return the associated segment.
 	 */
-	public static int segment( final long index ) {
-		return (int)( index >>> SEGMENT_SHIFT );
+	public static int segment(final long index) {
+		return (int) (index >>> SEGMENT_SHIFT);
 	}
-	
-	/** Computes the displacement associated with a given index.
+
+	/**
+	 * Computes the displacement associated with a given index.
 	 * 
-	 * @param index an index into a big array.
-	 * @return the associated displacement (in the associated {@linkplain #segment(long) segment}).
+	 * @param index
+	 *            an index into a big array.
+	 * @return the associated displacement (in the associated
+	 *         {@linkplain #segment(long) segment}).
 	 */
-	public static int displacement( final long index ) {
-		return (int)( index & SEGMENT_MASK );
+	public static int displacement(final long index) {
+		return (int) (index & SEGMENT_MASK);
 	}
-	
-	/** Computes the starting index of a given segment.
+
+	/**
+	 * Computes the starting index of a given segment.
 	 * 
-	 * @param segment the segment of a big array.
+	 * @param segment
+	 *            the segment of a big array.
 	 * @return the starting index of the segment.
 	 */
-	public static long start( final int segment ) {
-		return (long)segment << SEGMENT_SHIFT;
+	public static long start(final int segment) {
+		return (long) segment << SEGMENT_SHIFT;
 	}
-	
-	/** Computes the index associated with given segment and displacement.
+
+	/**
+	 * Computes the index associated with given segment and displacement.
 	 * 
-	 * @param segment the segment of a big array.
-	 * @param displacement the displacement into the segment.
-	 * @return the associated index: that is, {@link #segment(long) segment(index(segment, displacement)) == segment} and
-	 * {@link #displacement(long) displacement(index(segment, displacement)) == displacement}.
+	 * @param segment
+	 *            the segment of a big array.
+	 * @param displacement
+	 *            the displacement into the segment.
+	 * @return the associated index: that is, {@link #segment(long)
+	 *         segment(index(segment, displacement)) == segment} and
+	 *         {@link #displacement(long) displacement(index(segment,
+	 *         displacement)) == displacement}.
 	 */
-	public static long index( final int segment, final int displacement ) {
-		return start( segment ) + displacement;
+	public static long index(final int segment, final int displacement) {
+		return start(segment) + displacement;
 	}
-	
-	/** Ensures that a range given by its first (inclusive) and last (exclusive) elements fits a big array of given length.
+
+	/**
+	 * Ensures that a range given by its first (inclusive) and last (exclusive)
+	 * elements fits a big array of given length.
 	 *
-	 * <P>This method may be used whenever a big array range check is needed.
+	 * <P>
+	 * This method may be used whenever a big array range check is needed.
 	 *
-	 * @param bigArrayLength a big-array length.
-	 * @param from a start index (inclusive).
-	 * @param to an end index (inclusive).
-	 * @throws IllegalArgumentException if <code>from</code> is greater than <code>to</code>.
-	 * @throws ArrayIndexOutOfBoundsException if <code>from</code> or <code>to</code> are greater than <code>bigArrayLength</code> or negative.
+	 * @param bigArrayLength
+	 *            a big-array length.
+	 * @param from
+	 *            a start index (inclusive).
+	 * @param to
+	 *            an end index (inclusive).
+	 * @throws IllegalArgumentException
+	 *             if <code>from</code> is greater than <code>to</code>.
+	 * @throws ArrayIndexOutOfBoundsException
+	 *             if <code>from</code> or <code>to</code> are greater than
+	 *             <code>bigArrayLength</code> or negative.
 	 */
-	public static void ensureFromTo( final long bigArrayLength, final long from, final long to ) {
-		if ( from < 0 ) throw new ArrayIndexOutOfBoundsException( "Start index (" + from + ") is negative" );
-		if ( from > to ) throw new IllegalArgumentException( "Start index (" + from + ") is greater than end index (" + to + ")" );
-		if ( to > bigArrayLength ) throw new ArrayIndexOutOfBoundsException( "End index (" + to + ") is greater than big-array length (" + bigArrayLength + ")" );
+	public static void ensureFromTo(final long bigArrayLength, final long from, final long to) {
+		if (from < 0) throw new ArrayIndexOutOfBoundsException("Start index (" + from + ") is negative");
+		if (from > to) throw new IllegalArgumentException("Start index (" + from + ") is greater than end index (" + to + ")");
+		if (to > bigArrayLength) throw new ArrayIndexOutOfBoundsException("End index (" + to + ") is greater than big-array length (" + bigArrayLength + ")");
 	}
 
-	/** Ensures that a range given by an offset and a length fits a big array of given length.
+	/**
+	 * Ensures that a range given by an offset and a length fits a big array of
+	 * given length.
+	 *
+	 * <P>
+	 * This method may be used whenever a big array range check is needed.
 	 *
-	 * <P>This method may be used whenever a big array range check is needed.
+	 * @param bigArrayLength
+	 *            a big-array length.
+	 * @param offset
+	 *            a start index for the fragment
+	 * @param length
+	 *            a length (the number of elements in the fragment).
+	 * @throws IllegalArgumentException
+	 *             if <code>length</code> is negative.
+	 * @throws ArrayIndexOutOfBoundsException
+	 *             if <code>offset</code> is negative or <code>offset</code> +
+	 *             <code>length</code> is greater than
+	 *             <code>bigArrayLength</code>.
+	 */
+	public static void ensureOffsetLength(final long bigArrayLength, final long offset, final long length) {
+		if (offset < 0) throw new ArrayIndexOutOfBoundsException("Offset (" + offset + ") is negative");
+		if (length < 0) throw new IllegalArgumentException("Length (" + length + ") is negative");
+		if (offset + length > bigArrayLength) throw new ArrayIndexOutOfBoundsException("Last index (" + (offset + length) + ") is greater than big-array length (" + bigArrayLength + ")");
+	}
+
+	/**
+	 * Ensures that a big-array length is legal.
 	 *
-	 * @param bigArrayLength a big-array length.
-	 * @param offset a start index for the fragment
-	 * @param length a length (the number of elements in the fragment).
-	 * @throws IllegalArgumentException if <code>length</code> is negative.
-	 * @throws ArrayIndexOutOfBoundsException if <code>offset</code> is negative or <code>offset</code>+<code>length</code> is greater than <code>bigArrayLength</code>.
+	 * @param bigArrayLength
+	 *            a big-array length.
+	 * @throws IllegalArgumentException
+	 *             if <code>length</code> is negative, or larger than or equal
+	 *             to {@link #SEGMENT_SIZE} * {@link Integer#MAX_VALUE}.
 	 */
-	public static void ensureOffsetLength( final long bigArrayLength, final long offset, final long length ) {
-		if ( offset < 0 ) throw new ArrayIndexOutOfBoundsException( "Offset (" + offset + ") is negative" );
-		if ( length < 0 ) throw new IllegalArgumentException( "Length (" + length + ") is negative" );
-		if ( offset + length > bigArrayLength ) throw new ArrayIndexOutOfBoundsException( "Last index (" + ( offset + length ) + ") is greater than big-array length (" + bigArrayLength + ")" );
+	public static void ensureLength(final long bigArrayLength) {
+		if (bigArrayLength < 0) throw new IllegalArgumentException("Negative big-array size: " + bigArrayLength);
+		if (bigArrayLength >= (long) Integer.MAX_VALUE << SEGMENT_SHIFT) throw new IllegalArgumentException("Big-array size too big: " + bigArrayLength);
 	}
 
-	
 	private static final int SMALL = 7;
 	private static final int MEDIUM = 40;
 
 	/**
-	 * Transforms two consecutive sorted ranges into a single sorted range. The initial ranges are
-	 * <code>[first, middle)</code> and <code>[middle, last)</code>, and the resulting range is
-	 * <code>[first, last)</code>. Elements in the first input range will precede equal elements in
-	 * the second.
+	 * Transforms two consecutive sorted ranges into a single sorted range. The
+	 * initial ranges are <code>[first, middle)</code> and
+	 * <code>[middle, last)</code>, and the resulting range is
+	 * <code>[first, last)</code>. Elements in the first input range will
+	 * precede equal elements in the second.
 	 */
-	private static void inPlaceMerge( final long from, long mid, final long to, final LongComparator comp, final BigSwapper swapper ) {
-		if ( from >= mid || mid >= to ) return;
-		if ( to - from == 2 ) {
-			if ( comp.compare( mid, from ) < 0 ) {
-				swapper.swap( from, mid );
+	private static void inPlaceMerge(final long from, long mid, final long to, final LongComparator comp, final BigSwapper swapper) {
+		if (from >= mid || mid >= to) return;
+		if (to - from == 2) {
+			if (comp.compare(mid, from) < 0) {
+				swapper.swap(from, mid);
 			}
 			return;
 		}
 		long firstCut;
 		long secondCut;
-		if ( mid - from > to - mid ) {
-			firstCut = from + ( mid - from ) / 2;
-			secondCut = lowerBound( mid, to, firstCut, comp );
-		}
-		else {
-			secondCut = mid + ( to - mid ) / 2;
-			firstCut = upperBound( from, mid, secondCut, comp );
+		if (mid - from > to - mid) {
+			firstCut = from + (mid - from) / 2;
+			secondCut = lowerBound(mid, to, firstCut, comp);
+		} else {
+			secondCut = mid + (to - mid) / 2;
+			firstCut = upperBound(from, mid, secondCut, comp);
 		}
 
 		long first2 = firstCut;
 		long middle2 = mid;
 		long last2 = secondCut;
-		if ( middle2 != first2 && middle2 != last2 ) {
+		if (middle2 != first2 && middle2 != last2) {
 			long first1 = first2;
 			long last1 = middle2;
-			while ( first1 < --last1 )
-				swapper.swap( first1++, last1 );
+			while (first1 < --last1)
+				swapper.swap(first1++, last1);
 			first1 = middle2;
 			last1 = last2;
-			while ( first1 < --last1 )
-				swapper.swap( first1++, last1 );
+			while (first1 < --last1)
+				swapper.swap(first1++, last1);
 			first1 = first2;
 			last1 = last2;
-			while ( first1 < --last1 )
-				swapper.swap( first1++, last1 );
+			while (first1 < --last1)
+				swapper.swap(first1++, last1);
 		}
 
-		mid = firstCut + ( secondCut - mid );
-		inPlaceMerge( from, firstCut, mid, comp, swapper );
-		inPlaceMerge( mid, secondCut, to, comp, swapper );
+		mid = firstCut + (secondCut - mid);
+		inPlaceMerge(from, firstCut, mid, comp, swapper);
+		inPlaceMerge(mid, secondCut, to, comp, swapper);
 	}
 
 	/**
-	 * Performs a binary search on an already sorted range: finds the first position where an
-	 * element can be inserted without violating the ordering. Sorting is by a user-supplied
-	 * comparison function.
+	 * Performs a binary search on an already sorted range: finds the first
+	 * position where an element can be inserted without violating the ordering.
+	 * Sorting is by a user-supplied comparison function.
 	 * 
-	 * @param mid Beginning of the range.
-	 * @param to One past the end of the range.
-	 * @param firstCut Element to be searched for.
-	 * @param comp Comparison function.
-	 * @return The largest index i such that, for every j in the range <code>[first, i)</code>,
-	 * <code>comp.apply(array[j], x)</code> is <code>true</code>.
+	 * @param mid
+	 *            Beginning of the range.
+	 * @param to
+	 *            One past the end of the range.
+	 * @param firstCut
+	 *            Element to be searched for.
+	 * @param comp
+	 *            Comparison function.
+	 * @return The largest index i such that, for every j in the range
+	 *         <code>[first, i)</code>, <code>comp.apply(array[j], x)</code> is
+	 *         <code>true</code>.
 	 */
-	private static long lowerBound( long mid, final long to, final long firstCut, final LongComparator comp ) {
+	private static long lowerBound(long mid, final long to, final long firstCut, final LongComparator comp) {
 		long len = to - mid;
-		while ( len > 0 ) {
+		while (len > 0) {
 			long half = len / 2;
 			long middle = mid + half;
-			if ( comp.compare( middle, firstCut ) < 0 ) {
+			if (comp.compare(middle, firstCut) < 0) {
 				mid = middle + 1;
 				len -= half + 1;
-			}
-			else {
+			} else {
 				len = half;
 			}
 		}
@@ -288,152 +378,174 @@ public class BigArrays {
 	}
 
 	/** Returns the index of the median of three elements. */
-	private static long med3( final long a, final long b, final long c, final LongComparator comp ) {
-		final int ab = comp.compare( a, b );
-		final int ac = comp.compare( a, c );
-		final int bc = comp.compare( b, c );
-		return ( ab < 0 ?
-				( bc < 0 ? b : ac < 0 ? c : a ) :
-				( bc > 0 ? b : ac > 0 ? c : a ) );
+	private static long med3(final long a, final long b, final long c, final LongComparator comp) {
+		final int ab = comp.compare(a, b);
+		final int ac = comp.compare(a, c);
+		final int bc = comp.compare(b, c);
+		return (ab < 0 ? (bc < 0 ? b : ac < 0 ? c : a) : (bc > 0 ? b : ac > 0 ? c : a));
 	}
 
-	/** Sorts the specified range of elements using the specified big swapper and according to the order induced by the specified
-	 * comparator using mergesort.
+	/**
+	 * Sorts the specified range of elements using the specified big swapper and
+	 * according to the order induced by the specified comparator using
+	 * mergesort.
 	 * 
-	 * <p>This sort is guaranteed to be <i>stable</i>: equal elements will not be reordered as a result
-	 * of the sort. The sorting algorithm is an in-place mergesort that is significantly slower than a 
-	 * standard mergesort, as its running time is <i>O</i>(<var>n</var> (log <var>n</var>)<sup>2</sup>), but it does not allocate additional memory; as a result, it can be
-	 * used as a generic sorting algorithm.
+	 * <p>
+	 * This sort is guaranteed to be <i>stable</i>: equal elements will not be
+	 * reordered as a result of the sort. The sorting algorithm is an in-place
+	 * mergesort that is significantly slower than a standard mergesort, as its
+	 * running time is
+	 * <i>O</i>(<var>n</var> (log <var>n</var>)<sup>2</sup>), but it
+	 * does not allocate additional memory; as a result, it can be used as a
+	 * generic sorting algorithm.
 	 * 
-	 * @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 order of the generic data (arguments are positions).
-	 * @param swapper an object that knows how to swap the elements at any two positions.
+	 * @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 order of the generic data
+	 *            (arguments are positions).
+	 * @param swapper
+	 *            an object that knows how to swap the elements at any two
+	 *            positions.
 	 */
-	public static void mergeSort( final long from, final long to, final LongComparator comp, final BigSwapper swapper ) {
+	public static void mergeSort(final long from, final long to, final LongComparator comp, final BigSwapper swapper) {
 		final long length = to - from;
 
 		// Insertion sort on smallest arrays
-		if ( length < SMALL ) {
-			for ( long i = from; i < to; i++ ) {
-				for ( long j = i; j > from && ( comp.compare( j - 1, j ) > 0 ); j-- ) {
-					swapper.swap( j, j - 1 );
+		if (length < SMALL) {
+			for (long i = from; i < to; i++) {
+				for (long j = i; j > from && (comp.compare(j - 1, j) > 0); j--) {
+					swapper.swap(j, j - 1);
 				}
 			}
 			return;
 		}
 
 		// Recursively sort halves
-		long mid = ( from + to ) >>> 1;
-		mergeSort( from, mid, comp, swapper );
-		mergeSort( mid, to, comp, swapper );
+		long mid = (from + to) >>> 1;
+		mergeSort(from, mid, comp, swapper);
+		mergeSort(mid, to, comp, swapper);
 
 		// If list is already sorted, nothing left to do. This is an
 		// optimization that results in faster sorts for nearly ordered lists.
-		if ( comp.compare( mid - 1, mid ) <= 0 ) return;
+		if (comp.compare(mid - 1, mid) <= 0) return;
 
 		// Merge sorted halves
-		inPlaceMerge( from, mid, to, comp, swapper );
+		inPlaceMerge(from, mid, to, comp, swapper);
 	}
 
-	/** Sorts the specified range of elements using the specified big swapper and according to the order induced by the specified
-	 * comparator using quicksort. 
-	 * 
-	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
-	 * McIlroy, “Engineering a Sort Function”, <i>Software: Practice and Experience</i>, 23(11), pages
-	 * 1249−1265, 1993.
+	/**
+	 * Sorts the specified range of elements using the specified big swapper and
+	 * according to the order induced by the specified comparator using
+	 * quicksort.
 	 * 
-	 * @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 order of the generic data.
-	 * @param swapper an object that knows how to swap the elements at any two positions.
+	 * <p>
+	 * The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley
+	 * and M. Douglas McIlroy, “Engineering a Sort Function”,
+	 * <i>Software: Practice and Experience</i>, 23(11), pages 1249−1265,
+	 * 1993.
 	 * 
+	 * @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 order of the generic data.
+	 * @param swapper
+	 *            an object that knows how to swap the elements at any two
+	 *            positions.
 	 */
-	public static void quickSort( final long from, final long to, final LongComparator comp, final BigSwapper swapper ) {
+	public static void quickSort(final long from, final long to, final LongComparator comp, final BigSwapper swapper) {
 		final long len = to - from;
 		// Insertion sort on smallest arrays
-		if ( len < SMALL ) {
-			for ( long i = from; i < to; i++ )
-				for ( long j = i; j > from && ( comp.compare( j - 1, j ) > 0 ); j-- ) {
-					swapper.swap( j, j - 1 );
+		if (len < SMALL) {
+			for (long i = from; i < to; i++)
+				for (long j = i; j > from && (comp.compare(j - 1, j) > 0); j--) {
+					swapper.swap(j, j - 1);
 				}
 			return;
 		}
 
 		// Choose a partition element, v
 		long m = from + len / 2; // Small arrays, middle element
-		if ( len > SMALL ) {
+		if (len > SMALL) {
 			long l = from, n = to - 1;
-			if ( len > MEDIUM ) { // Big arrays, pseudomedian of 9
+			if (len > MEDIUM) { // Big arrays, pseudomedian of 9
 				long s = len / 8;
-				l = med3( l, l + s, l + 2 * s, comp );
-				m = med3( m - s, m, m + s, comp );
-				n = med3( n - 2 * s, n - s, n, comp );
+				l = med3(l, l + s, l + 2 * s, comp);
+				m = med3(m - s, m, m + s, comp);
+				n = med3(n - 2 * s, n - s, n, comp);
 			}
-			m = med3( l, m, n, comp ); // Mid-size, med of 3
+			m = med3(l, m, n, comp); // Mid-size, med of 3
 		}
 		// long v = x[m];
 
 		long a = from, b = a, c = to - 1, d = c;
 		// Establish Invariant: v* (<v)* (>v)* v*
-		while ( true ) {
+		while (true) {
 			int comparison;
-			while ( b <= c && ( ( comparison = comp.compare( b, m ) ) <= 0 ) ) {
-				if ( comparison == 0 ) {
-					if ( a == m ) m = b; // moving target; DELTA to JDK !!!
-					else if ( b == m ) m = a; // moving target; DELTA to JDK !!!
-					swapper.swap( a++, b );
+			while (b <= c && ((comparison = comp.compare(b, m)) <= 0)) {
+				if (comparison == 0) {
+					if (a == m) m = b; // moving target; DELTA to JDK !!!
+					else if (b == m) m = a; // moving target; DELTA to JDK !!!
+					swapper.swap(a++, b);
 				}
 				b++;
 			}
-			while ( c >= b && ( ( comparison = comp.compare( c, m ) ) >= 0 ) ) {
-				if ( comparison == 0 ) {
-					if ( c == m ) m = d; // moving target; DELTA to JDK !!!
-					else if ( d == m ) m = c; // moving target; DELTA to JDK !!!
-					swapper.swap( c, d-- );
+			while (c >= b && ((comparison = comp.compare(c, m)) >= 0)) {
+				if (comparison == 0) {
+					if (c == m) m = d; // moving target; DELTA to JDK !!!
+					else if (d == m) m = c; // moving target; DELTA to JDK !!!
+					swapper.swap(c, d--);
 				}
 				c--;
 			}
-			if ( b > c ) break;
-			if ( b == m ) m = d; // moving target; DELTA to JDK !!!
-			else if ( c == m ) m = c; // moving target; DELTA to JDK !!!
-			swapper.swap( b++, c-- );
+			if (b > c) break;
+			if (b == m) m = d; // moving target; DELTA to JDK !!!
+			else if (c == m) m = c; // moving target; DELTA to JDK !!!
+			swapper.swap(b++, c--);
 		}
 
 		// Swap partition elements back to middle
 		long s;
 		long n = from + len;
-		s = Math.min( a - from, b - a );
-		vecSwap( swapper, from, b - s, s );
-		s = Math.min( d - c, n - d - 1 );
-		vecSwap( swapper, b, n - s, s );
+		s = Math.min(a - from, b - a);
+		vecSwap(swapper, from, b - s, s);
+		s = Math.min(d - c, n - d - 1);
+		vecSwap(swapper, b, n - s, s);
 
 		// Recursively sort non-partition-elements
-		if ( ( s = b - a ) > 1 ) quickSort( from, from + s, comp, swapper );
-		if ( ( s = d - c ) > 1 ) quickSort( n - s, n, comp, swapper );
+		if ((s = b - a) > 1) quickSort(from, from + s, comp, swapper);
+		if ((s = d - c) > 1) quickSort(n - s, n, comp, swapper);
 	}
 
 	/**
-	 * Performs a binary search on an already-sorted range: finds the last position where an element
-	 * can be inserted without violating the ordering. Sorting is by a user-supplied comparison
-	 * function.
+	 * Performs a binary search on an already-sorted range: finds the last
+	 * position where an element can be inserted without violating the ordering.
+	 * Sorting is by a user-supplied comparison function.
 	 * 
-	 * @param from Beginning of the range.
-	 * @param mid One past the end of the range.
-	 * @param secondCut Element to be searched for.
-	 * @param comp Comparison function.
-	 * @return The largest index i such that, for every j in the range <code>[first, i)</code>,
-	 * <code>comp.apply(x, array[j])</code> is <code>false</code>.
+	 * @param from
+	 *            Beginning of the range.
+	 * @param mid
+	 *            One past the end of the range.
+	 * @param secondCut
+	 *            Element to be searched for.
+	 * @param comp
+	 *            Comparison function.
+	 * @return The largest index i such that, for every j in the range
+	 *         <code>[first, i)</code>, <code>comp.apply(x, array[j])</code> is
+	 *         <code>false</code>.
 	 */
-	private static long upperBound( long from, final long mid, final long secondCut, final LongComparator comp ) {
+	private static long upperBound(long from, final long mid, final long secondCut, final LongComparator comp) {
 		long len = mid - from;
-		while ( len > 0 ) {
+		while (len > 0) {
 			long half = len / 2;
 			long middle = from + half;
-			if ( comp.compare( secondCut, middle ) < 0 ) {
+			if (comp.compare(secondCut, middle) < 0) {
 				len = half;
-			}
-			else {
+			} else {
 				from = middle + 1;
 				len -= half + 1;
 			}
@@ -441,49 +553,51 @@ public class BigArrays {
 		return from;
 	}
 
-	/**
-	 * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
-	 */
-	private static void vecSwap( final BigSwapper swapper, long from, long l, final long s ) {
-		for ( int i = 0; i < s; i++, from++, l++ ) swapper.swap( from, l );
+	/** Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)]. */
+	private static void vecSwap(final BigSwapper swapper, long from, long l, final long s) {
+		for (int i = 0; i < s; i++, from++, l++)
+			swapper.swap(from, l);
 	}
-	
-	public static void main( final String arg[] ) {
-		int[][] a = IntBigArrays.newBigArray( 1L << Integer.parseInt( arg[ 0 ] ) );
+
+	public static void main(final String arg[]) {
+		int[][] a = IntBigArrays.newBigArray(1L << Integer.parseInt(arg[0]));
 		long x, y, z, start;
 
-		for( int k = 10; k-- != 0; ) {
+		for (int k = 10; k-- != 0;) {
 
 			start = -System.currentTimeMillis();
 
 			x = 0;
-			for( long i = IntBigArrays.length( a ); i-- != 0; ) x ^= i ^ IntBigArrays.get( a, i );
-			if ( x == 0 ) System.err.println();
+			for (long i = IntBigArrays.length(a); i-- != 0;)
+				x ^= i ^ IntBigArrays.get(a, i);
+			if (x == 0) System.err.println();
 
-			System.out.println( "Single loop: " + ( start + System.currentTimeMillis() ) + "ms" );
+			System.out.println("Single loop: " + (start + System.currentTimeMillis()) + "ms");
 
 			start = -System.currentTimeMillis();
 
 			y = 0;
-			for( int i = a.length; i-- != 0; ) {
-				final int[] t = a[ i ];
-				for( int d = t.length; d-- != 0; ) y ^= t[ d ] ^ index( i, d ); 
+			for (int i = a.length; i-- != 0;) {
+				final int[] t = a[i];
+				for (int d = t.length; d-- != 0;)
+					y ^= t[d] ^ index(i, d);
 			}
-			if ( y == 0 ) System.err.println();
-			if ( x != y ) throw new AssertionError();
+			if (y == 0) System.err.println();
+			if (x != y) throw new AssertionError();
 
-			System.out.println( "Double loop: " + ( start + System.currentTimeMillis() ) + "ms" );
+			System.out.println("Double loop: " + (start + System.currentTimeMillis()) + "ms");
 
 			z = 0;
-			long j = IntBigArrays.length( a );
-			for( int i = a.length; i-- != 0; ) {
-				final int[] t = a[ i ];
-				for( int d = t.length; d-- != 0; ) y ^= t[ d ] ^ --j; 
+			long j = IntBigArrays.length(a);
+			for (int i = a.length; i-- != 0;) {
+				final int[] t = a[i];
+				for (int d = t.length; d-- != 0;)
+					y ^= t[d] ^ --j;
 			}
-			if ( z == 0 ) System.err.println();
-			if ( x != z ) throw new AssertionError();
+			if (z == 0) System.err.println();
+			if (x != z) throw new AssertionError();
 
-			System.out.println( "Double loop (with additional index): " + ( start + System.currentTimeMillis() ) + "ms" );
+			System.out.println("Double loop (with additional index): " + (start + System.currentTimeMillis()) + "ms");
 		}
 	}
 }
diff --git a/src/it/unimi/dsi/fastutil/BigList.java b/src/it/unimi/dsi/fastutil/BigList.java
index b9948ff..6f97d2f 100644
--- a/src/it/unimi/dsi/fastutil/BigList.java
+++ b/src/it/unimi/dsi/fastutil/BigList.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2010-2014 Sebastiano Vigna 
+ * Copyright (C) 2010-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/BigListIterator.java b/src/it/unimi/dsi/fastutil/BigListIterator.java
index bbf2c1f..afc7dfe 100644
--- a/src/it/unimi/dsi/fastutil/BigListIterator.java
+++ b/src/it/unimi/dsi/fastutil/BigListIterator.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2010-2014 Sebastiano Vigna 
+ * Copyright (C) 2010-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/BigSwapper.java b/src/it/unimi/dsi/fastutil/BigSwapper.java
index 6d7a614..8f891db 100644
--- a/src/it/unimi/dsi/fastutil/BigSwapper.java
+++ b/src/it/unimi/dsi/fastutil/BigSwapper.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2010-2014 Sebastiano Vigna 
+ * Copyright (C) 2010-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/Function.java b/src/it/unimi/dsi/fastutil/Function.java
index 016105d..03bb61b 100644
--- a/src/it/unimi/dsi/fastutil/Function.java
+++ b/src/it/unimi/dsi/fastutil/Function.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/Hash.java b/src/it/unimi/dsi/fastutil/Hash.java
index 06a7c9e..2b52e19 100644
--- a/src/it/unimi/dsi/fastutil/Hash.java
+++ b/src/it/unimi/dsi/fastutil/Hash.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -84,8 +84,8 @@ public interface Hash {
 	 * #hashCode(Object) hash function}, with the obvious property that
 	 * equal objects must have the same hash code.
 	 *
-	 * <P>If your custom collection must be able to contain <code>null</code>,
-	 * then your strategy must be able to handle <code>null</code>, too.
+	 * <P>Note that the {@link #equals(Object,Object) equals()} method of a strategy must 
+	 * be able to handle <code>null</code>, too.
 	 */
 
 	public interface Strategy<K> {
diff --git a/src/it/unimi/dsi/fastutil/HashCommon.java b/src/it/unimi/dsi/fastutil/HashCommon.java
index 9f8aa2f..1d42f80 100644
--- a/src/it/unimi/dsi/fastutil/HashCommon.java
+++ b/src/it/unimi/dsi/fastutil/HashCommon.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -40,8 +40,7 @@ public class HashCommon {
 	/** Avalanches the bits of an integer by applying the finalisation step of MurmurHash3.
 	 * 
 	 * <p>This method implements the finalisation step of Austin Appleby's <a href="http://code.google.com/p/smhasher/">MurmurHash3</a>.
-	 * Its purpose is to avalanche the bits of the argument to within 0.25% bias. It is used, among other things, to scramble quickly (but deeply) the hash
-	 * values returned by {@link Object#hashCode()}.
+	 * Its purpose is to avalanche the bits of the argument to within 0.25% bias.
 	 * 
 	 * @param x an integer.
 	 * @return a hash value with good avalanching properties.
@@ -59,11 +58,7 @@ public class HashCommon {
 	/** Avalanches the bits of a long integer by applying the finalisation step of MurmurHash3.
 	 * 
 	 * <p>This method implements the finalisation step of Austin Appleby's <a href="http://code.google.com/p/smhasher/">MurmurHash3</a>.
-	 * Its purpose is to avalanche the bits of the argument to within 0.25% bias. It is used, among other things, to scramble quickly (but deeply) the hash
-	 * values returned by {@link Object#hashCode()}.
-	 * 
-	 * <p>Incidentally, iterating this method starting from a nonzero value will generate a sequence of nonzero
-	 * values that <a href="http://prng.di.unimi.it/">passes strongest statistical tests</a>.
+	 * Its purpose is to avalanche the bits of the argument to within 0.25% bias.
 	 * 
 	 * @param x a long integer.
 	 * @return a hash value with good avalanching properties.
diff --git a/src/it/unimi/dsi/fastutil/IndirectPriorityQueue.java b/src/it/unimi/dsi/fastutil/IndirectPriorityQueue.java
index 24f0508..74d1a16 100644
--- a/src/it/unimi/dsi/fastutil/IndirectPriorityQueue.java
+++ b/src/it/unimi/dsi/fastutil/IndirectPriorityQueue.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
diff --git a/src/it/unimi/dsi/fastutil/IndirectPriorityQueues.java b/src/it/unimi/dsi/fastutil/IndirectPriorityQueues.java
index cb12453..a96837c 100644
--- a/src/it/unimi/dsi/fastutil/IndirectPriorityQueues.java
+++ b/src/it/unimi/dsi/fastutil/IndirectPriorityQueues.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2003-2014 Sebastiano Vigna 
+ * Copyright (C) 2003-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/Maps.java b/src/it/unimi/dsi/fastutil/Maps.java
index 590542a..6934251 100644
--- a/src/it/unimi/dsi/fastutil/Maps.java
+++ b/src/it/unimi/dsi/fastutil/Maps.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2003-2014 Sebastiano Vigna 
+ * Copyright (C) 2003-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/PriorityQueue.java b/src/it/unimi/dsi/fastutil/PriorityQueue.java
index 7044be7..fe80c6b 100644
--- a/src/it/unimi/dsi/fastutil/PriorityQueue.java
+++ b/src/it/unimi/dsi/fastutil/PriorityQueue.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2003-2014 Paolo Boldi and Sebastiano Vigna 
+ * Copyright (C) 2003-2016 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.
diff --git a/src/it/unimi/dsi/fastutil/PriorityQueues.java b/src/it/unimi/dsi/fastutil/PriorityQueues.java
index 23acc5c..eba43d7 100644
--- a/src/it/unimi/dsi/fastutil/PriorityQueues.java
+++ b/src/it/unimi/dsi/fastutil/PriorityQueues.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2003-2014 Sebastiano Vigna 
+ * Copyright (C) 2003-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/Size64.java b/src/it/unimi/dsi/fastutil/Size64.java
index 2a6c7f0..05ff4cc 100644
--- a/src/it/unimi/dsi/fastutil/Size64.java
+++ b/src/it/unimi/dsi/fastutil/Size64.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2010-2014 Sebastiano Vigna 
+ * Copyright (C) 2010-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/Stack.java b/src/it/unimi/dsi/fastutil/Stack.java
index eb8e06e..2a601a9 100644
--- a/src/it/unimi/dsi/fastutil/Stack.java
+++ b/src/it/unimi/dsi/fastutil/Stack.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2002-2014 Sebastiano Vigna 
+ * Copyright (C) 2002-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/Swapper.java b/src/it/unimi/dsi/fastutil/Swapper.java
index 81cdcd3..5d4e2cb 100644
--- a/src/it/unimi/dsi/fastutil/Swapper.java
+++ b/src/it/unimi/dsi/fastutil/Swapper.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil;
 
 /*		 
- * Copyright (C) 2010-2014 Sebastiano Vigna 
+ * Copyright (C) 2010-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/io/FastBufferedInputStream.java b/src/it/unimi/dsi/fastutil/io/FastBufferedInputStream.java
index affacea..42dc05f 100644
--- a/src/it/unimi/dsi/fastutil/io/FastBufferedInputStream.java
+++ b/src/it/unimi/dsi/fastutil/io/FastBufferedInputStream.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil.io;
 
 /*		 
- * Copyright (C) 2005-2014 Sebastiano Vigna 
+ * Copyright (C) 2005-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/io/FastBufferedOutputStream.java b/src/it/unimi/dsi/fastutil/io/FastBufferedOutputStream.java
index 57ef494..8342dd8 100644
--- a/src/it/unimi/dsi/fastutil/io/FastBufferedOutputStream.java
+++ b/src/it/unimi/dsi/fastutil/io/FastBufferedOutputStream.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil.io;
 
 /*		 
- * Copyright (C) 2005-2014 Sebastiano Vigna 
+ * Copyright (C) 2005-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/io/FastByteArrayInputStream.java b/src/it/unimi/dsi/fastutil/io/FastByteArrayInputStream.java
index 5088baf..b7e354b 100644
--- a/src/it/unimi/dsi/fastutil/io/FastByteArrayInputStream.java
+++ b/src/it/unimi/dsi/fastutil/io/FastByteArrayInputStream.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil.io;
 
 /*		 
- * Copyright (C) 2005-2014 Sebastiano Vigna 
+ * Copyright (C) 2005-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/io/FastByteArrayOutputStream.java b/src/it/unimi/dsi/fastutil/io/FastByteArrayOutputStream.java
index 1a6629f..50b824c 100644
--- a/src/it/unimi/dsi/fastutil/io/FastByteArrayOutputStream.java
+++ b/src/it/unimi/dsi/fastutil/io/FastByteArrayOutputStream.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil.io;
 
 /*		 
- * Copyright (C) 2005-2014 Sebastiano Vigna 
+ * Copyright (C) 2005-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/io/FastMultiByteArrayInputStream.java b/src/it/unimi/dsi/fastutil/io/FastMultiByteArrayInputStream.java
index cfa7e6f..30cf028 100644
--- a/src/it/unimi/dsi/fastutil/io/FastMultiByteArrayInputStream.java
+++ b/src/it/unimi/dsi/fastutil/io/FastMultiByteArrayInputStream.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil.io;
 
 /*		 
- * Copyright (C) 2005-2014 Sebastiano Vigna 
+ * Copyright (C) 2005-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/io/InspectableFileCachedInputStream.java b/src/it/unimi/dsi/fastutil/io/InspectableFileCachedInputStream.java
index 5cee9bf..049483c 100644
--- a/src/it/unimi/dsi/fastutil/io/InspectableFileCachedInputStream.java
+++ b/src/it/unimi/dsi/fastutil/io/InspectableFileCachedInputStream.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil.io;
 
 /*		 
- * Copyright (C) 2005-2014 Sebastiano Vigna 
+ * Copyright (C) 2005-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/io/MeasurableInputStream.java b/src/it/unimi/dsi/fastutil/io/MeasurableInputStream.java
index 6ec5ac1..41e80d7 100644
--- a/src/it/unimi/dsi/fastutil/io/MeasurableInputStream.java
+++ b/src/it/unimi/dsi/fastutil/io/MeasurableInputStream.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil.io;
 
 /*		 
- * Copyright (C) 2005-2014 Sebastiano Vigna 
+ * Copyright (C) 2005-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/io/MeasurableOutputStream.java b/src/it/unimi/dsi/fastutil/io/MeasurableOutputStream.java
index a571c2f..8481a1a 100644
--- a/src/it/unimi/dsi/fastutil/io/MeasurableOutputStream.java
+++ b/src/it/unimi/dsi/fastutil/io/MeasurableOutputStream.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil.io;
 
 /*		 
- * Copyright (C) 2005-2014 Sebastiano Vigna 
+ * Copyright (C) 2005-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/io/MeasurableStream.java b/src/it/unimi/dsi/fastutil/io/MeasurableStream.java
index afd225e..50b40cd 100644
--- a/src/it/unimi/dsi/fastutil/io/MeasurableStream.java
+++ b/src/it/unimi/dsi/fastutil/io/MeasurableStream.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil.io;
 
 /*		 
- * Copyright (C) 2005-2014 Sebastiano Vigna 
+ * Copyright (C) 2005-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/it/unimi/dsi/fastutil/io/RepositionableStream.java b/src/it/unimi/dsi/fastutil/io/RepositionableStream.java
index 4dc70af..9ceda57 100644
--- a/src/it/unimi/dsi/fastutil/io/RepositionableStream.java
+++ b/src/it/unimi/dsi/fastutil/io/RepositionableStream.java
@@ -1,7 +1,7 @@
 package it.unimi.dsi.fastutil.io;
 
 /*		 
- * Copyright (C) 2005-2014 Sebastiano Vigna 
+ * Copyright (C) 2005-2016 Sebastiano Vigna
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/src/overview.html b/src/overview.html
index 87387d1..e979b02 100644
--- a/src/overview.html
+++ b/src/overview.html
@@ -322,8 +322,8 @@
 	it.unimi.dsi.fastutil.ints.IntSortedSet} and the values are a {@link
 	it.unimi.dsi.fastutil.longs.LongCollection}).
 
-      <LI>Hash-based maps that return primitive numeric values have an <code>add()</code>
-	method (see, e.g., {@link it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap#add(int,int)})
+      <LI>Hash-based and tree-based maps that return primitive numeric values have an <code>addTo()</code>
+	method (see, e.g., {@link it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap#addTo(int,int)})
 	that <em>adds</em> an increment to the current value of a key; it is
 	most useful to avoid the inefficient procedure of getting a value,
 	incrementing it and then putting it back into the map (typically, when
diff --git a/src/stylesheet.css b/src/stylesheet.css
deleted file mode 100644
index d134ace..0000000
--- a/src/stylesheet.css
+++ /dev/null
@@ -1,482 +0,0 @@
-/* Javadoc style sheet */
-/*
-Overall document style
-*/
-body {
-    background-color:#ffffff;
-    color:#353833;
-    font-family:Arial, Helvetica, sans-serif;
-    font-size:76%;
-    margin:0;
-}
-p {
-	font-size:1em;
-}
-a:link, a:visited {
-    text-decoration:none;
-    color:#4c6b87;
-}
-a:hover, a:focus {
-    text-decoration:none;
-    color:#bb7a2a;
-}
-a:active {
-    text-decoration:none;
-    color:#4c6b87;
-}
-a[name] {
-    color:#353833;
-}
-a[name]:hover {
-    text-decoration:none;
-    color:#353833;
-}
-pre {
-    font-size:1.2em;
-}
-h1 {
-    font-size:1.8em;
-}
-h2 {
-    font-size:1.5em;
-}
-h3 {
-    font-size:1.4em;
-}
-h4 {
-    font-size:1.3em;
-}
-h5 {
-    font-size:1.2em;
-}
-h6 {
-    font-size:1.1em;
-}
-ul {
-    list-style-type:disc;
-    font-size:1em;
-}
-code, tt {
-    font-size:1.2em;
-}
-dt code {
-    font-size:1.2em;
-}
-table tr td dt code {
-    font-size:1.2em;
-    vertical-align:top;
-}
-sup {
-    font-size:.6em;
-}
-/*
-Document title and Copyright styles
-*/
-.clear {
-    clear:both;
-    height:0px;
-    overflow:hidden;
-}
-.aboutLanguage {
-    float:right;
-    padding:0px 21px;
-    font-size:.8em;
-    z-index:200;
-    margin-top:-7px;
-}
-.legalCopy {
-    margin-left:.5em;
-}
-.bar a, .bar a:link, .bar a:visited, .bar a:active {
-    color:#FFFFFF;
-    text-decoration:none;
-}
-.bar a:hover, .bar a:focus {
-    color:#bb7a2a;
-}
-.tab {
-    background-color:#0066FF;
-    background-image:url(resources/titlebar.gif);
-    background-position:left top;
-    background-repeat:no-repeat;
-    color:#ffffff;
-    padding:8px;
-    width:5em;
-    font-weight:bold;
-}
-/*
-Navigation bar styles
-*/
-.bar {
-    background-image:url(resources/background.gif);
-    background-repeat:repeat-x;
-    color:#FFFFFF;
-    padding:.8em .5em .4em .8em;
-    height:auto;/*height:1.8em;*/
-    font-size:1em;
-    margin:0;
-}
-.topNav {
-    background-image:url(resources/background.gif);
-    background-repeat:repeat-x;
-    color:#FFFFFF;
-    float:left;
-    padding:0;
-    width:100%;
-    clear:right;
-    height:2.8em;
-    padding-top:10px;
-    overflow:hidden;
-}
-.bottomNav {
-    margin-top:10px;
-    background-image:url(resources/background.gif);
-    background-repeat:repeat-x;
-    color:#FFFFFF;
-    float:left;
-    padding:0;
-    width:100%;
-    clear:right;
-    height:2.8em;
-    padding-top:10px;
-    overflow:hidden;
-}
-.subNav {
-    background-color:#dee3e9;
-    border-bottom:1px solid #9eadc0;
-    float:left;
-    width:100%;
-    overflow:hidden;
-}
-.subNav div {
-    clear:left;
-    float:left;
-    padding:0 0 5px 6px;
-}
-ul.navList, ul.subNavList {
-    float:left;
-    margin:0 25px 0 0;
-    padding:0;
-}
-ul.navList li{
-    list-style:none;
-    float:left;
-    padding:3px 6px;
-}
-ul.subNavList li{
-    list-style:none;
-    float:left;
-    font-size:90%;
-}
-.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited {
-    color:#FFFFFF;
-    text-decoration:none;
-}
-.topNav a:hover, .bottomNav a:hover {
-    text-decoration:none;
-    color:#bb7a2a;
-}
-.navBarCell1Rev {
-    background-image:url(resources/tab.gif);
-    background-color:#a88834;
-    color:#FFFFFF;
-    margin: auto 5px;
-    border:1px solid #c9aa44;
-}
-/*
-Page header and footer styles
-*/
-.header, .footer {
-    clear:both;
-    margin:0 20px;
-    padding:5px 0 0 0;
-}
-.indexHeader {
-    margin:10px;
-    position:relative;
-}
-.indexHeader h1 {
-    font-size:1.3em;
-}
-.title {
-    color:#2c4557;
-    margin:10px 0;
-}
-.subTitle {
-    margin:5px 0 0 0;
-}
-.header ul {
-    margin:0 0 25px 0;
-    padding:0;
-    list-style-type:circle;
-}
-.footer ul {
-    margin:20px 0 5px 0;
-}
-.header ul li, .footer ul li {
-    list-style:inherit;
-    -webkit-margin-before: 1em;
-	-webkit-margin-after: 1em;
-	-webkit-margin-start: 0px;
-	-webkit-margin-end: 0px;
-}
-/*
-Heading styles
-*/
-div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 {
-    background-color:#dee3e9;
-    border-top:1px solid #9eadc0;
-    border-bottom:1px solid #9eadc0;
-    margin:0 0 6px -8px;
-    padding:2px 5px;
-}
-ul.blockList ul.blockList ul.blockList li.blockList h3 {
-    background-color:#dee3e9;
-    border-top:1px solid #9eadc0;
-    border-bottom:1px solid #9eadc0;
-    margin:0 0 6px -8px;
-    padding:2px 5px;
-}
-ul.blockList ul.blockList li.blockList h3 {
-    padding:0;
-    margin:15px 0;
-}
-ul.blockList li.blockList h2 {
-    padding:0px 0 20px 0;
-}
-/*
-Page layout container styles
-*/
-.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer {
-    clear:both;
-    padding:10px 20px;
-    position:relative;
-}
-.indexContainer {
-    margin:10px;
-    position:relative;
-    font-size:1.0em;
-}
-.indexContainer h2 {
-    font-size:1.1em;
-    padding:0 0 3px 0;
-}
-.indexContainer ul {
-    margin:0;
-    padding:0;
-}
-.indexContainer ul li {
-    list-style:none;
-}
-.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt {
-    font-size:1.1em;
-    font-weight:bold;
-    margin:10px 0 0 0;
-    color:#4E4E4E;
-}
-.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd {
-    margin:10px 0 10px 20px;
-}
-.serializedFormContainer dl.nameValue dt {
-    margin-left:1px;
-    font-size:1.1em;
-    display:inline;
-    font-weight:bold;
-}
-.serializedFormContainer dl.nameValue dd {
-    margin:0 0 0 1px;
-    font-size:1.1em;
-    display:inline;
-}
-/*
-List styles
-*/
-ul.horizontal li {
-    display:inline;
-    font-size:0.9em;
-}
-ul.inheritance {
-    margin:0;
-    padding:0;
-}
-ul.inheritance li {
-    display:inline;
-    list-style:none;
-}
-ul.inheritance li ul.inheritance {
-    margin-left:15px;
-    padding-left:15px;
-    padding-top:1px;
-}
-ul.blockList, ul.blockListLast {
-    margin:10px 0 10px 0;
-    padding:0;
-}
-ul.blockList li.blockList, ul.blockListLast li.blockList {
-    list-style:none;
-    margin-bottom:25px;
-}
-ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList {
-    padding:0px 20px 5px 10px;
-    border:1px solid #9eadc0;
-    background-color:#f9f9f9;
-}
-ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList {
-    padding:0 0 5px 8px;
-    background-color:#ffffff;
-    border:1px solid #9eadc0;
-    border-top:none;
-}
-ul.blockList ul.blockList ul.blockList ul.blockList li.blockList {
-    margin-left:0;
-    padding-left:0;
-    padding-bottom:15px;
-    border:none;
-    border-bottom:1px solid #9eadc0;
-}
-ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast {
-    list-style:none;
-    border-bottom:none;
-    padding-bottom:0;
-}
-table tr td dl, table tr td dl dt, table tr td dl dd {
-    margin-top:0;
-    margin-bottom:1px;
-}
-/*
-Table styles
-*/
-.contentContainer table, .classUseContainer table, .constantValuesContainer table {
-    border-bottom:1px solid #9eadc0;
-    width:100%;
-}
-.contentContainer ul li table, .classUseContainer ul li table, .constantValuesContainer ul li table {
-    width:100%;
-}
-.contentContainer .description table, .contentContainer .details table {
-    border-bottom:none;
-}
-.contentContainer ul li table th.colOne, .contentContainer ul li table th.colFirst, .contentContainer ul li table th.colLast, .classUseContainer ul li table th, .constantValuesContainer ul li table th, .contentContainer ul li table td.colOne, .contentContainer ul li table td.colFirst, .contentContainer ul li table td.colLast, .classUseContainer ul li table td, .constantValuesContainer ul li table td{
-    vertical-align:top;
-    padding-right:20px;
-}
-.contentContainer ul li table th.colLast, .classUseContainer ul li table th.colLast,.constantValuesContainer ul li table th.colLast,
-.contentContainer ul li table td.colLast, .classUseContainer ul li table td.colLast,.constantValuesContainer ul li table td.colLast,
-.contentContainer ul li table th.colOne, .classUseContainer ul li table th.colOne,
-.contentContainer ul li table td.colOne, .classUseContainer ul li table td.colOne {
-    padding-right:3px;
-}
-.overviewSummary caption, .packageSummary caption, .contentContainer ul.blockList li.blockList caption, .summary caption, .classUseContainer caption, .constantValuesContainer caption {
-    position:relative;
-    text-align:left;
-    background-repeat:no-repeat;
-    color:#FFFFFF;
-    font-weight:bold;
-    clear:none;
-    overflow:hidden;
-    padding:0px;
-    margin:0px;
-}
-caption a:link, caption a:hover, caption a:active, caption a:visited {
-    color:#FFFFFF;
-}
-.overviewSummary caption span, .packageSummary caption span, .contentContainer ul.blockList li.blockList caption span, .summary caption span, .classUseContainer caption span, .constantValuesContainer caption span {
-    white-space:nowrap;
-    padding-top:8px;
-    padding-left:8px;
-    display:block;
-    float:left;
-    background-image:url(resources/titlebar.gif);
-    height:18px;
-}
-.overviewSummary .tabEnd, .packageSummary .tabEnd, .contentContainer ul.blockList li.blockList .tabEnd, .summary .tabEnd, .classUseContainer .tabEnd, .constantValuesContainer .tabEnd {
-    width:10px;
-    background-image:url(resources/titlebar_end.gif);
-    background-repeat:no-repeat;
-    background-position:top right;
-    position:relative;
-    float:left;
-}
-ul.blockList ul.blockList li.blockList table {
-    margin:0 0 12px 0px;
-    width:100%;
-}
-.tableSubHeadingColor {
-    background-color: #EEEEFF;
-}
-.altColor {
-    background-color:#eeeeef;
-}
-.rowColor {
-    background-color:#ffffff;
-}
-.overviewSummary td, .packageSummary td, .contentContainer ul.blockList li.blockList td, .summary td, .classUseContainer td, .constantValuesContainer td {
-    text-align:left;
-    padding:3px 3px 3px 7px;
-}
-th.colFirst, th.colLast, th.colOne, .constantValuesContainer th {
-    background:#dee3e9;
-    border-top:1px solid #9eadc0;
-    border-bottom:1px solid #9eadc0;
-    text-align:left;
-    padding:3px 3px 3px 7px;
-}
-td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover {
-    font-weight:bold;
-}
-td.colFirst, th.colFirst {
-    border-left:1px solid #9eadc0;
-    white-space:nowrap;
-}
-td.colLast, th.colLast {
-    border-right:1px solid #9eadc0;
-}
-td.colOne, th.colOne {
-    border-right:1px solid #9eadc0;
-    border-left:1px solid #9eadc0;
-}
-table.overviewSummary  {
-    padding:0px;
-    margin-left:0px;
-}
-table.overviewSummary td.colFirst, table.overviewSummary th.colFirst,
-table.overviewSummary td.colOne, table.overviewSummary th.colOne {
-    width:25%;
-    vertical-align:middle;
-}
-table.packageSummary td.colFirst, table.overviewSummary th.colFirst {
-    width:25%;
-    vertical-align:middle;
-}
-/*
-Content styles
-*/
-.description pre {
-    margin-top:0;
-}
-.deprecatedContent {
-    margin:0;
-    padding:10px 0;
-}
-.docSummary {
-    padding:0;
-}
-/*
-Formatting effect styles
-*/
-.sourceLineNo {
-    color:green;
-    padding:0 30px 0 0;
-}
-h1.hidden {
-    visibility:hidden;
-    overflow:hidden;
-    font-size:.9em;
-}
-.block {
-    display:block;
-    margin:3px 0 0 0;
-}
-.strong {
-    font-weight:bold;
-}
diff --git a/test/it/unimi/dsi/fastutil/ArraysTest.java b/test/it/unimi/dsi/fastutil/ArraysTest.java
index 8376ab2..80b3b79 100644
--- a/test/it/unimi/dsi/fastutil/ArraysTest.java
+++ b/test/it/unimi/dsi/fastutil/ArraysTest.java
@@ -1,87 +1,159 @@
 package it.unimi.dsi.fastutil;
 
-import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
 import it.unimi.dsi.fastutil.ints.AbstractIntComparator;
+import it.unimi.dsi.fastutil.ints.IntArrays;
+import it.unimi.dsi.fastutil.ints.IntArraysTest;
+
+import java.util.Random;
 
 import org.junit.Test;
 
 public class ArraysTest {
 	
-	@Test
-	public void testMergeSort() {
-		int[] s = new int[] { 2, 1, 5, 2, 1, 0, 9, 1, 4, 2, 4, 6, 8, 9, 10, 12, 1, 7 };
-		final int[] a = s.clone();
-		
-		java.util.Arrays.sort( s );
-		int[] sorted = s.clone();
-		Arrays.mergeSort( 0, a.length, new AbstractIntComparator() {
+
+	private static void testMergeSort( final int x[] ) {
+		testMergeSort( x, 0, x.length );
+	}
+	
+	private static void testMergeSort( final int x[], int from, int to ) {
+		Arrays.mergeSort( from, to, new AbstractIntComparator() {
+			private static final long serialVersionUID = 1L;
+
 			@Override
 			public int compare( int k1, int k2 ) {
-				return a[ k1 ] - a[ k2 ]; 
+				return Integer.compare( x[ k1 ], x[ k2 ] ); 
 			}
 		}, new Swapper() {
 			@Override
 			public void swap( int k1, int k2 ) {
-				final int t = a[ k1 ];
-				a[ k1 ] = a[ k2 ];
-				a[ k2 ] = t;
+				final int t = x[ k1 ];
+				x[ k1 ] = x[ k2 ];
+				x[ k2 ] = t;
 			}
 		});
-		assertArrayEquals( sorted, a );
+		for( int i = to - 1; i-- != from; ) assertTrue( x[ i ] <= x[ i + 1 ] );
+	}
+
+	@Test
+	public void testMergeSort() {
+		testMergeSort( new int[] { 2, 1, 0, 4 } );
+		testMergeSort( new int[] { 2, -1, 0, -4 } );
+		testMergeSort( IntArrays.shuffle( IntArraysTest.identity( 100 ), new Random( 0 ) ) );
+
+		int[] t = new int[ 100 ];
+		Random random = new Random( 0 );
+		for( int i = t.length; i-- != 0; ) t[ i ] = random.nextInt();
+		testMergeSort( t );
+		t = new int[ 100000 ];
+		random = new Random( 0 );
+		for( int i = t.length; i-- != 0; ) t[ i ] = random.nextInt();
+		testMergeSort( t );
+		for( int i = 100; i-- != 10; ) t[ i ] = random.nextInt();
+		testMergeSort( t, 10, 100 );
+		for( int i = t.length; i-- != 0; ) t[ i ] = random.nextInt() & 0xF;
+		testMergeSort( t );
+
+		t = new int[ 10000000 ];
+		random = new Random( 0 );
+		for( int i = t.length; i-- != 0; ) t[ i ] = random.nextInt();
+		testMergeSort( t );
+	}
+	
+	private static void testQuickSort( final int x[] ) {
+		testQuickSort( x, 0, x.length );
+	}
+	
+	private static void testQuickSort( final int x[], int from, int to ) {
+		Arrays.quickSort( from, to, new AbstractIntComparator() {
+			private static final long serialVersionUID = 1L;
 
-		Arrays.mergeSort( 0, a.length, new AbstractIntComparator() {
 			@Override
 			public int compare( int k1, int k2 ) {
-				return a[ k1 ] - a[ k2 ]; 
+				return Integer.compare( x[ k1 ], x[ k2 ] ); 
 			}
 		}, new Swapper() {
 			@Override
 			public void swap( int k1, int k2 ) {
-				final int t = a[ k1 ];
-				a[ k1 ] = a[ k2 ];
-				a[ k2 ] = t;
+				final int t = x[ k1 ];
+				x[ k1 ] = x[ k2 ];
+				x[ k2 ] = t;
 			}
 		});
-		assertArrayEquals( sorted, a );
-
+		for( int i = to - 1; i-- != from; ) assertTrue( x[ i ] <= x[ i + 1 ] );
 	}
 
 	@Test
 	public void testQuickSort() {
-		int[] s = new int[] { 2, 1, 5, 2, 1, 0, 9, 1, 4, 2, 4, 6, 8, 9, 10, 12, 1, 7 };
-		
-		java.util.Arrays.sort( s );
-		int[] sorted = s.clone();
+		testQuickSort( new int[] { 2, 1, 0, 4 } );
+		testQuickSort( new int[] { 2, -1, 0, -4 } );
+		testQuickSort( IntArrays.shuffle( IntArraysTest.identity( 100 ), new Random( 0 ) ) );
 
-		final int[] a = s.clone();
-		Arrays.quickSort( 0, a.length, new AbstractIntComparator() {
-			@Override
-			public int compare( int k1, int k2 ) {
-				return a[ k1 ] - a[ k2 ]; 
-			}
-		}, new Swapper() {
-			@Override
-			public void swap( int k1, int k2 ) {
-				final int t = a[ k1 ];
-				a[ k1 ] = a[ k2 ];
-				a[ k2 ] = t;
-			}
-		});
-		assertArrayEquals( sorted, a );
+		int[] t = new int[ 100 ];
+		Random random = new Random( 0 );
+		for( int i = t.length; i-- != 0; ) t[ i ] = random.nextInt();
+		testQuickSort( t );
+		t = new int[ 100000 ];
+		random = new Random( 0 );
+		for( int i = t.length; i-- != 0; ) t[ i ] = random.nextInt();
+		testQuickSort( t );
+		for( int i = 100; i-- != 10; ) t[ i ] = random.nextInt();
+		testQuickSort( t, 10, 100 );
+		for( int i = t.length; i-- != 0; ) t[ i ] = random.nextInt() & 0xF;
+		testQuickSort( t );
+
+		t = new int[ 10000000 ];
+		random = new Random( 0 );
+		for( int i = t.length; i-- != 0; ) t[ i ] = random.nextInt();
+		testQuickSort( t );
+	}
+
+	private static void testParallelQuickSort( final int x[] ) {
+		testParallelQuickSort( x, 0, x.length );
+	}
+	
+	private static void testParallelQuickSort( final int x[], int from, int to ) {
+		Arrays.parallelQuickSort( from, to, new AbstractIntComparator() {
+			private static final long serialVersionUID = 1L;
 
-		Arrays.quickSort( 0, a.length, new AbstractIntComparator() {
 			@Override
 			public int compare( int k1, int k2 ) {
-				return a[ k1 ] - a[ k2 ]; 
+				return Integer.compare( x[ k1 ], x[ k2 ] ); 
 			}
 		}, new Swapper() {
 			@Override
 			public void swap( int k1, int k2 ) {
-				final int t = a[ k1 ];
-				a[ k1 ] = a[ k2 ];
-				a[ k2 ] = t;
+				final int t = x[ k1 ];
+				x[ k1 ] = x[ k2 ];
+				x[ k2 ] = t;
 			}
 		});
-		assertArrayEquals( sorted, a );
+		for( int i = to - 1; i-- != from; ) assertTrue( x[ i ] <= x[ i + 1 ] );
 	}
+	
+	@Test
+	public void testParallelQuickSort() {
+		testParallelQuickSort( new int[] { 2, 1, 0, 4 } );
+		testParallelQuickSort( new int[] { 2, -1, 0, -4 } );
+		testParallelQuickSort( IntArrays.shuffle( IntArraysTest.identity( 100 ), new Random( 0 ) ) );
+
+		int[] t = new int[ 100 ];
+		Random random = new Random( 0 );
+		for( int i = t.length; i-- != 0; ) t[ i ] = random.nextInt();
+		testParallelQuickSort( t );
+		t = new int[ 100000 ];
+		random = new Random( 0 );
+		for( int i = t.length; i-- != 0; ) t[ i ] = random.nextInt();
+		testParallelQuickSort( t );
+		for( int i = 100; i-- != 10; ) t[ i ] = random.nextInt();
+		testParallelQuickSort( t, 10, 100 );
+		for( int i = t.length; i-- != 0; ) t[ i ] = random.nextInt() & 0xF;
+		testParallelQuickSort( t );
+
+		t = new int[ 10000000 ];
+		random = new Random( 0 );
+		for( int i = t.length; i-- != 0; ) t[ i ] = random.nextInt();
+		testParallelQuickSort( t );
+	}
+
 }
diff --git a/test/it/unimi/dsi/fastutil/BigArraysTest.java b/test/it/unimi/dsi/fastutil/BigArraysTest.java
index 4d90b0c..7cfeaa6 100644
--- a/test/it/unimi/dsi/fastutil/BigArraysTest.java
+++ b/test/it/unimi/dsi/fastutil/BigArraysTest.java
@@ -20,6 +20,8 @@ public class BigArraysTest {
 		Arrays.sort( s );
 		int[][] sorted = IntBigArrays.wrap( s.clone() );
 		BigArrays.mergeSort( 0, IntBigArrays.length( a ), new AbstractLongComparator() {
+			private static final long serialVersionUID = 1L;
+
 			@Override
 			public int compare( long k1, long k2 ) {
 				return IntBigArrays.get( a, k1 ) - IntBigArrays.get( a, k2 ); 
@@ -33,6 +35,8 @@ public class BigArraysTest {
 		assertArrayEquals( sorted, a );
 
 		BigArrays.mergeSort( 0, IntBigArrays.length( a ), new AbstractLongComparator() {
+			private static final long serialVersionUID = 1L;
+
 			@Override
 			public int compare( long k1, long k2 ) {
 				return IntBigArrays.get( a, k1 ) - IntBigArrays.get( a, k2 ); 
@@ -56,6 +60,8 @@ public class BigArraysTest {
 
 		final int[][] a = IntBigArrays.wrap( s.clone()  );
 		BigArrays.quickSort( 0, IntBigArrays.length( a ), new AbstractLongComparator() {
+			private static final long serialVersionUID = 1L;
+
 			@Override
 			public int compare( long k1, long k2 ) {
 				return IntBigArrays.get( a, k1 ) - IntBigArrays.get( a, k2 ); 
@@ -69,6 +75,8 @@ public class BigArraysTest {
 		assertArrayEquals( sorted, a );
 
 		BigArrays.quickSort( 0, IntBigArrays.length( a ), new AbstractLongComparator() {
+			private static final long serialVersionUID = 1L;
+
 			@Override
 			public int compare( long k1, long k2 ) {
 				return IntBigArrays.get( a, k1 ) - IntBigArrays.get( a, k2 ); 
diff --git a/test/it/unimi/dsi/fastutil/doubles/DoubleBigArraysTest.java b/test/it/unimi/dsi/fastutil/doubles/DoubleBigArraysTest.java
index e62a7ab..df0953a 100644
--- a/test/it/unimi/dsi/fastutil/doubles/DoubleBigArraysTest.java
+++ b/test/it/unimi/dsi/fastutil/doubles/DoubleBigArraysTest.java
@@ -84,8 +84,8 @@ public class DoubleBigArraysTest {
 		double[][] b = DoubleBigArrays.wrap( a.clone() );
 
 		for( int i = -1; i < 20; i++ ) {
-			assertEquals( "" + i, Arrays.binarySearch( a, i ), DoubleBigArrays.binarySearch( b, i ) );
-			assertEquals( "" + i, Arrays.binarySearch( a, i ), DoubleBigArrays.binarySearch( b, i, DoubleComparators.NATURAL_COMPARATOR ) );
+			assertEquals( String.valueOf(i), Arrays.binarySearch( a, i ), DoubleBigArrays.binarySearch( b, i ) );
+			assertEquals( String.valueOf(i), Arrays.binarySearch( a, i ), DoubleBigArrays.binarySearch( b, i, DoubleComparators.NATURAL_COMPARATOR ) );
 		}
 	
 		for( int i = -1; i < 20; i++ ) {
diff --git a/test/it/unimi/dsi/fastutil/ints/Int2IntAVLTreeMapTest.java b/test/it/unimi/dsi/fastutil/ints/Int2IntAVLTreeMapTest.java
new file mode 100644
index 0000000..635e52e
--- /dev/null
+++ b/test/it/unimi/dsi/fastutil/ints/Int2IntAVLTreeMapTest.java
@@ -0,0 +1,25 @@
+package it.unimi.dsi.fastutil.ints;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
+
+import org.junit.Test;
+
+public class Int2IntAVLTreeMapTest {
+
+	@SuppressWarnings("deprecation")
+	@Test
+	public void testContainsNull() {
+		Int2IntAVLTreeMap m = new Int2IntAVLTreeMap( new int[] { 1, 2, 3 },  new int[] { 1, 2, 3 } );
+		assertFalse( m.containsKey( null ) );
+		assertTrue( m.get( null ) == null );
+	}
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testEquals() {
+		Int2IntAVLTreeMap m = new Int2IntAVLTreeMap( new int[] { 1, 2 },  new int[] { 1, 2 } );
+		assertFalse( m.equals( new Object2ObjectOpenHashMap<Integer,Integer>( new Integer[] { 1, null }, new Integer[] { 1, 1 } ) ) );
+	}	
+}
diff --git a/test/it/unimi/dsi/fastutil/ints/Int2IntArrayMapTest.java b/test/it/unimi/dsi/fastutil/ints/Int2IntArrayMapTest.java
index a010419..44ca7b8 100644
--- a/test/it/unimi/dsi/fastutil/ints/Int2IntArrayMapTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/Int2IntArrayMapTest.java
@@ -4,6 +4,8 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import it.unimi.dsi.fastutil.io.BinIO;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.objects.ObjectIterator;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -15,7 +17,65 @@ import org.junit.Test;
 
 public class Int2IntArrayMapTest  {
 
+	@Test
+	public void testRemove() {
+		Int2IntMap map = new Int2IntArrayMap();
+		assertFalse( map.entrySet().remove( new Object() ) );
+		map.put( 1, 2 );
+		map.put( 2, 3 );
+		assertFalse( map.entrySet().remove( new AbstractInt2IntMap.BasicEntry( 1, 1 ) ) );
+		assertFalse( map.entrySet().remove( new AbstractInt2IntMap.BasicEntry( 3, 2 ) ) );
+		assertTrue( map.entrySet().remove( new AbstractInt2IntMap.BasicEntry( 1, 2 ) ) );
+		assertFalse( map.entrySet().contains( new AbstractInt2IntMap.BasicEntry( 1, 2 ) ) );
+		assertEquals( map.size(), map.entrySet().size() );
+		assertFalse( map.containsKey( 1 ) );
+	}
+
+	@Test(expected = IllegalStateException.class)
+	public void testArrayMapEmptyEntrySetThrowsExceptionOnIteratorRemove() {
+		ObjectIterator<Entry<Integer, Integer>> iterator = new Int2IntArrayMap( 4 ).entrySet().iterator();
+		assertFalse( iterator.hasNext() );
+		iterator.remove();
+	}
+
+	@Test(expected = IllegalStateException.class)
+	public void testArrayMapEmptyEntrySetThrowsExceptionTwoIteratorRemoves() {
+		Int2IntArrayMap m = new Int2IntArrayMap();
+		m.put( 0, 0 );
+		m.put( 1, 1 );
+		ObjectIterator<Entry<Integer, Integer>> iterator = m.entrySet().iterator();
+		iterator.next();
+		iterator.remove();
+		iterator.remove();
+	}
+
+	@Test(expected = IllegalStateException.class)
+	public void testArrayMapEmptyEntrySetThrowsExceptionOnFastIteratorRemove() {
+		ObjectIterator<it.unimi.dsi.fastutil.ints.Int2IntMap.Entry> iterator = new Int2IntArrayMap().int2IntEntrySet().fastIterator();
+		assertFalse( iterator.hasNext() );
+		iterator.remove();
+	}
 
+	@Test(expected = IllegalStateException.class)
+	public void testArrayMapEmptyEntrySetThrowsExceptionTwoFastIteratorRemoves() {
+		Int2IntArrayMap m = new Int2IntArrayMap();
+		m.put( 0, 0 );
+		m.put( 1, 1 );
+		ObjectIterator<it.unimi.dsi.fastutil.ints.Int2IntMap.Entry> iterator = m.int2IntEntrySet().fastIterator();
+		iterator.next();
+		iterator.remove();
+		iterator.remove();
+	}
+
+	@SuppressWarnings("deprecation")
+	@Test
+	public void testContainsNull() {
+		Int2IntArrayMap m = new Int2IntArrayMap( new int[] { 1, 2, 3 },  new int[] { 1, 2, 3 } );
+		assertFalse( m.containsKey( null ) );
+		assertTrue( m.get( null ) == null );
+	}
+
+	@SuppressWarnings("boxing")
 	@Test
 	public void testEquals() {
 		Int2IntArrayMap a1 = new Int2IntArrayMap();
@@ -30,8 +90,11 @@ public class Int2IntArrayMapTest  {
 
 		assertEquals(a1, a2);
 
+		Int2IntArrayMap m = new Int2IntArrayMap( new int[] { 1, 2 },  new int[] { 1, 2 } );
+		assertFalse( m.equals( new Object2ObjectOpenHashMap<Integer,Integer>( new Integer[] { 1, null }, new Integer[] { 1, 1 } ) ) );
 	}
 
+	@SuppressWarnings("deprecation")
 	@Test
 	public void testMap() {
 		for( int i = 0; i <= 1; i++ ) {
@@ -109,4 +172,17 @@ public class Int2IntArrayMapTest  {
 		oos.close();
 		assertEquals( m, BinIO.loadObject( new ByteArrayInputStream( baos.toByteArray() ) ) );
 	}
+
+	@Test
+	public void testIteratorRemove() {
+		Int2IntArrayMap m = new Int2IntArrayMap( new int[] { 1, 2, 3 },  new int[] { 1, 2, 3 } );
+		ObjectIterator<Entry<Integer, Integer>> keySet = m.entrySet().iterator();
+		keySet.next();
+		keySet.next();
+		keySet.remove();
+		assertTrue( keySet.hasNext() );
+		Entry<Integer, Integer> next = keySet.next();
+		assertEquals( Integer.valueOf( 3 ), next.getKey() );
+		assertEquals( Integer.valueOf( 3 ), next.getValue() );
+	}
 }
diff --git a/test/it/unimi/dsi/fastutil/ints/Int2IntLinkedOpenHashMapTest.java b/test/it/unimi/dsi/fastutil/ints/Int2IntLinkedOpenHashMapTest.java
index a2672a0..75a35b4 100644
--- a/test/it/unimi/dsi/fastutil/ints/Int2IntLinkedOpenHashMapTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/Int2IntLinkedOpenHashMapTest.java
@@ -7,6 +7,7 @@ import static org.junit.Assert.assertTrue;
 import it.unimi.dsi.fastutil.Hash;
 import it.unimi.dsi.fastutil.HashCommon;
 import it.unimi.dsi.fastutil.ints.Int2IntMap.Entry;
+import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator;
 import it.unimi.dsi.fastutil.objects.ObjectIterator;
 
 import java.io.IOException;
@@ -129,7 +130,7 @@ public class Int2IntLinkedOpenHashMapTest {
 		return o1 == null ? o2 == null : o1.equals( o2 );
 	}
 
-	@SuppressWarnings("unchecked")
+	@SuppressWarnings({ "unchecked", "deprecation" })
 	protected static void test( int n, float f ) throws IOException, ClassNotFoundException {
 		Int2IntLinkedOpenHashMap m = new Int2IntLinkedOpenHashMap( Hash.DEFAULT_INITIAL_SIZE, f );
 		Map<Integer,Integer> t = new java.util.LinkedHashMap<Integer,Integer>();
@@ -444,6 +445,7 @@ public class Int2IntLinkedOpenHashMapTest {
 		assertEquals( 99, m.lastIntKey() );
 	}
 
+	@SuppressWarnings("deprecation")
 	@Test
 	public void testPut() {
 		Int2IntLinkedOpenHashMap m = new Int2IntLinkedOpenHashMap( Hash.DEFAULT_INITIAL_SIZE );
@@ -662,4 +664,49 @@ public class Int2IntLinkedOpenHashMapTest {
 		fastIterator.remove();
 		assertEquals( s.get( key ), -1 );
 	}
+	
+	
+	@Test(expected=NoSuchElementException.class)
+	public void testNextAtEnd() {
+		Int2IntLinkedOpenHashMap m = new Int2IntLinkedOpenHashMap();
+		m.addTo( 1, 1 );
+		m.addTo( 2, 2 );
+		m.addTo( 3, 3 );
+		ObjectBidirectionalIterator<java.util.Map.Entry<Integer, Integer>> iterator = m.entrySet().iterator( m.entrySet().last() );
+		assertFalse( iterator.hasNext() );
+		iterator.next();
+	}
+
+	@Test(expected=NoSuchElementException.class)
+	public void testNextAtEndFast() {
+		Int2IntLinkedOpenHashMap m = new Int2IntLinkedOpenHashMap();
+		m.addTo( 1, 1 );
+		m.addTo( 2, 2 );
+		m.addTo( 3, 3 );
+		ObjectBidirectionalIterator<Entry> iterator = m.int2IntEntrySet().iterator( m.int2IntEntrySet().last() );
+		assertFalse( iterator.hasNext() );
+		iterator.next();
+	}
+
+	@Test(expected=NoSuchElementException.class)
+	public void testPreviousAtStart() {
+		Int2IntLinkedOpenHashMap m = new Int2IntLinkedOpenHashMap();
+		m.addTo( 1, 1 );
+		m.addTo( 2, 2 );
+		m.addTo( 3, 3 );
+		ObjectBidirectionalIterator<java.util.Map.Entry<Integer, Integer>> iterator = m.entrySet().iterator();
+		assertFalse( iterator.hasPrevious() );
+		iterator.previous();
+	}
+
+	@Test(expected=NoSuchElementException.class)
+	public void testPreviousAtStartFast() {
+		Int2IntLinkedOpenHashMap m = new Int2IntLinkedOpenHashMap();
+		m.addTo( 1, 1 );
+		m.addTo( 2, 2 );
+		m.addTo( 3, 3 );
+		ObjectBidirectionalIterator<Entry> iterator = m.int2IntEntrySet().iterator();
+		assertFalse( iterator.hasPrevious() );
+		iterator.previous();
+	}
 }
diff --git a/test/it/unimi/dsi/fastutil/ints/Int2IntOpenCustomHashMapTest.java b/test/it/unimi/dsi/fastutil/ints/Int2IntOpenCustomHashMapTest.java
index aaf2074..3c96666 100644
--- a/test/it/unimi/dsi/fastutil/ints/Int2IntOpenCustomHashMapTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/Int2IntOpenCustomHashMapTest.java
@@ -8,6 +8,7 @@ import it.unimi.dsi.fastutil.Hash;
 import java.io.IOException;
 import java.io.Serializable;
 import java.util.HashMap;
+import java.util.Map.Entry;
 
 import org.junit.Ignore;
 import org.junit.Test;
@@ -18,6 +19,31 @@ import org.junit.Test;
 
 public class Int2IntOpenCustomHashMapTest {
 
+	@Test
+	public void testGetNullKey() {
+		final Int2IntOpenCustomHashMap s = new Int2IntOpenCustomHashMap( new IntHash.Strategy() {
+
+			@Override
+			public int hashCode( int o ) {
+				return o % 10;
+			}
+
+			@Override
+			public boolean equals( int a, int b ) {
+				return ( a - b ) % 10 == 0;
+			}
+		} );
+
+		s.put( 10, 10 );
+		assertTrue( s.containsKey( 0 ) );
+		Entry<Integer, Integer> e = s.entrySet().iterator().next();
+		assertEquals( 10, e.getKey().intValue() );
+		assertEquals( 10, e.getValue().intValue() );
+		s.remove( 0 );
+		assertTrue( s.isEmpty() );
+	}
+
+
 	private static final class Strategy implements IntHash.Strategy, Serializable {
 		private static final long serialVersionUID = 1L;
 
@@ -83,6 +109,7 @@ public class Int2IntOpenCustomHashMapTest {
 				) + "; actual: " + expected + "; stddev: " + Math.sqrt( totSquareProbes / m.n - expected * expected ) + "; max probes: " + maxProbes );
 	}
 
+	@SuppressWarnings("deprecation")
 	private static void test( int n, float f ) throws IOException, ClassNotFoundException {
 		int c;
 		final Integer key[] = new Integer[ (int)Math.ceil( n * f ) ];
diff --git a/test/it/unimi/dsi/fastutil/ints/Int2IntOpenHashMapTest.java b/test/it/unimi/dsi/fastutil/ints/Int2IntOpenHashMapTest.java
index 9c27639..4809f2d 100644
--- a/test/it/unimi/dsi/fastutil/ints/Int2IntOpenHashMapTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/Int2IntOpenHashMapTest.java
@@ -1,8 +1,14 @@
 package it.unimi.dsi.fastutil.ints;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
 import it.unimi.dsi.fastutil.Hash;
 import it.unimi.dsi.fastutil.HashCommon;
 import it.unimi.dsi.fastutil.ints.Int2IntMap.Entry;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
 import it.unimi.dsi.fastutil.objects.ObjectIterator;
 
 import java.io.IOException;
@@ -12,11 +18,25 @@ import java.util.Map;
 import org.junit.Ignore;
 import org.junit.Test;
 
-import static org.junit.Assert.*;
-
 @SuppressWarnings("rawtypes")
 public class Int2IntOpenHashMapTest {
 
+	@SuppressWarnings("deprecation")
+	@Test
+	public void testContainsNull() {
+		Int2IntOpenHashMap m = new Int2IntOpenHashMap( new int[] { 1, 2, 3 },  new int[] { 1, 2, 3 } );
+		assertFalse( m.containsKey( null ) );
+		assertTrue( m.get( null ) == null );
+	}
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testEquals() {
+		Int2IntOpenHashMap m = new Int2IntOpenHashMap( new int[] { 1, 2 },  new int[] { 1, 2 } );
+		assertFalse( m.equals( new Object2ObjectOpenHashMap<Integer,Integer>( new Integer[] { 1, null }, new Integer[] { 1, 1 } ) ) );
+	}
+
+
 	@Test
 	public void testStrangeRetainAllCase() {
 
@@ -75,7 +95,7 @@ public class Int2IntOpenHashMapTest {
 		return o1 == null ? o2 == null : o1.equals( o2 );
 	}
 
-	@SuppressWarnings({ "unchecked", "boxing" })
+	@SuppressWarnings({ "unchecked", "boxing", "deprecation" })
 	protected static void test( int n, float f ) throws IOException, ClassNotFoundException {
 		Int2IntOpenHashMap m = new Int2IntOpenHashMap( Hash.DEFAULT_INITIAL_SIZE, f );
 		Map t = new java.util.HashMap();
diff --git a/test/it/unimi/dsi/fastutil/ints/Int2IntRBTreeMapTest.java b/test/it/unimi/dsi/fastutil/ints/Int2IntRBTreeMapTest.java
new file mode 100644
index 0000000..28a1806
--- /dev/null
+++ b/test/it/unimi/dsi/fastutil/ints/Int2IntRBTreeMapTest.java
@@ -0,0 +1,25 @@
+package it.unimi.dsi.fastutil.ints;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
+
+import org.junit.Test;
+
+public class Int2IntRBTreeMapTest {
+
+	@SuppressWarnings("deprecation")
+	@Test
+	public void testContainsNull() {
+		Int2IntRBTreeMap m = new Int2IntRBTreeMap( new int[] { 1, 2, 3 },  new int[] { 1, 2, 3 } );
+		assertFalse( m.containsKey( null ) );
+		assertTrue( m.get( null ) == null );
+	}
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testEquals() {
+		Int2IntRBTreeMap m = new Int2IntRBTreeMap( new int[] { 1, 2 },  new int[] { 1, 2 } );
+		assertFalse( m.equals( new Object2ObjectOpenHashMap<Integer,Integer>( new Integer[] { 1, null }, new Integer[] { 1, 1 } ) ) );
+	}	
+}
diff --git a/test/it/unimi/dsi/fastutil/ints/IntArrayFIFOQueueTest.java b/test/it/unimi/dsi/fastutil/ints/IntArrayFIFOQueueTest.java
index c6449be..af9b789 100644
--- a/test/it/unimi/dsi/fastutil/ints/IntArrayFIFOQueueTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/IntArrayFIFOQueueTest.java
@@ -1,7 +1,6 @@
 package it.unimi.dsi.fastutil.ints;
 
 import static org.junit.Assert.assertEquals;
-
 import it.unimi.dsi.fastutil.io.BinIO;
 
 import java.io.File;
@@ -143,6 +142,7 @@ public class IntArrayFIFOQueueTest {
 		assertEquals( 0, q.dequeueInt() );
 	}
 
+	@SuppressWarnings("deprecation")
 	@Test
 	public void testImmediateReduce() {
 		IntArrayFIFOQueue q = new IntArrayFIFOQueue();
@@ -150,6 +150,7 @@ public class IntArrayFIFOQueueTest {
 		q.dequeue();
 	}
 
+	@SuppressWarnings("deprecation")
 	private final static void assertSameQueue( IntArrayFIFOQueue a, IntArrayFIFOQueue b ) {
 		assertEquals( a.size(), b.size() );
 		while( ! a.isEmpty() && ! b.isEmpty() ) assertEquals( a.dequeue(), b.dequeue() );
diff --git a/test/it/unimi/dsi/fastutil/ints/IntArrayIndirectPriorityQueueTest.java b/test/it/unimi/dsi/fastutil/ints/IntArrayIndirectPriorityQueueTest.java
index a28460c..07329c0 100644
--- a/test/it/unimi/dsi/fastutil/ints/IntArrayIndirectPriorityQueueTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/IntArrayIndirectPriorityQueueTest.java
@@ -68,7 +68,7 @@ public class IntArrayIndirectPriorityQueueTest {
 		return true;
 	}
 
-	public void test( int n ) {
+	public void test( int n, IntComparator comparator ) {
 		Exception mThrowsIllegal, tThrowsIllegal, mThrowsOutOfBounds, tThrowsOutOfBounds, mThrowsNoElement, tThrowsNoElement;
 		int rm = 0, rt = 0;
 		Random r = new Random( 0 );
@@ -76,8 +76,8 @@ public class IntArrayIndirectPriorityQueueTest {
 
 		for ( int i = 0; i < n; i++ ) ref[ i ] = r.nextInt();
 
-		IntArrayIndirectPriorityQueue m = new IntArrayIndirectPriorityQueue( ref );
-		IntHeapIndirectPriorityQueue t = new IntHeapIndirectPriorityQueue( ref );
+		IntArrayIndirectPriorityQueue m = new IntArrayIndirectPriorityQueue( ref, comparator );
+		IntHeapIndirectPriorityQueue t = new IntHeapIndirectPriorityQueue( ref, comparator );
 
 		/* We add pairs to t. */
 		for ( int i = 0; i < n / 2; i++ ) {
@@ -280,7 +280,7 @@ public class IntArrayIndirectPriorityQueueTest {
 
 			int[] temp = t.heap.clone();
 			IntArrays.quickSort( temp, 0, t.size() ); // To scramble a bit
-			m = new IntArrayIndirectPriorityQueue( m.refArray, temp, t.size() );
+			m = new IntArrayIndirectPriorityQueue( m.refArray, temp, t.size(), comparator );
 
 			assertTrue( "Error: m and t differ after wrap (" + m + ", " + t + ")", heapEqual( m.array, t.heap, m.size(), t.size() ) );
 
@@ -321,24 +321,27 @@ public class IntArrayIndirectPriorityQueueTest {
 
 	@Test
 	public void test1() {
-		test( 1 );
+		test( 1, null );
+		test( 1, IntComparators.OPPOSITE_COMPARATOR );
 
 	}
 
 	@Test
 	public void test10() {
-		test( 10 );
-
+		test( 10, null );
+		test( 10, IntComparators.OPPOSITE_COMPARATOR );
 	}
 
 	@Test
 	public void test100() {
-		test( 20 );
+		test( 100, null );
+		test( 100, IntComparators.OPPOSITE_COMPARATOR );
 	}
 
 	@Test
 	public void test1000() {
-		test( 1000 );
+		test( 1000, null );
+		test( 1000, IntComparators.OPPOSITE_COMPARATOR );
 	}
 
 }
diff --git a/test/it/unimi/dsi/fastutil/ints/IntArrayListTest.java b/test/it/unimi/dsi/fastutil/ints/IntArrayListTest.java
new file mode 100644
index 0000000..6d11db5
--- /dev/null
+++ b/test/it/unimi/dsi/fastutil/ints/IntArrayListTest.java
@@ -0,0 +1,44 @@
+package it.unimi.dsi.fastutil.ints;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+
+import org.junit.Test;
+
+public class IntArrayListTest {
+
+	@Test
+	public void testEmptyListIsDifferentFromEmptySet() {
+		assertFalse(IntLists.EMPTY_LIST.equals(IntSets.EMPTY_SET));
+		assertFalse(IntSets.EMPTY_SET.equals(IntLists.EMPTY_LIST));
+	}
+
+	@Test
+	public void testNullInContains() {
+		assertFalse(new IntArrayList().contains(null));
+	}
+
+	@Test
+	public void testAddUsingIteratorToTheFirstPosition() {
+		IntArrayList list = new IntArrayList();
+		list.add(24);
+		IntListIterator it = list.listIterator();
+		it.add(42);
+		assertTrue(it.hasNext());
+		assertEquals(IntArrayList.wrap( new int[] { 42, 24 } ), list);
+	}
+	
+	@Test
+	public void testRemoveAll() {
+		IntArrayList l = IntArrayList.wrap( new int[] { 0, 1, 1, 2 } );
+		l.removeAll( IntSets.singleton( 1 ) );
+		assertEquals( IntArrayList.wrap( new int[] { 0, 2 } ), l );
+
+		l = IntArrayList.wrap( new int[] { 0, 1, 1, 2 } );
+		l.removeAll( Collections.singleton( Integer.valueOf( 1 ) ) );
+		assertEquals( IntArrayList.wrap( new int[] { 0, 2 } ), l );
+	}
+}
diff --git a/test/it/unimi/dsi/fastutil/ints/IntArrayPriorityQueueTest.java b/test/it/unimi/dsi/fastutil/ints/IntArrayPriorityQueueTest.java
index 618ec40..0a8330a 100644
--- a/test/it/unimi/dsi/fastutil/ints/IntArrayPriorityQueueTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/IntArrayPriorityQueueTest.java
@@ -1,9 +1,14 @@
 package it.unimi.dsi.fastutil.ints;
 
 import static org.junit.Assert.assertEquals;
+import it.unimi.dsi.fastutil.io.BinIO;
+
+import java.io.File;
+import java.io.IOException;
 
 import org.junit.Test;
 
+ at SuppressWarnings("deprecation")
 public class IntArrayPriorityQueueTest {
 	
 	@Test
@@ -146,4 +151,21 @@ public class IntArrayPriorityQueueTest {
 			for( int j = 0; j < 10; j++ ) assertEquals( h.dequeueInt(), q.dequeueInt() );
 		}
 	}
+
+	@Test
+	public void testSerialize() throws IOException, ClassNotFoundException {
+		IntArrayPriorityQueue q = new IntArrayPriorityQueue();
+		for( int i = 0; i < 100; i++ ) q.enqueue( i );
+		
+		File file = File.createTempFile( getClass().getPackage().getName() + "-", "-tmp" );
+		file.deleteOnExit();
+		BinIO.storeObject( q, file );
+		IntArrayPriorityQueue r = (IntArrayPriorityQueue)BinIO.loadObject( file );
+		file.delete();
+		for( int i = 0; i < 100; i++ ) {
+			assertEquals( q.first(), r.first() );
+			assertEquals( q.dequeue(), r.dequeue() );
+		}
+	}
 }
+
diff --git a/test/it/unimi/dsi/fastutil/ints/IntArraySetTest.java b/test/it/unimi/dsi/fastutil/ints/IntArraySetTest.java
index ff7fb11..3a2fa11 100644
--- a/test/it/unimi/dsi/fastutil/ints/IntArraySetTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/IntArraySetTest.java
@@ -8,15 +8,24 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.Collections;
 
 import org.junit.Test;
+
 import static org.junit.Assert.*;
 
 public class IntArraySetTest {
-	
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testNullInEquals() {
+		assertFalse( new IntArraySet( Arrays.asList( 42 ) ).equals( Collections.singleton( null ) ) );
+	}
+
 	@Test
 	public void testSet() {
-		for( int i = 1; i <= 1; i++ ) {
+		for( int i = 0; i <= 1; i++ ) {
 			final IntArraySet s = i == 0 ? new IntArraySet() : new IntArraySet( new int[ i ] );
 			assertTrue( s.add( 1 ) );
 			assertEquals( 1 + i, s.size() );
@@ -77,4 +86,27 @@ public class IntArraySetTest {
 		oos.close();
 		assertEquals( s, BinIO.loadObject( new ByteArrayInputStream( baos.toByteArray() ) ) );
 	}
+
+	@Test
+	public void testRemove() {
+		IntSet set = new IntArraySet( new int[] { 42 } );
+
+		IntIterator iterator = set.iterator();
+		assertTrue(iterator.hasNext());
+		iterator.next();
+		iterator.remove();
+		assertFalse( iterator.hasNext() );
+		assertEquals( 0, set.size() );
+
+		set = new IntArraySet( new int[] { 42, 43, 44 } );
+
+		iterator = set.iterator();
+		assertTrue(iterator.hasNext());
+		iterator.next();
+		iterator.next();
+		iterator.remove();
+		assertEquals( 44, iterator.nextInt () );
+		assertFalse( iterator.hasNext() );
+		assertEquals( new IntArraySet( new int[] { 42, 44 } ), set );
+	}
 }
diff --git a/test/it/unimi/dsi/fastutil/ints/IntArraysTest.java b/test/it/unimi/dsi/fastutil/ints/IntArraysTest.java
index 39a1667..00c29ef 100644
--- a/test/it/unimi/dsi/fastutil/ints/IntArraysTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/IntArraysTest.java
@@ -29,6 +29,8 @@ public class IntArraysTest {
 		
 		final int[] d = a.clone();
 		IntArrays.mergeSort( d, new AbstractIntComparator() {
+			private static final long serialVersionUID = 1L;
+
 			@Override
 			public int compare( int k1, int k2 ) {
 				return k1 - k2;
@@ -37,6 +39,8 @@ public class IntArraysTest {
 		assertArrayEquals( sorted, d );
 
 		IntArrays.mergeSort( d, new AbstractIntComparator() {
+			private static final long serialVersionUID = 1L;
+
 			@Override
 			public int compare( int k1, int k2 ) {
 				return k1 - k2;
@@ -69,6 +73,8 @@ public class IntArraysTest {
 
 		final int[] d = a.clone();
 		IntArrays.quickSort( d, new AbstractIntComparator() {
+			private static final long serialVersionUID = 1L;
+
 			@Override
 			public int compare( int k1, int k2 ) {
 				return k1 - k2;
@@ -76,6 +82,8 @@ public class IntArraysTest {
 		});
 		assertArrayEquals( sorted, d );
 		IntArrays.quickSort( d, new AbstractIntComparator() {
+			private static final long serialVersionUID = 1L;
+
 			@Override
 			public int compare( int k1, int k2 ) {
 				return k1 - k2;
diff --git a/test/it/unimi/dsi/fastutil/ints/IntBigArrayBigListTest.java b/test/it/unimi/dsi/fastutil/ints/IntBigArrayBigListTest.java
index 2846aac..9a28aa3 100644
--- a/test/it/unimi/dsi/fastutil/ints/IntBigArrayBigListTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/IntBigArrayBigListTest.java
@@ -1,7 +1,11 @@
 package it.unimi.dsi.fastutil.ints;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import it.unimi.dsi.fastutil.BigArrays;
 
+import java.util.Collections;
 import java.util.Iterator;
 
 import org.junit.Ignore;
@@ -10,6 +14,58 @@ import org.junit.Test;
 @SuppressWarnings("rawtypes")
 public class IntBigArrayBigListTest {
 
+	@Test
+	public void testRemoveAllModifiesCollection() {
+		IntBigList list = new IntBigArrayBigList();
+		assertFalse( list.removeAll( Collections.emptySet() ) );
+		assertEquals( IntBigLists.EMPTY_BIG_LIST, list );
+	}
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testRemoveAllSkipSegment() {
+		IntBigList list = new IntBigArrayBigList();
+		for( long i = 0; i < BigArrays.SEGMENT_SIZE + 10; i++ ) list.add( (int)( i % 2 ) );
+		assertTrue( list.removeAll( IntSets.singleton( 1 ) ) );
+		assertEquals( BigArrays.SEGMENT_SIZE / 2 + 5, list.size64() );
+		for( long i = 0; i < BigArrays.SEGMENT_SIZE / 2 + 5; i++ ) assertEquals( 0, list.getInt( i ) );
+
+		list = new IntBigArrayBigList();
+		for( long i = 0; i < BigArrays.SEGMENT_SIZE + 10; i++ ) list.add( (int)( i % 2 ) );
+		assertTrue( list.removeAll( Collections.singleton( 1 ) ) );
+		assertEquals( BigArrays.SEGMENT_SIZE / 2 + 5, list.size64() );
+		for( long i = 0; i < BigArrays.SEGMENT_SIZE / 2 + 5; i++ ) assertEquals( 0, list.getInt( i ) );
+	}
+
+
+	@Test(expected = IndexOutOfBoundsException.class)
+	public void testListIteratorTooLow() {
+		new IntBigArrayBigList().listIterator( -1L );
+	}
+
+	@Test(expected = IndexOutOfBoundsException.class)
+	public void testListIteratorTooHigh() {
+		new IntBigArrayBigList().listIterator( 1L );
+	}
+
+	@Test
+	public void testAddWithIterator() {
+		IntBigList list = new IntBigArrayBigList();
+		list.iterator().add( 1 );
+		assertEquals( IntBigLists.singleton( 1 ), list );
+	}
+
+	@Test
+	public void testRemoveAll() {
+		IntBigArrayBigList l = IntBigArrayBigList.wrap( new int[][] { { 0, 1, 2 } } );
+		l.removeAll( IntSets.singleton( 1 ) );
+		assertEquals( IntBigArrayBigList.wrap( new int[][] { { 0, 2 } } ), l );
+
+		l = IntBigArrayBigList.wrap( new int[][] { { 0, 1, 1, 2 } } );
+		l.removeAll( Collections.singleton( Integer.valueOf( 1 ) ) );
+		assertEquals( IntBigArrayBigList.wrap( new int[][] { { 0, 2 } } ), l );
+	}
+
 	private static java.util.Random r = new java.util.Random( 0 );
 
 	private static int genKey() {
diff --git a/test/it/unimi/dsi/fastutil/ints/IntBigArraysTest.java b/test/it/unimi/dsi/fastutil/ints/IntBigArraysTest.java
index d4b6ee4..e171cc0 100644
--- a/test/it/unimi/dsi/fastutil/ints/IntBigArraysTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/IntBigArraysTest.java
@@ -81,8 +81,8 @@ public class IntBigArraysTest {
 		int[][] b = IntBigArrays.wrap( a.clone() );
 
 		for( int i = -1; i < 20; i++ ) {
-			assertEquals( "" + i, Arrays.binarySearch( a, i ), IntBigArrays.binarySearch( b, i ) );
-			assertEquals( "" + i, Arrays.binarySearch( a, i ), IntBigArrays.binarySearch( b, i, IntComparators.NATURAL_COMPARATOR ) );
+			assertEquals( String.valueOf(i), Arrays.binarySearch( a, i ), IntBigArrays.binarySearch( b, i ) );
+			assertEquals( String.valueOf(i), Arrays.binarySearch( a, i ), IntBigArrays.binarySearch( b, i, IntComparators.NATURAL_COMPARATOR ) );
 		}
 	
 		for( int i = -1; i < 20; i++ ) {
diff --git a/test/it/unimi/dsi/fastutil/ints/IntHeapPriorityQueueTest.java b/test/it/unimi/dsi/fastutil/ints/IntHeapPriorityQueueTest.java
new file mode 100644
index 0000000..4080485
--- /dev/null
+++ b/test/it/unimi/dsi/fastutil/ints/IntHeapPriorityQueueTest.java
@@ -0,0 +1,29 @@
+package it.unimi.dsi.fastutil.ints;
+
+import static org.junit.Assert.assertEquals;
+import it.unimi.dsi.fastutil.io.BinIO;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.Test;
+
+public class IntHeapPriorityQueueTest {
+	@SuppressWarnings("deprecation")
+	@Test
+	public void testSerialize() throws IOException, ClassNotFoundException {
+		IntHeapPriorityQueue q = new IntHeapPriorityQueue();
+		for( int i = 0; i < 100; i++ ) q.enqueue( i );
+		
+		File file = File.createTempFile( getClass().getPackage().getName() + "-", "-tmp" );
+		file.deleteOnExit();
+		BinIO.storeObject( q, file );
+		IntHeapPriorityQueue r = (IntHeapPriorityQueue)BinIO.loadObject( file );
+		file.delete();
+		for( int i = 0; i < 100; i++ ) {
+			assertEquals( q.first(), r.first() );
+			assertEquals( q.dequeue(), r.dequeue() );
+		}
+	}
+}
+
diff --git a/test/it/unimi/dsi/fastutil/ints/IntHeapSemiIndirectPriorityQueueTest.java b/test/it/unimi/dsi/fastutil/ints/IntHeapSemiIndirectPriorityQueueTest.java
index d44ded5..62b0b97 100644
--- a/test/it/unimi/dsi/fastutil/ints/IntHeapSemiIndirectPriorityQueueTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/IntHeapSemiIndirectPriorityQueueTest.java
@@ -54,6 +54,8 @@ public class IntHeapSemiIndirectPriorityQueueTest extends TestCase {
 		final int[] refArray = { 8, 16, 9 };
 
 		IntComparator comparator = new AbstractIntComparator() {
+			private static final long serialVersionUID = 1L;
+
 			@Override
 			public int compare( int k1, int k2 ) {
 				return ( k1 & 3 ) - ( k2 & 3 );
diff --git a/test/it/unimi/dsi/fastutil/ints/IntLinkedOpenCustomHashSetTest.java b/test/it/unimi/dsi/fastutil/ints/IntLinkedOpenCustomHashSetTest.java
new file mode 100644
index 0000000..6270c43
--- /dev/null
+++ b/test/it/unimi/dsi/fastutil/ints/IntLinkedOpenCustomHashSetTest.java
@@ -0,0 +1,47 @@
+package it.unimi.dsi.fastutil.ints;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class IntLinkedOpenCustomHashSetTest {
+
+	@Test
+	public void testGetNullKey() {
+		final IntLinkedOpenCustomHashSet s = new IntLinkedOpenCustomHashSet( new IntHash.Strategy() {
+
+			@Override
+			public int hashCode( int o ) {
+				return o % 10;
+			}
+
+			@Override
+			public boolean equals( int a, int b ) {
+				return ( a - b ) % 10 == 0;
+			}
+		} );
+
+		s.add( 3 );
+		s.add( 10 );
+		s.add( 0 );
+		assertTrue( s.contains( 0 ) );
+		assertTrue( s.contains( 10 ) );
+		assertTrue( s.contains( 3 ) );
+		assertFalse( s.contains( 1 ) );
+		IntListIterator i = s.iterator();
+		assertEquals( 3, i.nextInt() );
+		assertEquals( 10, i.nextInt() );
+		assertFalse( i.hasNext() );
+		
+		s.remove( 0 );
+		assertFalse( s.contains( 0 ) );
+		assertFalse( s.contains( 10 ) );
+		s.add( 10 );
+
+		i = s.iterator();
+		assertEquals( 3, i.nextInt() );
+		assertEquals( 10, i.nextInt() );
+		assertFalse( i.hasNext() );
+
+	}
+}
diff --git a/test/it/unimi/dsi/fastutil/ints/IntOpenCustomHashSetTest.java b/test/it/unimi/dsi/fastutil/ints/IntOpenCustomHashSetTest.java
index 2b808d3..ca53555 100644
--- a/test/it/unimi/dsi/fastutil/ints/IntOpenCustomHashSetTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/IntOpenCustomHashSetTest.java
@@ -13,11 +13,51 @@ import org.junit.Ignore;
 import org.junit.Test;
 
 @SuppressWarnings("rawtypes")
-
 /** Not a particularly good test, but it will check that we use everywhere the same hashing strategy. */
-
 public class IntOpenCustomHashSetTest {
 
+	@Test
+	public void testGetNullKey() {
+		final IntOpenCustomHashSet s = new IntOpenCustomHashSet( new IntHash.Strategy() {
+
+			@Override
+			public int hashCode( int o ) {
+				return o % 10;
+			}
+
+			@Override
+			public boolean equals( int a, int b ) {
+				return ( a - b ) % 10 == 0;
+			}
+		} );
+
+		s.add( 10 );
+		assertTrue( s.contains( 0 ) );
+		assertEquals( 10, s.iterator().nextInt() );
+	}
+
+
+	@Test
+	public void testCustomUsed() {
+		IntOpenCustomHashSet set = new IntOpenCustomHashSet( new IntHash.Strategy() {
+			@Override
+			public int hashCode( int e ) {
+				return Integer.hashCode( e & 0xFFFF );
+			}
+
+			@Override
+			public boolean equals( int a, int b ) {
+				return ( a & 0xFFFF ) == ( b & 0xFFFF );
+			}
+		} );
+
+		set.add( 1 << 16 | 1 );
+		set.add( 1 );
+		assertEquals( 1, set.size() );
+		assertTrue( set.contains( 1 ) );
+		assertTrue( set.contains( 1 << 16 | 1 ) );
+	}
+
 	private static final class Strategy implements IntHash.Strategy, Serializable {
 		private static final long serialVersionUID = 1L;
 
@@ -33,16 +73,16 @@ public class IntOpenCustomHashSetTest {
 	}
 
 	private final static Strategy strategy = new Strategy();
-	
+
 	private static java.util.Random r = new java.util.Random( 0 );
 
 	private static int genKey() {
 		return r.nextInt( 10 );
 	}
-	
+
 	@SuppressWarnings("boxing")
 	private static void checkTable( IntOpenCustomHashSet s ) {
-		final int[]key = s.key;
+		final int[] key = s.key;
 		assert ( s.n & -s.n ) == s.n : "Table length is not a power of two: " + s.n;
 		assert s.n == s.key.length - 1;
 		int n = s.n;
@@ -50,8 +90,8 @@ public class IntOpenCustomHashSetTest {
 			if ( key[ n ] != 0 && !s.contains( key[ n ] ) ) throw new AssertionError( "Hash table has key " + key[ n ]
 					+ " marked as occupied, but the key does not belong to the table" );
 
-		if ( s.containsNull && ! s.contains( 0 ) ) throw new AssertionError( "Hash table should contain zero by internal state, but it doesn't when queried" );
-		if ( ! s.containsNull && s.contains( 0 ) ) throw new AssertionError( "Hash table should not contain zero by internal state, but it does when queried" );
+		if ( s.containsNull && !s.contains( 0 ) ) throw new AssertionError( "Hash table should contain zero by internal state, but it doesn't when queried" );
+		if ( !s.containsNull && s.contains( 0 ) ) throw new AssertionError( "Hash table should not contain zero by internal state, but it does when queried" );
 
 		java.util.HashSet<Integer> t = new java.util.HashSet<Integer>();
 		for ( int i = s.size(); i-- != 0; )
@@ -93,16 +133,17 @@ public class IntOpenCustomHashSetTest {
 		HashSet<Integer> t = new HashSet<Integer>();
 		/* First of all, we fill t with random data. */
 
-		for ( int i = 0; i < key.length; i++ ) t.add( ( key[ i ] = new Integer( genKey() ) ) );
+		for ( int i = 0; i < key.length; i++ )
+			t.add( ( key[ i ] = new Integer( genKey() ) ) );
 
 		IntOpenCustomHashSet m = new IntOpenCustomHashSet( Hash.DEFAULT_INITIAL_SIZE, f, strategy );
 
-		
+
 		/* Now we add to m the same data */
 
 		m.addAll( t );
 		checkTable( m );
-		
+
 		assertTrue( "Error: !m.equals(t) after insertion", m.equals( t ) );
 		assertTrue( "Error: !t.equals(m) after insertion", t.equals( m ) );
 		printProbes( m );
@@ -124,20 +165,14 @@ public class IntOpenCustomHashSetTest {
 		}
 
 		assertEquals( "Error: m has only " + c + " keys instead of " + t.size() + " after insertion (iterating on m)", c, t.size() );
-		/*
-		 * Now we check that inquiries about random data give the same answer in m and t. For m we
-		 * use the polymorphic method.
-		 */
+		/* 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 < n; i++ ) {
 			int T = genKey();
 			assertEquals( "Error: divergence in keys between t and m (polymorphic method)", m.contains( T ), t.contains( ( Integer.valueOf( T ) ) ) );
 		}
 
-		/*
-		 * Again, we check that inquiries about random data give the same answer in m and t, but for
-		 * m we use the standard method.
-		 */
+		/* Again, we check that inquiries about random data give the same answer in m and t, but for m we use the standard method. */
 
 		for ( int i = 0; i < n; i++ ) {
 			int T = genKey();
@@ -239,18 +274,19 @@ public class IntOpenCustomHashSetTest {
 
 		/* Now we torture-test the hash table. This part is implemented only for integers and longs. */
 
-		for( int i = n; i-- != 0; ) m.add( i );
+		for ( int i = n; i-- != 0; )
+			m.add( i );
 		t.addAll( m );
 		printProbes( m );
 		checkTable( m );
 
-		for( int i = n; i-- != 0; )
+		for ( int i = n; i-- != 0; )
 			assertEquals( "Error: m and t differ on a key during torture-test insertion.", m.add( i ), t.add( ( Integer.valueOf( i ) ) ) );
 
 		assertTrue( "Error: !m.equals(t) after torture-test insertion", m.equals( t ) );
 		assertTrue( "Error: !t.equals(m) after torture-test insertion", t.equals( m ) );
 
-		for( int i = n; i-- != 0; )
+		for ( int i = n; i-- != 0; )
 			assertEquals( "Error: m and t differ on a key during torture-test insertion.", m.remove( i ), t.remove( ( Integer.valueOf( i ) ) ) );
 
 		assertTrue( "Error: !m.equals(t) after torture-test removal", m.equals( t ) );
diff --git a/test/it/unimi/dsi/fastutil/ints/IntOpenHashSetTest.java b/test/it/unimi/dsi/fastutil/ints/IntOpenHashSetTest.java
index 5d173ed..9f89ca3 100644
--- a/test/it/unimi/dsi/fastutil/ints/IntOpenHashSetTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/IntOpenHashSetTest.java
@@ -2,11 +2,12 @@ package it.unimi.dsi.fastutil.ints;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
 import it.unimi.dsi.fastutil.Hash;
 import it.unimi.dsi.fastutil.HashCommon;
+import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
 
 import java.io.IOException;
 import java.util.Arrays;
@@ -17,6 +18,47 @@ import org.junit.Test;
 @SuppressWarnings("rawtypes")
 public class IntOpenHashSetTest {
 
+	@SuppressWarnings("boxing")
+	@Test
+	public void testToArrayNullAtEnd() {
+		IntOpenHashSet s = new IntOpenHashSet( new int[] { 1, 2, 3 } );
+		assertEquals( 3, s.toArray( new Object[ 0 ] ).length );
+		assertEquals( 3, s.toArray( new Integer[ 0 ] ).length );
+		assertTrue( s.toArray( new Integer[] { -1, -1, -1, -1 } )[ 3 ] == null );
+	}
+
+	@Test
+	public void testContainsNull() {
+		IntOpenHashSet s = new IntOpenHashSet( new int[] { 1, 2, 3 } );
+		assertFalse( s.contains( null ) );
+	}
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testEquals() {
+		IntOpenHashSet s = new IntOpenHashSet( new int[] { 1, 2, 3 } );
+		assertFalse( s.equals( new ObjectOpenHashSet<Integer>( new Integer[] { 1, null } ) ) );
+	}
+
+	@Test
+	public void testInfiniteLoop0() {
+        IntOpenHashSet set = new IntOpenHashSet(4, 1.0f);
+        set.add(1);
+        set.add(2);
+        set.add(3);
+        set.remove(2);
+        set.trim();
+        set.remove(1); // Will hang inside this call
+    }
+
+	@Test
+	public void testInfiniteLoop1() {
+        IntOpenHashSet set = new IntOpenHashSet();
+        set.add(1);
+        set.add(2);
+        set.add(3);
+        set.trim(1);
+    }
 
 	@Test
 	public void testStrangeRetainAllCase() {
diff --git a/test/it/unimi/dsi/fastutil/ints/IntSemiIndirectHeapsTest.java b/test/it/unimi/dsi/fastutil/ints/IntSemiIndirectHeapsTest.java
index c74c44e..ccaf099 100644
--- a/test/it/unimi/dsi/fastutil/ints/IntSemiIndirectHeapsTest.java
+++ b/test/it/unimi/dsi/fastutil/ints/IntSemiIndirectHeapsTest.java
@@ -32,6 +32,8 @@ public class IntSemiIndirectHeapsTest {
 		final int[] heap = { 2, 1, 0 };
 
 		IntComparator comparator = new AbstractIntComparator() {
+			private static final long serialVersionUID = 1L;
+
 			@Override
 			public int compare( int k1, int k2 ) {
 				return ( k1 & 3 ) - ( k2 & 3 );
diff --git a/test/it/unimi/dsi/fastutil/longs/LongArraysTest.java b/test/it/unimi/dsi/fastutil/longs/LongArraysTest.java
index b1e63d8..dd4cf6e 100644
--- a/test/it/unimi/dsi/fastutil/longs/LongArraysTest.java
+++ b/test/it/unimi/dsi/fastutil/longs/LongArraysTest.java
@@ -2,7 +2,6 @@ package it.unimi.dsi.fastutil.longs;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertTrue;
-import it.unimi.dsi.fastutil.ints.IntArrays;
 
 import java.util.Random;
 
diff --git a/test/it/unimi/dsi/fastutil/objects/AbstractObject2IntFunctionTest.java b/test/it/unimi/dsi/fastutil/objects/AbstractObject2IntFunctionTest.java
index 67950da..e52f5e8 100644
--- a/test/it/unimi/dsi/fastutil/objects/AbstractObject2IntFunctionTest.java
+++ b/test/it/unimi/dsi/fastutil/objects/AbstractObject2IntFunctionTest.java
@@ -5,6 +5,7 @@ import static org.junit.Assert.*;
 import org.junit.Test;
 
 public class AbstractObject2IntFunctionTest {
+	@SuppressWarnings("deprecation")
 	@Test
 	public void testRemove() {
 		final Object2IntArrayMap<Object> a = new Object2IntArrayMap<Object>();
diff --git a/test/it/unimi/dsi/fastutil/objects/Object2IntOpenHashMapTest.java b/test/it/unimi/dsi/fastutil/objects/Object2IntOpenHashMapTest.java
index c995771..1435d3a 100644
--- a/test/it/unimi/dsi/fastutil/objects/Object2IntOpenHashMapTest.java
+++ b/test/it/unimi/dsi/fastutil/objects/Object2IntOpenHashMapTest.java
@@ -9,7 +9,7 @@ import org.junit.Ignore;
 import org.junit.Test;
 import static org.junit.Assert.*;
 
- at SuppressWarnings("rawtypes")
+ at SuppressWarnings({"rawtypes","deprecation"})
 public class Object2IntOpenHashMapTest {
 
 	private static java.util.Random r = new java.util.Random( 0 );
diff --git a/test/it/unimi/dsi/fastutil/objects/Object2ObjectArrayMapTest.java b/test/it/unimi/dsi/fastutil/objects/Object2ObjectArrayMapTest.java
new file mode 100644
index 0000000..27f7046
--- /dev/null
+++ b/test/it/unimi/dsi/fastutil/objects/Object2ObjectArrayMapTest.java
@@ -0,0 +1,140 @@
+package it.unimi.dsi.fastutil.objects;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import it.unimi.dsi.fastutil.io.BinIO;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.Map.Entry;
+
+import org.junit.Test;
+
+public class Object2ObjectArrayMapTest  {
+
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testContainsNull() {
+		Object2ObjectArrayMap<Integer,Integer> m = new Object2ObjectArrayMap<Integer,Integer>( new Integer[] { 1, 2, 3 },  new Integer[] { 1, 2, 3 } );
+		assertFalse( m.containsKey( null ) );
+		assertTrue( m.get( null ) == null );
+	}
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testEquals() {
+		Object2ObjectArrayMap<Integer,Integer> a1 = new Object2ObjectArrayMap<Integer,Integer>();
+		a1.put(0,  1);
+		a1.put(1000, -1);
+		a1.put(2000, 3);
+
+		Object2ObjectArrayMap<Integer,Integer> a2 = new Object2ObjectArrayMap<Integer,Integer>();
+		a2.put(0,  1);
+		a2.put(1000, -1);
+		a2.put(2000, 3);
+
+		assertEquals(a1, a2);
+
+		Object2ObjectArrayMap<Integer,Integer> m = new Object2ObjectArrayMap<Integer,Integer>( new Integer[] { 1, 2 },  new Integer[] { 1, 2 } );
+		assertFalse( m.equals( new Object2ObjectOpenHashMap<Integer,Integer>( new Integer[] { 1, null }, new Integer[] { 1, 1 } ) ) );
+	}
+
+	@SuppressWarnings({ "boxing" })
+	@Test
+	public void testMap() {
+		for( int i = 0; i <= 1; i++ ) {
+			Object2ObjectArrayMap<Integer,Integer> m = i == 0 ? new Object2ObjectArrayMap<Integer,Integer>() : new Object2ObjectArrayMap<Integer,Integer>( new Integer[] { 0 }, new Integer[] { 0 } );
+			assertEquals( null, m.put( 1, 1 ) );
+			assertEquals( 1 + i, m.size() );
+			assertTrue( m.containsKey( 1 ) );
+			assertTrue( m.containsValue( 1 ) );
+			assertEquals( null, m.put(  2, 2  ) );
+			assertTrue( m.containsKey( 2 ) );
+			assertTrue( m.containsValue( 2 ) );
+			assertEquals( 2 + i, m.size() );
+			assertEquals(  Integer.valueOf( 1 ), m.put( 1, 3 ) );
+			assertTrue( m.containsValue( 3 ) );
+			assertEquals( null, m.remove( 3 ) );
+			assertEquals( null, m.put(  3, 3  ) );
+			assertTrue( m.containsKey( 3 ) );
+			assertTrue( m.containsValue( 3 ) );
+			assertEquals( 3 + i, m.size() );
+			assertEquals( Integer.valueOf( 3 ), m.get( 1 ) );
+			assertEquals( Integer.valueOf( 2 ), m.get( 2 ) );
+			assertEquals( Integer.valueOf( 3 ), m.get( 3 ) );
+			assertEquals( new ObjectOpenHashSet<Integer>( i == 0 ? new Integer[] { 1, 2, 3 } : new Integer[] { 0, 1, 2, 3 } ), new ObjectOpenHashSet<Integer>( m.keySet().iterator() ) );
+			assertEquals( new ObjectOpenHashSet<Integer>( i == 0 ? new Integer[] { 3, 2, 3 } : new Integer[] { 0, 3, 2, 3 } ), new ObjectOpenHashSet<Integer>( m.values().iterator() ) );
+
+			for( Entry<Integer, Integer> e: m.entrySet() ) assertEquals( e.getValue(), m.get( e.getKey() ) );
+
+			assertTrue( i != 0 == m.entrySet().contains( new AbstractObject2ObjectMap.BasicEntry<Integer,Integer>( 0, 0 ) ) );
+			assertTrue( m.entrySet().contains( new AbstractObject2ObjectMap.BasicEntry<Integer,Integer>( 1, 3 ) ) );
+			assertTrue( m.entrySet().contains( new AbstractObject2ObjectMap.BasicEntry<Integer,Integer>( 2, 2 ) ) );
+			assertTrue( m.entrySet().contains( new AbstractObject2ObjectMap.BasicEntry<Integer,Integer>( 3, 3 ) ) );
+			assertFalse( m.entrySet().contains( new AbstractObject2ObjectMap.BasicEntry<Integer,Integer>( 1, 2 ) ) );
+			assertFalse( m.entrySet().contains( new AbstractObject2ObjectMap.BasicEntry<Integer,Integer>( 2, 1 ) ) );
+
+			assertEquals( Integer.valueOf( 3 ), m.remove( 3 ) );
+			assertEquals( 2 + i, m.size() );
+			assertEquals( Integer.valueOf( 3 ), m.remove( 1 ) );
+			assertEquals( 1 + i, m.size() );
+			assertFalse( m.containsKey( 1 ) );
+			assertEquals( Integer.valueOf( 2 ), m.remove( 2 ) );
+			assertEquals( 0 + i, m.size() );
+			assertFalse( m.containsKey( 1 ) );
+		}
+	}
+	
+	@SuppressWarnings("boxing")
+	@Test
+	public void testClone() {
+		Object2ObjectArrayMap<Integer,Integer> m = new Object2ObjectArrayMap<Integer,Integer>();
+		assertEquals( m, m.clone() );
+		m.put( 0, 1 );
+		assertEquals( m, m.clone() );
+		m.put( 0, 2 );
+		assertEquals( m, m.clone() );
+		m.put( 1, 2 );
+		assertEquals( m, m.clone() );
+		m.remove( 1 );
+		assertEquals( m, m.clone() );
+	}
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testSerialisation() throws IOException, ClassNotFoundException {
+		Object2ObjectArrayMap<Integer,Integer> m = new Object2ObjectArrayMap<Integer,Integer>();
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		ObjectOutputStream oos = new ObjectOutputStream( baos );
+		oos.writeObject( m );
+		oos.close();
+		assertEquals( m, BinIO.loadObject( new ByteArrayInputStream( baos.toByteArray() ) ) );
+		
+		m.put( 0, 1 );
+		m.put( 1, 2 );
+
+		baos.reset();
+		oos = new ObjectOutputStream( baos );
+		oos.writeObject( m );
+		oos.close();
+		assertEquals( m, BinIO.loadObject( new ByteArrayInputStream( baos.toByteArray() ) ) );
+	}
+	
+	@SuppressWarnings("boxing")
+	@Test
+	public void testIteratorRemove() {
+		Object2ObjectArrayMap<Integer,Integer> m = new Object2ObjectArrayMap<Integer,Integer>( new Integer[] { 1, 2, 3 },  new Integer[] { 1, 2, 3 } );
+		ObjectIterator<Entry<Integer, Integer>> keySet = m.entrySet().iterator();
+		keySet.next();
+		keySet.next();
+		keySet.remove();
+		assertTrue( keySet.hasNext() );
+		Entry<Integer, Integer> next = keySet.next();
+		assertEquals( Integer.valueOf( 3 ), next.getKey() );
+		assertEquals( Integer.valueOf( 3 ), next.getValue() );
+	}
+}
diff --git a/test/it/unimi/dsi/fastutil/objects/ObjectAVLTreeSetTest.java b/test/it/unimi/dsi/fastutil/objects/ObjectAVLTreeSetTest.java
new file mode 100644
index 0000000..2339e2c
--- /dev/null
+++ b/test/it/unimi/dsi/fastutil/objects/ObjectAVLTreeSetTest.java
@@ -0,0 +1,56 @@
+package it.unimi.dsi.fastutil.objects;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import it.unimi.dsi.fastutil.ints.Int2IntAVLTreeMap;
+import org.junit.Test;
+
+public class ObjectAVLTreeSetTest {
+
+	@Test
+	public void testGet() {
+		ObjectAVLTreeSet<Integer> s = new ObjectAVLTreeSet<Integer>();
+		Integer o = new Integer( 0 );
+		s.add( o );
+		assertSame( o,  s.get( new Integer( 0 ) ) );
+	}
+
+	@Test
+	public void testAddTo() {
+		Int2IntAVLTreeMap a = new Int2IntAVLTreeMap();
+		Int2IntAVLTreeMap b = new Int2IntAVLTreeMap();
+
+		// test addTo with empty map
+		a.addTo(0, 1); 			// 0 -> 1
+		assertEquals(1, a.get(0));
+
+		// test addTo with empty map and weird defaultReturnValue
+		b.defaultReturnValue(100);
+		a.addTo(0, 0); 			// 0 -> 100
+		assertEquals(100, b.get(0));
+
+		// test addTo with existing values
+		a.addTo(0, 1); 	 	  // 0 -> 2
+		b.addTo(0, -100); 	// 0 -> 0
+		assertEquals(2, a.get(0));
+		assertEquals(0, b.get(0));
+
+		// test addTo with overflow values
+		a.put(0, Integer.MAX_VALUE);
+		a.addTo(0, 1);			// 0 -> MIN_VALUE
+		assertEquals(Integer.MIN_VALUE, a.get(0));
+
+		// test various addTo operations
+		a.put(0, 0);
+		a.put(1, 1);
+		a.put(2, 2);
+
+		a.addTo(0, 10);			// 0 -> 10
+		a.addTo(1, 9);			// 1 -> 10
+		a.addTo(2, 8);			// 2 -> 10
+		assertEquals(10, a.get(0));
+		assertEquals(10, a.get(1));
+		assertEquals(10, a.get(2));
+	}
+}
diff --git a/test/it/unimi/dsi/fastutil/objects/ObjectArrayListTest.java b/test/it/unimi/dsi/fastutil/objects/ObjectArrayListTest.java
new file mode 100644
index 0000000..25d330b
--- /dev/null
+++ b/test/it/unimi/dsi/fastutil/objects/ObjectArrayListTest.java
@@ -0,0 +1,19 @@
+package it.unimi.dsi.fastutil.objects;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class ObjectArrayListTest {
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testRemoveAll() {
+		ObjectArrayList<Integer> l = ObjectArrayList.wrap( new Integer[] { 0, 1, 1, 2 } );
+		l.removeAll( ObjectSets.singleton( 1 ) );
+		assertEquals( ObjectArrayList.wrap( new Integer[] { 0, 2 } ), l );
+		assertTrue( l.elements()[ 2 ] == null );
+		assertTrue( l.elements()[ 3 ] == null );
+	}
+}
diff --git a/test/it/unimi/dsi/fastutil/objects/ObjectArrayPriorityQueueTest.java b/test/it/unimi/dsi/fastutil/objects/ObjectArrayPriorityQueueTest.java
new file mode 100644
index 0000000..39ca56f
--- /dev/null
+++ b/test/it/unimi/dsi/fastutil/objects/ObjectArrayPriorityQueueTest.java
@@ -0,0 +1,171 @@
+package it.unimi.dsi.fastutil.objects;
+
+import static org.junit.Assert.assertEquals;
+import it.unimi.dsi.fastutil.io.BinIO;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.Test;
+
+ at SuppressWarnings({"boxing","unchecked"})
+public class ObjectArrayPriorityQueueTest {
+	
+	@Test
+	public void testEnqueueDequeue() {
+		ObjectArrayPriorityQueue<Integer> q = new ObjectArrayPriorityQueue<Integer>();
+		ObjectHeapPriorityQueue<Integer> h = new ObjectHeapPriorityQueue<Integer>();
+		for( int i = 0; i < 100; i++ ) {
+			q.enqueue( i );
+			h.enqueue( i );
+		}
+		for( int i = 0; i < 100; i++ ) {
+			assertEquals( h.first(), q.first() );
+			assertEquals( h.dequeue(), q.dequeue() );
+		}
+
+		q = new ObjectArrayPriorityQueue<Integer>( 10 );
+		h.clear();
+		for( int i = 0; i < 100; i++ ) {
+			q.enqueue( i );
+			h.enqueue( i );
+		}
+		for( int i = 0; i < 100; i++ ) {
+			assertEquals( h.first(), q.first() );
+			assertEquals( h.dequeue(), q.dequeue() );
+		}
+
+		q = new ObjectArrayPriorityQueue<Integer>( 200 );
+		h.clear();
+		for( int i = 0; i < 100; i++ ) {
+			q.enqueue( i );
+			h.enqueue( i );
+		}
+		for( int i = 0; i < 100; i++ ) {
+			assertEquals( h.first(), q.first() );
+			assertEquals( h.dequeue(), q.dequeue() );
+		}
+	}
+
+
+	@Test
+	public void testEnqueueDequeueComp() {
+		ObjectArrayPriorityQueue<Integer> q = new ObjectArrayPriorityQueue<Integer>( ObjectComparators.OPPOSITE_COMPARATOR );
+		ObjectHeapPriorityQueue<Integer> h = new ObjectHeapPriorityQueue<Integer>( ObjectComparators.OPPOSITE_COMPARATOR );
+		for( int i = 0; i < 100; i++ ) {
+			q.enqueue( i );
+			h.enqueue( i );
+		}
+		for( int i = 0; i < 100; i++ ) {
+			assertEquals( h.first(), q.first() );
+			assertEquals( h.dequeue(), q.dequeue() );
+		}
+
+		q = new ObjectArrayPriorityQueue<Integer>( 10, ObjectComparators.OPPOSITE_COMPARATOR );
+		h.clear();
+		for( int i = 0; i < 100; i++ ) {
+			q.enqueue( i );
+			h.enqueue( i );
+		}
+		for( int i = 0; i < 100; i++ ) {
+			assertEquals( h.first(), q.first() );
+			assertEquals( h.dequeue(), q.dequeue() );
+		}
+
+		q = new ObjectArrayPriorityQueue<Integer>( 200, ObjectComparators.OPPOSITE_COMPARATOR );
+		h.clear();
+		for( int i = 0; i < 100; i++ ) {
+			q.enqueue( i );
+			h.enqueue( i );
+		}
+		for( int i = 0; i < 100; i++ ) {
+			assertEquals( h.first(), q.first() );
+			assertEquals( h.dequeue(), q.dequeue() );
+		}
+	}
+	
+	@Test
+	public void testMix() {
+		ObjectArrayPriorityQueue<Integer> q = new ObjectArrayPriorityQueue<Integer>();
+		ObjectHeapPriorityQueue<Integer> h = new ObjectHeapPriorityQueue<Integer>();
+		for( int i = 0; i < 200; i++ ) {
+			for( int j = 0; j < 20; j++ ) {
+				q.enqueue( j + i * 20 );
+				h.enqueue( j + i * 20 );
+			}
+			for( int j = 0; j < 10; j++ ) assertEquals( h.dequeue(), q.dequeue() );
+		}
+		
+		q = new ObjectArrayPriorityQueue<Integer>( 10 );
+		h = new ObjectHeapPriorityQueue<Integer>();
+		for( int i = 0; i < 200; i++ ) {
+			for( int j = 0; j < 20; j++ ) {
+				q.enqueue( j + i * -20 );
+				h.enqueue( j + i * -20 );
+				q.first();
+			}
+			for( int j = 0; j < 10; j++ ) assertEquals( h.dequeue(), q.dequeue() );
+		}
+
+		q = new ObjectArrayPriorityQueue<Integer>( 200 );
+		h = new ObjectHeapPriorityQueue<Integer>();
+		for( int i = 0; i < 200; i++ ) {
+			for( int j = 0; j < 20; j++ ) {
+				q.enqueue( j + i * 20 );
+				h.enqueue( j + i * 20 );
+			}
+			for( int j = 0; j < 10; j++ ) assertEquals( h.dequeue(), q.dequeue() );
+		}
+	}
+
+	@Test
+	public void testMixComp() {
+		ObjectArrayPriorityQueue<Integer> q = new ObjectArrayPriorityQueue<Integer>( ObjectComparators.OPPOSITE_COMPARATOR );
+		ObjectHeapPriorityQueue<Integer> h = new ObjectHeapPriorityQueue<Integer>( ObjectComparators.OPPOSITE_COMPARATOR );
+		for( int i = 0; i < 200; i++ ) {
+			for( int j = 0; j < 20; j++ ) {
+				q.enqueue( j + i * 20 );
+				h.enqueue( j + i * 20 );
+			}
+			for( int j = 0; j < 10; j++ ) assertEquals( h.dequeue(), q.dequeue() );
+		}
+		
+		q = new ObjectArrayPriorityQueue<Integer>( 10, ObjectComparators.OPPOSITE_COMPARATOR );
+		h = new ObjectHeapPriorityQueue<Integer>( ObjectComparators.OPPOSITE_COMPARATOR );
+		for( int i = 0; i < 200; i++ ) {
+			for( int j = 0; j < 20; j++ ) {
+				q.enqueue( j + i * -20 );
+				h.enqueue( j + i * -20 );
+				q.first();
+			}
+			for( int j = 0; j < 10; j++ ) assertEquals( h.dequeue(), q.dequeue() );
+		}
+
+		q = new ObjectArrayPriorityQueue<Integer>( 200, ObjectComparators.OPPOSITE_COMPARATOR );
+		h = new ObjectHeapPriorityQueue<Integer>( ObjectComparators.OPPOSITE_COMPARATOR );
+		for( int i = 0; i < 200; i++ ) {
+			for( int j = 0; j < 20; j++ ) {
+				q.enqueue( j + i * 20 );
+				h.enqueue( j + i * 20 );
+			}
+			for( int j = 0; j < 10; j++ ) assertEquals( h.dequeue(), q.dequeue() );
+		}
+	}
+
+	@Test
+	public void testSerialize() throws IOException, ClassNotFoundException {
+		ObjectArrayPriorityQueue<Integer> q = new ObjectArrayPriorityQueue<Integer>();
+		for( int i = 0; i < 100; i++ ) q.enqueue( i );
+		
+		File file = File.createTempFile( getClass().getPackage().getName() + "-", "-tmp" );
+		file.deleteOnExit();
+		BinIO.storeObject( q, file );
+		ObjectArrayPriorityQueue<Integer> r = (ObjectArrayPriorityQueue<Integer>)BinIO.loadObject( file );
+		file.delete();
+		for( int i = 0; i < 100; i++ ) {
+			assertEquals( q.first(), r.first() );
+			assertEquals( q.dequeue(), r.dequeue() );
+		}
+	}
+}
+
diff --git a/test/it/unimi/dsi/fastutil/ints/IntArraySetTest.java b/test/it/unimi/dsi/fastutil/objects/ObjectArraySetTest.java
similarity index 52%
copy from test/it/unimi/dsi/fastutil/ints/IntArraySetTest.java
copy to test/it/unimi/dsi/fastutil/objects/ObjectArraySetTest.java
index ff7fb11..66ae12b 100644
--- a/test/it/unimi/dsi/fastutil/ints/IntArraySetTest.java
+++ b/test/it/unimi/dsi/fastutil/objects/ObjectArraySetTest.java
@@ -1,23 +1,33 @@
-package it.unimi.dsi.fastutil.ints;
+package it.unimi.dsi.fastutil.objects;
 
-import it.unimi.dsi.fastutil.ints.IntArraySet;
-import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
+import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
 import it.unimi.dsi.fastutil.io.BinIO;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.ObjectOutputStream;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
 
 import org.junit.Test;
+
 import static org.junit.Assert.*;
 
-public class IntArraySetTest {
-	
+public class ObjectArraySetTest {
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testNullInEquals() {
+		assertFalse( new ObjectArraySet<Integer>( Arrays.asList( 42 ) ).equals( Collections.singleton( null ) ) );
+	}
+
+	@SuppressWarnings("boxing")
 	@Test
 	public void testSet() {
-		for( int i = 1; i <= 1; i++ ) {
-			final IntArraySet s = i == 0 ? new IntArraySet() : new IntArraySet( new int[ i ] );
+		for( int i = 0; i <= 1; i++ ) {
+			final ObjectArraySet<Integer> s = i == 0 ? new ObjectArraySet<Integer>() : new ObjectArraySet<Integer>( new Integer[] { 0 } );
 			assertTrue( s.add( 1 ) );
 			assertEquals( 1 + i, s.size() );
 			assertTrue( s.contains( 1 ) );
@@ -31,7 +41,7 @@ public class IntArraySetTest {
 			assertTrue( s.contains( 1 ) );
 			assertTrue( s.contains( 2 ) );
 			assertTrue( s.contains( 2 ) );
-			assertEquals( new IntOpenHashSet( i == 0 ? new int[] { 1, 2, 3 } : new int[] { 0, 1, 2, 3 } ), new IntOpenHashSet( s.iterator() ) );
+			assertEquals( new ObjectOpenHashSet<Integer>( i == 0 ? new Integer[] { 1, 2, 3 } : new Integer[] { 0, 1, 2, 3 } ), new ObjectOpenHashSet<Integer>( s.iterator() ) );
 			assertTrue( s.remove( 3 ) );
 			assertEquals( 2 + i, s.size() );
 			assertTrue( s.remove( 1 ) );
@@ -43,9 +53,10 @@ public class IntArraySetTest {
 		}
 	}
 	
+	@SuppressWarnings("boxing")
 	@Test
 	public void testClone() {
-		IntArraySet s = new IntArraySet();
+		ObjectArraySet<Integer> s = new ObjectArraySet<Integer>();
 		assertEquals( s, s.clone() );
 		s.add( 0 );
 		assertEquals( s, s.clone() );
@@ -59,9 +70,10 @@ public class IntArraySetTest {
 		assertEquals( s, s.clone() );
 	}
 
+	@SuppressWarnings("boxing")
 	@Test
 	public void testSerialisation() throws IOException, ClassNotFoundException {
-		IntArraySet s = new IntArraySet();
+		ObjectArraySet<Integer> s = new ObjectArraySet<Integer>();
 		ByteArrayOutputStream baos = new ByteArrayOutputStream();
 		ObjectOutputStream oos = new ObjectOutputStream( baos );
 		oos.writeObject( s );
@@ -77,4 +89,28 @@ public class IntArraySetTest {
 		oos.close();
 		assertEquals( s, BinIO.loadObject( new ByteArrayInputStream( baos.toByteArray() ) ) );
 	}
+
+	@Test
+	@SuppressWarnings("boxing")
+	public void testRemove() {
+		ObjectSet<Integer> set = new ObjectArraySet<Integer>( new Integer[] { 42 } );
+
+		Iterator<Integer> iterator = set.iterator();
+		assertTrue(iterator.hasNext());
+		iterator.next();
+		iterator.remove();
+		assertFalse( iterator.hasNext() );
+		assertEquals( 0, set.size() );
+
+		set = new ObjectArraySet<Integer>( new Integer[] { 42, 43, 44 } );
+
+		iterator = set.iterator();
+		assertTrue(iterator.hasNext());
+		iterator.next();
+		iterator.next();
+		iterator.remove();
+		assertEquals( Integer.valueOf( 44 ), iterator.next() );
+		assertFalse( iterator.hasNext() );
+		assertEquals( new ObjectArraySet<Integer>( new Integer[] { 42, 44 } ), set );
+	}
 }
diff --git a/test/it/unimi/dsi/fastutil/objects/ObjectBigArrayBigListTest.java b/test/it/unimi/dsi/fastutil/objects/ObjectBigArrayBigListTest.java
index 0cc841b..ebf10ec 100644
--- a/test/it/unimi/dsi/fastutil/objects/ObjectBigArrayBigListTest.java
+++ b/test/it/unimi/dsi/fastutil/objects/ObjectBigArrayBigListTest.java
@@ -1,7 +1,11 @@
 package it.unimi.dsi.fastutil.objects;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import it.unimi.dsi.fastutil.BigArrays;
 
+import java.util.Collections;
 import java.util.Iterator;
 
 import org.junit.Ignore;
@@ -10,6 +14,23 @@ import org.junit.Test;
 @SuppressWarnings("rawtypes")
 public class ObjectBigArrayBigListTest {
 
+	@Test
+	public void testRemoveAllModifiesCollection() {
+		ObjectBigList<Integer> list = new ObjectBigArrayBigList<Integer>();
+		assertFalse( list.removeAll( Collections.emptySet() ) );
+		assertEquals( ObjectBigLists.EMPTY_BIG_LIST, list );
+	}
+
+	@SuppressWarnings("boxing")
+	@Test
+	public void testRemoveAllSkipSegment() {
+		ObjectBigList<Integer> list = new ObjectBigArrayBigList<Integer>();
+		for( long i = 0; i < BigArrays.SEGMENT_SIZE + 10; i++ ) list.add( Integer.valueOf( (int)( i % 2 ) ) );
+		assertTrue( list.removeAll( ObjectSets.singleton( 1 ) ) );
+		assertEquals( BigArrays.SEGMENT_SIZE / 2 + 5, list.size64() );
+		for( long i = 0; i < BigArrays.SEGMENT_SIZE / 2 + 5; i++ ) assertEquals( Integer.valueOf( 0 ), list.get( i ) );
+	}
+
 	private static java.util.Random r = new java.util.Random( 0 );
 
 	private static int genKey() {
diff --git a/test/it/unimi/dsi/fastutil/objects/ObjectBigArraysTest.java b/test/it/unimi/dsi/fastutil/objects/ObjectBigArraysTest.java
index 2c8353a..1e5b2ab 100644
--- a/test/it/unimi/dsi/fastutil/objects/ObjectBigArraysTest.java
+++ b/test/it/unimi/dsi/fastutil/objects/ObjectBigArraysTest.java
@@ -76,8 +76,8 @@ public class ObjectBigArraysTest {
 		Integer[][] b = ObjectBigArrays.wrap( a.clone() );
 
 		for( int i = -1; i < 20; i++ ) { 
-			assertEquals( "" + i, Arrays.binarySearch( a, i ), ObjectBigArrays.binarySearch( b, i ) );
-			assertEquals( "" + i, Arrays.binarySearch( a, i ), ObjectBigArrays.binarySearch( b, i, ObjectComparators.NATURAL_COMPARATOR ) );
+			assertEquals( String.valueOf(i), Arrays.binarySearch( a, i ), ObjectBigArrays.binarySearch( b, i ) );
+			assertEquals( String.valueOf(i), Arrays.binarySearch( a, i ), ObjectBigArrays.binarySearch( b, i, ObjectComparators.NATURAL_COMPARATOR ) );
 		}
 	
 		for( int i = -1; i < 20; i++ ) {
diff --git a/test/it/unimi/dsi/fastutil/objects/ObjectHeapPriorityQueueTest.java b/test/it/unimi/dsi/fastutil/objects/ObjectHeapPriorityQueueTest.java
new file mode 100644
index 0000000..1d311ba
--- /dev/null
+++ b/test/it/unimi/dsi/fastutil/objects/ObjectHeapPriorityQueueTest.java
@@ -0,0 +1,30 @@
+package it.unimi.dsi.fastutil.objects;
+
+import static org.junit.Assert.assertEquals;
+import it.unimi.dsi.fastutil.io.BinIO;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.junit.Test;
+
+public class ObjectHeapPriorityQueueTest {
+	
+	@SuppressWarnings({ "unchecked", "boxing" })
+	@Test
+	public void testSerialize() throws IOException, ClassNotFoundException {
+		ObjectHeapPriorityQueue<Integer> q = new ObjectHeapPriorityQueue<Integer>();
+		for( int i = 0; i < 100; i++ ) q.enqueue( i );
+		
+		File file = File.createTempFile( getClass().getPackage().getName() + "-", "-tmp" );
+		file.deleteOnExit();
+		BinIO.storeObject( q, file );
+		ObjectHeapPriorityQueue<Integer> r = (ObjectHeapPriorityQueue<Integer>)BinIO.loadObject( file );
+		file.delete();
+		for( int i = 0; i < 100; i++ ) {
+			assertEquals( q.first(), r.first() );
+			assertEquals( q.dequeue(), r.dequeue() );
+		}
+	}
+}
+
diff --git a/test/it/unimi/dsi/fastutil/objects/ObjectOpenCustomHashSetTest.java b/test/it/unimi/dsi/fastutil/objects/ObjectOpenCustomHashSetTest.java
new file mode 100644
index 0000000..1b04fca
--- /dev/null
+++ b/test/it/unimi/dsi/fastutil/objects/ObjectOpenCustomHashSetTest.java
@@ -0,0 +1,33 @@
+package it.unimi.dsi.fastutil.objects;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import it.unimi.dsi.fastutil.Hash;
+
+import org.junit.Test;
+
+public class ObjectOpenCustomHashSetTest {
+
+	@Test
+	public void testGetNullKey() {
+		final ObjectOpenCustomHashSet<Integer> s = new ObjectOpenCustomHashSet<Integer>( new Hash.Strategy<Integer>() {
+
+			@Override
+			public int hashCode( Integer o ) {
+				return o == null ? 0 : o.intValue() % 10;
+			}
+
+			@Override
+			public boolean equals( Integer a, Integer b ) {
+				if ( ( ( a == null ) != ( b == null ) ) || a == null ) return false;
+				return ( a.intValue() - b.intValue() % 10 ) == 0;
+			}
+		});
+		
+		s.add( Integer.valueOf( 10 ) );
+		assertTrue( s.contains( Integer.valueOf( 0 ) ) );
+		assertEquals( 10, s.iterator().next().intValue() );
+	}
+
+
+}
diff --git a/test/it/unimi/dsi/fastutil/objects/ObjectOpenHashBigSetTest.java b/test/it/unimi/dsi/fastutil/objects/ObjectOpenHashBigSetTest.java
index ccbfa26..efc7791 100644
--- a/test/it/unimi/dsi/fastutil/objects/ObjectOpenHashBigSetTest.java
+++ b/test/it/unimi/dsi/fastutil/objects/ObjectOpenHashBigSetTest.java
@@ -146,6 +146,18 @@ public class ObjectOpenHashBigSetTest {
 			Object T = genKey();
 			assertTrue( "Error: divergence between t and m (standard method)", m.contains( ( T ) ) == t.contains( ( T ) ) );
 		}
+		/*
+		 * Check that addOrGet does indeed return the original instance, not a copy
+		 */
+		for ( java.util.Iterator i = m.iterator(); i.hasNext(); ) {
+			Object e = i.next();
+			Object e2 = m.addOrGet( new StringBuilder((String)e).toString() ); // Make a new object!
+			assertTrue( "addOrGet does not return the same object", e == e2 /* NOT just equals, but identity */ );
+		}
+		/* This should not have modified the table */
+		assertTrue( "Error: !m.equals(t) after addOrGet no-op", m.equals( t ) );
+		assertTrue( "Error: !t.equals(m) after addOrGet no-op", t.equals( m ) );
+
 		/* Now we put and remove random data in m and t, checking that the result is the same. */
 		for ( int i = 0; i < 20 * n; i++ ) {
 			Object T = genKey();
@@ -205,7 +217,7 @@ public class ObjectOpenHashBigSetTest {
 			assertTrue( "Error: divergence in remove() between t and m after save/read", m.remove( ( T ) ) == t.remove( ( T ) ) );
 		}
 		assertTrue( "Error: !m.equals(t) after post-save/read removal", m.equals( t ) );
-		assertTrue( "Error: !t.equals(m) after post-save/read removal", t.equals( m ) ); 		
+		assertTrue( "Error: !t.equals(m) after post-save/read removal", t.equals( m ) );
 		/*
 		 * Now we take out of m everything , and check that it is empty.
 		 */
diff --git a/test/it/unimi/dsi/fastutil/objects/ObjectOpenHashSetTest.java b/test/it/unimi/dsi/fastutil/objects/ObjectOpenHashSetTest.java
index 1bbc4f8..9026407 100644
--- a/test/it/unimi/dsi/fastutil/objects/ObjectOpenHashSetTest.java
+++ b/test/it/unimi/dsi/fastutil/objects/ObjectOpenHashSetTest.java
@@ -153,6 +153,18 @@ public class ObjectOpenHashSetTest {
 			Object T = genKey();
 			assertTrue( "Error: divergence between t and m (standard method)", m.contains( ( T ) ) == t.contains( ( T ) ) );
 		}
+		/*
+		 * Check that addOrGet does indeed return the original instance, not a copy
+		 */
+		for ( java.util.Iterator i = m.iterator(); i.hasNext(); ) {
+			Object e = i.next();
+			Object e2 = m.addOrGet( new StringBuilder((String)e).toString() ); // Make a new object!
+			assertTrue( "addOrGet does not return the same object", e == e2 );
+		}
+		/* This should not have modified the table */
+		assertTrue( "Error: !m.equals(t) after addOrGet no-op", m.equals( t ) );
+		assertTrue( "Error: !t.equals(m) after addOrGet no-op", t.equals( m ) );
+
 		/* Now we put and remove random data in m and t, checking that the result is the same. */
 		for ( int i = 0; i < 20 * n; i++ ) {
 			Object T = genKey();
@@ -162,7 +174,7 @@ public class ObjectOpenHashSetTest {
 		}
 		assertTrue( "Error: !m.equals(t) after removal", m.equals( t ) );
 		assertTrue( "Error: !t.equals(m) after removal", t.equals( m ) );
-		
+
 		checkTable( m );
 		printProbes( m );
 
@@ -218,7 +230,7 @@ public class ObjectOpenHashSetTest {
 			assertTrue( "Error: divergence in remove() between t and m after save/read", m.remove( ( T ) ) == t.remove( ( T ) ) );
 		}
 		assertTrue( "Error: !m.equals(t) after post-save/read removal", m.equals( t ) );
-		assertTrue( "Error: !t.equals(m) after post-save/read removal", t.equals( m ) ); 		
+		assertTrue( "Error: !t.equals(m) after post-save/read removal", t.equals( m ) );
 		/*
 		 * Now we take out of m everything , and check that it is empty.
 		 */
diff --git a/test/it/unimi/dsi/fastutil/objects/ObjectRBTreeSetTest.java b/test/it/unimi/dsi/fastutil/objects/ObjectRBTreeSetTest.java
new file mode 100644
index 0000000..fcfd3a3
--- /dev/null
+++ b/test/it/unimi/dsi/fastutil/objects/ObjectRBTreeSetTest.java
@@ -0,0 +1,56 @@
+package it.unimi.dsi.fastutil.objects;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+
+import it.unimi.dsi.fastutil.ints.Int2IntRBTreeMap;
+import org.junit.Test;
+
+public class ObjectRBTreeSetTest {
+
+	@Test
+	public void testGet() {
+		ObjectRBTreeSet<Integer> s = new ObjectRBTreeSet<Integer>();
+		Integer o = new Integer( 0 );
+		s.add( o );
+		assertSame( o,  s.get( new Integer( 0 ) ) );
+	}
+
+	@Test
+	public void testAddTo() {
+		Int2IntRBTreeMap a = new Int2IntRBTreeMap();
+		Int2IntRBTreeMap b = new Int2IntRBTreeMap();
+
+		// test addTo with empty map
+		a.addTo(0, 1); 			// 0 -> 1
+		assertEquals(1, a.get(0));
+
+		// test addTo with empty map and weird defaultReturnValue
+		b.defaultReturnValue(100);
+		a.addTo(0, 0); 			// 0 -> 100
+		assertEquals(100, b.get(0));
+
+		// test addTo with existing values
+		a.addTo(0, 1); 	 	  // 0 -> 2
+		b.addTo(0, -100); 	// 0 -> 0
+		assertEquals(2, a.get(0));
+		assertEquals(0, b.get(0));
+
+		// test addTo with overflow values
+		a.put(0, Integer.MAX_VALUE);
+		a.addTo(0, 1);			// 0 -> MIN_VALUE
+		assertEquals(Integer.MIN_VALUE, a.get(0));
+
+		// test various addTo operations
+		a.put(0, 0);
+		a.put(1, 1);
+		a.put(2, 2);
+
+		a.addTo(0, 10);			// 0 -> 10
+		a.addTo(1, 9);			// 1 -> 10
+		a.addTo(2, 8);			// 2 -> 10
+		assertEquals(10, a.get(0));
+		assertEquals(10, a.get(1));
+		assertEquals(10, a.get(2));
+	}
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/libfastutil-java.git



More information about the pkg-java-commits mailing list