it.unimi.dsi.fastutil.BigArrays Maven / Gradle / Ivy
Show all versions of fastutil-core Show documentation
/*
* Copyright (C) 2010-2021 Sebastiano Vigna
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* For the sorting code:
*
* Copyright (C) 1999 CERN - European Organization for Nuclear Research.
*
* Permission to use, copy, modify, distribute and sell this software and
* its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation. CERN makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without expressed or implied warranty.
*/
package it.unimi.dsi.fastutil;
import it.unimi.dsi.fastutil.ints.IntBigArrayBigList;
import it.unimi.dsi.fastutil.longs.LongComparator;
import it.unimi.dsi.fastutil.bytes.ByteBigArrays;
import it.unimi.dsi.fastutil.booleans.BooleanBigArrays;
import it.unimi.dsi.fastutil.chars.CharBigArrays;
import it.unimi.dsi.fastutil.shorts.ShortBigArrays;
import it.unimi.dsi.fastutil.ints.IntBigArrays;
import it.unimi.dsi.fastutil.longs.LongBigArrays;
import it.unimi.dsi.fastutil.floats.FloatBigArrays;
import it.unimi.dsi.fastutil.doubles.DoubleBigArrays;
import it.unimi.dsi.fastutil.objects.ObjectBigArrays;
import it.unimi.dsi.fastutil.booleans.BooleanArrays;
import it.unimi.dsi.fastutil.bytes.ByteArrays;
import it.unimi.dsi.fastutil.chars.CharArrays;
import it.unimi.dsi.fastutil.shorts.ShortArrays;
import it.unimi.dsi.fastutil.ints.IntArrays;
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;
/**
* A class providing static methods and objects that do useful things with big
* arrays.
*
* Introducing big arrays
*
*
* A big array 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} * (231 −
* 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[][]}.
* Note that {@link #SEGMENT_SIZE} has been chosen so that a single segment is
* smaller than 231 bytes independently of the data type. It might be
* enlarged in the future.
*
*
* If {@code a} is a big array, {@code a[0]}, {@code a[1]}, … are called
* the segments of the big array. All segments, except possibly for the
* last one, are of length {@link #SEGMENT_SIZE}. Given an index {@code i} into
* a big array, there is an associated {@linkplain #segment(long)
* segment} and an associated {@linkplain #displacement(long)
* displacement} into that segment. Access to single members happens by
* means of accessors (see, e.g., {@link #get(int[][], long)} and
* {@link #set(int[][], long, int)}), but you can also use the methods
* {@link #segment(long)}/{@link #displacement(long)} to access entries
* manually.
*
*
* The intended usage of most of the methods of this class is that they will be
* imported statically: for example,
*
*
* import static it.unimi.dsi.fastutil.BigArrays.copy;
* import static it.unimi.dsi.fastutil.BigArrays.get;
* import static it.unimi.dsi.fastutil.BigArrays.length;
* import static it.unimi.dsi.fastutil.BigArrays.set;
*
*
*
* Dynamic binding will take care of selecting the right method depending on the
* array type.
*
*
Scanning big arrays
*
*
* You can scan a big array using the following idiomatic form:
*
*
* 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]
* }
* }
*
*
* or using the simpler reversed version:
*
*
* for(int s = a.length; s-- != 0;) {
* final int[] t = a[s];
* for(int d = t.length; d-- != 0;) {
* do something with t[d]
* }
* }
*
*
* Inside the inner loop, the original index in {@code a} can be retrieved using
* {@link #index(int, int) index(segment, displacement)}. You can also use an
* additional long to keep track of the index.
*
*
* 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.
*
*
* 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:
*
*
* 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]
* }
* }
*
*
* or, in a reversed form,
*
*
* 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]
* }
* }
*
*
* Literal big arrays
*
*
* A literal big array can be easily created by using the suitable type-specific
* {@code wrap()} method (e.g., {@link BigArrays#wrap(int[])}) around a standard
* Java literal array.
*
*
Atomic big arrays
*
*
* 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)}).
*
*
Big alternatives
*
*
* 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.
*
*
Additional methods
*
*
* In particular, the {@code ensureCapacity()}, {@code grow()}, {@code trim()}
* and {@code setLength()} methods allow to handle arrays much like array lists.
*
*
* 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).
*/
public static final int SEGMENT_SHIFT = 27;
/**
* The current size of a segment (227) is the largest size that makes
* the physical memory allocation for a single segment strictly smaller than
* 231 bytes.
*/
public static final int SEGMENT_SIZE = 1 << SEGMENT_SHIFT;
/** The mask used to compute the displacement associated to an index. */
public static final int SEGMENT_MASK = SEGMENT_SIZE - 1;
protected BigArrays() {
}
/**
* Computes the segment associated with a given index.
*
* @param index
* an index into a big array.
* @return the associated segment.
*/
public static int segment(final long index) {
return (int) (index >>> SEGMENT_SHIFT);
}
/**
* 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}).
*/
public static int displacement(final long index) {
return (int) (index & SEGMENT_MASK);
}
/**
* Computes the starting index of a given segment.
*
* @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;
}
/**
* Computes the nearest segment starting index of a given index.
*
*
* This will either be {@code start(segment(index)} or
* {@code start(segment(index) + 1)}, whichever is closer, given the bounds can
* be respected. If neither segment start is within the bounds, then the index
* is returned unmodified.
*
*
* This method can be useful for operations that seek to align on the outer
* array's boundaries when possible.
*
* @implSpec The current implementation is branch heavy and is thus not suitable
* for use in inner loops. However, it should be fine for the
* recursive step, where split points are computed.
*
* @param index
* an index into a big array.
* @param min
* the minimum (inclusive) valid index of the big array in question
* @param max
* the maximum (exclusive) valid index of the big array in question
* @return the closest segment starting index to {@code index}
* @since 8.5.0
*/
public static long nearestSegmentStart(final long index, final long min, final long max) {
// There probably is a less branchy, bit twiddly way to do this, but this is
// fine for now.
// This isn't going to be used in inner loops, only the recursive call.
final long lower = start(segment(index));
final long upper = start(segment(index) + 1);
if (upper >= max) {
if (lower < min) {
return index;
}
return lower;
}
if (lower < min)
return upper;
// Overflow avoiding midpoint computation
final long mid = lower + ((upper - lower) >> 1);
return index <= mid ? lower : upper;
}
/**
* 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}.
*/
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.
*
*
* 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} is greater than {@code to}.
* @throws ArrayIndexOutOfBoundsException
* if {@code from} or {@code to} are greater than
* {@code bigArrayLength} 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 + ")");
}
/**
* Ensures that a range given by an offset and a length fits a big array of
* given length.
*
*
* 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} is negative.
* @throws ArrayIndexOutOfBoundsException
* if {@code offset} is negative or {@code offset} + {@code length}
* is greater than {@code bigArrayLength}.
*/
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.
* @throws IllegalArgumentException
* if {@code length} is negative, or larger than or equal to
* {@link #SEGMENT_SIZE} * {@link Integer#MAX_VALUE}.
*/
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)} and {@code [middle, last)}, and
* the resulting range is {@code [first, last)}. 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);
}
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);
}
long first2 = firstCut;
long middle2 = mid;
long last2 = secondCut;
if (middle2 != first2 && middle2 != last2) {
long first1 = first2;
long last1 = middle2;
while (first1 < --last1)
swapper.swap(first1++, last1);
first1 = middle2;
last1 = last2;
while (first1 < --last1)
swapper.swap(first1++, last1);
first1 = first2;
last1 = last2;
while (first1 < --last1)
swapper.swap(first1++, last1);
}
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.
*
* @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 comp.apply(array[j], x)} is {@code true}.
*/
private static long lowerBound(long mid, final long to, final long firstCut, final LongComparator comp) {
long len = to - mid;
while (len > 0) {
long half = len / 2;
long middle = mid + half;
if (comp.compare(middle, firstCut) < 0) {
mid = middle + 1;
len -= half + 1;
} else {
len = half;
}
}
return mid;
}
/** 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));
}
/**
* Sorts the specified range of elements using the specified big swapper and
* according to the order induced by the specified comparator using mergesort.
*
*
* This sort is guaranteed to be stable: 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
* O(n (log n)2), 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.
*/
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);
}
}
return;
}
// Recursively sort halves
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;
// Merge sorted halves
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.
*
*
* The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M.
* Douglas McIlroy, “Engineering a Sort Function”, Software:
* Practice and Experience, 23(11), pages 1249−1265, 1993.
*
* @param 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) {
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);
}
return;
}
// Choose a partition element, v
long m = from + len / 2; // Small arrays, middle element
if (len > SMALL) {
long l = from, n = to - 1;
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);
}
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*
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);
}
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--);
}
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);
// 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);
}
/**
* 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 comp.apply(x, array[j])} is {@code false}.
*/
private static long upperBound(long from, final long mid, final long secondCut, final LongComparator comp) {
long len = mid - from;
while (len > 0) {
long half = len / 2;
long middle = from + half;
if (comp.compare(secondCut, middle) < 0) {
len = half;
} else {
from = middle + 1;
len -= half + 1;
}
}
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);
}
/* Generic definitions */
/* Assertions (useful to generate conditional code) */
/* Narrowing and widening */
/* Current type and class (and size, if applicable) */
/* Value methods */
/* Interfaces (keys) */
/* Interfaces (values) */
/* Types and methods related to primitive-type support in the JDK */
/* Abstract implementations (keys) */
/* Abstract implementations (values) */
/* Static containers (keys) */
/* Static containers (values) */
/* Implementations */
/* Synchronized wrappers */
/* Unmodifiable wrappers */
/* Other wrappers */
/* Methods (keys) */
/* Methods (values) */
/* Methods (keys/values) */
/*
* Methods that have special names depending on keys (but the special names
* depend on values)
*/
/* Equality */
/* Object/Reference-only definitions (keys) */
/* Primitive-type-only definitions (keys) */
/* Object/Reference-only definitions (values) */
/* START_OF_JAVA_SOURCE */
/*
* Copyright (C) 2004-2021 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.
*/
/**
* Returns the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @return the element of the big array at the specified position.
*/
public static byte get(final byte[][] array, final long index) {
return array[segment(index)][displacement(index)];
}
/**
* Sets the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param value
* the new value for the array element at the specified position.
*/
public static void set(final byte[][] array, final long index, byte value) {
array[segment(index)][displacement(index)] = value;
}
/**
* Swaps the element of the given big array of specified indices.
*
* @param array
* a big array.
* @param first
* a position in the big array.
* @param second
* a position in the big array.
*/
public static void swap(final byte[][] array, final long first, final long second) {
final byte t = array[segment(first)][displacement(first)];
array[segment(first)][displacement(first)] = array[segment(second)][displacement(second)];
array[segment(second)][displacement(second)] = t;
}
/**
* Reverses the order of the elements in the specified big array.
*
* @param a
* the big array to be reversed.
* @return {@code a}.
*/
public static byte[][] reverse(final byte[][] a) {
final long length = length(a);
for (long i = length / 2; i-- != 0;)
swap(a, i, length - i - 1);
return a;
}
/**
* Adds the specified increment the element of the given big array of specified
* index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param incr
* the increment
*/
public static void add(final byte[][] array, final long index, byte incr) {
array[segment(index)][displacement(index)] += incr;
}
/**
* Multiplies by the specified factor the element of the given big array of
* specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param factor
* the factor
*/
public static void mul(final byte[][] array, final long index, byte factor) {
array[segment(index)][displacement(index)] *= factor;
}
/**
* Increments the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void incr(final byte[][] array, final long index) {
array[segment(index)][displacement(index)]++;
}
/**
* Decrements the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void decr(final byte[][] array, final long index) {
array[segment(index)][displacement(index)]--;
}
/**
* Returns the length of the given big array.
*
* @param array
* a big array.
* @return the length of the given big array.
*/
public static long length(final byte[][] array) {
final int length = array.length;
return length == 0 ? 0 : start(length - 1) + array[length - 1].length;
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination big array.
* Handles correctly overlapping regions of the same big array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copy(final byte[][] srcArray, final long srcPos, final byte[][] destArray, final long destPos,
long length) {
if (destPos <= srcPos) {
int srcSegment = segment(srcPos);
int destSegment = segment(destPos);
int srcDispl = displacement(srcPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(length,
Math.min(srcArray[srcSegment].length - srcDispl, destArray[destSegment].length - destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray[destSegment], destDispl, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
length -= l;
}
} else {
int srcSegment = segment(srcPos + length);
int destSegment = segment(destPos + length);
int srcDispl = displacement(srcPos + length);
int destDispl = displacement(destPos + length);
while (length > 0) {
if (srcDispl == 0) {
srcDispl = SEGMENT_SIZE;
srcSegment--;
}
if (destDispl == 0) {
destDispl = SEGMENT_SIZE;
destSegment--;
}
final int l = (int) Math.min(length, Math.min(srcDispl, destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl - l, destArray[destSegment], destDispl - l, l);
srcDispl -= l;
destDispl -= l;
length -= l;
}
}
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyFromBig(final byte[][] srcArray, final long srcPos, final byte[] destArray, int destPos,
int length) {
int srcSegment = segment(srcPos);
int srcDispl = displacement(srcPos);
while (length > 0) {
final int l = Math.min(srcArray[srcSegment].length - srcDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray, destPos, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
destPos += l;
length -= l;
}
}
/**
* Copies an array from the specified source array, beginning at the specified
* position, to the specified position of the destination big array.
*
* @param srcArray
* the source array.
* @param srcPos
* the starting position in the source array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyToBig(final byte[] srcArray, int srcPos, final byte[][] destArray, final long destPos,
long length) {
int destSegment = segment(destPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(destArray[destSegment].length - destDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray, srcPos, destArray[destSegment], destDispl, l);
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
srcPos += l;
length -= l;
}
}
/**
* Turns a standard array into a big array.
*
*
* Note that the returned big array might contain as a segment the original
* array.
*
* @param array
* an array.
* @return a new big array with the same length and content of {@code array}.
*/
public static byte[][] wrap(final byte[] array) {
if (array.length == 0)
return ByteBigArrays.EMPTY_BIG_ARRAY;
if (array.length <= SEGMENT_SIZE)
return new byte[][]{array};
final byte[][] bigArray = ByteBigArrays.newBigArray(array.length);
for (int i = 0; i < bigArray.length; i++)
System.arraycopy(array, (int) start(i), bigArray[i], 0, bigArray[i].length);
return bigArray;
}
/**
* Ensures that a big array can contain the given number of entries.
*
*
* If you cannot foresee whether this big array will need again to be enlarged,
* you should probably use {@code grow()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it contains {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code length(array)} entries are the same as those of {@code array}.
*/
public static byte[][] ensureCapacity(final byte[][] array, final long length) {
return ensureCapacity(array, length, length(array));
}
/**
* Forces a big array to contain the given number of entries, preserving just a
* part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return a big array with {@code length} entries whose first {@code preserve}
* entries are the same as those of {@code array}.
*/
public static byte[][] forceCapacity(final byte[][] array, final long length, final long preserve) {
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_SHIFT);
final byte[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0) {
for (int i = valid; i < baseLength - 1; i++)
base[i] = new byte[SEGMENT_SIZE];
base[baseLength - 1] = new byte[residual];
} else
for (int i = valid; i < baseLength; i++)
base[i] = new byte[SEGMENT_SIZE];
if (preserve - (valid * (long) SEGMENT_SIZE) > 0)
copy(array, valid * (long) SEGMENT_SIZE, base, valid * (long) SEGMENT_SIZE,
preserve - (valid * (long) SEGMENT_SIZE));
return base;
}
/**
* Ensures that a big array can contain the given number of entries, preserving
* just a part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code preserve} entries are the same as those of {@code array}.
*/
public static byte[][] ensureCapacity(final byte[][] array, final long length, final long preserve) {
return length > length(array) ? forceCapacity(array, length, preserve) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code length(array)} entries are the same as
* those of {@code array}.
*/
public static byte[][] grow(final byte[][] array, final long length) {
final long oldLength = length(array);
return length > oldLength ? grow(array, length, oldLength) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length, preserving just a part of the big array.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code preserve} entries are the same as those of
* {@code array}.
*/
public static byte[][] grow(final byte[][] array, final long length, final long preserve) {
final long oldLength = length(array);
return length > oldLength
? ensureCapacity(array, Math.max(oldLength + (oldLength >> 1), length), preserve)
: array;
}
/**
* Trims the given big array to the given length.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new maximum length for the big array.
* @return {@code array}, if it contains {@code length} entries or less;
* otherwise, a big array with {@code length} entries whose entries are
* the same as the first {@code length} entries of {@code array}.
*
*/
public static byte[][] trim(final byte[][] array, final long length) {
ensureLength(length);
final long oldLength = length(array);
if (length >= oldLength)
return array;
final int baseLength = (int) ((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
final byte[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0)
base[baseLength - 1] = ByteArrays.trim(base[baseLength - 1], residual);
return base;
}
/**
* Sets the length of the given big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new length for the big array.
* @return {@code array}, if it contains exactly {@code length} entries;
* otherwise, if it contains more than {@code length} entries,
* a big array with {@code length} entries whose entries are the same as
* the first {@code length} entries of {@code array}; otherwise, a big
* array with {@code length} entries whose first {@code length(array)}
* entries are the same as those of {@code array}.
*
*/
public static byte[][] setLength(final byte[][] array, final long length) {
final long oldLength = length(array);
if (length == oldLength)
return array;
if (length < oldLength)
return trim(array, length);
return ensureCapacity(array, length);
}
/**
* Returns a copy of a portion of a big array.
*
* @param array
* a big array.
* @param offset
* the first element to copy.
* @param length
* the number of elements to copy.
* @return a new big array containing {@code length} elements of {@code array}
* starting at {@code offset}.
*/
public static byte[][] copy(final byte[][] array, final long offset, final long length) {
ensureOffsetLength(array, offset, length);
final byte[][] a = ByteBigArrays.newBigArray(length);
copy(array, offset, a, 0, length);
return a;
}
/**
* Returns a copy of a big array.
*
* @param array
* a big array.
* @return a copy of {@code array}.
*/
public static byte[][] copy(final byte[][] array) {
final byte[][] base = array.clone();
for (int i = base.length; i-- != 0;)
base[i] = array[i].clone();
return base;
}
/**
* Fills the given big array with the given value.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param value
* the new value for all elements of the big array.
*/
public static void fill(final byte[][] array, final byte value) {
for (int i = array.length; i-- != 0;)
java.util.Arrays.fill(array[i], value);
}
/**
* Fills a portion of the given big array with the given value.
*
*
* If possible (i.e., {@code from} is 0) this method uses a backward loop. In
* this case, it is significantly faster than the corresponding method in
* {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param from
* the starting index of the portion to fill.
* @param to
* the end index of the portion to fill.
* @param value
* the new value for all elements of the specified portion of the big
* array.
*/
public static void fill(final byte[][] array, final long from, long to, final byte value) {
final long length = length(array);
BigArrays.ensureFromTo(length, from, to);
if (length == 0)
return; // To avoid addressing array[0]
int fromSegment = segment(from);
int toSegment = segment(to);
int fromDispl = displacement(from);
int toDispl = displacement(to);
if (fromSegment == toSegment) {
java.util.Arrays.fill(array[fromSegment], fromDispl, toDispl, value);
return;
}
if (toDispl != 0)
java.util.Arrays.fill(array[toSegment], 0, toDispl, value);
while (--toSegment > fromSegment)
java.util.Arrays.fill(array[toSegment], value);
java.util.Arrays.fill(array[fromSegment], fromDispl, SEGMENT_SIZE, value);
}
/**
* Returns true if the two big arrays are elementwise equal.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param a1
* a big array.
* @param a2
* another big array.
* @return true if the two big arrays are of the same length, and their elements
* are equal.
*/
public static boolean equals(final byte[][] a1, final byte a2[][]) {
if (length(a1) != length(a2))
return false;
int i = a1.length, j;
byte[] t, u;
while (i-- != 0) {
t = a1[i];
u = a2[i];
j = t.length;
while (j-- != 0)
if (!((t[j]) == (u[j])))
return false;
}
return true;
}
/*
* Returns a string representation of the contents of the specified big array.
*
* The string representation consists of a list of the big array's elements,
* enclosed in square brackets ("[]"). Adjacent elements are separated by the
* characters ", " (a comma followed by a space). Returns "null" if {@code a} is
* null.
*
* @param a the big array whose string representation to return.
*
* @return the string representation of {@code a}.
*/
public static String toString(final byte[][] a) {
if (a == null)
return "null";
final long last = length(a) - 1;
if (last == -1)
return "[]";
final StringBuilder b = new StringBuilder();
b.append('[');
for (long i = 0;; i++) {
b.append(String.valueOf(get(a, i)));
if (i == last)
return b.append(']').toString();
b.append(", ");
}
}
/**
* Ensures that a range given by its first (inclusive) and last (exclusive)
* elements fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param from
* a start index (inclusive).
* @param to
* an end index (inclusive).
* @throws IllegalArgumentException
* if {@code from} is greater than {@code to}.
* @throws ArrayIndexOutOfBoundsException
* if {@code from} or {@code to} are greater than the big array
* length or negative.
*/
public static void ensureFromTo(final byte[][] a, final long from, final long to) {
BigArrays.ensureFromTo(length(a), from, to);
}
/**
* Ensures that a range given by an offset and a length fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param offset
* a start index.
* @param length
* a length (the number of elements in the range).
* @throws IllegalArgumentException
* if {@code length} is negative.
* @throws ArrayIndexOutOfBoundsException
* if {@code offset} is negative or {@code offset}+{@code length} is
* greater than the big array length.
*/
public static void ensureOffsetLength(final byte[][] a, final long offset, final long length) {
BigArrays.ensureOffsetLength(length(a), offset, length);
}
/**
* Ensures that two big arrays are of the same length.
*
* @param a
* a big array.
* @param b
* another big array.
* @throws IllegalArgumentException
* if the two argument arrays are not of the same length.
*/
public static void ensureSameLength(final byte[][] a, final byte[][] b) {
if (length(a) != length(b))
throw new IllegalArgumentException("Array size mismatch: " + length(a) + " != " + length(b));
}
/**
* Shuffles the specified big array fragment using the specified pseudorandom
* number generator.
*
* @param a
* the big array to be shuffled.
* @param from
* the index of the first element (inclusive) to be shuffled.
* @param to
* the index of the last element (exclusive) to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static byte[][] shuffle(final byte[][] a, final long from, final long to, final Random random) {
for (long i = to - from; i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final byte t = BigArrays.get(a, from + i);
BigArrays.set(a, from + i, BigArrays.get(a, from + p));
BigArrays.set(a, from + p, t);
}
return a;
}
/**
* Shuffles the specified big array using the specified pseudorandom number
* generator.
*
* @param a
* the big array to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static byte[][] shuffle(final byte[][] a, final Random random) {
for (long i = length(a); i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final byte t = BigArrays.get(a, i);
BigArrays.set(a, i, BigArrays.get(a, p));
BigArrays.set(a, p, t);
}
return a;
}
/* Generic definitions */
/* Assertions (useful to generate conditional code) */
/* Narrowing and widening */
/* Current type and class (and size, if applicable) */
/* Value methods */
/* Interfaces (keys) */
/* Interfaces (values) */
/* Types and methods related to primitive-type support in the JDK */
/* Abstract implementations (keys) */
/* Abstract implementations (values) */
/* Static containers (keys) */
/* Static containers (values) */
/* Implementations */
/* Synchronized wrappers */
/* Unmodifiable wrappers */
/* Other wrappers */
/* Methods (keys) */
/* Methods (values) */
/* Methods (keys/values) */
/*
* Methods that have special names depending on keys (but the special names
* depend on values)
*/
/* Equality */
/* Object/Reference-only definitions (keys) */
/* Primitive-type-only definitions (keys) */
/* Object/Reference-only definitions (values) */
/* START_OF_JAVA_SOURCE */
/*
* Copyright (C) 2004-2021 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.
*/
/**
* Returns the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @return the element of the big array at the specified position.
*/
public static int get(final int[][] array, final long index) {
return array[segment(index)][displacement(index)];
}
/**
* Sets the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param value
* the new value for the array element at the specified position.
*/
public static void set(final int[][] array, final long index, int value) {
array[segment(index)][displacement(index)] = value;
}
/**
* 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 AtomicIntegerArray[] 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 int get(final AtomicIntegerArray[] 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 AtomicIntegerArray[] array, final long index, int 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 int getAndSet(final AtomicIntegerArray[] array, final long index, int 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 int getAndAdd(final AtomicIntegerArray[] array, final long index, int 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 int addAndGet(final AtomicIntegerArray[] array, final long index, int 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 int getAndIncrement(final AtomicIntegerArray[] 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 int incrementAndGet(final AtomicIntegerArray[] 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 int getAndDecrement(final AtomicIntegerArray[] 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 int decrementAndGet(final AtomicIntegerArray[] 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 AtomicIntegerArray[] array, final long index, int expected, int value) {
return array[segment(index)].compareAndSet(displacement(index), expected, value);
}
/**
* Swaps the element of the given big array of specified indices.
*
* @param array
* a big array.
* @param first
* a position in the big array.
* @param second
* a position in the big array.
*/
public static void swap(final int[][] array, final long first, final long second) {
final int t = array[segment(first)][displacement(first)];
array[segment(first)][displacement(first)] = array[segment(second)][displacement(second)];
array[segment(second)][displacement(second)] = t;
}
/**
* Reverses the order of the elements in the specified big array.
*
* @param a
* the big array to be reversed.
* @return {@code a}.
*/
public static int[][] reverse(final int[][] a) {
final long length = length(a);
for (long i = length / 2; i-- != 0;)
swap(a, i, length - i - 1);
return a;
}
/**
* Adds the specified increment the element of the given big array of specified
* index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param incr
* the increment
*/
public static void add(final int[][] array, final long index, int incr) {
array[segment(index)][displacement(index)] += incr;
}
/**
* Multiplies by the specified factor the element of the given big array of
* specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param factor
* the factor
*/
public static void mul(final int[][] array, final long index, int factor) {
array[segment(index)][displacement(index)] *= factor;
}
/**
* Increments the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void incr(final int[][] array, final long index) {
array[segment(index)][displacement(index)]++;
}
/**
* Decrements the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void decr(final int[][] array, final long index) {
array[segment(index)][displacement(index)]--;
}
/**
* Returns the length of the given big array.
*
* @param array
* a big array.
* @return the length of the given big array.
*/
public static long length(final int[][] array) {
final int length = array.length;
return length == 0 ? 0 : start(length - 1) + array[length - 1].length;
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination big array.
* Handles correctly overlapping regions of the same big array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copy(final int[][] srcArray, final long srcPos, final int[][] destArray, final long destPos,
long length) {
if (destPos <= srcPos) {
int srcSegment = segment(srcPos);
int destSegment = segment(destPos);
int srcDispl = displacement(srcPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(length,
Math.min(srcArray[srcSegment].length - srcDispl, destArray[destSegment].length - destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray[destSegment], destDispl, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
length -= l;
}
} else {
int srcSegment = segment(srcPos + length);
int destSegment = segment(destPos + length);
int srcDispl = displacement(srcPos + length);
int destDispl = displacement(destPos + length);
while (length > 0) {
if (srcDispl == 0) {
srcDispl = SEGMENT_SIZE;
srcSegment--;
}
if (destDispl == 0) {
destDispl = SEGMENT_SIZE;
destSegment--;
}
final int l = (int) Math.min(length, Math.min(srcDispl, destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl - l, destArray[destSegment], destDispl - l, l);
srcDispl -= l;
destDispl -= l;
length -= l;
}
}
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyFromBig(final int[][] srcArray, final long srcPos, final int[] destArray, int destPos,
int length) {
int srcSegment = segment(srcPos);
int srcDispl = displacement(srcPos);
while (length > 0) {
final int l = Math.min(srcArray[srcSegment].length - srcDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray, destPos, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
destPos += l;
length -= l;
}
}
/**
* Copies an array from the specified source array, beginning at the specified
* position, to the specified position of the destination big array.
*
* @param srcArray
* the source array.
* @param srcPos
* the starting position in the source array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyToBig(final int[] srcArray, int srcPos, final int[][] destArray, final long destPos,
long length) {
int destSegment = segment(destPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(destArray[destSegment].length - destDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray, srcPos, destArray[destSegment], destDispl, l);
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
srcPos += l;
length -= l;
}
}
/**
* Turns a standard array into a big array.
*
*
* Note that the returned big array might contain as a segment the original
* array.
*
* @param array
* an array.
* @return a new big array with the same length and content of {@code array}.
*/
public static int[][] wrap(final int[] array) {
if (array.length == 0)
return IntBigArrays.EMPTY_BIG_ARRAY;
if (array.length <= SEGMENT_SIZE)
return new int[][]{array};
final int[][] bigArray = IntBigArrays.newBigArray(array.length);
for (int i = 0; i < bigArray.length; i++)
System.arraycopy(array, (int) start(i), bigArray[i], 0, bigArray[i].length);
return bigArray;
}
/**
* Ensures that a big array can contain the given number of entries.
*
*
* If you cannot foresee whether this big array will need again to be enlarged,
* you should probably use {@code grow()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it contains {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code length(array)} entries are the same as those of {@code array}.
*/
public static int[][] ensureCapacity(final int[][] array, final long length) {
return ensureCapacity(array, length, length(array));
}
/**
* Forces a big array to contain the given number of entries, preserving just a
* part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return a big array with {@code length} entries whose first {@code preserve}
* entries are the same as those of {@code array}.
*/
public static int[][] forceCapacity(final int[][] array, final long length, final long preserve) {
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_SHIFT);
final int[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0) {
for (int i = valid; i < baseLength - 1; i++)
base[i] = new int[SEGMENT_SIZE];
base[baseLength - 1] = new int[residual];
} else
for (int i = valid; i < baseLength; i++)
base[i] = new int[SEGMENT_SIZE];
if (preserve - (valid * (long) SEGMENT_SIZE) > 0)
copy(array, valid * (long) SEGMENT_SIZE, base, valid * (long) SEGMENT_SIZE,
preserve - (valid * (long) SEGMENT_SIZE));
return base;
}
/**
* Ensures that a big array can contain the given number of entries, preserving
* just a part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code preserve} entries are the same as those of {@code array}.
*/
public static int[][] ensureCapacity(final int[][] array, final long length, final long preserve) {
return length > length(array) ? forceCapacity(array, length, preserve) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code length(array)} entries are the same as
* those of {@code array}.
*/
public static int[][] grow(final int[][] array, final long length) {
final long oldLength = length(array);
return length > oldLength ? grow(array, length, oldLength) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length, preserving just a part of the big array.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code preserve} entries are the same as those of
* {@code array}.
*/
public static int[][] grow(final int[][] array, final long length, final long preserve) {
final long oldLength = length(array);
return length > oldLength
? ensureCapacity(array, Math.max(oldLength + (oldLength >> 1), length), preserve)
: array;
}
/**
* Trims the given big array to the given length.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new maximum length for the big array.
* @return {@code array}, if it contains {@code length} entries or less;
* otherwise, a big array with {@code length} entries whose entries are
* the same as the first {@code length} entries of {@code array}.
*
*/
public static int[][] trim(final int[][] array, final long length) {
ensureLength(length);
final long oldLength = length(array);
if (length >= oldLength)
return array;
final int baseLength = (int) ((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
final int[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0)
base[baseLength - 1] = IntArrays.trim(base[baseLength - 1], residual);
return base;
}
/**
* Sets the length of the given big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new length for the big array.
* @return {@code array}, if it contains exactly {@code length} entries;
* otherwise, if it contains more than {@code length} entries,
* a big array with {@code length} entries whose entries are the same as
* the first {@code length} entries of {@code array}; otherwise, a big
* array with {@code length} entries whose first {@code length(array)}
* entries are the same as those of {@code array}.
*
*/
public static int[][] setLength(final int[][] array, final long length) {
final long oldLength = length(array);
if (length == oldLength)
return array;
if (length < oldLength)
return trim(array, length);
return ensureCapacity(array, length);
}
/**
* Returns a copy of a portion of a big array.
*
* @param array
* a big array.
* @param offset
* the first element to copy.
* @param length
* the number of elements to copy.
* @return a new big array containing {@code length} elements of {@code array}
* starting at {@code offset}.
*/
public static int[][] copy(final int[][] array, final long offset, final long length) {
ensureOffsetLength(array, offset, length);
final int[][] a = IntBigArrays.newBigArray(length);
copy(array, offset, a, 0, length);
return a;
}
/**
* Returns a copy of a big array.
*
* @param array
* a big array.
* @return a copy of {@code array}.
*/
public static int[][] copy(final int[][] array) {
final int[][] base = array.clone();
for (int i = base.length; i-- != 0;)
base[i] = array[i].clone();
return base;
}
/**
* Fills the given big array with the given value.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param value
* the new value for all elements of the big array.
*/
public static void fill(final int[][] array, final int value) {
for (int i = array.length; i-- != 0;)
java.util.Arrays.fill(array[i], value);
}
/**
* Fills a portion of the given big array with the given value.
*
*
* If possible (i.e., {@code from} is 0) this method uses a backward loop. In
* this case, it is significantly faster than the corresponding method in
* {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param from
* the starting index of the portion to fill.
* @param to
* the end index of the portion to fill.
* @param value
* the new value for all elements of the specified portion of the big
* array.
*/
public static void fill(final int[][] array, final long from, long to, final int value) {
final long length = length(array);
BigArrays.ensureFromTo(length, from, to);
if (length == 0)
return; // To avoid addressing array[0]
int fromSegment = segment(from);
int toSegment = segment(to);
int fromDispl = displacement(from);
int toDispl = displacement(to);
if (fromSegment == toSegment) {
java.util.Arrays.fill(array[fromSegment], fromDispl, toDispl, value);
return;
}
if (toDispl != 0)
java.util.Arrays.fill(array[toSegment], 0, toDispl, value);
while (--toSegment > fromSegment)
java.util.Arrays.fill(array[toSegment], value);
java.util.Arrays.fill(array[fromSegment], fromDispl, SEGMENT_SIZE, value);
}
/**
* Returns true if the two big arrays are elementwise equal.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param a1
* a big array.
* @param a2
* another big array.
* @return true if the two big arrays are of the same length, and their elements
* are equal.
*/
public static boolean equals(final int[][] a1, final int a2[][]) {
if (length(a1) != length(a2))
return false;
int i = a1.length, j;
int[] t, u;
while (i-- != 0) {
t = a1[i];
u = a2[i];
j = t.length;
while (j-- != 0)
if (!((t[j]) == (u[j])))
return false;
}
return true;
}
/*
* Returns a string representation of the contents of the specified big array.
*
* The string representation consists of a list of the big array's elements,
* enclosed in square brackets ("[]"). Adjacent elements are separated by the
* characters ", " (a comma followed by a space). Returns "null" if {@code a} is
* null.
*
* @param a the big array whose string representation to return.
*
* @return the string representation of {@code a}.
*/
public static String toString(final int[][] a) {
if (a == null)
return "null";
final long last = length(a) - 1;
if (last == -1)
return "[]";
final StringBuilder b = new StringBuilder();
b.append('[');
for (long i = 0;; i++) {
b.append(String.valueOf(get(a, i)));
if (i == last)
return b.append(']').toString();
b.append(", ");
}
}
/**
* Ensures that a range given by its first (inclusive) and last (exclusive)
* elements fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param from
* a start index (inclusive).
* @param to
* an end index (inclusive).
* @throws IllegalArgumentException
* if {@code from} is greater than {@code to}.
* @throws ArrayIndexOutOfBoundsException
* if {@code from} or {@code to} are greater than the big array
* length or negative.
*/
public static void ensureFromTo(final int[][] a, final long from, final long to) {
BigArrays.ensureFromTo(length(a), from, to);
}
/**
* Ensures that a range given by an offset and a length fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param offset
* a start index.
* @param length
* a length (the number of elements in the range).
* @throws IllegalArgumentException
* if {@code length} is negative.
* @throws ArrayIndexOutOfBoundsException
* if {@code offset} is negative or {@code offset}+{@code length} is
* greater than the big array length.
*/
public static void ensureOffsetLength(final int[][] a, final long offset, final long length) {
BigArrays.ensureOffsetLength(length(a), offset, length);
}
/**
* Ensures that two big arrays are of the same length.
*
* @param a
* a big array.
* @param b
* another big array.
* @throws IllegalArgumentException
* if the two argument arrays are not of the same length.
*/
public static void ensureSameLength(final int[][] a, final int[][] b) {
if (length(a) != length(b))
throw new IllegalArgumentException("Array size mismatch: " + length(a) + " != " + length(b));
}
/**
* Shuffles the specified big array fragment using the specified pseudorandom
* number generator.
*
* @param a
* the big array to be shuffled.
* @param from
* the index of the first element (inclusive) to be shuffled.
* @param to
* the index of the last element (exclusive) to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static int[][] shuffle(final int[][] a, final long from, final long to, final Random random) {
for (long i = to - from; i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final int t = BigArrays.get(a, from + i);
BigArrays.set(a, from + i, BigArrays.get(a, from + p));
BigArrays.set(a, from + p, t);
}
return a;
}
/**
* Shuffles the specified big array using the specified pseudorandom number
* generator.
*
* @param a
* the big array to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static int[][] shuffle(final int[][] a, final Random random) {
for (long i = length(a); i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final int t = BigArrays.get(a, i);
BigArrays.set(a, i, BigArrays.get(a, p));
BigArrays.set(a, p, t);
}
return a;
}
/* Generic definitions */
/* Assertions (useful to generate conditional code) */
/* Narrowing and widening */
/* Current type and class (and size, if applicable) */
/* Value methods */
/* Interfaces (keys) */
/* Interfaces (values) */
/* Types and methods related to primitive-type support in the JDK */
/* Abstract implementations (keys) */
/* Abstract implementations (values) */
/* Static containers (keys) */
/* Static containers (values) */
/* Implementations */
/* Synchronized wrappers */
/* Unmodifiable wrappers */
/* Other wrappers */
/* Methods (keys) */
/* Methods (values) */
/* Methods (keys/values) */
/*
* Methods that have special names depending on keys (but the special names
* depend on values)
*/
/* Equality */
/* Object/Reference-only definitions (keys) */
/* Primitive-type-only definitions (keys) */
/* Object/Reference-only definitions (values) */
/* START_OF_JAVA_SOURCE */
/*
* Copyright (C) 2004-2021 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.
*/
/**
* Returns the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @return the element of the big array at the specified position.
*/
public static long get(final long[][] array, final long index) {
return array[segment(index)][displacement(index)];
}
/**
* Sets the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param value
* the new value for the array element at the specified position.
*/
public static void set(final long[][] array, final long index, long value) {
array[segment(index)][displacement(index)] = value;
}
/**
* 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 AtomicLongArray[] 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 long get(final AtomicLongArray[] 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 AtomicLongArray[] array, final long index, long 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 long getAndSet(final AtomicLongArray[] array, final long index, long 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 long getAndAdd(final AtomicLongArray[] array, final long index, long 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 long addAndGet(final AtomicLongArray[] array, final long index, long 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 long getAndIncrement(final AtomicLongArray[] 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 long incrementAndGet(final AtomicLongArray[] 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 long getAndDecrement(final AtomicLongArray[] 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 long decrementAndGet(final AtomicLongArray[] 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 AtomicLongArray[] array, final long index, long expected, long value) {
return array[segment(index)].compareAndSet(displacement(index), expected, value);
}
/**
* Swaps the element of the given big array of specified indices.
*
* @param array
* a big array.
* @param first
* a position in the big array.
* @param second
* a position in the big array.
*/
public static void swap(final long[][] array, final long first, final long second) {
final long t = array[segment(first)][displacement(first)];
array[segment(first)][displacement(first)] = array[segment(second)][displacement(second)];
array[segment(second)][displacement(second)] = t;
}
/**
* Reverses the order of the elements in the specified big array.
*
* @param a
* the big array to be reversed.
* @return {@code a}.
*/
public static long[][] reverse(final long[][] a) {
final long length = length(a);
for (long i = length / 2; i-- != 0;)
swap(a, i, length - i - 1);
return a;
}
/**
* Adds the specified increment the element of the given big array of specified
* index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param incr
* the increment
*/
public static void add(final long[][] array, final long index, long incr) {
array[segment(index)][displacement(index)] += incr;
}
/**
* Multiplies by the specified factor the element of the given big array of
* specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param factor
* the factor
*/
public static void mul(final long[][] array, final long index, long factor) {
array[segment(index)][displacement(index)] *= factor;
}
/**
* Increments the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void incr(final long[][] array, final long index) {
array[segment(index)][displacement(index)]++;
}
/**
* Decrements the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void decr(final long[][] array, final long index) {
array[segment(index)][displacement(index)]--;
}
/**
* Returns the length of the given big array.
*
* @param array
* a big array.
* @return the length of the given big array.
*/
public static long length(final long[][] array) {
final int length = array.length;
return length == 0 ? 0 : start(length - 1) + array[length - 1].length;
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination big array.
* Handles correctly overlapping regions of the same big array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copy(final long[][] srcArray, final long srcPos, final long[][] destArray, final long destPos,
long length) {
if (destPos <= srcPos) {
int srcSegment = segment(srcPos);
int destSegment = segment(destPos);
int srcDispl = displacement(srcPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(length,
Math.min(srcArray[srcSegment].length - srcDispl, destArray[destSegment].length - destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray[destSegment], destDispl, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
length -= l;
}
} else {
int srcSegment = segment(srcPos + length);
int destSegment = segment(destPos + length);
int srcDispl = displacement(srcPos + length);
int destDispl = displacement(destPos + length);
while (length > 0) {
if (srcDispl == 0) {
srcDispl = SEGMENT_SIZE;
srcSegment--;
}
if (destDispl == 0) {
destDispl = SEGMENT_SIZE;
destSegment--;
}
final int l = (int) Math.min(length, Math.min(srcDispl, destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl - l, destArray[destSegment], destDispl - l, l);
srcDispl -= l;
destDispl -= l;
length -= l;
}
}
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyFromBig(final long[][] srcArray, final long srcPos, final long[] destArray, int destPos,
int length) {
int srcSegment = segment(srcPos);
int srcDispl = displacement(srcPos);
while (length > 0) {
final int l = Math.min(srcArray[srcSegment].length - srcDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray, destPos, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
destPos += l;
length -= l;
}
}
/**
* Copies an array from the specified source array, beginning at the specified
* position, to the specified position of the destination big array.
*
* @param srcArray
* the source array.
* @param srcPos
* the starting position in the source array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyToBig(final long[] srcArray, int srcPos, final long[][] destArray, final long destPos,
long length) {
int destSegment = segment(destPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(destArray[destSegment].length - destDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray, srcPos, destArray[destSegment], destDispl, l);
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
srcPos += l;
length -= l;
}
}
/**
* Turns a standard array into a big array.
*
*
* Note that the returned big array might contain as a segment the original
* array.
*
* @param array
* an array.
* @return a new big array with the same length and content of {@code array}.
*/
public static long[][] wrap(final long[] array) {
if (array.length == 0)
return LongBigArrays.EMPTY_BIG_ARRAY;
if (array.length <= SEGMENT_SIZE)
return new long[][]{array};
final long[][] bigArray = LongBigArrays.newBigArray(array.length);
for (int i = 0; i < bigArray.length; i++)
System.arraycopy(array, (int) start(i), bigArray[i], 0, bigArray[i].length);
return bigArray;
}
/**
* Ensures that a big array can contain the given number of entries.
*
*
* If you cannot foresee whether this big array will need again to be enlarged,
* you should probably use {@code grow()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it contains {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code length(array)} entries are the same as those of {@code array}.
*/
public static long[][] ensureCapacity(final long[][] array, final long length) {
return ensureCapacity(array, length, length(array));
}
/**
* Forces a big array to contain the given number of entries, preserving just a
* part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return a big array with {@code length} entries whose first {@code preserve}
* entries are the same as those of {@code array}.
*/
public static long[][] forceCapacity(final long[][] array, final long length, final long preserve) {
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_SHIFT);
final long[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0) {
for (int i = valid; i < baseLength - 1; i++)
base[i] = new long[SEGMENT_SIZE];
base[baseLength - 1] = new long[residual];
} else
for (int i = valid; i < baseLength; i++)
base[i] = new long[SEGMENT_SIZE];
if (preserve - (valid * (long) SEGMENT_SIZE) > 0)
copy(array, valid * (long) SEGMENT_SIZE, base, valid * (long) SEGMENT_SIZE,
preserve - (valid * (long) SEGMENT_SIZE));
return base;
}
/**
* Ensures that a big array can contain the given number of entries, preserving
* just a part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code preserve} entries are the same as those of {@code array}.
*/
public static long[][] ensureCapacity(final long[][] array, final long length, final long preserve) {
return length > length(array) ? forceCapacity(array, length, preserve) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code length(array)} entries are the same as
* those of {@code array}.
*/
public static long[][] grow(final long[][] array, final long length) {
final long oldLength = length(array);
return length > oldLength ? grow(array, length, oldLength) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length, preserving just a part of the big array.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code preserve} entries are the same as those of
* {@code array}.
*/
public static long[][] grow(final long[][] array, final long length, final long preserve) {
final long oldLength = length(array);
return length > oldLength
? ensureCapacity(array, Math.max(oldLength + (oldLength >> 1), length), preserve)
: array;
}
/**
* Trims the given big array to the given length.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new maximum length for the big array.
* @return {@code array}, if it contains {@code length} entries or less;
* otherwise, a big array with {@code length} entries whose entries are
* the same as the first {@code length} entries of {@code array}.
*
*/
public static long[][] trim(final long[][] array, final long length) {
ensureLength(length);
final long oldLength = length(array);
if (length >= oldLength)
return array;
final int baseLength = (int) ((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
final long[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0)
base[baseLength - 1] = LongArrays.trim(base[baseLength - 1], residual);
return base;
}
/**
* Sets the length of the given big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new length for the big array.
* @return {@code array}, if it contains exactly {@code length} entries;
* otherwise, if it contains more than {@code length} entries,
* a big array with {@code length} entries whose entries are the same as
* the first {@code length} entries of {@code array}; otherwise, a big
* array with {@code length} entries whose first {@code length(array)}
* entries are the same as those of {@code array}.
*
*/
public static long[][] setLength(final long[][] array, final long length) {
final long oldLength = length(array);
if (length == oldLength)
return array;
if (length < oldLength)
return trim(array, length);
return ensureCapacity(array, length);
}
/**
* Returns a copy of a portion of a big array.
*
* @param array
* a big array.
* @param offset
* the first element to copy.
* @param length
* the number of elements to copy.
* @return a new big array containing {@code length} elements of {@code array}
* starting at {@code offset}.
*/
public static long[][] copy(final long[][] array, final long offset, final long length) {
ensureOffsetLength(array, offset, length);
final long[][] a = LongBigArrays.newBigArray(length);
copy(array, offset, a, 0, length);
return a;
}
/**
* Returns a copy of a big array.
*
* @param array
* a big array.
* @return a copy of {@code array}.
*/
public static long[][] copy(final long[][] array) {
final long[][] base = array.clone();
for (int i = base.length; i-- != 0;)
base[i] = array[i].clone();
return base;
}
/**
* Fills the given big array with the given value.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param value
* the new value for all elements of the big array.
*/
public static void fill(final long[][] array, final long value) {
for (int i = array.length; i-- != 0;)
java.util.Arrays.fill(array[i], value);
}
/**
* Fills a portion of the given big array with the given value.
*
*
* If possible (i.e., {@code from} is 0) this method uses a backward loop. In
* this case, it is significantly faster than the corresponding method in
* {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param from
* the starting index of the portion to fill.
* @param to
* the end index of the portion to fill.
* @param value
* the new value for all elements of the specified portion of the big
* array.
*/
public static void fill(final long[][] array, final long from, long to, final long value) {
final long length = length(array);
BigArrays.ensureFromTo(length, from, to);
if (length == 0)
return; // To avoid addressing array[0]
int fromSegment = segment(from);
int toSegment = segment(to);
int fromDispl = displacement(from);
int toDispl = displacement(to);
if (fromSegment == toSegment) {
java.util.Arrays.fill(array[fromSegment], fromDispl, toDispl, value);
return;
}
if (toDispl != 0)
java.util.Arrays.fill(array[toSegment], 0, toDispl, value);
while (--toSegment > fromSegment)
java.util.Arrays.fill(array[toSegment], value);
java.util.Arrays.fill(array[fromSegment], fromDispl, SEGMENT_SIZE, value);
}
/**
* Returns true if the two big arrays are elementwise equal.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param a1
* a big array.
* @param a2
* another big array.
* @return true if the two big arrays are of the same length, and their elements
* are equal.
*/
public static boolean equals(final long[][] a1, final long a2[][]) {
if (length(a1) != length(a2))
return false;
int i = a1.length, j;
long[] t, u;
while (i-- != 0) {
t = a1[i];
u = a2[i];
j = t.length;
while (j-- != 0)
if (!((t[j]) == (u[j])))
return false;
}
return true;
}
/*
* Returns a string representation of the contents of the specified big array.
*
* The string representation consists of a list of the big array's elements,
* enclosed in square brackets ("[]"). Adjacent elements are separated by the
* characters ", " (a comma followed by a space). Returns "null" if {@code a} is
* null.
*
* @param a the big array whose string representation to return.
*
* @return the string representation of {@code a}.
*/
public static String toString(final long[][] a) {
if (a == null)
return "null";
final long last = length(a) - 1;
if (last == -1)
return "[]";
final StringBuilder b = new StringBuilder();
b.append('[');
for (long i = 0;; i++) {
b.append(String.valueOf(get(a, i)));
if (i == last)
return b.append(']').toString();
b.append(", ");
}
}
/**
* Ensures that a range given by its first (inclusive) and last (exclusive)
* elements fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param from
* a start index (inclusive).
* @param to
* an end index (inclusive).
* @throws IllegalArgumentException
* if {@code from} is greater than {@code to}.
* @throws ArrayIndexOutOfBoundsException
* if {@code from} or {@code to} are greater than the big array
* length or negative.
*/
public static void ensureFromTo(final long[][] a, final long from, final long to) {
BigArrays.ensureFromTo(length(a), from, to);
}
/**
* Ensures that a range given by an offset and a length fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param offset
* a start index.
* @param length
* a length (the number of elements in the range).
* @throws IllegalArgumentException
* if {@code length} is negative.
* @throws ArrayIndexOutOfBoundsException
* if {@code offset} is negative or {@code offset}+{@code length} is
* greater than the big array length.
*/
public static void ensureOffsetLength(final long[][] a, final long offset, final long length) {
BigArrays.ensureOffsetLength(length(a), offset, length);
}
/**
* Ensures that two big arrays are of the same length.
*
* @param a
* a big array.
* @param b
* another big array.
* @throws IllegalArgumentException
* if the two argument arrays are not of the same length.
*/
public static void ensureSameLength(final long[][] a, final long[][] b) {
if (length(a) != length(b))
throw new IllegalArgumentException("Array size mismatch: " + length(a) + " != " + length(b));
}
/**
* Shuffles the specified big array fragment using the specified pseudorandom
* number generator.
*
* @param a
* the big array to be shuffled.
* @param from
* the index of the first element (inclusive) to be shuffled.
* @param to
* the index of the last element (exclusive) to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static long[][] shuffle(final long[][] a, final long from, final long to, final Random random) {
for (long i = to - from; i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final long t = BigArrays.get(a, from + i);
BigArrays.set(a, from + i, BigArrays.get(a, from + p));
BigArrays.set(a, from + p, t);
}
return a;
}
/**
* Shuffles the specified big array using the specified pseudorandom number
* generator.
*
* @param a
* the big array to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static long[][] shuffle(final long[][] a, final Random random) {
for (long i = length(a); i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final long t = BigArrays.get(a, i);
BigArrays.set(a, i, BigArrays.get(a, p));
BigArrays.set(a, p, t);
}
return a;
}
/* Generic definitions */
/* Assertions (useful to generate conditional code) */
/* Narrowing and widening */
/* Current type and class (and size, if applicable) */
/* Value methods */
/* Interfaces (keys) */
/* Interfaces (values) */
/* Types and methods related to primitive-type support in the JDK */
/* Abstract implementations (keys) */
/* Abstract implementations (values) */
/* Static containers (keys) */
/* Static containers (values) */
/* Implementations */
/* Synchronized wrappers */
/* Unmodifiable wrappers */
/* Other wrappers */
/* Methods (keys) */
/* Methods (values) */
/* Methods (keys/values) */
/*
* Methods that have special names depending on keys (but the special names
* depend on values)
*/
/* Equality */
/* Object/Reference-only definitions (keys) */
/* Primitive-type-only definitions (keys) */
/* Object/Reference-only definitions (values) */
/* START_OF_JAVA_SOURCE */
/*
* Copyright (C) 2004-2021 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.
*/
/**
* Returns the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @return the element of the big array at the specified position.
*/
public static double get(final double[][] array, final long index) {
return array[segment(index)][displacement(index)];
}
/**
* Sets the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param value
* the new value for the array element at the specified position.
*/
public static void set(final double[][] array, final long index, double value) {
array[segment(index)][displacement(index)] = value;
}
/**
* Swaps the element of the given big array of specified indices.
*
* @param array
* a big array.
* @param first
* a position in the big array.
* @param second
* a position in the big array.
*/
public static void swap(final double[][] array, final long first, final long second) {
final double t = array[segment(first)][displacement(first)];
array[segment(first)][displacement(first)] = array[segment(second)][displacement(second)];
array[segment(second)][displacement(second)] = t;
}
/**
* Reverses the order of the elements in the specified big array.
*
* @param a
* the big array to be reversed.
* @return {@code a}.
*/
public static double[][] reverse(final double[][] a) {
final long length = length(a);
for (long i = length / 2; i-- != 0;)
swap(a, i, length - i - 1);
return a;
}
/**
* Adds the specified increment the element of the given big array of specified
* index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param incr
* the increment
*/
public static void add(final double[][] array, final long index, double incr) {
array[segment(index)][displacement(index)] += incr;
}
/**
* Multiplies by the specified factor the element of the given big array of
* specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param factor
* the factor
*/
public static void mul(final double[][] array, final long index, double factor) {
array[segment(index)][displacement(index)] *= factor;
}
/**
* Increments the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void incr(final double[][] array, final long index) {
array[segment(index)][displacement(index)]++;
}
/**
* Decrements the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void decr(final double[][] array, final long index) {
array[segment(index)][displacement(index)]--;
}
/**
* Returns the length of the given big array.
*
* @param array
* a big array.
* @return the length of the given big array.
*/
public static long length(final double[][] array) {
final int length = array.length;
return length == 0 ? 0 : start(length - 1) + array[length - 1].length;
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination big array.
* Handles correctly overlapping regions of the same big array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copy(final double[][] srcArray, final long srcPos, final double[][] destArray,
final long destPos, long length) {
if (destPos <= srcPos) {
int srcSegment = segment(srcPos);
int destSegment = segment(destPos);
int srcDispl = displacement(srcPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(length,
Math.min(srcArray[srcSegment].length - srcDispl, destArray[destSegment].length - destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray[destSegment], destDispl, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
length -= l;
}
} else {
int srcSegment = segment(srcPos + length);
int destSegment = segment(destPos + length);
int srcDispl = displacement(srcPos + length);
int destDispl = displacement(destPos + length);
while (length > 0) {
if (srcDispl == 0) {
srcDispl = SEGMENT_SIZE;
srcSegment--;
}
if (destDispl == 0) {
destDispl = SEGMENT_SIZE;
destSegment--;
}
final int l = (int) Math.min(length, Math.min(srcDispl, destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl - l, destArray[destSegment], destDispl - l, l);
srcDispl -= l;
destDispl -= l;
length -= l;
}
}
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyFromBig(final double[][] srcArray, final long srcPos, final double[] destArray, int destPos,
int length) {
int srcSegment = segment(srcPos);
int srcDispl = displacement(srcPos);
while (length > 0) {
final int l = Math.min(srcArray[srcSegment].length - srcDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray, destPos, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
destPos += l;
length -= l;
}
}
/**
* Copies an array from the specified source array, beginning at the specified
* position, to the specified position of the destination big array.
*
* @param srcArray
* the source array.
* @param srcPos
* the starting position in the source array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyToBig(final double[] srcArray, int srcPos, final double[][] destArray, final long destPos,
long length) {
int destSegment = segment(destPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(destArray[destSegment].length - destDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray, srcPos, destArray[destSegment], destDispl, l);
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
srcPos += l;
length -= l;
}
}
/**
* Turns a standard array into a big array.
*
*
* Note that the returned big array might contain as a segment the original
* array.
*
* @param array
* an array.
* @return a new big array with the same length and content of {@code array}.
*/
public static double[][] wrap(final double[] array) {
if (array.length == 0)
return DoubleBigArrays.EMPTY_BIG_ARRAY;
if (array.length <= SEGMENT_SIZE)
return new double[][]{array};
final double[][] bigArray = DoubleBigArrays.newBigArray(array.length);
for (int i = 0; i < bigArray.length; i++)
System.arraycopy(array, (int) start(i), bigArray[i], 0, bigArray[i].length);
return bigArray;
}
/**
* Ensures that a big array can contain the given number of entries.
*
*
* If you cannot foresee whether this big array will need again to be enlarged,
* you should probably use {@code grow()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it contains {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code length(array)} entries are the same as those of {@code array}.
*/
public static double[][] ensureCapacity(final double[][] array, final long length) {
return ensureCapacity(array, length, length(array));
}
/**
* Forces a big array to contain the given number of entries, preserving just a
* part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return a big array with {@code length} entries whose first {@code preserve}
* entries are the same as those of {@code array}.
*/
public static double[][] forceCapacity(final double[][] array, final long length, final long preserve) {
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_SHIFT);
final double[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0) {
for (int i = valid; i < baseLength - 1; i++)
base[i] = new double[SEGMENT_SIZE];
base[baseLength - 1] = new double[residual];
} else
for (int i = valid; i < baseLength; i++)
base[i] = new double[SEGMENT_SIZE];
if (preserve - (valid * (long) SEGMENT_SIZE) > 0)
copy(array, valid * (long) SEGMENT_SIZE, base, valid * (long) SEGMENT_SIZE,
preserve - (valid * (long) SEGMENT_SIZE));
return base;
}
/**
* Ensures that a big array can contain the given number of entries, preserving
* just a part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code preserve} entries are the same as those of {@code array}.
*/
public static double[][] ensureCapacity(final double[][] array, final long length, final long preserve) {
return length > length(array) ? forceCapacity(array, length, preserve) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code length(array)} entries are the same as
* those of {@code array}.
*/
public static double[][] grow(final double[][] array, final long length) {
final long oldLength = length(array);
return length > oldLength ? grow(array, length, oldLength) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length, preserving just a part of the big array.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code preserve} entries are the same as those of
* {@code array}.
*/
public static double[][] grow(final double[][] array, final long length, final long preserve) {
final long oldLength = length(array);
return length > oldLength
? ensureCapacity(array, Math.max(oldLength + (oldLength >> 1), length), preserve)
: array;
}
/**
* Trims the given big array to the given length.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new maximum length for the big array.
* @return {@code array}, if it contains {@code length} entries or less;
* otherwise, a big array with {@code length} entries whose entries are
* the same as the first {@code length} entries of {@code array}.
*
*/
public static double[][] trim(final double[][] array, final long length) {
ensureLength(length);
final long oldLength = length(array);
if (length >= oldLength)
return array;
final int baseLength = (int) ((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
final double[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0)
base[baseLength - 1] = DoubleArrays.trim(base[baseLength - 1], residual);
return base;
}
/**
* Sets the length of the given big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new length for the big array.
* @return {@code array}, if it contains exactly {@code length} entries;
* otherwise, if it contains more than {@code length} entries,
* a big array with {@code length} entries whose entries are the same as
* the first {@code length} entries of {@code array}; otherwise, a big
* array with {@code length} entries whose first {@code length(array)}
* entries are the same as those of {@code array}.
*
*/
public static double[][] setLength(final double[][] array, final long length) {
final long oldLength = length(array);
if (length == oldLength)
return array;
if (length < oldLength)
return trim(array, length);
return ensureCapacity(array, length);
}
/**
* Returns a copy of a portion of a big array.
*
* @param array
* a big array.
* @param offset
* the first element to copy.
* @param length
* the number of elements to copy.
* @return a new big array containing {@code length} elements of {@code array}
* starting at {@code offset}.
*/
public static double[][] copy(final double[][] array, final long offset, final long length) {
ensureOffsetLength(array, offset, length);
final double[][] a = DoubleBigArrays.newBigArray(length);
copy(array, offset, a, 0, length);
return a;
}
/**
* Returns a copy of a big array.
*
* @param array
* a big array.
* @return a copy of {@code array}.
*/
public static double[][] copy(final double[][] array) {
final double[][] base = array.clone();
for (int i = base.length; i-- != 0;)
base[i] = array[i].clone();
return base;
}
/**
* Fills the given big array with the given value.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param value
* the new value for all elements of the big array.
*/
public static void fill(final double[][] array, final double value) {
for (int i = array.length; i-- != 0;)
java.util.Arrays.fill(array[i], value);
}
/**
* Fills a portion of the given big array with the given value.
*
*
* If possible (i.e., {@code from} is 0) this method uses a backward loop. In
* this case, it is significantly faster than the corresponding method in
* {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param from
* the starting index of the portion to fill.
* @param to
* the end index of the portion to fill.
* @param value
* the new value for all elements of the specified portion of the big
* array.
*/
public static void fill(final double[][] array, final long from, long to, final double value) {
final long length = length(array);
BigArrays.ensureFromTo(length, from, to);
if (length == 0)
return; // To avoid addressing array[0]
int fromSegment = segment(from);
int toSegment = segment(to);
int fromDispl = displacement(from);
int toDispl = displacement(to);
if (fromSegment == toSegment) {
java.util.Arrays.fill(array[fromSegment], fromDispl, toDispl, value);
return;
}
if (toDispl != 0)
java.util.Arrays.fill(array[toSegment], 0, toDispl, value);
while (--toSegment > fromSegment)
java.util.Arrays.fill(array[toSegment], value);
java.util.Arrays.fill(array[fromSegment], fromDispl, SEGMENT_SIZE, value);
}
/**
* Returns true if the two big arrays are elementwise equal.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param a1
* a big array.
* @param a2
* another big array.
* @return true if the two big arrays are of the same length, and their elements
* are equal.
*/
public static boolean equals(final double[][] a1, final double a2[][]) {
if (length(a1) != length(a2))
return false;
int i = a1.length, j;
double[] t, u;
while (i-- != 0) {
t = a1[i];
u = a2[i];
j = t.length;
while (j-- != 0)
if (!(Double.doubleToLongBits(t[j]) == Double.doubleToLongBits(u[j])))
return false;
}
return true;
}
/*
* Returns a string representation of the contents of the specified big array.
*
* The string representation consists of a list of the big array's elements,
* enclosed in square brackets ("[]"). Adjacent elements are separated by the
* characters ", " (a comma followed by a space). Returns "null" if {@code a} is
* null.
*
* @param a the big array whose string representation to return.
*
* @return the string representation of {@code a}.
*/
public static String toString(final double[][] a) {
if (a == null)
return "null";
final long last = length(a) - 1;
if (last == -1)
return "[]";
final StringBuilder b = new StringBuilder();
b.append('[');
for (long i = 0;; i++) {
b.append(String.valueOf(get(a, i)));
if (i == last)
return b.append(']').toString();
b.append(", ");
}
}
/**
* Ensures that a range given by its first (inclusive) and last (exclusive)
* elements fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param from
* a start index (inclusive).
* @param to
* an end index (inclusive).
* @throws IllegalArgumentException
* if {@code from} is greater than {@code to}.
* @throws ArrayIndexOutOfBoundsException
* if {@code from} or {@code to} are greater than the big array
* length or negative.
*/
public static void ensureFromTo(final double[][] a, final long from, final long to) {
BigArrays.ensureFromTo(length(a), from, to);
}
/**
* Ensures that a range given by an offset and a length fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param offset
* a start index.
* @param length
* a length (the number of elements in the range).
* @throws IllegalArgumentException
* if {@code length} is negative.
* @throws ArrayIndexOutOfBoundsException
* if {@code offset} is negative or {@code offset}+{@code length} is
* greater than the big array length.
*/
public static void ensureOffsetLength(final double[][] a, final long offset, final long length) {
BigArrays.ensureOffsetLength(length(a), offset, length);
}
/**
* Ensures that two big arrays are of the same length.
*
* @param a
* a big array.
* @param b
* another big array.
* @throws IllegalArgumentException
* if the two argument arrays are not of the same length.
*/
public static void ensureSameLength(final double[][] a, final double[][] b) {
if (length(a) != length(b))
throw new IllegalArgumentException("Array size mismatch: " + length(a) + " != " + length(b));
}
/**
* Shuffles the specified big array fragment using the specified pseudorandom
* number generator.
*
* @param a
* the big array to be shuffled.
* @param from
* the index of the first element (inclusive) to be shuffled.
* @param to
* the index of the last element (exclusive) to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static double[][] shuffle(final double[][] a, final long from, final long to, final Random random) {
for (long i = to - from; i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final double t = BigArrays.get(a, from + i);
BigArrays.set(a, from + i, BigArrays.get(a, from + p));
BigArrays.set(a, from + p, t);
}
return a;
}
/**
* Shuffles the specified big array using the specified pseudorandom number
* generator.
*
* @param a
* the big array to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static double[][] shuffle(final double[][] a, final Random random) {
for (long i = length(a); i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final double t = BigArrays.get(a, i);
BigArrays.set(a, i, BigArrays.get(a, p));
BigArrays.set(a, p, t);
}
return a;
}
/* Generic definitions */
/* Assertions (useful to generate conditional code) */
/* Narrowing and widening */
/* Current type and class (and size, if applicable) */
/* Value methods */
/* Interfaces (keys) */
/* Interfaces (values) */
/* Types and methods related to primitive-type support in the JDK */
/* Abstract implementations (keys) */
/* Abstract implementations (values) */
/* Static containers (keys) */
/* Static containers (values) */
/* Implementations */
/* Synchronized wrappers */
/* Unmodifiable wrappers */
/* Other wrappers */
/* Methods (keys) */
/* Methods (values) */
/* Methods (keys/values) */
/*
* Methods that have special names depending on keys (but the special names
* depend on values)
*/
/* Equality */
/* Object/Reference-only definitions (keys) */
/* Primitive-type-only definitions (keys) */
/* Object/Reference-only definitions (values) */
/* START_OF_JAVA_SOURCE */
/*
* Copyright (C) 2004-2021 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.
*/
/**
* Returns the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @return the element of the big array at the specified position.
*/
public static boolean get(final boolean[][] array, final long index) {
return array[segment(index)][displacement(index)];
}
/**
* Sets the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param value
* the new value for the array element at the specified position.
*/
public static void set(final boolean[][] array, final long index, boolean value) {
array[segment(index)][displacement(index)] = value;
}
/**
* Swaps the element of the given big array of specified indices.
*
* @param array
* a big array.
* @param first
* a position in the big array.
* @param second
* a position in the big array.
*/
public static void swap(final boolean[][] array, final long first, final long second) {
final boolean t = array[segment(first)][displacement(first)];
array[segment(first)][displacement(first)] = array[segment(second)][displacement(second)];
array[segment(second)][displacement(second)] = t;
}
/**
* Reverses the order of the elements in the specified big array.
*
* @param a
* the big array to be reversed.
* @return {@code a}.
*/
public static boolean[][] reverse(final boolean[][] a) {
final long length = length(a);
for (long i = length / 2; i-- != 0;)
swap(a, i, length - i - 1);
return a;
}
/**
* Returns the length of the given big array.
*
* @param array
* a big array.
* @return the length of the given big array.
*/
public static long length(final boolean[][] array) {
final int length = array.length;
return length == 0 ? 0 : start(length - 1) + array[length - 1].length;
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination big array.
* Handles correctly overlapping regions of the same big array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copy(final boolean[][] srcArray, final long srcPos, final boolean[][] destArray,
final long destPos, long length) {
if (destPos <= srcPos) {
int srcSegment = segment(srcPos);
int destSegment = segment(destPos);
int srcDispl = displacement(srcPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(length,
Math.min(srcArray[srcSegment].length - srcDispl, destArray[destSegment].length - destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray[destSegment], destDispl, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
length -= l;
}
} else {
int srcSegment = segment(srcPos + length);
int destSegment = segment(destPos + length);
int srcDispl = displacement(srcPos + length);
int destDispl = displacement(destPos + length);
while (length > 0) {
if (srcDispl == 0) {
srcDispl = SEGMENT_SIZE;
srcSegment--;
}
if (destDispl == 0) {
destDispl = SEGMENT_SIZE;
destSegment--;
}
final int l = (int) Math.min(length, Math.min(srcDispl, destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl - l, destArray[destSegment], destDispl - l, l);
srcDispl -= l;
destDispl -= l;
length -= l;
}
}
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyFromBig(final boolean[][] srcArray, final long srcPos, final boolean[] destArray,
int destPos, int length) {
int srcSegment = segment(srcPos);
int srcDispl = displacement(srcPos);
while (length > 0) {
final int l = Math.min(srcArray[srcSegment].length - srcDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray, destPos, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
destPos += l;
length -= l;
}
}
/**
* Copies an array from the specified source array, beginning at the specified
* position, to the specified position of the destination big array.
*
* @param srcArray
* the source array.
* @param srcPos
* the starting position in the source array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyToBig(final boolean[] srcArray, int srcPos, final boolean[][] destArray, final long destPos,
long length) {
int destSegment = segment(destPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(destArray[destSegment].length - destDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray, srcPos, destArray[destSegment], destDispl, l);
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
srcPos += l;
length -= l;
}
}
/**
* Turns a standard array into a big array.
*
*
* Note that the returned big array might contain as a segment the original
* array.
*
* @param array
* an array.
* @return a new big array with the same length and content of {@code array}.
*/
public static boolean[][] wrap(final boolean[] array) {
if (array.length == 0)
return BooleanBigArrays.EMPTY_BIG_ARRAY;
if (array.length <= SEGMENT_SIZE)
return new boolean[][]{array};
final boolean[][] bigArray = BooleanBigArrays.newBigArray(array.length);
for (int i = 0; i < bigArray.length; i++)
System.arraycopy(array, (int) start(i), bigArray[i], 0, bigArray[i].length);
return bigArray;
}
/**
* Ensures that a big array can contain the given number of entries.
*
*
* If you cannot foresee whether this big array will need again to be enlarged,
* you should probably use {@code grow()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it contains {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code length(array)} entries are the same as those of {@code array}.
*/
public static boolean[][] ensureCapacity(final boolean[][] array, final long length) {
return ensureCapacity(array, length, length(array));
}
/**
* Forces a big array to contain the given number of entries, preserving just a
* part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return a big array with {@code length} entries whose first {@code preserve}
* entries are the same as those of {@code array}.
*/
public static boolean[][] forceCapacity(final boolean[][] array, final long length, final long preserve) {
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_SHIFT);
final boolean[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0) {
for (int i = valid; i < baseLength - 1; i++)
base[i] = new boolean[SEGMENT_SIZE];
base[baseLength - 1] = new boolean[residual];
} else
for (int i = valid; i < baseLength; i++)
base[i] = new boolean[SEGMENT_SIZE];
if (preserve - (valid * (long) SEGMENT_SIZE) > 0)
copy(array, valid * (long) SEGMENT_SIZE, base, valid * (long) SEGMENT_SIZE,
preserve - (valid * (long) SEGMENT_SIZE));
return base;
}
/**
* Ensures that a big array can contain the given number of entries, preserving
* just a part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code preserve} entries are the same as those of {@code array}.
*/
public static boolean[][] ensureCapacity(final boolean[][] array, final long length, final long preserve) {
return length > length(array) ? forceCapacity(array, length, preserve) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code length(array)} entries are the same as
* those of {@code array}.
*/
public static boolean[][] grow(final boolean[][] array, final long length) {
final long oldLength = length(array);
return length > oldLength ? grow(array, length, oldLength) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length, preserving just a part of the big array.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code preserve} entries are the same as those of
* {@code array}.
*/
public static boolean[][] grow(final boolean[][] array, final long length, final long preserve) {
final long oldLength = length(array);
return length > oldLength
? ensureCapacity(array, Math.max(oldLength + (oldLength >> 1), length), preserve)
: array;
}
/**
* Trims the given big array to the given length.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new maximum length for the big array.
* @return {@code array}, if it contains {@code length} entries or less;
* otherwise, a big array with {@code length} entries whose entries are
* the same as the first {@code length} entries of {@code array}.
*
*/
public static boolean[][] trim(final boolean[][] array, final long length) {
ensureLength(length);
final long oldLength = length(array);
if (length >= oldLength)
return array;
final int baseLength = (int) ((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
final boolean[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0)
base[baseLength - 1] = BooleanArrays.trim(base[baseLength - 1], residual);
return base;
}
/**
* Sets the length of the given big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new length for the big array.
* @return {@code array}, if it contains exactly {@code length} entries;
* otherwise, if it contains more than {@code length} entries,
* a big array with {@code length} entries whose entries are the same as
* the first {@code length} entries of {@code array}; otherwise, a big
* array with {@code length} entries whose first {@code length(array)}
* entries are the same as those of {@code array}.
*
*/
public static boolean[][] setLength(final boolean[][] array, final long length) {
final long oldLength = length(array);
if (length == oldLength)
return array;
if (length < oldLength)
return trim(array, length);
return ensureCapacity(array, length);
}
/**
* Returns a copy of a portion of a big array.
*
* @param array
* a big array.
* @param offset
* the first element to copy.
* @param length
* the number of elements to copy.
* @return a new big array containing {@code length} elements of {@code array}
* starting at {@code offset}.
*/
public static boolean[][] copy(final boolean[][] array, final long offset, final long length) {
ensureOffsetLength(array, offset, length);
final boolean[][] a = BooleanBigArrays.newBigArray(length);
copy(array, offset, a, 0, length);
return a;
}
/**
* Returns a copy of a big array.
*
* @param array
* a big array.
* @return a copy of {@code array}.
*/
public static boolean[][] copy(final boolean[][] array) {
final boolean[][] base = array.clone();
for (int i = base.length; i-- != 0;)
base[i] = array[i].clone();
return base;
}
/**
* Fills the given big array with the given value.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param value
* the new value for all elements of the big array.
*/
public static void fill(final boolean[][] array, final boolean value) {
for (int i = array.length; i-- != 0;)
java.util.Arrays.fill(array[i], value);
}
/**
* Fills a portion of the given big array with the given value.
*
*
* If possible (i.e., {@code from} is 0) this method uses a backward loop. In
* this case, it is significantly faster than the corresponding method in
* {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param from
* the starting index of the portion to fill.
* @param to
* the end index of the portion to fill.
* @param value
* the new value for all elements of the specified portion of the big
* array.
*/
public static void fill(final boolean[][] array, final long from, long to, final boolean value) {
final long length = length(array);
BigArrays.ensureFromTo(length, from, to);
if (length == 0)
return; // To avoid addressing array[0]
int fromSegment = segment(from);
int toSegment = segment(to);
int fromDispl = displacement(from);
int toDispl = displacement(to);
if (fromSegment == toSegment) {
java.util.Arrays.fill(array[fromSegment], fromDispl, toDispl, value);
return;
}
if (toDispl != 0)
java.util.Arrays.fill(array[toSegment], 0, toDispl, value);
while (--toSegment > fromSegment)
java.util.Arrays.fill(array[toSegment], value);
java.util.Arrays.fill(array[fromSegment], fromDispl, SEGMENT_SIZE, value);
}
/**
* Returns true if the two big arrays are elementwise equal.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param a1
* a big array.
* @param a2
* another big array.
* @return true if the two big arrays are of the same length, and their elements
* are equal.
*/
public static boolean equals(final boolean[][] a1, final boolean a2[][]) {
if (length(a1) != length(a2))
return false;
int i = a1.length, j;
boolean[] t, u;
while (i-- != 0) {
t = a1[i];
u = a2[i];
j = t.length;
while (j-- != 0)
if (!((t[j]) == (u[j])))
return false;
}
return true;
}
/*
* Returns a string representation of the contents of the specified big array.
*
* The string representation consists of a list of the big array's elements,
* enclosed in square brackets ("[]"). Adjacent elements are separated by the
* characters ", " (a comma followed by a space). Returns "null" if {@code a} is
* null.
*
* @param a the big array whose string representation to return.
*
* @return the string representation of {@code a}.
*/
public static String toString(final boolean[][] a) {
if (a == null)
return "null";
final long last = length(a) - 1;
if (last == -1)
return "[]";
final StringBuilder b = new StringBuilder();
b.append('[');
for (long i = 0;; i++) {
b.append(String.valueOf(get(a, i)));
if (i == last)
return b.append(']').toString();
b.append(", ");
}
}
/**
* Ensures that a range given by its first (inclusive) and last (exclusive)
* elements fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param from
* a start index (inclusive).
* @param to
* an end index (inclusive).
* @throws IllegalArgumentException
* if {@code from} is greater than {@code to}.
* @throws ArrayIndexOutOfBoundsException
* if {@code from} or {@code to} are greater than the big array
* length or negative.
*/
public static void ensureFromTo(final boolean[][] a, final long from, final long to) {
BigArrays.ensureFromTo(length(a), from, to);
}
/**
* Ensures that a range given by an offset and a length fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param offset
* a start index.
* @param length
* a length (the number of elements in the range).
* @throws IllegalArgumentException
* if {@code length} is negative.
* @throws ArrayIndexOutOfBoundsException
* if {@code offset} is negative or {@code offset}+{@code length} is
* greater than the big array length.
*/
public static void ensureOffsetLength(final boolean[][] a, final long offset, final long length) {
BigArrays.ensureOffsetLength(length(a), offset, length);
}
/**
* Ensures that two big arrays are of the same length.
*
* @param a
* a big array.
* @param b
* another big array.
* @throws IllegalArgumentException
* if the two argument arrays are not of the same length.
*/
public static void ensureSameLength(final boolean[][] a, final boolean[][] b) {
if (length(a) != length(b))
throw new IllegalArgumentException("Array size mismatch: " + length(a) + " != " + length(b));
}
/**
* Shuffles the specified big array fragment using the specified pseudorandom
* number generator.
*
* @param a
* the big array to be shuffled.
* @param from
* the index of the first element (inclusive) to be shuffled.
* @param to
* the index of the last element (exclusive) to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static boolean[][] shuffle(final boolean[][] a, final long from, final long to, final Random random) {
for (long i = to - from; i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final boolean t = BigArrays.get(a, from + i);
BigArrays.set(a, from + i, BigArrays.get(a, from + p));
BigArrays.set(a, from + p, t);
}
return a;
}
/**
* Shuffles the specified big array using the specified pseudorandom number
* generator.
*
* @param a
* the big array to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static boolean[][] shuffle(final boolean[][] a, final Random random) {
for (long i = length(a); i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final boolean t = BigArrays.get(a, i);
BigArrays.set(a, i, BigArrays.get(a, p));
BigArrays.set(a, p, t);
}
return a;
}
/* Generic definitions */
/* Assertions (useful to generate conditional code) */
/* Narrowing and widening */
/* Current type and class (and size, if applicable) */
/* Value methods */
/* Interfaces (keys) */
/* Interfaces (values) */
/* Types and methods related to primitive-type support in the JDK */
/* Abstract implementations (keys) */
/* Abstract implementations (values) */
/* Static containers (keys) */
/* Static containers (values) */
/* Implementations */
/* Synchronized wrappers */
/* Unmodifiable wrappers */
/* Other wrappers */
/* Methods (keys) */
/* Methods (values) */
/* Methods (keys/values) */
/*
* Methods that have special names depending on keys (but the special names
* depend on values)
*/
/* Equality */
/* Object/Reference-only definitions (keys) */
/* Primitive-type-only definitions (keys) */
/* Object/Reference-only definitions (values) */
/* START_OF_JAVA_SOURCE */
/*
* Copyright (C) 2004-2021 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.
*/
/**
* Returns the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @return the element of the big array at the specified position.
*/
public static short get(final short[][] array, final long index) {
return array[segment(index)][displacement(index)];
}
/**
* Sets the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param value
* the new value for the array element at the specified position.
*/
public static void set(final short[][] array, final long index, short value) {
array[segment(index)][displacement(index)] = value;
}
/**
* Swaps the element of the given big array of specified indices.
*
* @param array
* a big array.
* @param first
* a position in the big array.
* @param second
* a position in the big array.
*/
public static void swap(final short[][] array, final long first, final long second) {
final short t = array[segment(first)][displacement(first)];
array[segment(first)][displacement(first)] = array[segment(second)][displacement(second)];
array[segment(second)][displacement(second)] = t;
}
/**
* Reverses the order of the elements in the specified big array.
*
* @param a
* the big array to be reversed.
* @return {@code a}.
*/
public static short[][] reverse(final short[][] a) {
final long length = length(a);
for (long i = length / 2; i-- != 0;)
swap(a, i, length - i - 1);
return a;
}
/**
* Adds the specified increment the element of the given big array of specified
* index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param incr
* the increment
*/
public static void add(final short[][] array, final long index, short incr) {
array[segment(index)][displacement(index)] += incr;
}
/**
* Multiplies by the specified factor the element of the given big array of
* specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param factor
* the factor
*/
public static void mul(final short[][] array, final long index, short factor) {
array[segment(index)][displacement(index)] *= factor;
}
/**
* Increments the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void incr(final short[][] array, final long index) {
array[segment(index)][displacement(index)]++;
}
/**
* Decrements the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void decr(final short[][] array, final long index) {
array[segment(index)][displacement(index)]--;
}
/**
* Returns the length of the given big array.
*
* @param array
* a big array.
* @return the length of the given big array.
*/
public static long length(final short[][] array) {
final int length = array.length;
return length == 0 ? 0 : start(length - 1) + array[length - 1].length;
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination big array.
* Handles correctly overlapping regions of the same big array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copy(final short[][] srcArray, final long srcPos, final short[][] destArray, final long destPos,
long length) {
if (destPos <= srcPos) {
int srcSegment = segment(srcPos);
int destSegment = segment(destPos);
int srcDispl = displacement(srcPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(length,
Math.min(srcArray[srcSegment].length - srcDispl, destArray[destSegment].length - destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray[destSegment], destDispl, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
length -= l;
}
} else {
int srcSegment = segment(srcPos + length);
int destSegment = segment(destPos + length);
int srcDispl = displacement(srcPos + length);
int destDispl = displacement(destPos + length);
while (length > 0) {
if (srcDispl == 0) {
srcDispl = SEGMENT_SIZE;
srcSegment--;
}
if (destDispl == 0) {
destDispl = SEGMENT_SIZE;
destSegment--;
}
final int l = (int) Math.min(length, Math.min(srcDispl, destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl - l, destArray[destSegment], destDispl - l, l);
srcDispl -= l;
destDispl -= l;
length -= l;
}
}
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyFromBig(final short[][] srcArray, final long srcPos, final short[] destArray, int destPos,
int length) {
int srcSegment = segment(srcPos);
int srcDispl = displacement(srcPos);
while (length > 0) {
final int l = Math.min(srcArray[srcSegment].length - srcDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray, destPos, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
destPos += l;
length -= l;
}
}
/**
* Copies an array from the specified source array, beginning at the specified
* position, to the specified position of the destination big array.
*
* @param srcArray
* the source array.
* @param srcPos
* the starting position in the source array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyToBig(final short[] srcArray, int srcPos, final short[][] destArray, final long destPos,
long length) {
int destSegment = segment(destPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(destArray[destSegment].length - destDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray, srcPos, destArray[destSegment], destDispl, l);
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
srcPos += l;
length -= l;
}
}
/**
* Turns a standard array into a big array.
*
*
* Note that the returned big array might contain as a segment the original
* array.
*
* @param array
* an array.
* @return a new big array with the same length and content of {@code array}.
*/
public static short[][] wrap(final short[] array) {
if (array.length == 0)
return ShortBigArrays.EMPTY_BIG_ARRAY;
if (array.length <= SEGMENT_SIZE)
return new short[][]{array};
final short[][] bigArray = ShortBigArrays.newBigArray(array.length);
for (int i = 0; i < bigArray.length; i++)
System.arraycopy(array, (int) start(i), bigArray[i], 0, bigArray[i].length);
return bigArray;
}
/**
* Ensures that a big array can contain the given number of entries.
*
*
* If you cannot foresee whether this big array will need again to be enlarged,
* you should probably use {@code grow()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it contains {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code length(array)} entries are the same as those of {@code array}.
*/
public static short[][] ensureCapacity(final short[][] array, final long length) {
return ensureCapacity(array, length, length(array));
}
/**
* Forces a big array to contain the given number of entries, preserving just a
* part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return a big array with {@code length} entries whose first {@code preserve}
* entries are the same as those of {@code array}.
*/
public static short[][] forceCapacity(final short[][] array, final long length, final long preserve) {
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_SHIFT);
final short[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0) {
for (int i = valid; i < baseLength - 1; i++)
base[i] = new short[SEGMENT_SIZE];
base[baseLength - 1] = new short[residual];
} else
for (int i = valid; i < baseLength; i++)
base[i] = new short[SEGMENT_SIZE];
if (preserve - (valid * (long) SEGMENT_SIZE) > 0)
copy(array, valid * (long) SEGMENT_SIZE, base, valid * (long) SEGMENT_SIZE,
preserve - (valid * (long) SEGMENT_SIZE));
return base;
}
/**
* Ensures that a big array can contain the given number of entries, preserving
* just a part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code preserve} entries are the same as those of {@code array}.
*/
public static short[][] ensureCapacity(final short[][] array, final long length, final long preserve) {
return length > length(array) ? forceCapacity(array, length, preserve) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code length(array)} entries are the same as
* those of {@code array}.
*/
public static short[][] grow(final short[][] array, final long length) {
final long oldLength = length(array);
return length > oldLength ? grow(array, length, oldLength) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length, preserving just a part of the big array.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code preserve} entries are the same as those of
* {@code array}.
*/
public static short[][] grow(final short[][] array, final long length, final long preserve) {
final long oldLength = length(array);
return length > oldLength
? ensureCapacity(array, Math.max(oldLength + (oldLength >> 1), length), preserve)
: array;
}
/**
* Trims the given big array to the given length.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new maximum length for the big array.
* @return {@code array}, if it contains {@code length} entries or less;
* otherwise, a big array with {@code length} entries whose entries are
* the same as the first {@code length} entries of {@code array}.
*
*/
public static short[][] trim(final short[][] array, final long length) {
ensureLength(length);
final long oldLength = length(array);
if (length >= oldLength)
return array;
final int baseLength = (int) ((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
final short[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0)
base[baseLength - 1] = ShortArrays.trim(base[baseLength - 1], residual);
return base;
}
/**
* Sets the length of the given big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new length for the big array.
* @return {@code array}, if it contains exactly {@code length} entries;
* otherwise, if it contains more than {@code length} entries,
* a big array with {@code length} entries whose entries are the same as
* the first {@code length} entries of {@code array}; otherwise, a big
* array with {@code length} entries whose first {@code length(array)}
* entries are the same as those of {@code array}.
*
*/
public static short[][] setLength(final short[][] array, final long length) {
final long oldLength = length(array);
if (length == oldLength)
return array;
if (length < oldLength)
return trim(array, length);
return ensureCapacity(array, length);
}
/**
* Returns a copy of a portion of a big array.
*
* @param array
* a big array.
* @param offset
* the first element to copy.
* @param length
* the number of elements to copy.
* @return a new big array containing {@code length} elements of {@code array}
* starting at {@code offset}.
*/
public static short[][] copy(final short[][] array, final long offset, final long length) {
ensureOffsetLength(array, offset, length);
final short[][] a = ShortBigArrays.newBigArray(length);
copy(array, offset, a, 0, length);
return a;
}
/**
* Returns a copy of a big array.
*
* @param array
* a big array.
* @return a copy of {@code array}.
*/
public static short[][] copy(final short[][] array) {
final short[][] base = array.clone();
for (int i = base.length; i-- != 0;)
base[i] = array[i].clone();
return base;
}
/**
* Fills the given big array with the given value.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param value
* the new value for all elements of the big array.
*/
public static void fill(final short[][] array, final short value) {
for (int i = array.length; i-- != 0;)
java.util.Arrays.fill(array[i], value);
}
/**
* Fills a portion of the given big array with the given value.
*
*
* If possible (i.e., {@code from} is 0) this method uses a backward loop. In
* this case, it is significantly faster than the corresponding method in
* {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param from
* the starting index of the portion to fill.
* @param to
* the end index of the portion to fill.
* @param value
* the new value for all elements of the specified portion of the big
* array.
*/
public static void fill(final short[][] array, final long from, long to, final short value) {
final long length = length(array);
BigArrays.ensureFromTo(length, from, to);
if (length == 0)
return; // To avoid addressing array[0]
int fromSegment = segment(from);
int toSegment = segment(to);
int fromDispl = displacement(from);
int toDispl = displacement(to);
if (fromSegment == toSegment) {
java.util.Arrays.fill(array[fromSegment], fromDispl, toDispl, value);
return;
}
if (toDispl != 0)
java.util.Arrays.fill(array[toSegment], 0, toDispl, value);
while (--toSegment > fromSegment)
java.util.Arrays.fill(array[toSegment], value);
java.util.Arrays.fill(array[fromSegment], fromDispl, SEGMENT_SIZE, value);
}
/**
* Returns true if the two big arrays are elementwise equal.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param a1
* a big array.
* @param a2
* another big array.
* @return true if the two big arrays are of the same length, and their elements
* are equal.
*/
public static boolean equals(final short[][] a1, final short a2[][]) {
if (length(a1) != length(a2))
return false;
int i = a1.length, j;
short[] t, u;
while (i-- != 0) {
t = a1[i];
u = a2[i];
j = t.length;
while (j-- != 0)
if (!((t[j]) == (u[j])))
return false;
}
return true;
}
/*
* Returns a string representation of the contents of the specified big array.
*
* The string representation consists of a list of the big array's elements,
* enclosed in square brackets ("[]"). Adjacent elements are separated by the
* characters ", " (a comma followed by a space). Returns "null" if {@code a} is
* null.
*
* @param a the big array whose string representation to return.
*
* @return the string representation of {@code a}.
*/
public static String toString(final short[][] a) {
if (a == null)
return "null";
final long last = length(a) - 1;
if (last == -1)
return "[]";
final StringBuilder b = new StringBuilder();
b.append('[');
for (long i = 0;; i++) {
b.append(String.valueOf(get(a, i)));
if (i == last)
return b.append(']').toString();
b.append(", ");
}
}
/**
* Ensures that a range given by its first (inclusive) and last (exclusive)
* elements fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param from
* a start index (inclusive).
* @param to
* an end index (inclusive).
* @throws IllegalArgumentException
* if {@code from} is greater than {@code to}.
* @throws ArrayIndexOutOfBoundsException
* if {@code from} or {@code to} are greater than the big array
* length or negative.
*/
public static void ensureFromTo(final short[][] a, final long from, final long to) {
BigArrays.ensureFromTo(length(a), from, to);
}
/**
* Ensures that a range given by an offset and a length fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param offset
* a start index.
* @param length
* a length (the number of elements in the range).
* @throws IllegalArgumentException
* if {@code length} is negative.
* @throws ArrayIndexOutOfBoundsException
* if {@code offset} is negative or {@code offset}+{@code length} is
* greater than the big array length.
*/
public static void ensureOffsetLength(final short[][] a, final long offset, final long length) {
BigArrays.ensureOffsetLength(length(a), offset, length);
}
/**
* Ensures that two big arrays are of the same length.
*
* @param a
* a big array.
* @param b
* another big array.
* @throws IllegalArgumentException
* if the two argument arrays are not of the same length.
*/
public static void ensureSameLength(final short[][] a, final short[][] b) {
if (length(a) != length(b))
throw new IllegalArgumentException("Array size mismatch: " + length(a) + " != " + length(b));
}
/**
* Shuffles the specified big array fragment using the specified pseudorandom
* number generator.
*
* @param a
* the big array to be shuffled.
* @param from
* the index of the first element (inclusive) to be shuffled.
* @param to
* the index of the last element (exclusive) to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static short[][] shuffle(final short[][] a, final long from, final long to, final Random random) {
for (long i = to - from; i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final short t = BigArrays.get(a, from + i);
BigArrays.set(a, from + i, BigArrays.get(a, from + p));
BigArrays.set(a, from + p, t);
}
return a;
}
/**
* Shuffles the specified big array using the specified pseudorandom number
* generator.
*
* @param a
* the big array to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static short[][] shuffle(final short[][] a, final Random random) {
for (long i = length(a); i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final short t = BigArrays.get(a, i);
BigArrays.set(a, i, BigArrays.get(a, p));
BigArrays.set(a, p, t);
}
return a;
}
/* Generic definitions */
/* Assertions (useful to generate conditional code) */
/* Narrowing and widening */
/* Current type and class (and size, if applicable) */
/* Value methods */
/* Interfaces (keys) */
/* Interfaces (values) */
/* Types and methods related to primitive-type support in the JDK */
/* Abstract implementations (keys) */
/* Abstract implementations (values) */
/* Static containers (keys) */
/* Static containers (values) */
/* Implementations */
/* Synchronized wrappers */
/* Unmodifiable wrappers */
/* Other wrappers */
/* Methods (keys) */
/* Methods (values) */
/* Methods (keys/values) */
/*
* Methods that have special names depending on keys (but the special names
* depend on values)
*/
/* Equality */
/* Object/Reference-only definitions (keys) */
/* Primitive-type-only definitions (keys) */
/* Object/Reference-only definitions (values) */
/* START_OF_JAVA_SOURCE */
/*
* Copyright (C) 2004-2021 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.
*/
/**
* Returns the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @return the element of the big array at the specified position.
*/
public static char get(final char[][] array, final long index) {
return array[segment(index)][displacement(index)];
}
/**
* Sets the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param value
* the new value for the array element at the specified position.
*/
public static void set(final char[][] array, final long index, char value) {
array[segment(index)][displacement(index)] = value;
}
/**
* Swaps the element of the given big array of specified indices.
*
* @param array
* a big array.
* @param first
* a position in the big array.
* @param second
* a position in the big array.
*/
public static void swap(final char[][] array, final long first, final long second) {
final char t = array[segment(first)][displacement(first)];
array[segment(first)][displacement(first)] = array[segment(second)][displacement(second)];
array[segment(second)][displacement(second)] = t;
}
/**
* Reverses the order of the elements in the specified big array.
*
* @param a
* the big array to be reversed.
* @return {@code a}.
*/
public static char[][] reverse(final char[][] a) {
final long length = length(a);
for (long i = length / 2; i-- != 0;)
swap(a, i, length - i - 1);
return a;
}
/**
* Adds the specified increment the element of the given big array of specified
* index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param incr
* the increment
*/
public static void add(final char[][] array, final long index, char incr) {
array[segment(index)][displacement(index)] += incr;
}
/**
* Multiplies by the specified factor the element of the given big array of
* specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param factor
* the factor
*/
public static void mul(final char[][] array, final long index, char factor) {
array[segment(index)][displacement(index)] *= factor;
}
/**
* Increments the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void incr(final char[][] array, final long index) {
array[segment(index)][displacement(index)]++;
}
/**
* Decrements the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void decr(final char[][] array, final long index) {
array[segment(index)][displacement(index)]--;
}
/**
* Returns the length of the given big array.
*
* @param array
* a big array.
* @return the length of the given big array.
*/
public static long length(final char[][] array) {
final int length = array.length;
return length == 0 ? 0 : start(length - 1) + array[length - 1].length;
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination big array.
* Handles correctly overlapping regions of the same big array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copy(final char[][] srcArray, final long srcPos, final char[][] destArray, final long destPos,
long length) {
if (destPos <= srcPos) {
int srcSegment = segment(srcPos);
int destSegment = segment(destPos);
int srcDispl = displacement(srcPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(length,
Math.min(srcArray[srcSegment].length - srcDispl, destArray[destSegment].length - destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray[destSegment], destDispl, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
length -= l;
}
} else {
int srcSegment = segment(srcPos + length);
int destSegment = segment(destPos + length);
int srcDispl = displacement(srcPos + length);
int destDispl = displacement(destPos + length);
while (length > 0) {
if (srcDispl == 0) {
srcDispl = SEGMENT_SIZE;
srcSegment--;
}
if (destDispl == 0) {
destDispl = SEGMENT_SIZE;
destSegment--;
}
final int l = (int) Math.min(length, Math.min(srcDispl, destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl - l, destArray[destSegment], destDispl - l, l);
srcDispl -= l;
destDispl -= l;
length -= l;
}
}
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyFromBig(final char[][] srcArray, final long srcPos, final char[] destArray, int destPos,
int length) {
int srcSegment = segment(srcPos);
int srcDispl = displacement(srcPos);
while (length > 0) {
final int l = Math.min(srcArray[srcSegment].length - srcDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray, destPos, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
destPos += l;
length -= l;
}
}
/**
* Copies an array from the specified source array, beginning at the specified
* position, to the specified position of the destination big array.
*
* @param srcArray
* the source array.
* @param srcPos
* the starting position in the source array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyToBig(final char[] srcArray, int srcPos, final char[][] destArray, final long destPos,
long length) {
int destSegment = segment(destPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(destArray[destSegment].length - destDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray, srcPos, destArray[destSegment], destDispl, l);
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
srcPos += l;
length -= l;
}
}
/**
* Turns a standard array into a big array.
*
*
* Note that the returned big array might contain as a segment the original
* array.
*
* @param array
* an array.
* @return a new big array with the same length and content of {@code array}.
*/
public static char[][] wrap(final char[] array) {
if (array.length == 0)
return CharBigArrays.EMPTY_BIG_ARRAY;
if (array.length <= SEGMENT_SIZE)
return new char[][]{array};
final char[][] bigArray = CharBigArrays.newBigArray(array.length);
for (int i = 0; i < bigArray.length; i++)
System.arraycopy(array, (int) start(i), bigArray[i], 0, bigArray[i].length);
return bigArray;
}
/**
* Ensures that a big array can contain the given number of entries.
*
*
* If you cannot foresee whether this big array will need again to be enlarged,
* you should probably use {@code grow()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it contains {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code length(array)} entries are the same as those of {@code array}.
*/
public static char[][] ensureCapacity(final char[][] array, final long length) {
return ensureCapacity(array, length, length(array));
}
/**
* Forces a big array to contain the given number of entries, preserving just a
* part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return a big array with {@code length} entries whose first {@code preserve}
* entries are the same as those of {@code array}.
*/
public static char[][] forceCapacity(final char[][] array, final long length, final long preserve) {
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_SHIFT);
final char[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0) {
for (int i = valid; i < baseLength - 1; i++)
base[i] = new char[SEGMENT_SIZE];
base[baseLength - 1] = new char[residual];
} else
for (int i = valid; i < baseLength; i++)
base[i] = new char[SEGMENT_SIZE];
if (preserve - (valid * (long) SEGMENT_SIZE) > 0)
copy(array, valid * (long) SEGMENT_SIZE, base, valid * (long) SEGMENT_SIZE,
preserve - (valid * (long) SEGMENT_SIZE));
return base;
}
/**
* Ensures that a big array can contain the given number of entries, preserving
* just a part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code preserve} entries are the same as those of {@code array}.
*/
public static char[][] ensureCapacity(final char[][] array, final long length, final long preserve) {
return length > length(array) ? forceCapacity(array, length, preserve) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code length(array)} entries are the same as
* those of {@code array}.
*/
public static char[][] grow(final char[][] array, final long length) {
final long oldLength = length(array);
return length > oldLength ? grow(array, length, oldLength) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length, preserving just a part of the big array.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code preserve} entries are the same as those of
* {@code array}.
*/
public static char[][] grow(final char[][] array, final long length, final long preserve) {
final long oldLength = length(array);
return length > oldLength
? ensureCapacity(array, Math.max(oldLength + (oldLength >> 1), length), preserve)
: array;
}
/**
* Trims the given big array to the given length.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new maximum length for the big array.
* @return {@code array}, if it contains {@code length} entries or less;
* otherwise, a big array with {@code length} entries whose entries are
* the same as the first {@code length} entries of {@code array}.
*
*/
public static char[][] trim(final char[][] array, final long length) {
ensureLength(length);
final long oldLength = length(array);
if (length >= oldLength)
return array;
final int baseLength = (int) ((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
final char[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0)
base[baseLength - 1] = CharArrays.trim(base[baseLength - 1], residual);
return base;
}
/**
* Sets the length of the given big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new length for the big array.
* @return {@code array}, if it contains exactly {@code length} entries;
* otherwise, if it contains more than {@code length} entries,
* a big array with {@code length} entries whose entries are the same as
* the first {@code length} entries of {@code array}; otherwise, a big
* array with {@code length} entries whose first {@code length(array)}
* entries are the same as those of {@code array}.
*
*/
public static char[][] setLength(final char[][] array, final long length) {
final long oldLength = length(array);
if (length == oldLength)
return array;
if (length < oldLength)
return trim(array, length);
return ensureCapacity(array, length);
}
/**
* Returns a copy of a portion of a big array.
*
* @param array
* a big array.
* @param offset
* the first element to copy.
* @param length
* the number of elements to copy.
* @return a new big array containing {@code length} elements of {@code array}
* starting at {@code offset}.
*/
public static char[][] copy(final char[][] array, final long offset, final long length) {
ensureOffsetLength(array, offset, length);
final char[][] a = CharBigArrays.newBigArray(length);
copy(array, offset, a, 0, length);
return a;
}
/**
* Returns a copy of a big array.
*
* @param array
* a big array.
* @return a copy of {@code array}.
*/
public static char[][] copy(final char[][] array) {
final char[][] base = array.clone();
for (int i = base.length; i-- != 0;)
base[i] = array[i].clone();
return base;
}
/**
* Fills the given big array with the given value.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param value
* the new value for all elements of the big array.
*/
public static void fill(final char[][] array, final char value) {
for (int i = array.length; i-- != 0;)
java.util.Arrays.fill(array[i], value);
}
/**
* Fills a portion of the given big array with the given value.
*
*
* If possible (i.e., {@code from} is 0) this method uses a backward loop. In
* this case, it is significantly faster than the corresponding method in
* {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param from
* the starting index of the portion to fill.
* @param to
* the end index of the portion to fill.
* @param value
* the new value for all elements of the specified portion of the big
* array.
*/
public static void fill(final char[][] array, final long from, long to, final char value) {
final long length = length(array);
BigArrays.ensureFromTo(length, from, to);
if (length == 0)
return; // To avoid addressing array[0]
int fromSegment = segment(from);
int toSegment = segment(to);
int fromDispl = displacement(from);
int toDispl = displacement(to);
if (fromSegment == toSegment) {
java.util.Arrays.fill(array[fromSegment], fromDispl, toDispl, value);
return;
}
if (toDispl != 0)
java.util.Arrays.fill(array[toSegment], 0, toDispl, value);
while (--toSegment > fromSegment)
java.util.Arrays.fill(array[toSegment], value);
java.util.Arrays.fill(array[fromSegment], fromDispl, SEGMENT_SIZE, value);
}
/**
* Returns true if the two big arrays are elementwise equal.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param a1
* a big array.
* @param a2
* another big array.
* @return true if the two big arrays are of the same length, and their elements
* are equal.
*/
public static boolean equals(final char[][] a1, final char a2[][]) {
if (length(a1) != length(a2))
return false;
int i = a1.length, j;
char[] t, u;
while (i-- != 0) {
t = a1[i];
u = a2[i];
j = t.length;
while (j-- != 0)
if (!((t[j]) == (u[j])))
return false;
}
return true;
}
/*
* Returns a string representation of the contents of the specified big array.
*
* The string representation consists of a list of the big array's elements,
* enclosed in square brackets ("[]"). Adjacent elements are separated by the
* characters ", " (a comma followed by a space). Returns "null" if {@code a} is
* null.
*
* @param a the big array whose string representation to return.
*
* @return the string representation of {@code a}.
*/
public static String toString(final char[][] a) {
if (a == null)
return "null";
final long last = length(a) - 1;
if (last == -1)
return "[]";
final StringBuilder b = new StringBuilder();
b.append('[');
for (long i = 0;; i++) {
b.append(String.valueOf(get(a, i)));
if (i == last)
return b.append(']').toString();
b.append(", ");
}
}
/**
* Ensures that a range given by its first (inclusive) and last (exclusive)
* elements fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param from
* a start index (inclusive).
* @param to
* an end index (inclusive).
* @throws IllegalArgumentException
* if {@code from} is greater than {@code to}.
* @throws ArrayIndexOutOfBoundsException
* if {@code from} or {@code to} are greater than the big array
* length or negative.
*/
public static void ensureFromTo(final char[][] a, final long from, final long to) {
BigArrays.ensureFromTo(length(a), from, to);
}
/**
* Ensures that a range given by an offset and a length fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param offset
* a start index.
* @param length
* a length (the number of elements in the range).
* @throws IllegalArgumentException
* if {@code length} is negative.
* @throws ArrayIndexOutOfBoundsException
* if {@code offset} is negative or {@code offset}+{@code length} is
* greater than the big array length.
*/
public static void ensureOffsetLength(final char[][] a, final long offset, final long length) {
BigArrays.ensureOffsetLength(length(a), offset, length);
}
/**
* Ensures that two big arrays are of the same length.
*
* @param a
* a big array.
* @param b
* another big array.
* @throws IllegalArgumentException
* if the two argument arrays are not of the same length.
*/
public static void ensureSameLength(final char[][] a, final char[][] b) {
if (length(a) != length(b))
throw new IllegalArgumentException("Array size mismatch: " + length(a) + " != " + length(b));
}
/**
* Shuffles the specified big array fragment using the specified pseudorandom
* number generator.
*
* @param a
* the big array to be shuffled.
* @param from
* the index of the first element (inclusive) to be shuffled.
* @param to
* the index of the last element (exclusive) to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static char[][] shuffle(final char[][] a, final long from, final long to, final Random random) {
for (long i = to - from; i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final char t = BigArrays.get(a, from + i);
BigArrays.set(a, from + i, BigArrays.get(a, from + p));
BigArrays.set(a, from + p, t);
}
return a;
}
/**
* Shuffles the specified big array using the specified pseudorandom number
* generator.
*
* @param a
* the big array to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static char[][] shuffle(final char[][] a, final Random random) {
for (long i = length(a); i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final char t = BigArrays.get(a, i);
BigArrays.set(a, i, BigArrays.get(a, p));
BigArrays.set(a, p, t);
}
return a;
}
/* Generic definitions */
/* Assertions (useful to generate conditional code) */
/* Narrowing and widening */
/* Current type and class (and size, if applicable) */
/* Value methods */
/* Interfaces (keys) */
/* Interfaces (values) */
/* Types and methods related to primitive-type support in the JDK */
/* Abstract implementations (keys) */
/* Abstract implementations (values) */
/* Static containers (keys) */
/* Static containers (values) */
/* Implementations */
/* Synchronized wrappers */
/* Unmodifiable wrappers */
/* Other wrappers */
/* Methods (keys) */
/* Methods (values) */
/* Methods (keys/values) */
/*
* Methods that have special names depending on keys (but the special names
* depend on values)
*/
/* Equality */
/* Object/Reference-only definitions (keys) */
/* Primitive-type-only definitions (keys) */
/* Object/Reference-only definitions (values) */
/* START_OF_JAVA_SOURCE */
/*
* Copyright (C) 2004-2021 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.
*/
/**
* Returns the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @return the element of the big array at the specified position.
*/
public static float get(final float[][] array, final long index) {
return array[segment(index)][displacement(index)];
}
/**
* Sets the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param value
* the new value for the array element at the specified position.
*/
public static void set(final float[][] array, final long index, float value) {
array[segment(index)][displacement(index)] = value;
}
/**
* Swaps the element of the given big array of specified indices.
*
* @param array
* a big array.
* @param first
* a position in the big array.
* @param second
* a position in the big array.
*/
public static void swap(final float[][] array, final long first, final long second) {
final float t = array[segment(first)][displacement(first)];
array[segment(first)][displacement(first)] = array[segment(second)][displacement(second)];
array[segment(second)][displacement(second)] = t;
}
/**
* Reverses the order of the elements in the specified big array.
*
* @param a
* the big array to be reversed.
* @return {@code a}.
*/
public static float[][] reverse(final float[][] a) {
final long length = length(a);
for (long i = length / 2; i-- != 0;)
swap(a, i, length - i - 1);
return a;
}
/**
* Adds the specified increment the element of the given big array of specified
* index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param incr
* the increment
*/
public static void add(final float[][] array, final long index, float incr) {
array[segment(index)][displacement(index)] += incr;
}
/**
* Multiplies by the specified factor the element of the given big array of
* specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param factor
* the factor
*/
public static void mul(final float[][] array, final long index, float factor) {
array[segment(index)][displacement(index)] *= factor;
}
/**
* Increments the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void incr(final float[][] array, final long index) {
array[segment(index)][displacement(index)]++;
}
/**
* Decrements the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
*/
public static void decr(final float[][] array, final long index) {
array[segment(index)][displacement(index)]--;
}
/**
* Returns the length of the given big array.
*
* @param array
* a big array.
* @return the length of the given big array.
*/
public static long length(final float[][] array) {
final int length = array.length;
return length == 0 ? 0 : start(length - 1) + array[length - 1].length;
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination big array.
* Handles correctly overlapping regions of the same big array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copy(final float[][] srcArray, final long srcPos, final float[][] destArray, final long destPos,
long length) {
if (destPos <= srcPos) {
int srcSegment = segment(srcPos);
int destSegment = segment(destPos);
int srcDispl = displacement(srcPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(length,
Math.min(srcArray[srcSegment].length - srcDispl, destArray[destSegment].length - destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray[destSegment], destDispl, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
length -= l;
}
} else {
int srcSegment = segment(srcPos + length);
int destSegment = segment(destPos + length);
int srcDispl = displacement(srcPos + length);
int destDispl = displacement(destPos + length);
while (length > 0) {
if (srcDispl == 0) {
srcDispl = SEGMENT_SIZE;
srcSegment--;
}
if (destDispl == 0) {
destDispl = SEGMENT_SIZE;
destSegment--;
}
final int l = (int) Math.min(length, Math.min(srcDispl, destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl - l, destArray[destSegment], destDispl - l, l);
srcDispl -= l;
destDispl -= l;
length -= l;
}
}
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyFromBig(final float[][] srcArray, final long srcPos, final float[] destArray, int destPos,
int length) {
int srcSegment = segment(srcPos);
int srcDispl = displacement(srcPos);
while (length > 0) {
final int l = Math.min(srcArray[srcSegment].length - srcDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray, destPos, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
destPos += l;
length -= l;
}
}
/**
* Copies an array from the specified source array, beginning at the specified
* position, to the specified position of the destination big array.
*
* @param srcArray
* the source array.
* @param srcPos
* the starting position in the source array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyToBig(final float[] srcArray, int srcPos, final float[][] destArray, final long destPos,
long length) {
int destSegment = segment(destPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(destArray[destSegment].length - destDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray, srcPos, destArray[destSegment], destDispl, l);
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
srcPos += l;
length -= l;
}
}
/**
* Turns a standard array into a big array.
*
*
* Note that the returned big array might contain as a segment the original
* array.
*
* @param array
* an array.
* @return a new big array with the same length and content of {@code array}.
*/
public static float[][] wrap(final float[] array) {
if (array.length == 0)
return FloatBigArrays.EMPTY_BIG_ARRAY;
if (array.length <= SEGMENT_SIZE)
return new float[][]{array};
final float[][] bigArray = FloatBigArrays.newBigArray(array.length);
for (int i = 0; i < bigArray.length; i++)
System.arraycopy(array, (int) start(i), bigArray[i], 0, bigArray[i].length);
return bigArray;
}
/**
* Ensures that a big array can contain the given number of entries.
*
*
* If you cannot foresee whether this big array will need again to be enlarged,
* you should probably use {@code grow()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it contains {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code length(array)} entries are the same as those of {@code array}.
*/
public static float[][] ensureCapacity(final float[][] array, final long length) {
return ensureCapacity(array, length, length(array));
}
/**
* Forces a big array to contain the given number of entries, preserving just a
* part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return a big array with {@code length} entries whose first {@code preserve}
* entries are the same as those of {@code array}.
*/
public static float[][] forceCapacity(final float[][] array, final long length, final long preserve) {
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_SHIFT);
final float[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0) {
for (int i = valid; i < baseLength - 1; i++)
base[i] = new float[SEGMENT_SIZE];
base[baseLength - 1] = new float[residual];
} else
for (int i = valid; i < baseLength; i++)
base[i] = new float[SEGMENT_SIZE];
if (preserve - (valid * (long) SEGMENT_SIZE) > 0)
copy(array, valid * (long) SEGMENT_SIZE, base, valid * (long) SEGMENT_SIZE,
preserve - (valid * (long) SEGMENT_SIZE));
return base;
}
/**
* Ensures that a big array can contain the given number of entries, preserving
* just a part of the big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code preserve} entries are the same as those of {@code array}.
*/
public static float[][] ensureCapacity(final float[][] array, final long length, final long preserve) {
return length > length(array) ? forceCapacity(array, length, preserve) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code length(array)} entries are the same as
* those of {@code array}.
*/
public static float[][] grow(final float[][] array, final long length) {
final long oldLength = length(array);
return length > oldLength ? grow(array, length, oldLength) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length, preserving just a part of the big array.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code preserve} entries are the same as those of
* {@code array}.
*/
public static float[][] grow(final float[][] array, final long length, final long preserve) {
final long oldLength = length(array);
return length > oldLength
? ensureCapacity(array, Math.max(oldLength + (oldLength >> 1), length), preserve)
: array;
}
/**
* Trims the given big array to the given length.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new maximum length for the big array.
* @return {@code array}, if it contains {@code length} entries or less;
* otherwise, a big array with {@code length} entries whose entries are
* the same as the first {@code length} entries of {@code array}.
*
*/
public static float[][] trim(final float[][] array, final long length) {
ensureLength(length);
final long oldLength = length(array);
if (length >= oldLength)
return array;
final int baseLength = (int) ((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
final float[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0)
base[baseLength - 1] = FloatArrays.trim(base[baseLength - 1], residual);
return base;
}
/**
* Sets the length of the given big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new length for the big array.
* @return {@code array}, if it contains exactly {@code length} entries;
* otherwise, if it contains more than {@code length} entries,
* a big array with {@code length} entries whose entries are the same as
* the first {@code length} entries of {@code array}; otherwise, a big
* array with {@code length} entries whose first {@code length(array)}
* entries are the same as those of {@code array}.
*
*/
public static float[][] setLength(final float[][] array, final long length) {
final long oldLength = length(array);
if (length == oldLength)
return array;
if (length < oldLength)
return trim(array, length);
return ensureCapacity(array, length);
}
/**
* Returns a copy of a portion of a big array.
*
* @param array
* a big array.
* @param offset
* the first element to copy.
* @param length
* the number of elements to copy.
* @return a new big array containing {@code length} elements of {@code array}
* starting at {@code offset}.
*/
public static float[][] copy(final float[][] array, final long offset, final long length) {
ensureOffsetLength(array, offset, length);
final float[][] a = FloatBigArrays.newBigArray(length);
copy(array, offset, a, 0, length);
return a;
}
/**
* Returns a copy of a big array.
*
* @param array
* a big array.
* @return a copy of {@code array}.
*/
public static float[][] copy(final float[][] array) {
final float[][] base = array.clone();
for (int i = base.length; i-- != 0;)
base[i] = array[i].clone();
return base;
}
/**
* Fills the given big array with the given value.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param value
* the new value for all elements of the big array.
*/
public static void fill(final float[][] array, final float value) {
for (int i = array.length; i-- != 0;)
java.util.Arrays.fill(array[i], value);
}
/**
* Fills a portion of the given big array with the given value.
*
*
* If possible (i.e., {@code from} is 0) this method uses a backward loop. In
* this case, it is significantly faster than the corresponding method in
* {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param from
* the starting index of the portion to fill.
* @param to
* the end index of the portion to fill.
* @param value
* the new value for all elements of the specified portion of the big
* array.
*/
public static void fill(final float[][] array, final long from, long to, final float value) {
final long length = length(array);
BigArrays.ensureFromTo(length, from, to);
if (length == 0)
return; // To avoid addressing array[0]
int fromSegment = segment(from);
int toSegment = segment(to);
int fromDispl = displacement(from);
int toDispl = displacement(to);
if (fromSegment == toSegment) {
java.util.Arrays.fill(array[fromSegment], fromDispl, toDispl, value);
return;
}
if (toDispl != 0)
java.util.Arrays.fill(array[toSegment], 0, toDispl, value);
while (--toSegment > fromSegment)
java.util.Arrays.fill(array[toSegment], value);
java.util.Arrays.fill(array[fromSegment], fromDispl, SEGMENT_SIZE, value);
}
/**
* Returns true if the two big arrays are elementwise equal.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param a1
* a big array.
* @param a2
* another big array.
* @return true if the two big arrays are of the same length, and their elements
* are equal.
*/
public static boolean equals(final float[][] a1, final float a2[][]) {
if (length(a1) != length(a2))
return false;
int i = a1.length, j;
float[] t, u;
while (i-- != 0) {
t = a1[i];
u = a2[i];
j = t.length;
while (j-- != 0)
if (!(Float.floatToIntBits(t[j]) == Float.floatToIntBits(u[j])))
return false;
}
return true;
}
/*
* Returns a string representation of the contents of the specified big array.
*
* The string representation consists of a list of the big array's elements,
* enclosed in square brackets ("[]"). Adjacent elements are separated by the
* characters ", " (a comma followed by a space). Returns "null" if {@code a} is
* null.
*
* @param a the big array whose string representation to return.
*
* @return the string representation of {@code a}.
*/
public static String toString(final float[][] a) {
if (a == null)
return "null";
final long last = length(a) - 1;
if (last == -1)
return "[]";
final StringBuilder b = new StringBuilder();
b.append('[');
for (long i = 0;; i++) {
b.append(String.valueOf(get(a, i)));
if (i == last)
return b.append(']').toString();
b.append(", ");
}
}
/**
* Ensures that a range given by its first (inclusive) and last (exclusive)
* elements fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param from
* a start index (inclusive).
* @param to
* an end index (inclusive).
* @throws IllegalArgumentException
* if {@code from} is greater than {@code to}.
* @throws ArrayIndexOutOfBoundsException
* if {@code from} or {@code to} are greater than the big array
* length or negative.
*/
public static void ensureFromTo(final float[][] a, final long from, final long to) {
BigArrays.ensureFromTo(length(a), from, to);
}
/**
* Ensures that a range given by an offset and a length fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param offset
* a start index.
* @param length
* a length (the number of elements in the range).
* @throws IllegalArgumentException
* if {@code length} is negative.
* @throws ArrayIndexOutOfBoundsException
* if {@code offset} is negative or {@code offset}+{@code length} is
* greater than the big array length.
*/
public static void ensureOffsetLength(final float[][] a, final long offset, final long length) {
BigArrays.ensureOffsetLength(length(a), offset, length);
}
/**
* Ensures that two big arrays are of the same length.
*
* @param a
* a big array.
* @param b
* another big array.
* @throws IllegalArgumentException
* if the two argument arrays are not of the same length.
*/
public static void ensureSameLength(final float[][] a, final float[][] b) {
if (length(a) != length(b))
throw new IllegalArgumentException("Array size mismatch: " + length(a) + " != " + length(b));
}
/**
* Shuffles the specified big array fragment using the specified pseudorandom
* number generator.
*
* @param a
* the big array to be shuffled.
* @param from
* the index of the first element (inclusive) to be shuffled.
* @param to
* the index of the last element (exclusive) to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static float[][] shuffle(final float[][] a, final long from, final long to, final Random random) {
for (long i = to - from; i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final float t = BigArrays.get(a, from + i);
BigArrays.set(a, from + i, BigArrays.get(a, from + p));
BigArrays.set(a, from + p, t);
}
return a;
}
/**
* Shuffles the specified big array using the specified pseudorandom number
* generator.
*
* @param a
* the big array to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static float[][] shuffle(final float[][] a, final Random random) {
for (long i = length(a); i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final float t = BigArrays.get(a, i);
BigArrays.set(a, i, BigArrays.get(a, p));
BigArrays.set(a, p, t);
}
return a;
}
/* Generic definitions */
/* Assertions (useful to generate conditional code) */
/* Narrowing and widening */
/* Current type and class (and size, if applicable) */
/* Value methods */
/* Interfaces (keys) */
/* Interfaces (values) */
/* Types and methods related to primitive-type support in the JDK */
/* Abstract implementations (keys) */
/* Abstract implementations (values) */
/* Static containers (keys) */
/* Static containers (values) */
/* Implementations */
/* Synchronized wrappers */
/* Unmodifiable wrappers */
/* Other wrappers */
/* Methods (keys) */
/* Methods (values) */
/* Methods (keys/values) */
/*
* Methods that have special names depending on keys (but the special names
* depend on values)
*/
/* Equality */
/* Object/Reference-only definitions (keys) */
/* Object/Reference-only definitions (values) */
/* START_OF_JAVA_SOURCE */
/*
* Copyright (C) 2004-2021 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.
*/
/**
* Returns the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @return the element of the big array at the specified position.
*/
public static K get(final K[][] array, final long index) {
return array[segment(index)][displacement(index)];
}
/**
* Sets the element of the given big array of specified index.
*
* @param array
* a big array.
* @param index
* a position in the big array.
* @param value
* the new value for the array element at the specified position.
*/
public static void set(final K[][] array, final long index, K value) {
array[segment(index)][displacement(index)] = value;
}
/**
* Swaps the element of the given big array of specified indices.
*
* @param array
* a big array.
* @param first
* a position in the big array.
* @param second
* a position in the big array.
*/
public static void swap(final K[][] array, final long first, final long second) {
final K t = array[segment(first)][displacement(first)];
array[segment(first)][displacement(first)] = array[segment(second)][displacement(second)];
array[segment(second)][displacement(second)] = t;
}
/**
* Reverses the order of the elements in the specified big array.
*
* @param a
* the big array to be reversed.
* @return {@code a}.
*/
public static K[][] reverse(final K[][] a) {
final long length = length(a);
for (long i = length / 2; i-- != 0;)
swap(a, i, length - i - 1);
return a;
}
/**
* Returns the length of the given big array.
*
* @param array
* a big array.
* @return the length of the given big array.
*/
public static long length(final K[][] array) {
final int length = array.length;
return length == 0 ? 0 : start(length - 1) + array[length - 1].length;
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination big array.
* Handles correctly overlapping regions of the same big array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copy(final K[][] srcArray, final long srcPos, final K[][] destArray, final long destPos,
long length) {
if (destPos <= srcPos) {
int srcSegment = segment(srcPos);
int destSegment = segment(destPos);
int srcDispl = displacement(srcPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(length,
Math.min(srcArray[srcSegment].length - srcDispl, destArray[destSegment].length - destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray[destSegment], destDispl, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
length -= l;
}
} else {
int srcSegment = segment(srcPos + length);
int destSegment = segment(destPos + length);
int srcDispl = displacement(srcPos + length);
int destDispl = displacement(destPos + length);
while (length > 0) {
if (srcDispl == 0) {
srcDispl = SEGMENT_SIZE;
srcSegment--;
}
if (destDispl == 0) {
destDispl = SEGMENT_SIZE;
destSegment--;
}
final int l = (int) Math.min(length, Math.min(srcDispl, destDispl));
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl - l, destArray[destSegment], destDispl - l, l);
srcDispl -= l;
destDispl -= l;
length -= l;
}
}
}
/**
* Copies a big array from the specified source big array, beginning at the
* specified position, to the specified position of the destination array.
*
* @param srcArray
* the source big array.
* @param srcPos
* the starting position in the source big array.
* @param destArray
* the destination array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyFromBig(final K[][] srcArray, final long srcPos, final K[] destArray, int destPos,
int length) {
int srcSegment = segment(srcPos);
int srcDispl = displacement(srcPos);
while (length > 0) {
final int l = Math.min(srcArray[srcSegment].length - srcDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray[srcSegment], srcDispl, destArray, destPos, l);
if ((srcDispl += l) == SEGMENT_SIZE) {
srcDispl = 0;
srcSegment++;
}
destPos += l;
length -= l;
}
}
/**
* Copies an array from the specified source array, beginning at the specified
* position, to the specified position of the destination big array.
*
* @param srcArray
* the source array.
* @param srcPos
* the starting position in the source array.
* @param destArray
* the destination big array.
* @param destPos
* the starting position in the destination data.
* @param length
* the number of elements to be copied.
*/
public static void copyToBig(final K[] srcArray, int srcPos, final K[][] destArray, final long destPos,
long length) {
int destSegment = segment(destPos);
int destDispl = displacement(destPos);
while (length > 0) {
final int l = (int) Math.min(destArray[destSegment].length - destDispl, length);
if (l == 0)
throw new ArrayIndexOutOfBoundsException();
System.arraycopy(srcArray, srcPos, destArray[destSegment], destDispl, l);
if ((destDispl += l) == SEGMENT_SIZE) {
destDispl = 0;
destSegment++;
}
srcPos += l;
length -= l;
}
}
/**
* Turns a standard array into a big array.
*
*
* Note that the returned big array might contain as a segment the original
* array.
*
* @param array
* an array.
* @return a new big array with the same length and content of {@code array}.
*/
@SuppressWarnings("unchecked")
public static K[][] wrap(final K[] array) {
if (array.length == 0 && array.getClass() == Object[].class)
return (K[][]) ObjectBigArrays.EMPTY_BIG_ARRAY;
if (array.length <= SEGMENT_SIZE) {
final K[][] bigArray = (K[][]) java.lang.reflect.Array.newInstance(array.getClass(), 1);
bigArray[0] = array;
return bigArray;
}
final K[][] bigArray = (K[][]) ObjectBigArrays.newBigArray(array.getClass(), array.length);
for (int i = 0; i < bigArray.length; i++)
System.arraycopy(array, (int) start(i), bigArray[i], 0, bigArray[i].length);
return bigArray;
}
/**
* Ensures that a big array can contain the given number of entries.
*
*
* If you cannot foresee whether this big array will need again to be enlarged,
* you should probably use {@code grow()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it contains {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code length(array)} entries are the same as those of {@code array}.
*/
public static K[][] ensureCapacity(final K[][] array, final long length) {
return ensureCapacity(array, length, length(array));
}
/**
* Forces a big array to contain the given number of entries, preserving just a
* part of the big array.
*
*
* This method returns a new big array of the given length whose element are of
* the same class as of those of {@code array}.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return a big array with {@code length} entries whose first {@code preserve}
* entries are the same as those of {@code array}.
*/
@SuppressWarnings("unchecked")
public static K[][] forceCapacity(final K[][] array, final long length, final long preserve) {
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_SHIFT);
final K[][] base = java.util.Arrays.copyOf(array, baseLength);
final Class> componentType = array.getClass().getComponentType();
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0) {
for (int i = valid; i < baseLength - 1; i++)
base[i] = (K[]) java.lang.reflect.Array.newInstance(componentType.getComponentType(), SEGMENT_SIZE);
base[baseLength - 1] = (K[]) java.lang.reflect.Array.newInstance(componentType.getComponentType(),
residual);
} else
for (int i = valid; i < baseLength; i++)
base[i] = (K[]) java.lang.reflect.Array.newInstance(componentType.getComponentType(), SEGMENT_SIZE);
if (preserve - (valid * (long) SEGMENT_SIZE) > 0)
copy(array, valid * (long) SEGMENT_SIZE, base, valid * (long) SEGMENT_SIZE,
preserve - (valid * (long) SEGMENT_SIZE));
return base;
}
/**
* Ensures that a big array can contain the given number of entries, preserving
* just a part of the big array.
*
*
* This method returns a new big array of the given length whose element are of
* the same class as of those of {@code array}.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries or more;
* otherwise, a big array with {@code length} entries whose first
* {@code preserve} entries are the same as those of {@code array}.
*/
@SuppressWarnings("unchecked")
public static K[][] ensureCapacity(final K[][] array, final long length, final long preserve) {
return length > length(array) ? forceCapacity(array, length, preserve) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code length(array)} entries are the same as
* those of {@code array}.
*/
public static K[][] grow(final K[][] array, final long length) {
final long oldLength = length(array);
return length > oldLength ? grow(array, length, oldLength) : array;
}
/**
* Grows the given big array to the maximum between the given length and the
* current length increased by 50%, provided that the given length is larger
* than the current length, preserving just a part of the big array.
*
*
* If you want complete control on the big array growth, you should probably use
* {@code ensureCapacity()} instead.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new minimum length for this big array.
* @param preserve
* the number of elements of the big array that must be preserved in
* case a new allocation is necessary.
* @return {@code array}, if it can contain {@code length} entries; otherwise, a
* big array with max({@code length},{@code length(array)}/φ)
* entries whose first {@code preserve} entries are the same as those of
* {@code array}.
*/
public static K[][] grow(final K[][] array, final long length, final long preserve) {
final long oldLength = length(array);
return length > oldLength
? ensureCapacity(array, Math.max(oldLength + (oldLength >> 1), length), preserve)
: array;
}
/**
* Trims the given big array to the given length.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new maximum length for the big array.
* @return {@code array}, if it contains {@code length} entries or less;
* otherwise, a big array with {@code length} entries whose entries are
* the same as the first {@code length} entries of {@code array}.
*
*/
public static K[][] trim(final K[][] array, final long length) {
ensureLength(length);
final long oldLength = length(array);
if (length >= oldLength)
return array;
final int baseLength = (int) ((length + SEGMENT_MASK) >>> SEGMENT_SHIFT);
final K[][] base = java.util.Arrays.copyOf(array, baseLength);
final int residual = (int) (length & SEGMENT_MASK);
if (residual != 0)
base[baseLength - 1] = ObjectArrays.trim(base[baseLength - 1], residual);
return base;
}
/**
* Sets the length of the given big array.
*
*
* Warning: the returned array might use part of the segments
* of the original array, which must be considered read-only after calling this
* method.
*
* @param array
* a big array.
* @param length
* the new length for the big array.
* @return {@code array}, if it contains exactly {@code length} entries;
* otherwise, if it contains more than {@code length} entries,
* a big array with {@code length} entries whose entries are the same as
* the first {@code length} entries of {@code array}; otherwise, a big
* array with {@code length} entries whose first {@code length(array)}
* entries are the same as those of {@code array}.
*
*/
public static K[][] setLength(final K[][] array, final long length) {
final long oldLength = length(array);
if (length == oldLength)
return array;
if (length < oldLength)
return trim(array, length);
return ensureCapacity(array, length);
}
/**
* Returns a copy of a portion of a big array.
*
* @param array
* a big array.
* @param offset
* the first element to copy.
* @param length
* the number of elements to copy.
* @return a new big array containing {@code length} elements of {@code array}
* starting at {@code offset}.
*/
public static K[][] copy(final K[][] array, final long offset, final long length) {
ensureOffsetLength(array, offset, length);
final K[][] a = ObjectBigArrays.newBigArray(array, length);
copy(array, offset, a, 0, length);
return a;
}
/**
* Returns a copy of a big array.
*
* @param array
* a big array.
* @return a copy of {@code array}.
*/
public static K[][] copy(final K[][] array) {
final K[][] base = array.clone();
for (int i = base.length; i-- != 0;)
base[i] = array[i].clone();
return base;
}
/**
* Fills the given big array with the given value.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param value
* the new value for all elements of the big array.
*/
public static void fill(final K[][] array, final K value) {
for (int i = array.length; i-- != 0;)
java.util.Arrays.fill(array[i], value);
}
/**
* Fills a portion of the given big array with the given value.
*
*
* If possible (i.e., {@code from} is 0) this method uses a backward loop. In
* this case, it is significantly faster than the corresponding method in
* {@link java.util.Arrays}.
*
* @param array
* a big array.
* @param from
* the starting index of the portion to fill.
* @param to
* the end index of the portion to fill.
* @param value
* the new value for all elements of the specified portion of the big
* array.
*/
public static void fill(final K[][] array, final long from, long to, final K value) {
final long length = length(array);
BigArrays.ensureFromTo(length, from, to);
if (length == 0)
return; // To avoid addressing array[0]
int fromSegment = segment(from);
int toSegment = segment(to);
int fromDispl = displacement(from);
int toDispl = displacement(to);
if (fromSegment == toSegment) {
java.util.Arrays.fill(array[fromSegment], fromDispl, toDispl, value);
return;
}
if (toDispl != 0)
java.util.Arrays.fill(array[toSegment], 0, toDispl, value);
while (--toSegment > fromSegment)
java.util.Arrays.fill(array[toSegment], value);
java.util.Arrays.fill(array[fromSegment], fromDispl, SEGMENT_SIZE, value);
}
/**
* Returns true if the two big arrays are elementwise equal.
*
*
* This method uses a backward loop. It is significantly faster than the
* corresponding method in {@link java.util.Arrays}.
*
* @param a1
* a big array.
* @param a2
* another big array.
* @return true if the two big arrays are of the same length, and their elements
* are equal.
*/
public static boolean equals(final K[][] a1, final K a2[][]) {
if (length(a1) != length(a2))
return false;
int i = a1.length, j;
K[] t, u;
while (i-- != 0) {
t = a1[i];
u = a2[i];
j = t.length;
while (j-- != 0)
if (!java.util.Objects.equals(t[j], u[j]))
return false;
}
return true;
}
/*
* Returns a string representation of the contents of the specified big array.
*
* The string representation consists of a list of the big array's elements,
* enclosed in square brackets ("[]"). Adjacent elements are separated by the
* characters ", " (a comma followed by a space). Returns "null" if {@code a} is
* null.
*
* @param a the big array whose string representation to return.
*
* @return the string representation of {@code a}.
*/
public static String toString(final K[][] a) {
if (a == null)
return "null";
final long last = length(a) - 1;
if (last == -1)
return "[]";
final StringBuilder b = new StringBuilder();
b.append('[');
for (long i = 0;; i++) {
b.append(String.valueOf(get(a, i)));
if (i == last)
return b.append(']').toString();
b.append(", ");
}
}
/**
* Ensures that a range given by its first (inclusive) and last (exclusive)
* elements fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param from
* a start index (inclusive).
* @param to
* an end index (inclusive).
* @throws IllegalArgumentException
* if {@code from} is greater than {@code to}.
* @throws ArrayIndexOutOfBoundsException
* if {@code from} or {@code to} are greater than the big array
* length or negative.
*/
public static void ensureFromTo(final K[][] a, final long from, final long to) {
BigArrays.ensureFromTo(length(a), from, to);
}
/**
* Ensures that a range given by an offset and a length fits a big array.
*
*
* This method may be used whenever a big array range check is needed.
*
* @param a
* a big array.
* @param offset
* a start index.
* @param length
* a length (the number of elements in the range).
* @throws IllegalArgumentException
* if {@code length} is negative.
* @throws ArrayIndexOutOfBoundsException
* if {@code offset} is negative or {@code offset}+{@code length} is
* greater than the big array length.
*/
public static void ensureOffsetLength(final K[][] a, final long offset, final long length) {
BigArrays.ensureOffsetLength(length(a), offset, length);
}
/**
* Ensures that two big arrays are of the same length.
*
* @param a
* a big array.
* @param b
* another big array.
* @throws IllegalArgumentException
* if the two argument arrays are not of the same length.
*/
public static void ensureSameLength(final K[][] a, final K[][] b) {
if (length(a) != length(b))
throw new IllegalArgumentException("Array size mismatch: " + length(a) + " != " + length(b));
}
/**
* Shuffles the specified big array fragment using the specified pseudorandom
* number generator.
*
* @param a
* the big array to be shuffled.
* @param from
* the index of the first element (inclusive) to be shuffled.
* @param to
* the index of the last element (exclusive) to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static K[][] shuffle(final K[][] a, final long from, final long to, final Random random) {
for (long i = to - from; i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final K t = BigArrays.get(a, from + i);
BigArrays.set(a, from + i, BigArrays.get(a, from + p));
BigArrays.set(a, from + p, t);
}
return a;
}
/**
* Shuffles the specified big array using the specified pseudorandom number
* generator.
*
* @param a
* the big array to be shuffled.
* @param random
* a pseudorandom number generator.
* @return {@code a}.
*/
public static K[][] shuffle(final K[][] a, final Random random) {
for (long i = length(a); i-- != 0;) {
final long p = (random.nextLong() & 0x7FFFFFFFFFFFFFFFL) % (i + 1);
final K t = BigArrays.get(a, i);
BigArrays.set(a, i, BigArrays.get(a, p));
BigArrays.set(a, p, t);
}
return a;
}
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;) {
start = -System.currentTimeMillis();
x = 0;
for (long i = length(a); i-- != 0;)
x ^= i ^ get(a, i);
if (x == 0)
System.err.println();
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);
}
if (y == 0)
System.err.println();
if (x != y)
throw new AssertionError();
System.out.println("Double loop: " + (start + System.currentTimeMillis()) + "ms");
z = 0;
long j = 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();
System.out.println("Double loop (with additional index): " + (start + System.currentTimeMillis()) + "ms");
}
}
}