[Git][java-team/libfastutil-java][upstream] New upstream version 8.4.2

Pierre Gruet gitlab at salsa.debian.org
Wed Oct 21 22:56:13 BST 2020



Pierre Gruet pushed to branch upstream at Debian Java Maintainers / libfastutil-java


Commits:
3d7591be by Pierre Gruet at 2020-10-21T20:38:33+02:00
New upstream version 8.4.2
- - - - -


21 changed files:

- CHANGES
- build.properties
- + drv/ArrayFrontCodedBigList.drv
- drv/ArrayFrontCodedList.drv
- drv/ArrayMap.drv
- drv/ArraySet.drv
- drv/BigArrays.drv
- drv/BigArraysCommon.drv
- drv/BigArraysFragment.drv
- drv/List.drv
- drv/OpenHashMap.drv
- drv/OpenHashSet.drv
- gencsource.sh
- makefile
- pom.xml
- src/it/unimi/dsi/fastutil/SafeMath.java
- src/overview.html
- + test/it/unimi/dsi/fastutil/ints/Int2IntArrayMapTest.java
- test/it/unimi/dsi/fastutil/ints/IntArraySetTest.java
- test/it/unimi/dsi/fastutil/ints/IntBigArraysTest.java
- test/it/unimi/dsi/fastutil/ints/IntOpenHashSetTest.java


Changes:

=====================================
CHANGES
=====================================
@@ -1,3 +1,24 @@
+8.4.2
+
+- Big front-coded lists.
+
+8.4.1
+
+- Ported basic parallel quicksort to big arrays.
+
+8.4.0
+
+- Limited support for atomic big arrays of integers and longs.
+
+8.3.2
+
+- The documentation and the constructor for hash-based containers
+  was allowing a load factor of 1. Thanks to Andy Clegg for
+  reporting this bug.
+
+- The copy constructor of array-based containers are now more efficient.
+  Thanks to Vladimir Krivosheev for proposing this enhancement.
+
 8.3.1
 
 - Fixed old-standing bug in the remove() method of the key set of


=====================================
build.properties
=====================================
@@ -3,7 +3,7 @@ javadoc.base=/usr/share/javadoc
 
 build.sysclasspath=ignore
 
-version=8.3.1
+version=8.4.2
 
 dist=dist
 src=src


=====================================
drv/ArrayFrontCodedBigList.drv
=====================================
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2002-2020 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 static it.unimi.dsi.fastutil.BigArrays.copyFromBig;
+import static it.unimi.dsi.fastutil.BigArrays.copyToBig;
+import static it.unimi.dsi.fastutil.BigArrays.grow;
+import static it.unimi.dsi.fastutil.BigArrays.trim;
+
+import static PACKAGE.ARRAY_FRONT_CODED_LIST.count;
+import static PACKAGE.ARRAY_FRONT_CODED_LIST.readInt;
+import static PACKAGE.ARRAY_FRONT_CODED_LIST.writeInt;
+
+import it.unimi.dsi.fastutil.BigArrays;
+import it.unimi.dsi.fastutil.objects.AbstractObjectBigList;
+import it.unimi.dsi.fastutil.objects.ObjectBigListIterator;
+import it.unimi.dsi.fastutil.longs.LongBigArrays;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.Collection;
+import java.util.NoSuchElementException;
+import java.util.RandomAccess;
+
+/** Compact storage of big lists of arrays using front coding.
+ *
+ * <p>This class stores immutably a big list of arrays in a single {@linkplain it.unimi.dsi.fastutil.BigArrays big array}
+ * using front coding (of course, the compression will be reasonable only if
+ * the list is sorted lexicographically—see below). It implements an
+ * immutable type-specific list that returns the <var>i</var>-th array when
+ * calling {@link #get(long) get(<var>i</var>)}. The returned array may be
+ * freely modified.
+ *
+ * <p>Front coding is based on the idea that if the <var>i</var>-th and the
+ * (<var>i</var>+1)-th array have a common prefix, we might store the length
+ * of the common prefix, and then the rest of the second array.
+ *
+ * <p>This approach, of course, requires that once in a while an array is
+ * stored entirely.  The <em>ratio</em> of a front-coded list defines how
+ * often this happens (once every {@link #ratio()} arrays). A higher ratio
+ * means more compression, but means also a longer access time, as more arrays
+ * have to be probed to build the result. Note that we must build an array
+ * every time {@link #get(long)} is called, but this class provides also methods
+ * that extract one of the stored arrays in a given array, reducing garbage
+ * collection. See the documentation of the family of {@code get()}
+ * methods.
+ *
+ * <p>By setting the ratio to 1 we actually disable front coding: however, we
+ * still have a data structure storing large list of arrays with a reduced
+ * overhead (just one integer per array, plus the space required for lengths).
+ *
+ * <p>Note that the typical usage of front-coded lists is under the form of
+ * serialized objects; usually, the data that has to be compacted is processed
+ * offline, and the resulting structure is stored permanently. Since the
+ * pointer array is not stored, the serialized format is very small.
+ *
+ * <H2>Implementation Details</H2>
+ *
+ * <p>All arrays are stored in a {@linkplain it.unimi.dsi.fastutil.BigArrays big array}. A separate array of pointers
+ * indexes arrays whose position is a multiple of the ratio: thus, a higher ratio
+ * means also less pointers.
+ *
+ * <p>More in detail, an array whose position is a multiple of the ratio is
+ * stored as the array length, followed by the elements of the array. The array
+ * length is coded by a simple variable-length list of <var>k</var>-1 bit
+ * blocks, where <var>k</var> is the number of bits of the underlying primitive
+ * type.  All other arrays are stored as follows: let {@code common} the
+ * length of the maximum common prefix between the array and its predecessor.
+ * Then we store the array length decremented by {@code common}, followed
+ * by {@code common}, followed by the array elements whose index is
+ * greater than or equal to {@code common}. For instance, if we store
+ * {@code foo}, {@code foobar}, {@code football} and
+ * {@code fool} in a front-coded character-array list with ratio 3, the
+ * character array will contain
+ *
+ * <pre>
+ * <b>3</b> f o o <b>3</b> <b>3</b> b a r <b>5</b> <b>3</b> t b a l l <b>4</b> f o o l
+ * </pre>
+ */
+
+public class ARRAY_FRONT_CODED_BIG_LIST extends AbstractObjectBigList<KEY_TYPE[]> implements Serializable, Cloneable, RandomAccess {
+
+	private static final long serialVersionUID = 1L;
+
+	/** The number of arrays in the list. */
+	protected final long n;
+	/** The ratio of this front-coded list. */
+	protected final int ratio;
+	/** The big array containing the compressed arrays. */
+	protected final KEY_TYPE[][] array;
+	/** The pointers to entire arrays in the list. */
+	protected transient long[][] p;
+
+	/** Creates a new front-coded list containing the arrays returned by the given iterator.
+	 *
+	 * @param arrays an iterator returning arrays.
+	 * @param ratio the desired ratio.
+	 */
+
+	public ARRAY_FRONT_CODED_BIG_LIST(final Iterator<KEY_TYPE[]> arrays, final int ratio) {
+
+		if (ratio < 1) throw new IllegalArgumentException("Illegal ratio (" + ratio + ")");
+
+		KEY_TYPE[][] array = BIG_ARRAYS.EMPTY_BIG_ARRAY;
+		long[][] p = LongBigArrays.EMPTY_BIG_ARRAY;
+
+		KEY_TYPE[][] a = new KEY_TYPE[2][];
+		long curSize = 0;
+		long n = 0;
+		int b = 0, common, length, minLength;
+
+		while(arrays.hasNext()) {
+			a[b] = arrays.next();
+			length = a[b].length;
+
+			if (n % ratio == 0) {
+				p = grow(p, n / ratio + 1);
+				BigArrays.set(p, n / ratio, curSize);
+
+				array = grow(array, curSize + count(length) + length, curSize);
+				curSize += writeInt(array, length, curSize);
+				copyToBig(a[b], 0, array, curSize, length);
+				curSize += length;
+			}
+			else {
+				minLength = a[1 - b].length;
+				if (length < minLength) minLength = length;
+				for(common = 0; common < minLength; common++) if (a[0][common] != a[1][common]) break;
+				length -= common;
+
+				array = grow(array, curSize + count(length) + count(common) + length, curSize);
+				curSize += writeInt(array, length, curSize);
+				curSize += writeInt(array, common, curSize);
+				copyToBig(a[b], common, array, curSize, length);
+				curSize += length;
+			}
+
+			b = 1 - b;
+			n++;
+		}
+
+		this.n = n;
+		this.ratio = ratio;
+		this.array = trim(array, curSize);
+		this.p = trim(p, (n + ratio - 1) / ratio);
+
+	}
+
+	/** Creates a new front-coded list containing the arrays in the given collection.
+	 *
+	 * @param c a collection containing arrays.
+	 * @param ratio the desired ratio.
+	 */
+
+	public ARRAY_FRONT_CODED_BIG_LIST(final Collection<KEY_TYPE[]> c, final int ratio) {
+		this(c.iterator(), ratio);
+	}
+
+
+
+	public int ratio() {
+		return ratio;
+	}
+
+
+	/** Computes the length of the array at the given index.
+	 *
+	 * <p>This private version of {@link #arrayLength(long)} does not check its argument.
+	 *
+	 * @param index an index.
+	 * @return the length of the {@code index}-th array.
+	 */
+	private int length(final long index) {
+		final KEY_TYPE[][] array = this.array;
+		final int delta = (int)(index % ratio); // The index into the p array, and the delta inside the block.
+
+		long pos = BigArrays.get(p, index / ratio); // The position into the array of the first entire word before the index-th.
+		int length = readInt(array, pos);
+
+		if (delta == 0) return length;
+
+		// First of all, we recover the array length and the maximum amount of copied elements.
+		int common;
+		pos += count(length) + length;
+		length = readInt(array, pos);
+		common = readInt(array, pos + count(length));
+
+		for(int i = 0; i < delta - 1; i++) {
+			pos += count(length) + count(common) + length;
+			length = readInt(array, pos);
+			common = readInt(array, pos + count(length));
+		}
+
+		return length + common;
+	}
+
+
+	/** Computes the length of the array at the given index.
+	 *
+	 * @param index an index.
+	 * @return the length of the {@code index}-th array.
+	 */
+	public int arrayLength(final long index) {
+		ensureRestrictedIndex(index);
+		return length(index);
+	}
+
+	/** Extracts the array at the given index.
+	 *
+	 * @param index an index.
+	 * @param a the array that will store the result (we assume that it can hold the result).
+	 * @param offset an offset into {@code a} where elements will be store.
+	 * @param length a maximum number of elements to store in {@code a}.
+	 * @return the length of the extracted array.
+	 */
+	private int extract(final long index, final KEY_TYPE a[], final int offset, final int length) {
+		final int delta = (int)(index % ratio); // The delta inside the block.
+		final long startPos = BigArrays.get(p, index / ratio); // The position into the array of the first entire word before the index-th.
+		long pos, prevArrayPos;
+		int arrayLength = readInt(array, pos = startPos), currLen = 0, actualCommon;
+
+		if (delta == 0) {
+			pos = BigArrays.get(p, index / ratio) + count(arrayLength);
+			copyFromBig(array, pos, a, offset, Math.min(length, arrayLength));
+			return arrayLength;
+		}
+
+		int common = 0;
+
+		for(int i = 0; i < delta; i++) {
+			prevArrayPos = pos + count(arrayLength) + (i != 0 ? count(common) : 0);
+			pos = prevArrayPos + arrayLength;
+
+			arrayLength = readInt(array, pos);
+			common = readInt(array, pos + count(arrayLength));
+
+			actualCommon = Math.min(common, length);
+			if (actualCommon <= currLen) currLen = actualCommon;
+			else {
+				copyFromBig(array, prevArrayPos, a, currLen + offset, actualCommon - currLen);
+				currLen = actualCommon;
+			}
+		}
+
+		if (currLen < length) copyFromBig(array, pos + count(arrayLength) + count(common), a, currLen + offset, Math.min(arrayLength, length - currLen));
+
+		return arrayLength + common;
+	}
+
+	/** {@inheritDoc}
+	 * <p>This implementation delegates to {@link #getArray(long)}. */
+	@Override
+	public KEY_TYPE[] get(final long index) {
+		return getArray(index);
+	}
+
+	/** Returns an array stored in this front-coded list.
+	 *
+	 * @param index an index.
+	 * @return the corresponding array stored in this front-coded list.
+	 */
+	public KEY_TYPE[] getArray(final long index) {
+		ensureRestrictedIndex(index);
+		final int length = length(index);
+		final KEY_TYPE a[] = new KEY_TYPE[length];
+		extract(index, a, 0, length);
+		return a;
+	}
+
+	/** Stores in the given array elements from an array stored in this front-coded list.
+	 *
+	 * @param index an index.
+	 * @param a the array that will store the result.
+	 * @param offset an offset into {@code a} where elements will be store.
+	 * @param length a maximum number of elements to store in {@code a}.
+	 * @return if {@code a} can hold the extracted elements, the number of extracted elements;
+	 * otherwise, the number of remaining elements with the sign changed.
+	 */
+	public int get(final long index, final KEY_TYPE[] a, final int offset, final int length) {
+		ensureRestrictedIndex(index);
+		ARRAYS.ensureOffsetLength(a, offset, length);
+
+		final int arrayLength = extract(index, a, offset, length);
+		if (length >= arrayLength) return arrayLength;
+		return length - arrayLength;
+	}
+
+	/** Stores in the given array an array stored in this front-coded list.
+	 *
+	 * @param index an index.
+	 * @param a the array that will store the content of the result (we assume that it can hold the result).
+	 * @return if {@code a} can hold the extracted elements, the number of extracted elements;
+	 * otherwise, the number of remaining elements with the sign changed.
+	 */
+	public int get(final long index, final KEY_TYPE[] a) {
+		return get(index, a, 0, a.length);
+	}
+
+	@Override
+	public long size64() {
+		return n;
+	}
+
+	@Override
+	public ObjectBigListIterator<KEY_TYPE[]> listIterator(final long start) {
+		ensureIndex(start);
+
+		return new ObjectBigListIterator<KEY_TYPE[]>() {
+				KEY_TYPE s[] = ARRAYS.EMPTY_ARRAY;
+				long i = 0;
+				long pos = 0;
+				boolean inSync; // Whether the current value in a is the string just before the next to be produced.
+
+				{
+					if (start != 0) {
+						if (start == n) i = start; // If we start at the end, we do nothing.
+						else {
+							pos = BigArrays.get(p, start / ratio);
+							int j = (int)(start % ratio);
+							i = start - j;
+							while(j-- != 0) next();
+						}
+					}
+				}
+
+				@Override
+				public boolean hasNext() {
+					return i < n;
+				}
+
+				@Override
+				public boolean hasPrevious() {
+					return i > 0;
+				}
+
+				@Override
+				public long previousIndex() {
+					return i - 1;
+				}
+
+				@Override
+				public long nextIndex() {
+					return i;
+				}
+
+				@Override
+				public KEY_TYPE[] next() {
+					int length, common;
+
+					if (! hasNext()) throw new NoSuchElementException();
+
+					if (i % ratio == 0) {
+						pos = BigArrays.get(p, i / ratio);
+						length = readInt(array, pos);
+						s = ARRAYS.ensureCapacity(s, length, 0);
+						copyFromBig(array, pos + count(length), s, 0, length);
+						pos += length + count(length);
+						inSync = true;
+					}
+					else {
+						if (inSync) {
+							length = readInt(array, pos);
+							common = readInt(array, pos + count(length));
+							s = ARRAYS.ensureCapacity(s, length + common, common);
+							copyFromBig(array, pos + count(length) + count (common), s, common, length);
+							pos += count(length) + count(common) + length;
+							length += common;
+						}
+						else {
+							s = ARRAYS.ensureCapacity(s, length = length(i), 0);
+							extract(i, s, 0, length);
+						}
+					}
+					i++;
+					return ARRAYS.copy(s, 0, length);
+				}
+
+				@Override
+				public KEY_TYPE[] previous() {
+					if (! hasPrevious()) throw new NoSuchElementException();
+					inSync = false;
+					return getArray(--i);
+				}
+			};
+	}
+
+
+	/** Returns a copy of this list.
+	 *
+	 *  @return a copy of this list.
+	 */
+	@Override
+	public ARRAY_FRONT_CODED_BIG_LIST clone() {
+		return this;
+	}
+
+	@Override
+	public String toString() {
+		final StringBuffer s = new StringBuffer();
+		s.append("[");
+		for(long i = 0; i < n; i++) {
+			if (i != 0) s.append(", ");
+			s.append(ARRAY_LIST.wrap(getArray(i)).toString());
+		}
+		s.append("]");
+		return s.toString();
+	}
+
+	/** Computes the pointer big array using the currently set ratio, number of elements and underlying array.
+	 *
+	 * @return the computed pointer big array.
+	 */
+
+	protected long[][] rebuildPointerArray() {
+		final long[][] p = LongBigArrays.newBigArray((n + ratio - 1) / ratio);
+		final KEY_TYPE a[][] = array;
+		int length, count;
+		long pos = 0;
+
+		for(int i = 0, j = 0, skip = ratio - 1; i < n; i++) {
+			length = readInt(a, pos);
+			count = count(length);
+			if (++skip == ratio) {
+				skip = 0;
+				BigArrays.set(p, j++, pos);
+				pos += count + length;
+			}
+			else pos += count + count(readInt(a, pos + count)) + length;
+		}
+
+		return p;
+	}
+
+
+	private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
+		s.defaultReadObject();
+
+		// Rebuild pointer array
+		p = rebuildPointerArray();
+	}
+}


=====================================
drv/ArrayFrontCodedList.drv
=====================================
@@ -36,7 +36,7 @@ import java.util.RandomAccess;
 
 /** Compact storage of lists of arrays using front coding.
  *
- * <p>This class stores immutably a list of arrays in a single large array
+ * <p>This class stores immutably a list of arrays in a single {@linkplain it.unimi.dsi.fastutil.BigArrays big array}
  * using front coding (of course, the compression will be reasonable only if
  * the list is sorted lexicographically—see below). It implements an
  * immutable type-specific list that returns the <var>i</var>-th array when
@@ -177,7 +177,7 @@ public class ARRAY_FRONT_CODED_LIST extends AbstractObjectList<KEY_TYPE[]> imple
 	 * @param pos the starting position.
 	 * @return the length coded at {@code pos}.
 	 */
-	private static int readInt(final KEY_TYPE a[][], long pos) {
+	static int readInt(final KEY_TYPE a[][], long pos) {
 #if KEY_CLASS_Integer
 		return BigArrays.get(a, pos);
 #elif KEY_CLASS_Long
@@ -205,7 +205,7 @@ public class ARRAY_FRONT_CODED_LIST extends AbstractObjectList<KEY_TYPE[]> imple
 	 * @param length the length to be coded.
 	 * @return the number of elements coding {@code length}.
 	 */
-	private static int count(final int length) {
+	static int count(final int length) {
 #if KEY_CLASS_Integer || KEY_CLASS_Long
 		return 1;
 #elif KEY_CLASS_Character || KEY_CLASS_Short
@@ -225,7 +225,7 @@ public class ARRAY_FRONT_CODED_LIST extends AbstractObjectList<KEY_TYPE[]> imple
 	 * @param pos the starting position.
 	 * @return the number of elements coding {@code length}.
 	 */
-	private static int writeInt(final KEY_TYPE a[][], int length, long pos) {
+	static int writeInt(final KEY_TYPE a[][], int length, long pos) {
 #if KEY_CLASS_Long
 		BigArrays.set(a, pos, length);
 		return 1;
@@ -280,6 +280,7 @@ public class ARRAY_FRONT_CODED_LIST extends AbstractObjectList<KEY_TYPE[]> imple
 	 *
 	 * <p>This private version of {@link #arrayLength(int)} does not check its argument.
 	 *
+	 * @param array the data array.
 	 * @param index an index.
 	 * @return the length of the {@code index}-th array.
 	 */
@@ -551,180 +552,4 @@ public class ARRAY_FRONT_CODED_LIST extends AbstractObjectList<KEY_TYPE[]> imple
 		// Rebuild pointer array
 		p = rebuildPointerArray();
 	}
-
-
-#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 KEY_CLASS_Byte || KEY_CLASS_Short || KEY_CLASS_Character
-		return (KEY_TYPE)(r.nextInt());
-#elif KEYS_PRIMITIVE
-		return r.NEXT_KEY();
-#elif KEY_CLASS_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 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, 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 contentEquals(java.util.List x, java.util.List y) {
-		if (x.size() != y.size()) return false;
-		for(int i = 0; i < x.size(); i++) if (! java.util.Arrays.equals((KEY_TYPE[])x.get(i), (KEY_TYPE[])y.get(i))) return false;
-		return true;
-	}
-
-	private static int l[];
-	private static KEY_TYPE[][] a;
-
-
-	private static void runTest(int n) {
-		int c;
-
-		l = new int[n];
-		a = new KEY_TYPE[n][];
-
-		for(int i = 0; i < n; i++) l[i] = (int)(Math.abs(r.nextGaussian())*32);
-		for(int i = 0; i < n; i++) a[i] = new KEY_TYPE[l[i]];
-		for(int i = 0; i < n; i++) for(int j = 0; j < l[i]; j++) a[i][j] = genKey();
-
-		ARRAY_FRONT_CODED_LIST m = new ARRAY_FRONT_CODED_LIST(it.unimi.dsi.fastutil.objects.ObjectIterators.wrap(a), r.nextInt(4) + 1);
-		it.unimi.dsi.fastutil.objects.ObjectArrayList t = new it.unimi.dsi.fastutil.objects.ObjectArrayList(a);
-
-		//System.out.println(m);
-		//for(i = 0; i < t.size(); i++) System.out.println(ARRAY_LIST.wrap((KEY_TYPE[])t.get(i)));
-
-		/* Now we check that m actually holds that data. */
-
-		ensure(contentEquals(m, t), "Error (" + seed + "): m does not equal t at creation");
-
-		/* Now we check cloning. */
-
-		ensure(contentEquals(m, (java.util.List)m.clone()), "Error (" + seed + "): m does not equal m.clone()");
-
-		/* Now we play with iterators. */
-
-		{
-			ObjectListIterator i;
-			java.util.ListIterator j;
-			Object J;
-			i = m.listIterator();
-			j = 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()) {
-					ensure(java.util.Arrays.equals((KEY_TYPE[])i.next(), (KEY_TYPE[])j.next()), "Error (" + seed + "): divergence in next()");
-
-				}
-				else if (r.nextFloat() < .2 && i.hasPrevious()) {
-					ensure(java.util.Arrays.equals((KEY_TYPE[])i.previous(), (KEY_TYPE[])j.previous()), "Error (" + seed + "): divergence in previous()");
-				}
-
-				ensure(i.nextIndex() == j.nextIndex(), "Error (" + seed + "): divergence in nextIndex()");
-				ensure(i.previousIndex() == j.previousIndex(), "Error (" + seed + "): divergence in previousIndex()");
-
-			}
-
-		}
-
-		{
-			Object previous = null;
-			Object I, J;
-			int from = r.nextInt(m.size() +1);
-			ObjectListIterator i;
-			java.util.ListIterator j;
-			i = m.listIterator(from);
-			j = t.listIterator(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()) {
-					ensure(java.util.Arrays.equals((KEY_TYPE[])i.next(), (KEY_TYPE[])j.next()), "Error (" + seed + "): divergence in next() (iterator with starting point " + from + ")");
-					//System.err.println("Done next " + I + " " + J + "  " + badPrevious);
-
-				}
-				else if (r.nextFloat() < .2 && i.hasPrevious()) {
-					ensure(java.util.Arrays.equals((KEY_TYPE[])i.previous(), (KEY_TYPE[])j.previous()), "Error (" + seed + "): divergence in previous() (iterator with starting point " + from + ")");
-
-				}
-			}
-
-		}
-
-
-
-		try {
-			java.io.File ff = new java.io.File("it.unimi.dsi.fastutil.test." + m.getClass().getSimpleName() + "." + n);
-			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 = (ARRAY_FRONT_CODED_LIST)ois.readObject();
-			ois.close();
-			ff.delete();
-		}
-		catch(Exception e) {
-			e.printStackTrace();
-			System.exit(1);
-		}
-
-		ensure(contentEquals(m, t), "Error (" + seed + "): m does not equal t after save/read");
-
-		System.out.println("Test OK");
-		return;
-	}
-
-
-	public static void main(String args[]) {
-		int n  = Integer.parseInt(args[1]);
-		if (args.length > 2) r = new java.util.Random(seed = Long.parseLong(args[2]));
-
-		try {
-			if ("speedTest".equals(args[0]) || "speedComp".equals(args[0])) speedTest(n, "speedComp".equals(args[0]));
-			else if ("test".equals(args[0])) runTest(n);
-		} catch(Throwable e) {
-			e.printStackTrace(System.err);
-			System.err.println("seed: " + seed);
-		}
-	}
-
-#endif
-
-
 }


=====================================
drv/ArrayMap.drv
=====================================
@@ -79,7 +79,13 @@ public class ARRAY_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENERIC
 	 */
 	public ARRAY_MAP(final MAP KEY_VALUE_GENERIC m) {
 		this(m.size());
-		putAll(m);
+		int i = 0;
+		for(MAP.Entry KEY_VALUE_GENERIC e : m.ENTRYSET()) {
+			key[i] = e.ENTRY_GET_KEY();
+			value[i] = e.ENTRY_GET_VALUE();
+			i++;
+		}
+		size = i;
 	}
 
 	/** Creates a new empty array map copying the entries of a given map.
@@ -88,7 +94,13 @@ public class ARRAY_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENERIC
 	 */
 	public ARRAY_MAP(final Map<? extends KEY_GENERIC_CLASS, ? extends VALUE_GENERIC_CLASS> m) {
 		this(m.size());
-		putAll(m);
+		int i = 0;
+		for(Map.Entry<? extends KEY_GENERIC_CLASS, ? extends VALUE_GENERIC_CLASS> e : m.entrySet()) {
+			key[i] = KEY_CLASS2TYPE(e.getKey());
+			value[i] = VALUE_CLASS2TYPE(e.getValue());
+			i++;
+		}
+		size = i;
 	}
 
 	/** Creates a new array map with given key and value backing arrays, using the given number of elements.


=====================================
drv/ArraySet.drv
=====================================
@@ -19,6 +19,7 @@ package PACKAGE;
 
 import java.util.Collection;
 import java.util.NoSuchElementException;
+import java.util.Set;
 
 /** A simple, brute-force implementation of a set based on a backing array.
  *
@@ -72,6 +73,32 @@ public class ARRAY_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implements j
 		addAll(c);
 	}
 
+	/** Creates a new array set copying the contents of a given collection.
+	 * @param c a collection.
+	 */
+	public ARRAY_SET(SET KEY_GENERIC c) {
+		this(c.size());
+		int i = 0;
+		for(KEY_TYPE x : c) {
+			a[i] = x;
+			i++;
+		}
+		size = i;
+	}
+
+	/** Creates a new array set copying the contents of a given set.
+	 * @param c a collection.
+	 */
+	public ARRAY_SET(final Set<? extends KEY_GENERIC_CLASS> c) {
+		this(c.size());
+		int i = 0;
+		for(KEY_GENERIC_CLASS x: c) {
+			a[i] = KEY_CLASS2TYPE(x);
+			i++;
+		}
+		size = i;
+	}
+
 
 	/** Creates a new array set using the given backing array and the given number of elements of the array.
 	 *


=====================================
drv/BigArrays.drv
=====================================
@@ -30,6 +30,8 @@ package PACKAGE;
 
 import java.util.Arrays;
 import java.util.Random;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.RecursiveAction;
 
 import it.unimi.dsi.fastutil.BigArrays;
 import it.unimi.dsi.fastutil.Hash;
@@ -42,6 +44,12 @@ import static it.unimi.dsi.fastutil.BigArrays.SEGMENT_SHIFT;
 import static it.unimi.dsi.fastutil.BigArrays.SEGMENT_SIZE;
 
 #if KEYS_PRIMITIVE
+#if KEY_CLASS_Integer
+import java.util.concurrent.atomic.AtomicIntegerArray;
+#endif
+#if KEY_CLASS_Long 
+import java.util.concurrent.atomic.AtomicLongArray;
+#endif
 
 #if ! KEY_CLASS_Byte && ! KEY_CLASS_Boolean
 import it.unimi.dsi.fastutil.bytes.ByteBigArrays;
@@ -309,6 +317,32 @@ public final class BIG_ARRAYS {
 		return base;
 	}
 
+#if KEY_CLASS_Long || KEY_CLASS_Integer
+	/** A static, final, empty big atomic array. */
+	public static final ATOMIC_ARRAY[] EMPTY_BIG_ATOMIC_ARRAY = {};
+
+	/** Creates a new big atomic array.
+	 *
+	 * @param length the length of the new big array.
+	 * @return a new big atomic array of given length.
+	 */
+
+	public static ATOMIC_ARRAY[] newBigAtomicArray(final long length) {
+		if (length == 0) return EMPTY_BIG_ATOMIC_ARRAY;
+		ensureLength(length);
+		final int baseLength = (int)((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
+		ATOMIC_ARRAY[] base = new ATOMIC_ARRAY[baseLength];
+		final int residual = (int)(length & SEGMENT_MASK);
+		if (residual != 0) {
+			for(int i = 0; i < baseLength - 1; i++) base[i] = new ATOMIC_ARRAY(SEGMENT_SIZE);
+			base[baseLength - 1] = new ATOMIC_ARRAY(residual);
+		}
+		else for(int i = 0; i < baseLength; i++) base[i] = new ATOMIC_ARRAY(SEGMENT_SIZE);
+
+		return base;
+	}
+#endif
+
 #if KEY_CLASS_Object
 	/** Turns a standard array into a big array.
 	 *
@@ -712,11 +746,12 @@ public final class BIG_ARRAYS {
 	@SuppressWarnings({"rawtypes"})
 	public static final Hash.Strategy HASH_STRATEGY = new BigArrayHashStrategy();
 
-	private static final int SMALL = 7;
+	private static final int QUICKSORT_NO_REC = 7;
+	private static final int PARALLEL_QUICKSORT_NO_FORK = 8192;
 	private static final int MEDIUM = 40;
 
-	private static KEY_GENERIC void vecSwap(final KEY_GENERIC_TYPE[][] x, long a, long b, final long n) {
-		for(int i = 0; i < n; i++, a++, b++) swap(x, a, b);
+	private static KEY_GENERIC void swap(final KEY_GENERIC_TYPE[][] x, long a, long b, final long n) {
+		for(int i = 0; i < n; i++, a++, b++) BigArrays.swap(x, a, b);
 	}
 
 	private static KEY_GENERIC long med3(final KEY_GENERIC_TYPE x[][], final long a, final long b, final long c, KEY_COMPARATOR KEY_GENERIC comp) {
@@ -732,7 +767,7 @@ public final class BIG_ARRAYS {
 		for(long i = from; i < to - 1; i++) {
 			long m = i;
 			for(long j = i + 1; j < to; j++) if (comp.compare(BigArrays.get(a, j), BigArrays.get(a, m)) < 0) m = j;
-			if (m != i) swap(a, i, m);
+			if (m != i) BigArrays.swap(a, i, m);
 		}
 	}
 
@@ -752,14 +787,14 @@ public final class BIG_ARRAYS {
 		final long len = to - from;
 
 		// Selection sort on smallest arrays
-		if (len < SMALL) {
+		if (len < QUICKSORT_NO_REC) {
 			selectionSort(x, from, to, comp);
 			return;
 		}
 
 		// Choose a partition element, v
 		long m = from + len / 2;	 // Small arrays, middle element
-		if (len > SMALL) {
+		if (len > QUICKSORT_NO_REC) {
 			long l = from;
 			long n = to - 1;
 			if (len > MEDIUM) {		// Big arrays, pseudomedian of 9
@@ -778,23 +813,23 @@ public final class BIG_ARRAYS {
 		while(true) {
 			int comparison;
 			while (b <= c && (comparison = comp.compare(BigArrays.get(x, b), v)) <= 0) {
-				if (comparison == 0) swap(x, a++, b);
+				if (comparison == 0) BigArrays.swap(x, a++, b);
 				b++;
 			}
 			while (c >= b && (comparison = comp.compare(BigArrays.get(x, c), v)) >=0) {
-				if (comparison == 0) swap(x, c, d--);
+				if (comparison == 0) BigArrays.swap(x, c, d--);
 				c--;
 			}
 			if (b > c) break;
-			swap(x, b++, c--);
+			BigArrays.swap(x, b++, c--);
 		}
 
 		// Swap partition elements back to middle
 		long s, n = to;
 		s = Math.min(a - from, b - a);
-		vecSwap(x, from, b - s, s);
+		swap(x, from, b - s, s);
 		s = Math.min(d - c, n - d- 1);
-		vecSwap(x, b, n - s, s);
+		swap(x, b, n - s, s);
 
 		// Recursively sort non-partition-elements
 		if ((s = b - a) > 1) quickSort(x, from, from + s, comp);
@@ -818,7 +853,7 @@ public final class BIG_ARRAYS {
 		for(long i = from; i < to - 1; i++) {
 			long m = i;
 			for(long j = i + 1; j < to; j++) if (KEY_LESS(BigArrays.get(a, j), BigArrays.get(a, m))) m = j;
-			if (m != i) swap(a, i, m);
+			if (m != i) BigArrays.swap(a, i, m);
 		}
 	}
 
@@ -834,7 +869,7 @@ public final class BIG_ARRAYS {
 	 *
 	 */
 	public static KEY_GENERIC void quickSort(final KEY_GENERIC_TYPE[][] x, final KEY_COMPARATOR KEY_GENERIC comp) {
-		quickSort(x, 0, BIG_ARRAYS.length(x), comp);
+		quickSort(x, 0, BigArrays.length(x), comp);
 	}
 
 	/** Sorts the specified range of elements according to the natural ascending order using quicksort.
@@ -853,14 +888,14 @@ public final class BIG_ARRAYS {
 		final long len = to - from;
 
 		// Selection sort on smallest arrays
-		if (len < SMALL) {
+		if (len < QUICKSORT_NO_REC) {
 			selectionSort(x, from, to);
 			return;
 		}
 
 		// Choose a partition element, v
 		long m = from + len / 2;	 // Small arrays, middle element
-		if (len > SMALL) {
+		if (len > QUICKSORT_NO_REC) {
 			long l = from;
 			long n = to - 1;
 			if (len > MEDIUM) {		// Big arrays, pseudomedian of 9
@@ -879,23 +914,23 @@ public final class BIG_ARRAYS {
 		while(true) {
 			int comparison;
 			while (b <= c && (comparison = KEY_CMP(BigArrays.get(x, b), v)) <= 0) {
-				if (comparison == 0) swap(x, a++, b);
+				if (comparison == 0) BigArrays.swap(x, a++, b);
 				b++;
 			}
 			while (c >= b && (comparison = KEY_CMP(BigArrays.get(x, c), v)) >=0) {
-				if (comparison == 0) swap(x, c, d--);
+				if (comparison == 0) BigArrays.swap(x, c, d--);
 				c--;
 			}
 			if (b > c) break;
-			swap(x, b++, c--);
+			BigArrays.swap(x, b++, c--);
 		}
 
 		// Swap partition elements back to middle
 		long s, n = to;
 		s = Math.min(a - from, b - a);
-		vecSwap(x, from, b - s, s);
+		swap(x, from, b - s, s);
 		s = Math.min(d - c, n - d- 1);
-		vecSwap(x, b, n - s, s);
+		swap(x, b, n - s, s);
 
 		// Recursively sort non-partition-elements
 		if ((s = b - a) > 1) quickSort(x, from, from + s);
@@ -914,10 +949,212 @@ public final class BIG_ARRAYS {
 	 */
 
 	public static KEY_GENERIC void quickSort(final KEY_GENERIC_TYPE[][] x) {
-		quickSort(x, 0, BIG_ARRAYS.length(x));
+		quickSort(x, 0, BigArrays.length(x));
+	}
+
+
+	protected static class ForkJoinQuickSort KEY_GENERIC extends RecursiveAction {
+		private static final long serialVersionUID = 1L;
+		private final long from;
+		private final long to;
+		private final KEY_GENERIC_TYPE[][] x;
+
+		public ForkJoinQuickSort(final KEY_GENERIC_TYPE[][] x , final long from , final long to) {
+			this.from = from;
+			this.to = to;
+			this.x = x;
+		}
+
+		@Override
+		SUPPRESS_WARNINGS_KEY_UNCHECKED
+		protected void compute() {
+			final KEY_GENERIC_TYPE[][] x = this.x;
+			final long len = to - from;
+			if (len < PARALLEL_QUICKSORT_NO_FORK) {
+				quickSort(x, from, to);
+				return;
+			}
+			// Choose a partition element, v
+			long m = from + len / 2;
+			long l = from;
+			long n = to - 1;
+			long s = len / 8;
+			l = med3(x, l, l + s, l + 2 * s);
+			m = med3(x, m - s, m, m + s);
+			n = med3(x, n - 2 * s, n - s, n);
+			m = med3(x, l, m, n);
+			final KEY_GENERIC_TYPE v = BigArrays.get(x, m);
+			// Establish Invariant: v* (<v)* (>v)* v*
+			long a = from, b = a, c = to - 1, d = c;
+			while (true) {
+				int comparison;
+				while (b <= c && (comparison = KEY_CMP(BigArrays.get(x, b), v)) <= 0) {
+					if (comparison == 0) BigArrays.swap(x, a++, b);
+					b++;
+				}
+				while (c >= b && (comparison = KEY_CMP(BigArrays.get(x, c), v)) >= 0) {
+					if (comparison == 0) BigArrays.swap(x, c, d--);
+					c--;
+				}
+				if (b > c) break;
+				BigArrays.swap(x, b++, c--);
+			}
+			// Swap partition elements back to middle
+			long t;
+			s = Math.min(a - from, b - a);
+			swap(x, from, b - s, s);
+			s = Math.min(d - c, to - d - 1);
+			swap(x, b, to - s, s);
+			// Recursively sort non-partition-elements
+			s = b - a;
+			t = d - c;
+			if (s > 1 && t > 1) invokeAll(new ForkJoinQuickSort KEY_GENERIC_DIAMOND(x, from, from + s), new ForkJoinQuickSort KEY_GENERIC_DIAMOND(x, to - t, to));
+			else if (s > 1) invokeAll(new ForkJoinQuickSort KEY_GENERIC_DIAMOND(x, from, from + s));
+			else invokeAll(new ForkJoinQuickSort KEY_GENERIC_DIAMOND(x, to - t, to));
+		}
+	}
+
+	/**  Sorts the specified range of elements according to the natural ascending order 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 x the big array to be sorted.
+	 * @param from the index of the first element (inclusive) to be sorted.
+	 * @param to the index of the last element (exclusive) to be sorted.
+	 */
+	public static KEY_GENERIC void parallelQuickSort(final KEY_GENERIC_TYPE[][] x, final long from, final long to) {
+		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_DIAMOND(x, from, to));
+			pool.shutdown();
+		}
+	}
+
+	/** Sorts a big array according to the natural ascending order 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 x the big array to be sorted.
+	 *
+	 */
+	public static KEY_GENERIC void parallelQuickSort(final KEY_GENERIC_TYPE[][] x) {
+		parallelQuickSort(x, 0, BigArrays.length(x));
 	}
 
 
+	protected static class ForkJoinQuickSortComp KEY_GENERIC extends RecursiveAction {
+		private static final long serialVersionUID = 1L;
+		private final long from;
+		private final long to;
+		private final KEY_GENERIC_TYPE[][] x;
+		private final KEY_COMPARATOR KEY_GENERIC comp;
+
+		public ForkJoinQuickSortComp(final KEY_GENERIC_TYPE[][] x , final long from , final long to, final KEY_COMPARATOR KEY_GENERIC comp) {
+			this.from = from;
+			this.to = to;
+			this.x = x;
+			this.comp = comp;
+		}
+
+		@Override
+		protected void compute() {
+			final KEY_GENERIC_TYPE[][] x = this.x;
+			final long len = to - from;
+			if (len < PARALLEL_QUICKSORT_NO_FORK) {
+				quickSort(x, from, to, comp);
+				return;
+			}
+			// Choose a partition element, v
+			long m = from + len / 2;
+			long l = from;
+			long n = to - 1;
+			long s = len / 8;
+			l = med3(x, l, l + s, l + 2 * s, comp);
+			m = med3(x, m - s, m, m + s, comp);
+			n = med3(x, n - 2 * s, n - s, n, comp);
+			m = med3(x, l, m, n, comp);
+			final KEY_GENERIC_TYPE v = BigArrays.get(x, m);
+			// Establish Invariant: v* (<v)* (>v)* v*
+			long a = from, b = a, c = to - 1, d = c;
+			while (true) {
+				int comparison;
+				while (b <= c && (comparison = comp.compare(BigArrays.get(x, b), v)) <= 0) {
+					if (comparison == 0) BigArrays.swap(x, a++, b);
+					b++;
+				}
+				while (c >= b && (comparison = comp.compare(BigArrays.get(x, c), v)) >= 0) {
+					if (comparison == 0) BigArrays.swap(x, c, d--);
+					c--;
+				}
+				if (b > c) break;
+				BigArrays.swap(x, b++, c--);
+			}
+			// Swap partition elements back to middle
+			long t;
+			s = Math.min(a - from, b - a);
+			swap(x, from, b - s, s);
+			s = Math.min(d - c, to - d - 1);
+			swap(x, b, to - s, s);
+			// Recursively sort non-partition-elements
+			s = b - a;
+			t = d - c;
+			if (s > 1 && t > 1) invokeAll(new ForkJoinQuickSortComp KEY_GENERIC_DIAMOND(x, from, from + s, comp), new ForkJoinQuickSortComp KEY_GENERIC_DIAMOND(x, to - t, to, comp));
+			else if (s > 1) invokeAll(new ForkJoinQuickSortComp KEY_GENERIC_DIAMOND(x, from, from + s, comp));
+			else invokeAll(new ForkJoinQuickSortComp KEY_GENERIC_DIAMOND(x, to - t, to, comp));
+		}
+	}
+
+	/** Sorts the specified range of elements according to the order induced by the specified
+	 * 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 x the big array to be sorted.
+	 * @param from the index of the first element (inclusive) to be sorted.
+	 * @param to the index of the last element (exclusive) to be sorted.
+	 * @param comp the comparator to determine the sorting order.
+	 */
+	public static KEY_GENERIC void parallelQuickSort(final KEY_GENERIC_TYPE[][] x, final long from, final long to, final KEY_COMPARATOR KEY_GENERIC comp) {
+		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_DIAMOND(x, from, to, comp));
+			pool.shutdown();
+		}
+	}
+
+	/** Sorts a big array according to the order induced by the specified
+	 * 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 x the big array to be sorted.
+	 * @param comp the comparator to determine the sorting order.
+	 */
+	public static KEY_GENERIC void parallelQuickSort(final KEY_GENERIC_TYPE[][] x, final KEY_COMPARATOR KEY_GENERIC comp) {
+		parallelQuickSort(x, 0, BigArrays.length(x), comp);
+	}
 
 
 #if ! KEY_CLASS_Boolean
@@ -982,7 +1219,7 @@ public final class BIG_ARRAYS {
 	 * @see java.util.Arrays
 	 */
 	public static KEY_GENERIC long binarySearch(final KEY_GENERIC_TYPE[][] a, final KEY_TYPE key) {
-		return binarySearch(a, 0, BIG_ARRAYS.length(a), key);
+		return binarySearch(a, 0, BigArrays.length(a), key);
 	}
 
 	/**
@@ -1040,7 +1277,7 @@ public final class BIG_ARRAYS {
 	 * @see java.util.Arrays
 	 */
 	public static KEY_GENERIC long binarySearch(final KEY_GENERIC_TYPE[][] a, final KEY_GENERIC_TYPE key, final KEY_COMPARATOR KEY_GENERIC c) {
-		return binarySearch(a, 0, BIG_ARRAYS.length(a), key, c);
+		return binarySearch(a, 0, BigArrays.length(a), key, c);
 	}
 
 
@@ -1083,7 +1320,7 @@ public final class BIG_ARRAYS {
 	 * @param a the big array to be sorted.
 	 */
 	public static void radixSort(final KEY_TYPE[][] a) {
-		radixSort(a, 0, BIG_ARRAYS.length(a));
+		radixSort(a, 0, BigArrays.length(a));
 	}
 
 	/** Sorts the specified big array using radix sort.
@@ -1223,7 +1460,7 @@ public final class BIG_ARRAYS {
 	 */
 
 	public static void radixSort(final KEY_TYPE[][] a, final KEY_TYPE[][] b) {
-		radixSort(a, b, 0, BIG_ARRAYS.length(a));
+		radixSort(a, b, 0, BigArrays.length(a));
 	}
 
 	/** Sorts the specified pair of big arrays lexicographically using radix sort.
@@ -1250,7 +1487,7 @@ public final class BIG_ARRAYS {
 	 */
 	public static void radixSort(final KEY_TYPE[][] a, final KEY_TYPE[][] b, final long from, final long to) {
 		final int layers = 2;
-		if (BIG_ARRAYS.length(a) != BIG_ARRAYS.length(b)) throw new IllegalArgumentException("Array size mismatch.");
+		if (BigArrays.length(a) != BigArrays.length(b)) throw new IllegalArgumentException("Array size mismatch.");
 		final int maxLevel = DIGITS_PER_ELEMENT * layers - 1;
 
 		final int stackSize = ((1 << DIGIT_BITS) - 1) * (layers * DIGITS_PER_ELEMENT - 1) + 1;


=====================================
drv/BigArraysCommon.drv
=====================================
@@ -49,6 +49,8 @@ import it.unimi.dsi.fastutil.longs.LongArrays;
 import it.unimi.dsi.fastutil.floats.FloatArrays;
 import it.unimi.dsi.fastutil.doubles.DoubleArrays;
 import it.unimi.dsi.fastutil.objects.ObjectArrays;
+import java.util.concurrent.atomic.AtomicIntegerArray;
+import java.util.concurrent.atomic.AtomicLongArray;
 
 import java.util.Random;
 
@@ -168,6 +170,15 @@ import java.util.Random;
  * for some reason (e.g., stress testing) {@link #SEGMENT_SIZE} is set to a
  * value smaller than the inner array length.
  *
+ * <h2>Atomic big arrays</h2>
+ *
+ * <p>Limited support is available for atomic big arrays of integers and longs, with a similar syntax. Atomic big arrays are
+ * arrays of instances of {@link java.util.concurrent.atomic.AtomicIntegerArray} or
+ * {@link java.util.concurrent.atomic.AtomicLongArray} of length {@link #SEGMENT_SIZE} (or less, for
+ * the last segment, as usual) and their size cannot be changed. Some methods from those classes are
+ * available in {@link BigArrays} for atomic big arrays (e.g.,
+ * {@link BigArrays#incrementAndGet(AtomicIntegerArray[], long)}).
+ *
  * <h2>Big alternatives</h2>
  *
  * <p>


=====================================
drv/BigArraysFragment.drv
=====================================
@@ -37,6 +37,125 @@
 		array[segment(index)][displacement(index)] = value;
 	}
 
+#if KEY_CLASS_Long || KEY_CLASS_Integer
+	/** Returns the length of the given big atomic array.
+	 *
+	 * @param array a big atomic array.
+	 * @return the length of the given big atomic array.
+	 */
+	public static long length(final ATOMIC_ARRAY[] array) {
+		final int length = array.length;
+		return length == 0 ? 0 : start(length - 1) + array[length - 1].length();
+	}
+
+	/** Returns the element of the given big atomic array of specified index.
+	 *
+	 * @param array a big atomic array.
+	 * @param index a position in the big atomic array.
+	 * @return the element of the big atomic array at the specified position.
+	 */
+	public static KEY_TYPE get(final ATOMIC_ARRAY[] array, final long index) {
+		return array[segment(index)].get(displacement(index));
+	}
+
+	/** Sets an element of the given big atomic array to a specified value
+	 *
+	 * @param array a big atomic array.
+	 * @param index a position in the big atomic array.
+	 * @param value a new value for the element of the big atomic array at the specified position.
+	 */
+	public static void set(final ATOMIC_ARRAY[] array, final long index, KEY_TYPE value) {
+		array[segment(index)].set(displacement(index), value);
+	}
+
+	/** Atomically sets an element of the given big atomic array to a specified value, returning the old value.
+	 *
+	 * @param array a big atomic array.
+	 * @param index a position in the big atomic array.
+	 * @param value a new value for the element of the big atomic array at the specified position.
+	 * @return the old value of the element of the big atomic array at the specified position.
+	 */
+	public static KEY_TYPE getAndSet(final ATOMIC_ARRAY[] array, final long index, KEY_TYPE value) {
+		return array[segment(index)].getAndSet(displacement(index), value);
+	}
+
+	/** Atomically adds a value to an element of the given big atomic array, returning the old value.
+	 *
+	 * @param array a big atomic array.
+	 * @param index a position in the big atomic array.
+	 * @param value a value to add to the element of the big atomic array at the specified position.
+	 * @return the old value of the element of the big atomic array at the specified position.
+	 */
+	public static KEY_TYPE getAndAdd(final ATOMIC_ARRAY[] array, final long index, KEY_TYPE value) {
+		return array[segment(index)].getAndAdd(displacement(index), value);
+	}
+
+	/** Atomically adds a value to an element of the given big atomic array, returning the new value.
+	 *
+	 * @param array a big atomic array.
+	 * @param index a position in the big atomic array.
+	 * @param value a value to add to the element of the big atomic array at the specified position.
+	 * @return the new value of the element of the big atomic array at the specified position.
+	 */
+	public static KEY_TYPE addAndGet(final ATOMIC_ARRAY[] array, final long index, KEY_TYPE value) {
+		return array[segment(index)].addAndGet(displacement(index), value);
+	}
+
+	/** Atomically increments an element of the given big atomic array, returning the old value.
+	 *
+	 * @param array a big atomic array.
+	 * @param index a position in the big atomic array.
+	 * @return the old value of the element of the big atomic array at the specified position.
+	 */
+	public static KEY_TYPE getAndIncrement(final ATOMIC_ARRAY[] array, final long index) {
+		return array[segment(index)].getAndDecrement(displacement(index));
+	}
+
+	/** Atomically increments an element of the given big atomic array, returning the new value.
+	 *
+	 * @param array a big atomic array.
+	 * @param index a position in the big atomic array.
+	 * @return the new value of the element of the big atomic array at the specified position.
+	 */
+	public static KEY_TYPE incrementAndGet(final ATOMIC_ARRAY[] array, final long index) {
+		return array[segment(index)].incrementAndGet(displacement(index));
+	}
+
+	/** Atomically decrements an element of the given big atomic array, returning the old value.
+	 *
+	 * @param array a big atomic array.
+	 * @param index a position in the big atomic array.
+	 * @return the old value of the element of the big atomic array at the specified position.
+	 */
+	public static KEY_TYPE getAndDecrement(final ATOMIC_ARRAY[] array, final long index) {
+		return array[segment(index)].getAndDecrement(displacement(index));
+	}
+
+	/** Atomically decrements an element of the given big atomic array, returning the new value.
+	 *
+	 * @param array a big atomic array.
+	 * @param index a position in the big atomic array.
+	 * @return the new value of the element of the big atomic array at the specified position.
+	 */
+	public static KEY_TYPE decrementAndGet(final ATOMIC_ARRAY[] array, final long index) {
+		return array[segment(index)].decrementAndGet(displacement(index));
+	}
+
+	/** Atomically sets an element of the given big atomic array of specified index to specified value, given 
+	 *  the current value is equal to a given expected value.
+	 *
+	 * @param array a big atomic array.
+	 * @param index a position in the big atomic array.
+	 * @param expected an expected value for the element of the big atomic array at the specified position.
+	 * @param value a new value for the element of the big atomic array at the specified position.
+	 * @return the element of the big atomic array at the specified position.
+	 */
+	public static boolean compareAndSet(final ATOMIC_ARRAY[] array, final long index, KEY_TYPE expected, KEY_TYPE value) {
+		return array[segment(index)].compareAndSet(displacement(index), expected, value);
+	}
+
+#endif
+
 	/** Swaps the element of the given big array of specified indices.
 	 *
 	 * @param array a big array.


=====================================
drv/List.drv
=====================================
@@ -155,7 +155,7 @@ public interface LIST KEY_GENERIC extends List<KEY_GENERIC_CLASS>, COLLECTION KE
 	 * <pre><code>
 	 * ListIterator iter = listIterator(index);
 	 * int i = 0;
-	 * while (i < length) {
+	 * while (i < length) {
 	 *   iter.next();
 	 *   iter.set(a[offset + i++]);
 	 * }
@@ -334,7 +334,7 @@ public interface LIST KEY_GENERIC extends List<KEY_GENERIC_CLASS>, COLLECTION KE
 	 * {@link #toArray()}, sorts the array, then replaces all elements using the
 	 * {@link #setElements} function.
 	 *
-	 * @implNote It is possible for this method to call {@link #unstableSort} if it can
+	 * @implneNote It is possible for this method to call {@link #unstableSort} if it can
 	 * determine that the results of a stable and unstable sort are completely equivalent.
 	 * This means if you override {@link #unstableSort}, it should <em>not</em> call this
 	 * method unless you override this method as well.


=====================================
drv/OpenHashMap.drv
=====================================
@@ -251,7 +251,7 @@ public class OPEN_HASH_MAP KEY_VALUE_GENERIC extends ABSTRACT_MAP KEY_VALUE_GENE
 	SUPPRESS_WARNINGS_KEY_VALUE_UNCHECKED
 	public OPEN_HASH_MAP(final int expected, 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 (f <= 0 || f >= 1) throw new IllegalArgumentException("Load factor must be greater than 0 and smaller than 1");
 		if (expected < 0) throw new IllegalArgumentException("The expected number of elements must be nonnegative");
 
 		this.f = f;


=====================================
drv/OpenHashSet.drv
=====================================
@@ -206,7 +206,7 @@ public class OPEN_HASH_SET KEY_GENERIC extends ABSTRACT_SET KEY_GENERIC implemen
 	SUPPRESS_WARNINGS_KEY_UNCHECKED
 	public OPEN_HASH_SET(final int expected, 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 (f <= 0 || f >= 1) throw new IllegalArgumentException("Load factor must be greater than 0 and smaller than 1");
 		if (expected < 0) throw new IllegalArgumentException("The expected number of elements must be nonnegative");
 
 		this.f = f;


=====================================
gencsource.sh
=====================================
@@ -346,6 +346,7 @@ fi)\
 "#define LIST ${TYPE_CAP[$k]}List\n"\
 "#define BIG_LIST ${TYPE_CAP[$k]}BigList\n"\
 "#define STACK ${TYPE_STD[$k]}Stack\n"\
+"#define ATOMIC_ARRAY Atomic${CLASS[$k]}Array\n"\
 "#define PRIORITY_QUEUE ${TYPE_STD[$k]}PriorityQueue\n"\
 "#define INDIRECT_PRIORITY_QUEUE ${TYPE_STD[$k]}IndirectPriorityQueue\n"\
 "#define INDIRECT_DOUBLE_PRIORITY_QUEUE ${TYPE_STD[$k]}IndirectDoublePriorityQueue\n"\
@@ -454,6 +455,7 @@ fi)\
 "#define ARRAY_LIST ${TYPE_CAP[$k]}ArrayList\n"\
 "#define BIG_ARRAY_BIG_LIST ${TYPE_CAP[$k]}BigArrayBigList\n"\
 "#define ARRAY_FRONT_CODED_LIST ${TYPE_CAP[$k]}ArrayFrontCodedList\n"\
+"#define ARRAY_FRONT_CODED_BIG_LIST ${TYPE_CAP[$k]}ArrayFrontCodedBigList\n"\
 "#define HEAP_PRIORITY_QUEUE ${TYPE_CAP2[$k]}HeapPriorityQueue\n"\
 "#define HEAP_SEMI_INDIRECT_PRIORITY_QUEUE ${TYPE_CAP2[$k]}HeapSemiIndirectPriorityQueue\n"\
 "#define HEAP_INDIRECT_PRIORITY_QUEUE ${TYPE_CAP2[$k]}HeapIndirectPriorityQueue\n"\


=====================================
makefile
=====================================
@@ -404,6 +404,11 @@ $(FRONT_CODED_LISTS): drv/ArrayFrontCodedList.drv; ./gencsource.sh $< $@ >$@
 
 CSOURCES += $(FRONT_CODED_LISTS)
 
+FRONT_CODED_BIG_LISTS := $(foreach k, $(if $(SMALL_TYPES),Byte Short Char,) Int Long, $(GEN_SRCDIR)/$(PKG_PATH)/$(PACKAGE_$(k))/$(k)ArrayFrontCodedBigList.c)
+$(FRONT_CODED_BIG_LISTS): drv/ArrayFrontCodedBigList.drv; ./gencsource.sh $< $@ >$@
+
+CSOURCES += $(FRONT_CODED_BIG_LISTS)
+
 HEAP_PRIORITY_QUEUES := $(foreach k,$(TYPE_NOBOOL_NOREF), $(GEN_SRCDIR)/$(PKG_PATH)/$(PACKAGE_$(k))/$(k)HeapPriorityQueue.c)
 $(HEAP_PRIORITY_QUEUES): drv/HeapPriorityQueue.drv; ./gencsource.sh $< $@ >$@
 


=====================================
pom.xml
=====================================
@@ -4,7 +4,7 @@
   <artifactId>fastutil</artifactId>
   <packaging>jar</packaging>
   <name>fastutil</name>
-  <version>8.3.1</version>
+  <version>8.4.2</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://fastutil.di.unimi.it/</url>
   <licenses>


=====================================
src/it/unimi/dsi/fastutil/SafeMath.java
=====================================
@@ -42,7 +42,7 @@ public final class SafeMath {
 	public static float safeDoubleToFloat(final double value) {
 		if (Double.isNaN(value)) return Float.NaN;
 		if (Double.isInfinite(value)) return value < 0.0d ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
-		if (value < Float.MIN_VALUE || Float.MAX_VALUE < value) throw new IllegalArgumentException(value + " can't be represented as float (out of range)");
+		if (value < -Float.MAX_VALUE || Float.MAX_VALUE < value) throw new IllegalArgumentException(value + " can't be represented as float (out of range)");
 		final float floatValue = (float) value;
 		if (floatValue != value) throw new IllegalArgumentException(value + " can't be represented as float (imprecise)");
 		return floatValue;


=====================================
src/overview.html
=====================================
@@ -11,7 +11,7 @@
     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. It is
     free software
-    distributed under the <a HREF="http://www.apache.org/licenses/liCENSE-2.0.html">Apache License 2.0</a>.
+    distributed under the <a HREF="http://www.apache.org/licenses/LICENSE-2.0.html">Apache License 2.0</a>.
 
 
 
@@ -92,6 +92,7 @@
     {@link it.unimi.dsi.fastutil.BigArrays} and {@link it.unimi.dsi.fastutil.ints.IntBigArrays}
     to get an idea of the generic and type-specific methods available.
 
+	<p>Limited support is available for big atomic arrays of integers and longs.
 
     <h3>Fast and practical I/O</h3>
 
@@ -456,7 +457,7 @@
     <li>The standard entry-set iterators for hash-based maps use an entry object
     that refers to the data contained in the hash table. If you retrieve an
     entry and delete it, the entry object will become invalid and will throw
-    an {@link java.util.ArrayIndexOutOfBounds} exception. This does not
+    an {@link java.util.ArrayIndexOutOfBoundsException} exception. This does not
     apply to fast iterators (see above).</li>
 
     <li>A name clash between the list and collection interfaces
@@ -519,7 +520,7 @@
     <p><code>fastutil</code>
     provides interfaces, abstract implementations and the usual array of wrappers
     in the suitable static container (e.g., {@link it.unimi.dsi.fastutil.ints.Int2IntFunctions}).
-    Implementations will be provided by other projects (e.g., <a href="http://sux.dsi.unimi.it/">Sux4J</a>).
+    Implementations will be provided by other projects (e.g., <a href="http://sux.di.unimi.it/">Sux4J</a>).
     Type-specific functions require just to define their {@code get()} methods: thus, they can be defined
     by lambda expressions.
 
@@ -701,7 +702,7 @@
     as well as static containers (see, e.g., {@link it.unimi.dsi.fastutil.ints.IntBigLists}).
     Whereas it is unlikely that such collection will be in main memory as big arrays, there
     are number of situations, such as exposing large files through a list interface or
-    storing a large amount of data using <a href="http://sux4j.dsi.unimi.it/">succinct data structures</a>,
+    storing a large amount of data using <a href="http://sux4j.di.unimi.it/">succinct data structures</a>,
     in which a big list interface is natural.
 
     <p>Unfortunately, {@linkplain java.util.List lists} and {@linkplain it.unimi.dsi.fastutil.BigList big lists},
@@ -794,7 +795,7 @@
     your virtual machine, JVM versions, CPU etc.
 
     <p>More precisely, when you ask for a map that will hold <var>n</var>
-    elements with load factor 0 < <var>f</var> ≤ 1,
+    elements with load factor 0 < <var>f</var> < 1,
     2<sup>⌈log <var>n</var> / <var>f</var>⌉</sup>
     entries are allocated. When the table is filled up beyond the load factor, it is rehashed
     doubling its size. When it is emptied below <em>one fourth</em> of the load factor, it


=====================================
test/it/unimi/dsi/fastutil/ints/Int2IntArrayMapTest.java
=====================================
@@ -0,0 +1,32 @@
+package it.unimi.dsi.fastutil.ints;
+
+/*
+ * Copyright (C) 2020 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.
+ */
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.HashMap;
+
+import org.junit.Test;
+
+public class Int2IntArrayMapTest {
+	@Test
+	public void testCopyConstructor() {
+		final Int2IntOpenHashMap m = new Int2IntOpenHashMap(new int [] {1, 2}, new int[] {3, 4});
+		assertEquals(new Int2IntArrayMap(m), m);
+		assertEquals(new HashMap<>(m), m);
+	}
+}


=====================================
test/it/unimi/dsi/fastutil/ints/IntArraySetTest.java
=====================================
@@ -16,9 +16,9 @@ package it.unimi.dsi.fastutil.ints;
  * limitations under the License.
  */
 
-import it.unimi.dsi.fastutil.ints.IntArraySet;
-import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
-import it.unimi.dsi.fastutil.io.BinIO;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -26,13 +26,21 @@ import java.io.IOException;
 import java.io.ObjectOutputStream;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 
 import org.junit.Test;
 
-import static org.junit.Assert.*;
+import it.unimi.dsi.fastutil.io.BinIO;
 
 public class IntArraySetTest {
 
+	@Test
+	public void testCopyConstructor() {
+		final IntOpenHashSet s = new IntOpenHashSet(new int[] { 1, 2 });
+		assertEquals(new IntArraySet(s), s);
+		assertEquals(new HashSet<>(s), s);
+	}
+
 	@SuppressWarnings("boxing")
 	@Test
 	public void testNullInEquals() {
@@ -70,7 +78,7 @@ public class IntArraySetTest {
 
 	@Test
 	public void testClone() {
-		IntArraySet s = new IntArraySet();
+		final IntArraySet s = new IntArraySet();
 		assertEquals(s, s.clone());
 		s.add(0);
 		assertEquals(s, s.clone());
@@ -86,8 +94,8 @@ public class IntArraySetTest {
 
 	@Test
 	public void testSerialisation() throws IOException, ClassNotFoundException {
-		IntArraySet s = new IntArraySet();
-		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		final IntArraySet s = new IntArraySet();
+		final ByteArrayOutputStream baos = new ByteArrayOutputStream();
 		ObjectOutputStream oos = new ObjectOutputStream(baos);
 		oos.writeObject(s);
 		oos.close();


=====================================
test/it/unimi/dsi/fastutil/ints/IntBigArraysTest.java
=====================================
@@ -75,6 +75,78 @@ public class IntBigArraysTest {
 
 	}
 
+	@Test
+	public void testParallelQuickSort1Comp() {
+		int[][] t = {{ 2, 1, 0, 4 }};
+		IntBigArrays.parallelQuickSort(t, IntComparators.OPPOSITE_COMPARATOR);
+		for (long i = length(t) - 1; i-- != 0;) assertTrue(get(t, i) >= get(t, i + 1));
+
+		t = new int[][] {{ 2, -1, 0, -4 }};
+		IntBigArrays.parallelQuickSort(t, IntComparators.OPPOSITE_COMPARATOR);
+		for (long i = length(t) - 1; i-- != 0;) assertTrue(get(t, i) >= get(t, i + 1));
+
+		t = IntBigArrays.shuffle(identity(100), new Random(0));
+		IntBigArrays.parallelQuickSort(t, IntComparators.OPPOSITE_COMPARATOR);
+		for (long i = length(t) - 1; i-- != 0;) assertTrue(get(t, i) >= get(t, i + 1));
+
+		t = new int[1][100];
+		Random random = new Random(0);
+		for (long i = length(t) - 1; i-- != 0;) set(t, i, random.nextInt());
+		IntBigArrays.parallelQuickSort(t, IntComparators.OPPOSITE_COMPARATOR);
+		for (long i = length(t) - 1; i-- != 0;) assertTrue(get(t, i) >= get(t, i + 1));
+
+		t = new int[1][100000];
+		random = new Random(0);
+		for (long i = length(t); i-- != 0;) set(t, i, random.nextInt());
+		IntBigArrays.parallelQuickSort(t, IntComparators.OPPOSITE_COMPARATOR);
+		for (long i = length(t) - 1; i-- != 0;) assertTrue(get(t, i) >= get(t, i + 1));
+		for(int i = 100; i-- != 10;) set(t, i, random.nextInt());
+		IntBigArrays.parallelQuickSort(t, 10, 100, IntComparators.OPPOSITE_COMPARATOR);
+		for (int i = 99; i-- != 10;) assertTrue(get(t, i) >= get(t, i + 1));
+
+		t = new int[1][10000000];
+		random = new Random(0);
+		for (long i = length(t); i-- != 0;) set(t, i, random.nextInt());
+		IntBigArrays.parallelQuickSort(t, IntComparators.OPPOSITE_COMPARATOR);
+		for (long i = length(t) - 1; i-- != 0;) assertTrue(get(t, i) >= get(t, i + 1));
+	}
+
+	@Test
+	public void testParallelQuickSort1() {
+		int[][] t = { { 2, 1, 0, 4 } };
+		IntBigArrays.parallelQuickSort(t);
+		for (long i = length(t) - 1; i-- != 0;) assertTrue(get(t, i) <= get(t, i + 1));
+
+		t = new int[][] { { 2, -1, 0, -4 } };
+		IntBigArrays.parallelQuickSort(t);
+		for (long i = length(t) - 1; i-- != 0;) assertTrue(get(t, i) <= get(t, i + 1));
+
+		t = IntBigArrays.shuffle(identity(100), new Random(0));
+		IntBigArrays.parallelQuickSort(t);
+		for (long i = length(t) - 1; i-- != 0;) assertTrue(get(t, i) <= get(t, i + 1));
+
+		t = new int[1][100];
+		Random random = new Random(0);
+		for (long i = length(t); i-- != 0;) set(t, i, random.nextInt());
+		IntBigArrays.parallelQuickSort(t);
+		for (long i = length(t) - 1; i-- != 0;) assertTrue(get(t, i) <= get(t, i + 1));
+
+		t = new int[1][100000];
+		random = new Random(0);
+		for (long i = length(t); i-- != 0;) set(t, i, random.nextInt());
+		IntBigArrays.parallelQuickSort(t);
+		for (long i = length(t) - 1; i-- != 0;) assertTrue(get(t, i) <= get(t, i + 1));
+		for (int i = 100; i-- != 10;) set(t, i, random.nextInt());
+		IntBigArrays.parallelQuickSort(t, 10, 100);
+		for (int i = 99; i-- != 10;) assertTrue(get(t, i) <= get(t, i + 1));
+
+		t = new int[1][10000000];
+		random = new Random(0);
+		for (long i = length(t); i-- != 0;) set(t, i, random.nextInt());
+		IntBigArrays.parallelQuickSort(t);
+		for (long i = length(t) - 1; i-- != 0;) assertTrue(get(t, i) <= get(t, i + 1));
+	}
+
 	private void testCopy(final int n) {
 		final int[][] a = IntBigArrays.newBigArray(n);
 		for (int i = 0; i < n; i++) set(a, i, i);


=====================================
test/it/unimi/dsi/fastutil/ints/IntOpenHashSetTest.java
=====================================
@@ -58,17 +58,6 @@ public class IntOpenHashSetTest {
 		assertFalse(s.equals(new ObjectOpenHashSet<>(new Integer[] { 1, null })));
 	}
 
-	@Test
-	public void testInfiniteLoop0() {
-		final 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() {
 		final IntOpenHashSet set = new IntOpenHashSet();
@@ -131,7 +120,7 @@ public class IntOpenHashSetTest {
 	@Test
 	public void testSmallExpectedValuesWeirdLoadFactors() {
 		for(int expected = 0; expected < 5; expected ++)
-			for(final float loadFactor: new float[] { Float.MIN_VALUE, .25f, .5f, .75f, 1 - Float.MIN_VALUE }) {
+			for(final float loadFactor: new float[] { Float.MIN_VALUE, .25f, .5f, .75f, 0.9999999f }) {
 				final IntOpenHashSet s = new IntOpenHashSet(0, loadFactor);
 				assertTrue(s.add(2));
 				assertTrue(s.add(3));
@@ -317,7 +306,7 @@ public class IntOpenHashSetTest {
 		int maxProbes = 0;
 		final int[] key = m.key;
 		final double f = (double)m.size / m.n;
-		for (int i = 0, c = 0; i < m.n; i++) {
+		for (int i = 0, c = 0; i < m.n; i++)
 			if (key[i] != 0) c++;
 			else {
 				if (c != 0) {
@@ -330,7 +319,6 @@ public class IntOpenHashSetTest {
 				totProbes++;
 				totSquareProbes++;
 			}
-		}
 
 		final double expected = (double)totProbes / m.n;
 		System.err.println("Expected probes: " + (



View it on GitLab: https://salsa.debian.org/java-team/libfastutil-java/-/commit/3d7591be09e2d94289015dc4af33f9c1a790127d

-- 
View it on GitLab: https://salsa.debian.org/java-team/libfastutil-java/-/commit/3d7591be09e2d94289015dc4af33f9c1a790127d
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20201021/92d3f142/attachment.html>


More information about the pkg-java-commits mailing list