From 8856eed99403409f9904fb8315ff4f2e95065239 Mon Sep 17 00:00:00 2001 From: Aikar Date: Mon, 21 Mar 2016 18:17:14 -0400 Subject: [PATCH] Add minimal fastutil int based collections diff --git a/src/main/java/it/unimi/dsi/fastutil/AbstractIndirectDoublePriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/AbstractIndirectDoublePriorityQueue.java new file mode 100644 index 0000000..4778cfa --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/AbstractIndirectDoublePriorityQueue.java @@ -0,0 +1,29 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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. + */ + +/** An abstract class providing basic methods for implementing the {@link IndirectDoublePriorityQueue} interface. + * + *

This class defines {@link #secondaryLast()} as throwing an + * {@link UnsupportedOperationException}. + */ + +public abstract class AbstractIndirectDoublePriorityQueue extends AbstractIndirectPriorityQueue implements IndirectDoublePriorityQueue { + + public int secondaryLast() { throw new UnsupportedOperationException(); } + +} diff --git a/src/main/java/it/unimi/dsi/fastutil/AbstractIndirectPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/AbstractIndirectPriorityQueue.java new file mode 100644 index 0000000..7138801 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/AbstractIndirectPriorityQueue.java @@ -0,0 +1,41 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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. + */ + +/** An abstract class providing basic methods for implementing the {@link IndirectPriorityQueue} interface. + * + *

This class defines {@link #changed(int)}, {@link #allChanged()}, {@link #remove(int)} and {@link #last()} as throwing an + * {@link UnsupportedOperationException}. + */ + +public abstract class AbstractIndirectPriorityQueue implements IndirectPriorityQueue { + + public int last() { throw new UnsupportedOperationException(); } + + public void changed() { changed( first() ); } + + public void changed( int index ) { throw new UnsupportedOperationException(); } + + public void allChanged() { throw new UnsupportedOperationException(); } + + public boolean remove( int index ) { throw new UnsupportedOperationException(); } + + public boolean contains( int index ) { throw new UnsupportedOperationException(); } + + public boolean isEmpty() { return size() == 0; } + +} diff --git a/src/main/java/it/unimi/dsi/fastutil/AbstractPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/AbstractPriorityQueue.java new file mode 100644 index 0000000..7e819f3 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/AbstractPriorityQueue.java @@ -0,0 +1,35 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import it.unimi.dsi.fastutil.PriorityQueue; + +/** An abstract class providing basic methods for implementing the {@link PriorityQueue} interface. + * + *

This class defines {@link #changed()} and {@link #last()} as throwing an + * {@link UnsupportedOperationException}. + */ + +public abstract class AbstractPriorityQueue implements PriorityQueue { + + public void changed() { throw new UnsupportedOperationException(); } + + public K last() { throw new UnsupportedOperationException(); } + + public boolean isEmpty() { return size() == 0; } + +} diff --git a/src/main/java/it/unimi/dsi/fastutil/AbstractStack.java b/src/main/java/it/unimi/dsi/fastutil/AbstractStack.java new file mode 100644 index 0000000..faf3e7c --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/AbstractStack.java @@ -0,0 +1,41 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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. + */ + + +/** An abstract class providing basic methods for implementing the {@link Stack} interface. + * + *

This class just defines {@link Stack#top()} as {@link Stack#peek(int) peek(0)}, and + * {@link Stack#peek(int)} as throwing an {@link UnsupportedOperationException}. + * + * Subclasses of this class may choose to implement just {@link Stack#push(Object)}, + * {@link Stack#pop()} and {@link Stack#isEmpty()}, or (but this is not + * required) go farther and implement {@link Stack#top()}, or even {@link + * Stack#peek(int)}. + */ + +public abstract class AbstractStack implements Stack { + + public K top() { + return peek( 0 ); + } + + public K peek( int i ) { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/java/it/unimi/dsi/fastutil/Arrays.java b/src/main/java/it/unimi/dsi/fastutil/Arrays.java new file mode 100644 index 0000000..e57cc0a --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/Arrays.java @@ -0,0 +1,437 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import it.unimi.dsi.fastutil.ints.IntComparator; + +import java.util.ArrayList; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.RecursiveAction; + +/** A class providing static methods and objects that do useful things with arrays. + * + *

In addition to commodity methods, this class contains {@link Swapper}-based implementations + * of {@linkplain #quickSort(int, int, IntComparator, Swapper) quicksort} and of + * a stable, in-place {@linkplain #mergeSort(int, int, IntComparator, Swapper) mergesort}. These + * generic sorting methods can be used to sort any kind of list, but they find their natural + * usage, for instance, in sorting arrays in parallel. + * + * @see Arrays + */ + +public class Arrays { + + private Arrays() {} + + /** This is a safe value used by {@link ArrayList} (as of Java 7) to avoid + * throwing {@link OutOfMemoryError} on some JVMs. We adopt the same value. */ + public static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + + /** Ensures that a range given by its first (inclusive) and last (exclusive) elements fits an array of given length. + * + *

This method may be used whenever an array range check is needed. + * + * @param arrayLength an array length. + * @param from a start index (inclusive). + * @param to an end index (inclusive). + * @throws IllegalArgumentException if from is greater than to. + * @throws ArrayIndexOutOfBoundsException if from or to are greater than arrayLength or negative. + */ + public static void ensureFromTo( final int arrayLength, final int from, final int 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 > arrayLength ) throw new ArrayIndexOutOfBoundsException( "End index (" + to + ") is greater than array length (" + arrayLength + ")" ); + } + + /** Ensures that a range given by an offset and a length fits an array of given length. + * + *

This method may be used whenever an array range check is needed. + * + * @param arrayLength an array length. + * @param offset a start index for the fragment + * @param length a length (the number of elements in the fragment). + * @throws IllegalArgumentException if length is negative. + * @throws ArrayIndexOutOfBoundsException if offset is negative or offset+length is greater than arrayLength. + */ + public static void ensureOffsetLength( final int arrayLength, final int offset, final int length ) { + if ( offset < 0 ) throw new ArrayIndexOutOfBoundsException( "Offset (" + offset + ") is negative" ); + if ( length < 0 ) throw new IllegalArgumentException( "Length (" + length + ") is negative" ); + if ( offset + length > arrayLength ) throw new ArrayIndexOutOfBoundsException( "Last index (" + ( offset + length ) + ") is greater than array length (" + arrayLength + ")" ); + } + + /** + * Transforms two consecutive sorted ranges into a single sorted range. The initial ranges are + * [first..middle) and [middle..last), and the resulting range is + * [first..last). Elements in the first input range will precede equal elements in + * the second. + */ + private static void inPlaceMerge( final int from, int mid, final int to, final IntComparator comp, final Swapper swapper ) { + if ( from >= mid || mid >= to ) return; + if ( to - from == 2 ) { + if ( comp.compare( mid, from ) < 0 ) swapper.swap( from, mid ); + return; + } + + int firstCut; + int 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 ); + } + + int first2 = firstCut; + int middle2 = mid; + int last2 = secondCut; + if ( middle2 != first2 && middle2 != last2 ) { + int first1 = first2; + int 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 from the index of the first element (inclusive) to be included in the binary search. + * @param to the index of the last element (exclusive) to be included in the binary search. + * @param pos the position of the element to be searched for. + * @param comp the comparison function. + * @return the largest index i such that, for every j in the range [first..i), + * comp.compare(j, pos) is true. + */ + private static int lowerBound( int from, final int to, final int pos, final IntComparator comp ) { + // if (comp==null) throw new NullPointerException(); + int len = to - from; + while ( len > 0 ) { + int half = len / 2; + int middle = from + half; + if ( comp.compare( middle, pos ) < 0 ) { + from = middle + 1; + len -= half + 1; + } + else { + len = half; + } + } + return from; + } + + + /** + * 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 the index of the first element (inclusive) to be included in the binary search. + * @param to the index of the last element (exclusive) to be included in the binary search. + * @param pos the position of the element to be searched for. + * @param comp the comparison function. + * @return The largest index i such that, for every j in the range [first..i), + * comp.compare(pos, j) is false. + */ + private static int upperBound( int from, final int mid, final int pos, final IntComparator comp ) { + // if (comp==null) throw new NullPointerException(); + int len = mid - from; + while ( len > 0 ) { + int half = len / 2; + int middle = from + half; + if ( comp.compare( pos, middle ) < 0 ) { + len = half; + } + else { + from = middle + 1; + len -= half + 1; + } + } + return from; + } + + /** + * Returns the index of the median of the three indexed chars. + */ + private static int med3( final int a, final int b, final int c, final IntComparator comp ) { + int ab = comp.compare( a, b ); + int ac = comp.compare( a, c ); + int bc = comp.compare( b, c ); + return ( ab < 0 ? + ( bc < 0 ? b : ac < 0 ? c : a ) : + ( bc > 0 ? b : ac > 0 ? c : a ) ); + } + + private static final int MERGESORT_NO_REC = 16; + + /** Sorts the specified range of elements using the specified swapper and according to the order induced by the specified + * comparator using mergesort. + * + *

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 c 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 int from, final int to, final IntComparator c, final Swapper swapper ) { + /* + * We retain the same method signature as quickSort. Given only a comparator and swapper we + * do not know how to copy and move elements from/to temporary arrays. Hence, in contrast to + * the JDK mergesorts this is an "in-place" mergesort, i.e. does not allocate any temporary + * arrays. A non-inplace mergesort would perhaps be faster in most cases, but would require + * non-intuitive delegate objects... + */ + final int length = to - from; + + // Insertion sort on smallest arrays + if ( length < MERGESORT_NO_REC ) { + for ( int i = from; i < to; i++ ) { + for ( int j = i; j > from && ( c.compare( j - 1, j ) > 0 ); j-- ) { + swapper.swap( j, j - 1 ); + } + } + return; + } + + // Recursively sort halves + int mid = ( from + to ) >>> 1; + mergeSort( from, mid, c, swapper ); + mergeSort( mid, to, c, swapper ); + + // If list is already sorted, nothing left to do. This is an + // optimization that results in faster sorts for nearly ordered lists. + if ( c.compare( mid - 1, mid ) <= 0 ) return; + + // Merge sorted halves + inPlaceMerge( from, mid, to, c, swapper ); + } + + /** Swaps two sequences of elements using a provided swapper. + * + * @param swapper the swapper. + * @param a a position in {@code x}. + * @param b another position in {@code x}. + * @param n the number of elements to exchange starting at {@code a} and {@code b}. + */ + protected static void swap( final Swapper swapper, int a, int b, final int n ) { + for ( int i = 0; i < n; i++, a++, b++ ) swapper.swap( a, b ); + } + + private static final int QUICKSORT_NO_REC = 16; + private static final int PARALLEL_QUICKSORT_NO_FORK = 8192; + private static final int QUICKSORT_MEDIAN_OF_9 = 128; + + protected static class ForkJoinGenericQuickSort extends RecursiveAction { + private static final long serialVersionUID = 1L; + private final int from; + private final int to; + private final IntComparator comp; + private final Swapper swapper; + + public ForkJoinGenericQuickSort( final int from, final int to, final IntComparator comp, final Swapper swapper ) { + this.from = from; + this.to = to; + this.comp = comp; + this.swapper = swapper; + } + + @Override + protected void compute() { + final int len = to - from; + if ( len < PARALLEL_QUICKSORT_NO_FORK ) { + quickSort( from, to, comp, swapper ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + int s = len / 8; + l = med3( l, l + s, l + 2 * s, comp ); + m = med3( m - s, m, m + s, comp ); + n = med3( n - 2 * s, n - s, n, comp ); + m = med3( l, m, n, comp ); + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison; + while ( b <= c && ( ( comparison = comp.compare( b, m ) ) <= 0 ) ) { + if ( comparison == 0 ) { + // Fix reference to pivot if necessary + if ( a == m ) m = b; + else if ( b == m ) m = a; + swapper.swap( a++, b ); + } + b++; + } + while ( c >= b && ( ( comparison = comp.compare( c, m ) ) >= 0 ) ) { + if ( comparison == 0 ) { + // Fix reference to pivot if necessary + if ( c == m ) m = d; + else if ( d == m ) m = c; + swapper.swap( c, d-- ); + } + c--; + } + if ( b > c ) break; + // Fix reference to pivot if necessary + if ( b == m ) m = d; + else if ( c == m ) m = c; + swapper.swap( b++, c-- ); + } + + // Swap partition elements back to middle + s = Math.min( a - from, b - a ); + swap( swapper, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( swapper, b, to - s, s ); + + // Recursively sort non-partition-elements + int t; + s = b - a; + t = d - c; + if ( s > 1 && t > 1 ) invokeAll( new ForkJoinGenericQuickSort( from, from + s, comp, swapper ), new ForkJoinGenericQuickSort( to - t, to, comp, swapper ) ); + else if ( s > 1 ) invokeAll( new ForkJoinGenericQuickSort( from, from + s, comp, swapper ) ); + else invokeAll( new ForkJoinGenericQuickSort( to - t, to, comp, swapper ) ); + } + } + + /** Sorts the specified range of elements using the specified swapper and according to the order induced by the specified + * comparator using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with {@link Runtime#availableProcessors()} parallel threads. + * + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param comp the comparator to determine the order of the generic data. + * @param swapper an object that knows how to swap the elements at any two positions. + * + */ + public static void parallelQuickSort( final int from, final int to, final IntComparator comp, final Swapper swapper ) { + final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() ); + pool.invoke( new ForkJoinGenericQuickSort( from, to, comp, swapper ) ); + pool.shutdown(); + } + + + /** Sorts the specified range of elements using the specified swapper and according to the order induced by the specified + * comparator using parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with {@link Runtime#availableProcessors()} parallel threads. + * + * @param 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 int from, final int to, final IntComparator comp, final Swapper swapper ) { + final int len = to - from; + // Insertion sort on smallest arrays + if ( len < QUICKSORT_NO_REC ) { + for ( int i = from; i < to; i++ ) + for ( int j = i; j > from && ( comp.compare( j - 1, j ) > 0 ); j-- ) { + swapper.swap( j, j - 1 ); + } + return; + } + + // Choose a partition element, v + int m = from + len / 2; // Small arrays, middle element + int l = from; + int n = to - 1; + if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9 + int s = len / 8; + l = med3( l, l + s, l + 2 * s, comp ); + m = med3( m - s, m, m + s, comp ); + n = med3( n - 2 * s, n - s, n, comp ); + } + m = med3( l, m, n, comp ); // Mid-size, med of 3 + // int v = x[m]; + + int a = from; + int b = a; + int c = to - 1; + // Establish Invariant: v* (v)* v* + int d = c; + while ( true ) { + int comparison; + while ( b <= c && ( ( comparison = comp.compare( b, m ) ) <= 0 ) ) { + if ( comparison == 0 ) { + // Fix reference to pivot if necessary + if ( a == m ) m = b; + else if ( b == m ) m = a; + swapper.swap( a++, b ); + } + b++; + } + while ( c >= b && ( ( comparison = comp.compare( c, m ) ) >= 0 ) ) { + if ( comparison == 0 ) { + // Fix reference to pivot if necessary + if ( c == m ) m = d; + else if ( d == m ) m = c; + swapper.swap( c, d-- ); + } + c--; + } + if ( b > c ) break; + // Fix reference to pivot if necessary + if ( b == m ) m = d; + else if ( c == m ) m = c; + swapper.swap( b++, c-- ); + } + + // Swap partition elements back to middle + int s; + s = Math.min( a - from, b - a ); + swap( swapper, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( swapper, b, to - s, s ); + + // Recursively sort non-partition-elements + if ( ( s = b - a ) > 1 ) quickSort( from, from + s, comp, swapper ); + if ( ( s = d - c ) > 1 ) quickSort( to - s, to, comp, swapper ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/BidirectionalIterator.java b/src/main/java/it/unimi/dsi/fastutil/BidirectionalIterator.java new file mode 100644 index 0000000..526d78e --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/BidirectionalIterator.java @@ -0,0 +1,55 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import java.util.Iterator; +import java.util.ListIterator; + +/** A bidirectional {@link Iterator}. + * + *

This kind of iterator is essentially a {@link ListIterator} that + * does not support {@link ListIterator#previousIndex()} and {@link + * ListIterator#nextIndex()}. It is useful for those maps that can easily + * provide bidirectional iteration, but provide no index. + * + *

Note that iterators returned by fastutil classes are more + * specific, and support skipping. This class serves the purpose of organising + * in a cleaner way the relationships between various iterators. + * + * @see Iterator + * @see ListIterator + */ + +public interface BidirectionalIterator extends Iterator { + + /** Returns the previous element from the collection. + * + * @return the previous element from the collection. + * @see java.util.ListIterator#previous() + */ + + K previous(); + + /** Returns whether there is a previous element. + * + * @return whether there is a previous element. + * @see java.util.ListIterator#hasPrevious() + */ + + boolean hasPrevious(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/BigSwapper.java b/src/main/java/it/unimi/dsi/fastutil/BigSwapper.java new file mode 100644 index 0000000..8f891db --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/BigSwapper.java @@ -0,0 +1,32 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2010-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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. + */ + + +/** An object that can swap elements whose positions is specified by longs. + * + * @see BigArrays#quickSort(long, long, it.unimi.dsi.fastutil.longs.LongComparator, BigSwapper) + */ + +public interface BigSwapper { + /** Swaps the data at the given positions. + * + * @param a the first position to swap. + * @param b the second position to swap. + */ + void swap( long a, long b ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/Function.java b/src/main/java/it/unimi/dsi/fastutil/Function.java new file mode 100644 index 0000000..03bb61b --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/Function.java @@ -0,0 +1,101 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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. + */ + + +/** A function mapping keys into values. + * + *

Instances of this class represent functions: the main difference with {@link java.util.Map} + * is that functions do not in principle allow enumeration of their domain or range. The need for + * this interface lies in the existence of several highly optimized implementations of + * functions (e.g., minimal perfect hashes) which do not actually store their domain or range explicitly. + * In case the domain is known, {@link #containsKey(Object)} can be used to perform membership queries. + * + *

The choice of naming all methods exactly as in {@link java.util.Map} makes it possible + * for all type-specific maps to extend type-specific functions (e.g., {@link it.unimi.dsi.fastutil.ints.Int2IntMap} + * extends {@link it.unimi.dsi.fastutil.ints.Int2IntFunction}). However, {@link #size()} is allowed to return -1 to denote + * that the number of keys is not available (e.g., in the case of a string hash function). + * + *

Note that there is an {@link it.unimi.dsi.fastutil.objects.Object2ObjectFunction} that + * can also set its default return value. + * + *

Warning: Equality of functions is not specified + * by contract, and it will usually be by reference, as there is no way to enumerate the keys + * and establish whether two functions represent the same mathematical entity. + * + * @see java.util.Map + */ + +public interface Function { + + /** Associates the specified value with the specified key in this function (optional operation). + * + * @param key the key. + * @param value the value. + * @return the old value, or null if no value was present for the given key. + * @see java.util.Map#put(Object,Object) + */ + + V put( K key, V value ); + + /** Returns the value associated by this function to the specified key. + * + * @param key the key. + * @return the corresponding value, or null if no value was present for the given key. + * @see java.util.Map#get(Object) + */ + + V get( Object key ); + + /** Returns true if this function contains a mapping for the specified key. + * + *

Note that for some kind of functions (e.g., hashes) this method + * will always return true. + * + * @param key the key. + * @return true if this function associates a value to key. + * @see java.util.Map#containsKey(Object) + */ + + boolean containsKey( Object key ); + + /** Removes this key and the associated value from this function if it is present (optional operation). + * + * @param key the key. + * @return the old value, or null if no value was present for the given key. + * @see java.util.Map#remove(Object) + */ + + V remove( Object key ); + + /** Returns the intended number of keys in this function, or -1 if no such number exists. + * + *

Most function implementations will have some knowledge of the intended number of keys + * in their domain. In some cases, however, this might not be possible. + * + * @return the intended number of keys in this function, or -1 if that number is not available. + */ + int size(); + + /** Removes all associations from this function (optional operation). + * + * @see java.util.Map#clear() + */ + + void clear(); + +} diff --git a/src/main/java/it/unimi/dsi/fastutil/Hash.java b/src/main/java/it/unimi/dsi/fastutil/Hash.java new file mode 100644 index 0000000..2b52e19 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/Hash.java @@ -0,0 +1,173 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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. + */ + + +/** Basic data for all hash-based classes. + * + *

Historical note

+ * + *

Warning: the following comments are here for historical reasons, + * and apply just to the double hash classes that can be optionally generated. + * The standard fastutil distribution since 6.1.0 uses linear-probing hash + * tables, and tables are always sized as powers of two. + * + *

The classes in fastutil are built around open-addressing hashing + * implemented via double hashing. Following Knuth's suggestions in the third volume of The Art of Computer + * Programming, we use for the table size a prime p such that + * p-2 is also prime. In this way hashing is implemented with modulo p, + * and secondary hashing with modulo p-2. + * + *

Entries in a table can be in three states: {@link #FREE}, {@link #OCCUPIED} or {@link #REMOVED}. + * The naive handling of removed entries requires that you search for a free entry as if they were occupied. However, + * fastutil implements two useful optimizations, based on the following invariant: + *

+ * Let i0, i1, …, ip-1 be + * the permutation of the table indices induced by the key k, that is, i0 is the hash + * of k and the following indices are obtained by adding (modulo p) the secondary hash plus one. + * If there is a {@link #OCCUPIED} entry with key k, its index in the sequence above comes before + * the indices of any {@link #REMOVED} entries with key k. + *
+ * + *

When we search for the key k we scan the entries in the + * sequence i0, i1, …, + * ip-1 and stop when k is found, + * when we finished the sequence or when we find a {@link #FREE} entry. Note + * that the correctness of this procedure it is not completely trivial. Indeed, + * when we stop at a {@link #REMOVED} entry with key k we must rely + * on the invariant to be sure that no {@link #OCCUPIED} entry with the same + * key can appear later. If we insert and remove frequently the same entries, + * this optimization can be very effective (note, however, that when using + * objects as keys or values deleted entries are set to a special fixed value to + * optimize garbage collection). + * + *

Moreover, during the probe we keep the index of the first {@link #REMOVED} entry we meet. + * If we actually have to insert a new element, we use that + * entry if we can, thus avoiding to pollute another {@link #FREE} entry. Since this position comes + * a fortiori before any {@link #REMOVED} entries with the same key, we are also keeping the invariant true. + */ + +public interface Hash { + + /** The initial default size of a hash table. */ + final public int DEFAULT_INITIAL_SIZE = 16; + /** The default load factor of a hash table. */ + final public float DEFAULT_LOAD_FACTOR = .75f; + /** The load factor for a (usually small) table that is meant to be particularly fast. */ + final public float FAST_LOAD_FACTOR = .5f; + /** The load factor for a (usually very small) table that is meant to be extremely fast. */ + final public float VERY_FAST_LOAD_FACTOR = .25f; + + /** A generic hash strategy. + * + *

Custom hash structures (e.g., {@link + * it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet}) allow to hash objects + * using arbitrary functions, a typical example being that of {@linkplain + * it.unimi.dsi.fastutil.ints.IntArrays#HASH_STRATEGY arrays}. Of course, + * one has to compare objects for equality consistently with the chosen + * function. A hash strategy, thus, specifies an {@linkplain + * #equals(Object,Object) equality method} and a {@linkplain + * #hashCode(Object) hash function}, with the obvious property that + * equal objects must have the same hash code. + * + *

Note that the {@link #equals(Object,Object) equals()} method of a strategy must + * be able to handle null, too. + */ + + public interface Strategy { + + /** Returns the hash code of the specified object with respect to this hash strategy. + * + * @param o an object (or null). + * @return the hash code of the given object with respect to this hash strategy. + */ + + public int hashCode( K o ); + + /** Returns true if the given objects are equal with respect to this hash strategy. + * + * @param a an object (or null). + * @param b another object (or null). + * @return true if the two specified objects are equal with respect to this hash strategy. + */ + public boolean equals( K a, K b ); + } + + /** The default growth factor of a hash table. */ + final public int DEFAULT_GROWTH_FACTOR = 16; + /** The state of a free hash table entry. */ + final public byte FREE = 0; + /** The state of a occupied hash table entry. */ + final public byte OCCUPIED = -1; + /** The state of a hash table entry freed by a deletion. */ + final public byte REMOVED = 1; + + /** A list of primes to be used as table sizes. The i-th element is + * the largest prime p smaller than 2(i+28)/16 + * and such that p-2 is also prime (or 1, for the first few entries). */ + + final public int PRIMES[] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5, 5, 5, 5, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 13, 13, 13, 13, 13, 13, 13, 13, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 31, 31, 31, 31, 31, 31, 31, 43, 43, 43, 43, 43, + 43, 43, 43, 61, 61, 61, 61, 61, 73, 73, 73, 73, 73, 73, 73, 103, 103, 109, + 109, 109, 109, 109, 139, 139, 151, 151, 151, 151, 181, 181, 193, 199, 199, + 199, 229, 241, 241, 241, 271, 283, 283, 313, 313, 313, 349, 349, 349, 349, + 421, 433, 463, 463, 463, 523, 523, 571, 601, 619, 661, 661, 661, 661, 661, + 823, 859, 883, 883, 883, 1021, 1063, 1093, 1153, 1153, 1231, 1321, 1321, + 1429, 1489, 1489, 1621, 1699, 1789, 1873, 1951, 2029, 2131, 2143, 2311, + 2383, 2383, 2593, 2731, 2803, 3001, 3121, 3259, 3391, 3583, 3673, 3919, + 4093, 4273, 4423, 4651, 4801, 5023, 5281, 5521, 5743, 5881, 6301, 6571, + 6871, 7129, 7489, 7759, 8089, 8539, 8863, 9283, 9721, 10141, 10531, 11071, + 11551, 12073, 12613, 13009, 13759, 14323, 14869, 15649, 16363, 17029, + 17839, 18541, 19471, 20233, 21193, 22159, 23059, 24181, 25171, 26263, + 27541, 28753, 30013, 31321, 32719, 34213, 35731, 37309, 38923, 40639, + 42463, 44281, 46309, 48313, 50461, 52711, 55051, 57529, 60091, 62299, + 65521, 68281, 71413, 74611, 77713, 81373, 84979, 88663, 92671, 96739, + 100801, 105529, 109849, 115021, 120079, 125509, 131011, 136861, 142873, + 149251, 155863, 162751, 169891, 177433, 185071, 193381, 202129, 211063, + 220021, 229981, 240349, 250969, 262111, 273643, 285841, 298411, 311713, + 325543, 339841, 355009, 370663, 386989, 404269, 422113, 440809, 460081, + 480463, 501829, 524221, 547399, 571603, 596929, 623353, 651019, 679909, + 709741, 741343, 774133, 808441, 844201, 881539, 920743, 961531, 1004119, + 1048573, 1094923, 1143283, 1193911, 1246963, 1302181, 1359733, 1420039, + 1482853, 1548541, 1616899, 1688413, 1763431, 1841293, 1922773, 2008081, + 2097133, 2189989, 2286883, 2388163, 2493853, 2604013, 2719669, 2840041, + 2965603, 3097123, 3234241, 3377191, 3526933, 3682363, 3845983, 4016041, + 4193803, 4379719, 4573873, 4776223, 4987891, 5208523, 5439223, 5680153, + 5931313, 6194191, 6468463, 6754879, 7053331, 7366069, 7692343, 8032639, + 8388451, 8759953, 9147661, 9552733, 9975193, 10417291, 10878619, 11360203, + 11863153, 12387841, 12936529, 13509343, 14107801, 14732413, 15384673, + 16065559, 16777141, 17519893, 18295633, 19105483, 19951231, 20834689, + 21757291, 22720591, 23726449, 24776953, 25873963, 27018853, 28215619, + 29464579, 30769093, 32131711, 33554011, 35039911, 36591211, 38211163, + 39903121, 41669479, 43514521, 45441199, 47452879, 49553941, 51747991, + 54039079, 56431513, 58930021, 61539091, 64263571, 67108669, 70079959, + 73182409, 76422793, 79806229, 83339383, 87029053, 90881083, 94906249, + 99108043, 103495879, 108077731, 112863013, 117860053, 123078019, 128526943, + 134217439, 140159911, 146365159, 152845393, 159612601, 166679173, + 174058849, 181765093, 189812341, 198216103, 206991601, 216156043, + 225726379, 235720159, 246156271, 257054491, 268435009, 280319203, + 292730833, 305691181, 319225021, 333358513, 348117151, 363529759, + 379624279, 396432481, 413983771, 432312511, 451452613, 471440161, + 492312523, 514109251, 536870839, 560640001, 585461743, 611382451, + 638450569, 666717199, 696235363, 727060069, 759249643, 792864871, + 827967631, 864625033, 902905501, 942880663, 984625531, 1028218189, + 1073741719, 1121280091, 1170923713, 1222764841, 1276901371, 1333434301, + 1392470281, 1454120779, 1518500173, 1585729993, 1655935399, 1729249999, + 1805811253, 1885761133, 1969251079, 2056437379, 2147482951 }; + +} diff --git a/src/main/java/it/unimi/dsi/fastutil/HashCommon.java b/src/main/java/it/unimi/dsi/fastutil/HashCommon.java new file mode 100644 index 0000000..1d42f80 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/HashCommon.java @@ -0,0 +1,240 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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. + */ + + +/** Common code for all hash-based classes. */ + +public class HashCommon { + + protected HashCommon() {}; + + /** This reference is used to fill keys and values of removed entries (if + they are objects). null cannot be used as it would confuse the + search algorithm in the presence of an actual null key. */ + public static final Object REMOVED = new Object(); + + /** 232 · φ, φ = (√5 − 1)/2. */ + private static final int INT_PHI = 0x9E3779B9; + /** The reciprocal of {@link #INT_PHI} modulo 232. */ + private static final int INV_INT_PHI = 0x144cbc89; + /** 264 · φ, φ = (√5 − 1)/2. */ + private static final long LONG_PHI = 0x9E3779B97F4A7C15L; + /** The reciprocal of {@link #LONG_PHI} modulo 264. */ + private static final long INV_LONG_PHI = 0xf1de83e19937733dL; + + /** Avalanches the bits of an integer by applying the finalisation step of MurmurHash3. + * + *

This method implements the finalisation step of Austin Appleby's MurmurHash3. + * Its purpose is to avalanche the bits of the argument to within 0.25% bias. + * + * @param x an integer. + * @return a hash value with good avalanching properties. + */ + public final static int murmurHash3( int x ) { + x ^= x >>> 16; + x *= 0x85ebca6b; + x ^= x >>> 13; + x *= 0xc2b2ae35; + x ^= x >>> 16; + return x; + } + + + /** Avalanches the bits of a long integer by applying the finalisation step of MurmurHash3. + * + *

This method implements the finalisation step of Austin Appleby's MurmurHash3. + * Its purpose is to avalanche the bits of the argument to within 0.25% bias. + * + * @param x a long integer. + * @return a hash value with good avalanching properties. + */ + public final static long murmurHash3( long x ) { + x ^= x >>> 33; + x *= 0xff51afd7ed558ccdL; + x ^= x >>> 33; + x *= 0xc4ceb9fe1a85ec53L; + x ^= x >>> 33; + return x; + } + + /** Quickly mixes the bits of an integer. + * + *

This method mixes the bits of the argument by multiplying by the golden ratio and + * xorshifting the result. It is borrowed from Koloboke, and + * it has slightly worse behaviour than {@link #murmurHash3(int)} (in open-addressing hash tables the average number of probes + * is slightly larger), but it's much faster. + * + * @param x an integer. + * @return a hash value obtained by mixing the bits of {@code x}. + * @see #invMix(int) + */ + public final static int mix( final int x ) { + final int h = x * INT_PHI; + return h ^ (h >>> 16); + } + + /** The inverse of {@link #mix(int)}. This method is mainly useful to create unit tests. + * + * @param x an integer. + * @return a value that passed through {@link #mix(int)} would give {@code x}. + */ + public final static int invMix( final int x ) { + return ( x ^ x >>> 16 ) * INV_INT_PHI; + } + + /** Quickly mixes the bits of a long integer. + * + *

This method mixes the bits of the argument by multiplying by the golden ratio and + * xorshifting twice the result. It is borrowed from Koloboke, and + * it has slightly worse behaviour than {@link #murmurHash3(long)} (in open-addressing hash tables the average number of probes + * is slightly larger), but it's much faster. + * + * @param x a long integer. + * @return a hash value obtained by mixing the bits of {@code x}. + */ + public final static long mix( final long x ) { + long h = x * LONG_PHI; + h ^= h >>> 32; + return h ^ (h >>> 16); + } + + /** The inverse of {@link #mix(long)}. This method is mainly useful to create unit tests. + * + * @param x a long integer. + * @return a value that passed through {@link #mix(long)} would give {@code x}. + */ + public final static long invMix( long x ) { + x ^= x >>> 32; + x ^= x >>> 16; + return ( x ^ x >>> 32 ) * INV_LONG_PHI; + } + + + /** Returns the hash code that would be returned by {@link Float#hashCode()}. + * + * @param f a float. + * @return the same code as {@link Float#hashCode() new Float(f).hashCode()}. + */ + + final public static int float2int( final float f ) { + return Float.floatToRawIntBits( f ); + } + + /** Returns the hash code that would be returned by {@link Double#hashCode()}. + * + * @param d a double. + * @return the same code as {@link Double#hashCode() new Double(f).hashCode()}. + */ + + final public static int double2int( final double d ) { + final long l = Double.doubleToRawLongBits( d ); + return (int)( l ^ ( l >>> 32 ) ); + } + + /** Returns the hash code that would be returned by {@link Long#hashCode()}. + * + * @param l a long. + * @return the same code as {@link Long#hashCode() new Long(f).hashCode()}. + */ + final public static int long2int( final long l ) { + return (int)( l ^ ( l >>> 32 ) ); + } + + /** Return the least power of two greater than or equal to the specified value. + * + *

Note that this function will return 1 when the argument is 0. + * + * @param x an integer smaller than or equal to 230. + * @return the least power of two greater than or equal to the specified value. + */ + public static int nextPowerOfTwo( int x ) { + if ( x == 0 ) return 1; + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + return ( x | x >> 16 ) + 1; + } + + /** Return the least power of two greater than or equal to the specified value. + * + *

Note that this function will return 1 when the argument is 0. + * + * @param x a long integer smaller than or equal to 262. + * @return the least power of two greater than or equal to the specified value. + */ + public static long nextPowerOfTwo( long x ) { + if ( x == 0 ) return 1; + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return ( x | x >> 32 ) + 1; + } + + + /** Returns the maximum number of entries that can be filled before rehashing. + * + * @param n the size of the backing array. + * @param f the load factor. + * @return the maximum number of entries before rehashing. + */ + public static int maxFill( final int n, final float f ) { + /* We must guarantee that there is always at least + * one free entry (even with pathological load factors). */ + return Math.min( (int)Math.ceil( n * f ), n - 1 ); + } + + /** Returns the maximum number of entries that can be filled before rehashing. + * + * @param n the size of the backing array. + * @param f the load factor. + * @return the maximum number of entries before rehashing. + */ + public static long maxFill( final long n, final float f ) { + /* We must guarantee that there is always at least + * one free entry (even with pathological load factors). */ + return Math.min( (long)Math.ceil( n * f ), n - 1 ); + } + + /** Returns the least power of two smaller than or equal to 230 and larger than or equal to Math.ceil( expected / f ). + * + * @param expected the expected number of elements in a hash table. + * @param f the load factor. + * @return the minimum possible size for a backing array. + * @throws IllegalArgumentException if the necessary size is larger than 230. + */ + public static int arraySize( final int expected, final float f ) { + final long s = Math.max( 2, nextPowerOfTwo( (long)Math.ceil( expected / f ) ) ); + if ( s > (1 << 30) ) throw new IllegalArgumentException( "Too large (" + expected + " expected elements with load factor " + f + ")" ); + return (int)s; + } + + /** Returns the least power of two larger than or equal to Math.ceil( expected / f ). + * + * @param expected the expected number of elements in a hash table. + * @param f the load factor. + * @return the minimum possible size for a backing big array. + */ + public static long bigArraySize( final long expected, final float f ) { + return nextPowerOfTwo( (long)Math.ceil( expected / f ) ); + } +} \ No newline at end of file diff --git a/src/main/java/it/unimi/dsi/fastutil/IndirectDoublePriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/IndirectDoublePriorityQueue.java new file mode 100644 index 0000000..97ce3c5 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/IndirectDoublePriorityQueue.java @@ -0,0 +1,61 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import java.util.Comparator; + +/** An indirect double priority queue. + * + *

An indirect double priority queue uses two distinct comparators (called primary + * and secondary) to keep its elements ordered. It makes it possible to access the + * first element w.r.t. the secondary comparatory using {@link #secondaryFirst()} (and, optionally, + * the last element using {@link #secondaryLast()}). The remaining methods + * work like those of an {@linkplain it.unimi.dsi.fastutil.IndirectPriorityQueue indirect priority queue} based on the + * primary comparator. + */ + +public interface IndirectDoublePriorityQueue extends IndirectPriorityQueue { + + /** Returns the secondary comparator of this queue. + * + * @return the secondary comparator of this queue. + * @see #secondaryFirst() + */ + public Comparator secondaryComparator(); + + /** Returns the first element of this queue with respect to the {@linkplain #secondaryComparator() secondary comparator}. + * + * @return the first element of this queue w.r.t. the {@linkplain #secondaryComparator() secondary comparator}. + */ + public int secondaryFirst(); + + /** Returns the last element of this queue with respect to the {@linkplain #secondaryComparator() secondary comparator} (optional operation). + * + * @return the last element of this queue w.r.t. the {@linkplain #secondaryComparator() secondary comparator}. + */ + public int secondaryLast(); + + /** Retrieves the secondary front of the queue in a given array (optional operation). + * + * @param a an array large enough to hold the secondary front (e.g., at least long as the reference array). + * @return the number of elements actually written (starting from the first position of a). + * @see IndirectPriorityQueue#front(int[]) + */ + + public int secondaryFront( final int[] a ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/IndirectDoublePriorityQueues.java b/src/main/java/it/unimi/dsi/fastutil/IndirectDoublePriorityQueues.java new file mode 100644 index 0000000..f85a2a7 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/IndirectDoublePriorityQueues.java @@ -0,0 +1,110 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2003-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import java.util.Comparator; +import java.util.NoSuchElementException; + +/** A class providing static methods and objects that do useful things with indirect priority queues. + * + * @see IndirectDoublePriorityQueue + */ + +public class IndirectDoublePriorityQueues { + + private IndirectDoublePriorityQueues() {} + + /** An immutable class representing the empty indirect double priority queue. + * + *

This class may be useful to implement your own in case you subclass + * {@link IndirectDoublePriorityQueue}. + */ + + public static class EmptyIndirectDoublePriorityQueue extends IndirectPriorityQueues.EmptyIndirectPriorityQueue { + + protected EmptyIndirectDoublePriorityQueue() {} + + public int secondaryFirst() { throw new NoSuchElementException(); } + public int secondaryLast() { throw new NoSuchElementException(); } + public Comparator secondaryComparator() { return null; } + + } + + /** An empty indirect double priority queue (immutable). + */ + + public final static EmptyIndirectDoublePriorityQueue EMPTY_QUEUE = new EmptyIndirectDoublePriorityQueue(); + + + /** A synchronized wrapper class for indirect double priority queues. */ + + public static class SynchronizedIndirectDoublePriorityQueue implements IndirectDoublePriorityQueue { + + public static final long serialVersionUID = -7046029254386353129L; + + final protected IndirectDoublePriorityQueue q; + final protected Object sync; + + protected SynchronizedIndirectDoublePriorityQueue( final IndirectDoublePriorityQueue q, final Object sync ) { + this.q = q; + this.sync = sync; + } + + protected SynchronizedIndirectDoublePriorityQueue( final IndirectDoublePriorityQueue q ) { + this.q = q; + this.sync = this; + } + + public void enqueue( int index ) { synchronized( sync ) { q.enqueue( index ); } } + public int dequeue() { synchronized( sync ) { return q.dequeue(); } } + public int first() { synchronized( sync ) { return q.first(); } } + public int last() { synchronized( sync ) { return q.last(); } } + public boolean contains( final int index ) { synchronized( sync ) { return q.contains( index ); } } + public int secondaryFirst() { synchronized( sync ) { return q.secondaryFirst(); } } + public int secondaryLast() { synchronized( sync ) { return q.secondaryLast(); } } + public boolean isEmpty() { synchronized( sync ) { return q.isEmpty(); } } + public int size() { synchronized( sync ) { return q.size(); } } + public void clear() { synchronized( sync ) { q.clear(); } } + public void changed() { synchronized( sync ) { q.changed(); } } + public void allChanged() { synchronized( sync ) { q.allChanged(); } } + public void changed( int i ) { synchronized( sync ) { q.changed( i ); } } + public boolean remove( int i ) { synchronized( sync ) { return q.remove( i ); } } + public Comparator comparator() { synchronized( sync ) { return q.comparator(); } } + public Comparator secondaryComparator() { synchronized( sync ) { return q.secondaryComparator(); } } + public int secondaryFront( int[] a ) { return q.secondaryFront( a ); } + public int front( int[] a ) { return q.front( a ); } + } + + + /** Returns a synchronized type-specific indirect double priority queue backed by the specified type-specific indirect double priority queue. + * + * @param q the indirect double priority queue to be wrapped in a synchronized indirect double priority queue. + * @return a synchronized view of the specified indirect double priority queue. + */ + public static IndirectDoublePriorityQueue synchronize( final IndirectDoublePriorityQueue q ) { return new SynchronizedIndirectDoublePriorityQueue( q ); } + + /** Returns a synchronized type-specific indirect double priority queue backed by the specified type-specific indirect double priority queue, using an assigned object to synchronize. + * + * @param q the indirect double priority queue to be wrapped in a synchronized indirect double priority queue. + * @param sync an object that will be used to synchronize the access to the indirect double priority queue. + * @return a synchronized view of the specified indirect double priority queue. + */ + + public static IndirectDoublePriorityQueue synchronize( final IndirectDoublePriorityQueue q, final Object sync ) { return new SynchronizedIndirectDoublePriorityQueue( q, sync ); } + +} diff --git a/src/main/java/it/unimi/dsi/fastutil/IndirectPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/IndirectPriorityQueue.java new file mode 100644 index 0000000..74d1a16 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/IndirectPriorityQueue.java @@ -0,0 +1,162 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import java.util.Comparator; +import java.util.NoSuchElementException; + +/** An indirect priority queue. + * + *

An indirect priority queue provides a way to {@linkplain #enqueue(int) + * enqueue} by index elements taken from a given reference list, + * and to {@linkplain #dequeue() dequeue} them in some specified order. + * Elements that are smaller in the specified order are + * dequeued first. It + * is also possible to get the {@linkplain #first() index of the first element}, that + * is, the index that would be dequeued next. + * + *

Additionally, the queue may provide a method to peek at the index of the + * element that would be dequeued {@linkplain #last() last}. + * + *

The reference list should not change during queue operations (or, more + * precisely, the relative order of the elements corresponding to indices in the queue should not + * change). Nonetheless, some implementations may give the caller a way to + * notify the queue that the {@linkplain #changed() first element has changed its + * relative position in the order}. + * + *

Optionally, an indirect priority queue may even provide methods to notify + * {@linkplain #changed(int) the change of any element of the + * reference list}, to check {@linkplain #contains(int) the presence of + * an index in the queue}, and to {@linkplain #remove(int) remove an index from the queue}. + * It may even allow to notify that {@linkplain #allChanged() all elements have changed}. + * + *

It is always possible to enqueue two distinct indices corresponding to + * equal elements of the reference list. However, depending on the + * implementation, it may or may not be possible to enqueue twice the same + * index. + * + *

Note that all element manipulation happens via indices. + */ + +public interface IndirectPriorityQueue { + + /** Enqueues a new element. + * + * @param index the element to enqueue. + */ + + void enqueue( int index ); + + /** Dequeues the {@linkplain #first() first} element from this queue. + * + * @return the dequeued element. + * @throws NoSuchElementException if this queue is empty. + */ + + int dequeue(); + + /** Checks whether this queue is empty. + * + * @return true if this queue is empty. + */ + + boolean isEmpty(); + + /** Returns the number of elements in this queue. + * + * @return the number of elements in this queue. + */ + + int size(); + + /** Removes all elements from this queue. + */ + + void clear(); + + /** Returns the first element of this queue. + * + * @return the first element. + * @throws NoSuchElementException if this queue is empty. + */ + + int first(); + + /** Returns the last element of this queue, that is, the element the would be dequeued last (optional operation). + * + * @return the last element. + * @throws NoSuchElementException if this queue is empty. + */ + + int last(); + + /** Notifies this queue that the {@linkplain #first() first element} has changed (optional operation). + * + */ + + void changed(); + + /** Returns the comparator associated with this queue, or null if it uses its elements' natural ordering. + * + * @return the comparator associated with this sorted set, or null if it uses its elements' natural ordering. + */ + Comparator comparator(); + + /** Notifies this queue that the specified element has changed (optional operation). + * + *

Note that the specified element must belong to this queue. + * + * @param index the element that has changed. + * @throws NoSuchElementException if the specified element is not in this queue. + */ + + public void changed( int index ); + + /** Notifies this queue that the all elements have changed (optional operation). + */ + + public void allChanged(); + + /** Checks whether a given index belongs to this queue (optional operation). + * + * @param index an index possibly in the queue. + * @return true if the specified index belongs to this queue. + */ + public boolean contains( int index ); + + /** Removes the specified element from this queue (optional operation). + * + * @param index the element to be removed. + * @return true if the index was in the queue. + */ + + public boolean remove( int index ); + + /** Retrieves the front of this queue in a given array (optional operation). + * + *

The front of an indirect queue is the set of indices whose associated elements in the reference array + * are equal to the element associated to the {@linkplain #first() first index}. These indices can be always obtain by dequeueing, but + * this method should retrieve efficiently such indices in the given array without modifying the state of this queue. + * + * @param a an array large enough to hold the front (e.g., at least long as the reference array). + * @return the number of elements actually written (starting from the first position of a). + */ + + public int front( final int[] a ); + +} diff --git a/src/main/java/it/unimi/dsi/fastutil/IndirectPriorityQueues.java b/src/main/java/it/unimi/dsi/fastutil/IndirectPriorityQueues.java new file mode 100644 index 0000000..a96837c --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/IndirectPriorityQueues.java @@ -0,0 +1,118 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2003-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import java.util.Comparator; +import java.util.NoSuchElementException; + +/** A class providing static methods and objects that do useful things with indirect priority queues. + * + * @see IndirectPriorityQueue + */ + +public class IndirectPriorityQueues { + + private IndirectPriorityQueues() {} + + /** An immutable class representing the empty indirect priority queue. + * + *

This class may be useful to implement your own in case you subclass + * {@link IndirectPriorityQueue}. + */ + + @SuppressWarnings("rawtypes") + public static class EmptyIndirectPriorityQueue extends AbstractIndirectPriorityQueue { + + protected EmptyIndirectPriorityQueue() {} + + public void enqueue( final int i ) { throw new UnsupportedOperationException(); } + public int dequeue() { throw new NoSuchElementException(); } + public boolean isEmpty() { return true; } + public int size() { return 0; } + public boolean contains( int index ) { return false; } + public void clear() {} + public int first() { throw new NoSuchElementException(); } + public int last() { throw new NoSuchElementException(); } + public void changed() { throw new NoSuchElementException(); } + public void allChanged() {} + public Comparator comparator() { return null; } + public void changed( final int i ) { throw new IllegalArgumentException( "Index " + i + " is not in the queue" ); } + public boolean remove( final int i ) { return false; } + public int front( int[] a ) { return 0; } + + } + + /** An empty indirect priority queue (immutable). + */ + + public final static EmptyIndirectPriorityQueue EMPTY_QUEUE = new EmptyIndirectPriorityQueue(); + + + /** A synchronized wrapper class for indirect priority queues. */ + + public static class SynchronizedIndirectPriorityQueue implements IndirectPriorityQueue { + + public static final long serialVersionUID = -7046029254386353129L; + + final protected IndirectPriorityQueue q; + final protected Object sync; + + protected SynchronizedIndirectPriorityQueue( final IndirectPriorityQueue q, final Object sync ) { + this.q = q; + this.sync = sync; + } + + protected SynchronizedIndirectPriorityQueue( final IndirectPriorityQueue q ) { + this.q = q; + this.sync = this; + } + + public void enqueue( int x ) { synchronized( sync ) { q.enqueue( x ); } } + public int dequeue() { synchronized( sync ) { return q.dequeue(); } } + public boolean contains( final int index ) { synchronized( sync ) { return q.contains( index ); } } + public int first() { synchronized( sync ) { return q.first(); } } + public int last() { synchronized( sync ) { return q.last(); } } + public boolean isEmpty() { synchronized( sync ) { return q.isEmpty(); } } + public int size() { synchronized( sync ) { return q.size(); } } + public void clear() { synchronized( sync ) { q.clear(); } } + public void changed() { synchronized( sync ) { q.changed(); } } + public void allChanged() { synchronized( sync ) { q.allChanged(); } } + public void changed( int i ) { synchronized( sync ) { q.changed( i ); } } + public boolean remove( int i ) { synchronized( sync ) { return q.remove( i ); } } + public Comparator comparator() { synchronized( sync ) { return q.comparator(); } } + public int front( int[] a ) { return q.front( a ); } + } + + + /** Returns a synchronized type-specific indirect priority queue backed by the specified type-specific indirect priority queue. + * + * @param q the indirect priority queue to be wrapped in a synchronized indirect priority queue. + * @return a synchronized view of the specified indirect priority queue. + */ + public static IndirectPriorityQueue synchronize( final IndirectPriorityQueue q ) { return new SynchronizedIndirectPriorityQueue( q ); } + + /** Returns a synchronized type-specific indirect priority queue backed by the specified type-specific indirect priority queue, using an assigned object to synchronize. + * + * @param q the indirect priority queue to be wrapped in a synchronized indirect priority queue. + * @param sync an object that will be used to synchronize the access to the indirect priority queue. + * @return a synchronized view of the specified indirect priority queue. + */ + + public static IndirectPriorityQueue synchronize( final IndirectPriorityQueue q, final Object sync ) { return new SynchronizedIndirectPriorityQueue( q, sync ); } + +} diff --git a/src/main/java/it/unimi/dsi/fastutil/Maps.java b/src/main/java/it/unimi/dsi/fastutil/Maps.java new file mode 100644 index 0000000..6934251 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/Maps.java @@ -0,0 +1,36 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2003-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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. + */ + + +/** A class providing static methods and objects that do useful things with maps. + * + * @see java.util.Collections + */ + +public class Maps { + + private Maps() {} + + /** A standard default return value to be used in maps containing null values. + * @deprecated Since fastutil 5.0, the introduction of generics + * makes this object pretty useless. + */ + + @Deprecated + public static final Object MISSING = new Object(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/PriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/PriorityQueue.java new file mode 100644 index 0000000..fe80c6b --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/PriorityQueue.java @@ -0,0 +1,102 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import java.util.Comparator; +import java.util.NoSuchElementException; + +/** A priority queue. + * + *

A priority queue provides a way to {@linkplain #enqueue(Object) enqueue} + * elements, and to {@linkplain #dequeue() dequeue} them in some specified + * order. Elements that are smaller in the specified order are + * dequeued first. It is also possible to get the {@linkplain #first() first + * element}, that is, the element that would be dequeued next. + * + *

Additionally, the queue may provide a method to peek at + * element that would be dequeued {@linkplain #last() last}. + * + *

The relative order of the elements enqueued should not change during + * queue operations. Nonetheless, some implementations may give the caller a + * way to notify the queue that the {@linkplain #changed() first element has + * changed its relative position in the order}. + */ + +public interface PriorityQueue { + + /** Enqueues a new element. + * + * @param x the element to enqueue.. + */ + + void enqueue( K x ); + + /** Dequeues the {@linkplain #first() first} element from the queue. + * + * @return the dequeued element. + * @throws NoSuchElementException if the queue is empty. + */ + + K dequeue(); + + /** Checks whether the queue is empty. + * + * @return true if the queue is empty. + */ + + boolean isEmpty(); + + /** Returns the number of elements in this queue. + * + * @return the number of elements in this queue. + */ + + int size(); + + /** Removes all elements from this queue. + */ + + void clear(); + + /** Returns the first element of the queue. + * + * @return the first element. + * @throws NoSuchElementException if the queue is empty. + */ + + K first(); + + /** Returns the last element of the queue, that is, the element the would be dequeued last (optional operation). + * + * @return the last element. + * @throws NoSuchElementException if the queue is empty. + */ + + K last(); + + /** Notifies the queue that the {@linkplain #first() first} element has changed (optional operation). + */ + + void changed(); + + /** Returns the comparator associated with this queue, or null if it uses its elements' natural ordering. + * + * @return the comparator associated with this sorted set, or null if it uses its elements' natural ordering. + */ + Comparator comparator(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/PriorityQueues.java b/src/main/java/it/unimi/dsi/fastutil/PriorityQueues.java new file mode 100644 index 0000000..eba43d7 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/PriorityQueues.java @@ -0,0 +1,109 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2003-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import java.util.Comparator; +import java.util.NoSuchElementException; + +import it.unimi.dsi.fastutil.PriorityQueue; + +/** A class providing static methods and objects that do useful things with priority queues. + * + * @see it.unimi.dsi.fastutil.PriorityQueue + */ + +public class PriorityQueues { + + private PriorityQueues() {} + + /** An immutable class representing the empty priority queue. + * + *

This class may be useful to implement your own in case you subclass + * {@link PriorityQueue}. + */ + + @SuppressWarnings("rawtypes") + public static class EmptyPriorityQueue extends AbstractPriorityQueue { + + protected EmptyPriorityQueue() {} + + public void enqueue( Object o ) { throw new UnsupportedOperationException(); } + public Object dequeue() { throw new NoSuchElementException(); } + public boolean isEmpty() { return true; } + public int size() { return 0; } + public void clear() {} + public Object first() { throw new NoSuchElementException(); } + public Object last() { throw new NoSuchElementException(); } + public void changed() { throw new NoSuchElementException(); } + public Comparator comparator() { return null; } + + } + + /** An empty indirect priority queue (immutable). + */ + + public final static EmptyPriorityQueue EMPTY_QUEUE = new EmptyPriorityQueue(); + + + /** A synchronized wrapper class for priority queues. */ + + public static class SynchronizedPriorityQueue implements PriorityQueue { + + public static final long serialVersionUID = -7046029254386353129L; + + final protected PriorityQueue q; + final protected Object sync; + + protected SynchronizedPriorityQueue( final PriorityQueue q, final Object sync ) { + this.q = q; + this.sync = sync; + } + + protected SynchronizedPriorityQueue( final PriorityQueue q ) { + this.q = q; + this.sync = this; + } + + public void enqueue( K x ) { synchronized( sync ) { q.enqueue( x ); } } + public K dequeue() { synchronized( sync ) { return q.dequeue(); } } + public K first() { synchronized( sync ) { return q.first(); } } + public K last() { synchronized( sync ) { return q.last(); } } + public boolean isEmpty() { synchronized( sync ) { return q.isEmpty(); } } + public int size() { synchronized( sync ) { return q.size(); } } + public void clear() { synchronized( sync ) { q.clear(); } } + public void changed() { synchronized( sync ) { q.changed(); } } + public Comparator comparator() { synchronized( sync ) { return q.comparator(); } } + } + + + /** Returns a synchronized priority queue backed by the specified priority queue. + * + * @param q the priority queue to be wrapped in a synchronized priority queue. + * @return a synchronized view of the specified priority queue. + */ + public static PriorityQueue synchronize( final PriorityQueue q ) { return new SynchronizedPriorityQueue( q ); } + + /** Returns a synchronized priority queue backed by the specified priority queue, using an assigned object to synchronize. + * + * @param q the priority queue to be wrapped in a synchronized priority queue. + * @param sync an object that will be used to synchronize the access to the priority queue. + * @return a synchronized view of the specified priority queue. + */ + + public static PriorityQueue synchronize( final PriorityQueue q, final Object sync ) { return new SynchronizedPriorityQueue( q, sync ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/Size64.java b/src/main/java/it/unimi/dsi/fastutil/Size64.java new file mode 100644 index 0000000..05ff4cc --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/Size64.java @@ -0,0 +1,50 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2010-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Collection; + +/** An interface for data structures whose size can exceed {@link Integer#MAX_VALUE}. + * + *

The only methods specified by this interfaces are {@link #size64()}, and + * a deprecated {@link #size()} identical to {@link Collection#size()}. Implementations + * can work around the type problem of {@link java.util.Collection#size()} + * (e.g., not being able to return more than {@link Integer#MAX_VALUE}) by implementing this + * interface. Callers interested in large structures + * can use a reflective call to instanceof to check for the presence of {@link #size64()}. + * + *

We remark that it is always a good idea to implement both {@link #size()} and {@link #size64()}, + * as the former might be implemented by a superclass in an incompatible way. If you implement this interface, + * just implement {@link #size()} as a deprecated method returning Math.min(Integer.MAX_VALUE, size64()). + */ + +public interface Size64 { + /** Returns the size of this data structure as a long. + * + * @return the size of this data structure. + */ + long size64(); + + /** Returns the size of this data structure, minimized with {@link Integer#MAX_VALUE}. + * + * @return the size of this data structure, minimized with {@link Integer#MAX_VALUE}. + * @see java.util.Collection#size() + * @deprecated Use {@link #size64()} instead. + */ + @Deprecated + int size(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/Stack.java b/src/main/java/it/unimi/dsi/fastutil/Stack.java new file mode 100644 index 0000000..2a601a9 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/Stack.java @@ -0,0 +1,73 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import java.util.NoSuchElementException; + +/** A stack. + * + *

A stack must provide the classical {@link #push(Object)} and + * {@link #pop()} operations, but may be also peekable + * to some extent: it may provide just the {@link #top()} function, + * or even a more powerful {@link #peek(int)} method that provides + * access to all elements on the stack (indexed from the top, which + * has index 0). + */ + +public interface Stack { + + /** Pushes the given object on the stack. + * + * @param o the object that will become the new top of the stack. + */ + + void push( K o ); + + /** Pops the top off the stack. + * + * @return the top of the stack. + * @throws NoSuchElementException if the stack is empty. + */ + + K pop(); + + /** Checks whether the stack is empty. + * + * @return true if the stack is empty. + */ + + boolean isEmpty(); + + /** Peeks at the top of the stack (optional operation). + * + * @return the top of the stack. + * @throws NoSuchElementException if the stack is empty. + */ + + K top(); + + /** Peeks at an element on the stack (optional operation). + * + * @param i an index from the stop of the stack (0 represents the top). + * @return the i-th element on the stack. + * @throws IndexOutOfBoundsException if the designated element does not exist.. + */ + + K peek( int i ); + +} diff --git a/src/main/java/it/unimi/dsi/fastutil/Swapper.java b/src/main/java/it/unimi/dsi/fastutil/Swapper.java new file mode 100644 index 0000000..5d4e2cb --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/Swapper.java @@ -0,0 +1,31 @@ +package it.unimi.dsi.fastutil; + +/* + * Copyright (C) 2010-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * 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. + */ + +/** An object that can swap elements whose position is specified by integers + * + * @see Arrays#quickSort(int, int, it.unimi.dsi.fastutil.ints.IntComparator, Swapper) + */ + +public interface Swapper { + /** Swaps the data at the given positions. + * + * @param a the first position to swap. + * @param b the second position to swap. + */ + void swap( int a, int b ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/AbstractInt2ObjectFunction.java b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractInt2ObjectFunction.java new file mode 100644 index 0000000..fba1030 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractInt2ObjectFunction.java @@ -0,0 +1,150 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +/** An abstract class providing basic methods for functions implementing a type-specific interface. + * + *

Optional operations just throw an {@link + * UnsupportedOperationException}. Generic versions of accessors delegate to + * the corresponding type-specific counterparts following the interface rules + * (they take care of returning null on a missing key). + * + *

This class handles directly a default return + * value (including {@linkplain #defaultReturnValue() methods to access + * it}). Instances of classes inheriting from this class have just to return + * defRetValue to denote lack of a key in type-specific methods. The value + * is serialized. + * + *

Implementing subclasses have just to provide type-specific get(), + * type-specific containsKey(), and size() methods. + * + */ +public abstract class AbstractInt2ObjectFunction implements Int2ObjectFunction , java.io.Serializable { + private static final long serialVersionUID = -4940583368468432370L; + protected AbstractInt2ObjectFunction() {} + /** + * The default return value for get(), put() and + * remove(). + */ + protected V defRetValue; + public void defaultReturnValue( final V rv ) { + defRetValue = rv; + } + public V defaultReturnValue() { + return defRetValue; + } + public V put( int key, V value ) { + throw new UnsupportedOperationException(); + } + public V remove( int key ) { + throw new UnsupportedOperationException(); + } + public void clear() { + throw new UnsupportedOperationException(); + } + public boolean containsKey( final Object ok ) { + if ( ok == null ) return false; + return containsKey( ((((Integer)(ok)).intValue())) ); + } + /** Delegates to the corresponding type-specific method, taking care of returning null on a missing key. + * + *

This method must check whether the provided key is in the map using containsKey(). Thus, + * it probes the map twice. Implementors of subclasses should override it with a more efficient method. + */ + public V get( final Object ok ) { + if ( ok == null ) return null; + final int k = ((((Integer)(ok)).intValue())); + return containsKey( k ) ? (get( k )) : null; + } + /** Delegates to the corresponding type-specific method, taking care of returning null on a missing key. + * + *

This method must check whether the provided key is in the map using containsKey(). Thus, + * it probes the map twice. Implementors of subclasses should override it with a more efficient method. + * + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public V put( final Integer ok, final V ov ) { + final int k = ((ok).intValue()); + final boolean containsKey = containsKey( k ); + final V v = put( k, (ov) ); + return containsKey ? (v) : null; + } + /** Delegates to the corresponding type-specific method, taking care of returning null on a missing key. + * + *

This method must check whether the provided key is in the map using containsKey(). Thus, + * it probes the map twice. Implementors of subclasses should override it with a more efficient method. + */ + public V remove( final Object ok ) { + if ( ok == null ) return null; + final int k = ((((Integer)(ok)).intValue())); + final boolean containsKey = containsKey( k ); + final V v = remove( k ); + return containsKey ? (v) : null; + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/AbstractInt2ObjectMap.java b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractInt2ObjectMap.java new file mode 100644 index 0000000..9579648 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractInt2ObjectMap.java @@ -0,0 +1,271 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.AbstractObjectIterator; +import it.unimi.dsi.fastutil.objects.ObjectSet; +import java.util.Iterator; +import java.util.Map; +/** An abstract class providing basic methods for maps implementing a type-specific interface. + * + *

Optional operations just throw an {@link + * UnsupportedOperationException}. Generic versions of accessors delegate to + * the corresponding type-specific counterparts following the interface rules + * (they take care of returning null on a missing key). + * + *

As a further help, this class provides a {@link BasicEntry BasicEntry} inner class + * that implements a type-specific version of {@link java.util.Map.Entry}; it + * is particularly useful for those classes that do not implement their own + * entries (e.g., most immutable maps). + */ +public abstract class AbstractInt2ObjectMap extends AbstractInt2ObjectFunction implements Int2ObjectMap , java.io.Serializable { + private static final long serialVersionUID = -4940583368468432370L; + protected AbstractInt2ObjectMap() {} + /** Checks whether the given value is contained in {@link #values()}. */ + public boolean containsValue( Object v ) { + return values().contains( v ); + } + /** Checks whether the given value is contained in {@link #keySet()}. */ + public boolean containsKey( int k ) { + return keySet().contains( k ); + } + /** Puts all pairs in the given map. + * If the map implements the interface of this map, + * it uses the faster iterators. + * + * @param m a map. + */ + @SuppressWarnings({"unchecked","deprecation"}) + public void putAll(Map m) { + int n = m.size(); + final Iterator> i = m.entrySet().iterator(); + if (m instanceof Int2ObjectMap) { + Int2ObjectMap.Entry e; + while(n-- != 0) { + e = (Int2ObjectMap.Entry )i.next(); + put(e.getIntKey(), e.getValue()); + } + } + else { + Map.Entry e; + while(n-- != 0) { + e = i.next(); + put(e.getKey(), e.getValue()); + } + } + } + public boolean isEmpty() { + return size() == 0; + } + /** This class provides a basic but complete type-specific entry class for all those maps implementations + * that do not have entries on their own (e.g., most immutable maps). + * + *

This class does not implement {@link java.util.Map.Entry#setValue(Object) setValue()}, as the modification + * would not be reflected in the base map. + */ + public static class BasicEntry implements Int2ObjectMap.Entry { + protected int key; + protected V value; + public BasicEntry( final Integer key, final V value ) { + this.key = ((key).intValue()); + this.value = (value); + } + public BasicEntry( final int key, final V value ) { + this.key = key; + this.value = value; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer getKey() { + return (Integer.valueOf(key)); + } + public int getIntKey() { + return key; + } + public V getValue() { + return (value); + } + public V setValue( final V value ) { + throw new UnsupportedOperationException(); + } + public boolean equals( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + Map.Entry e = (Map.Entry)o; + return ( (key) == (((((Integer)(e.getKey())).intValue()))) ) && ( (value) == null ? ((e.getValue())) == null : (value).equals((e.getValue())) ); + } + public int hashCode() { + return (key) ^ ( (value) == null ? 0 : (value).hashCode() ); + } + public String toString() { + return key + "->" + value; + } + } + /** Returns a type-specific-set view of the keys of this map. + * + *

The view is backed by the set returned by {@link #entrySet()}. Note that + * no attempt is made at caching the result of this method, as this would + * require adding some attributes that lightweight implementations would + * not need. Subclasses may easily override this policy by calling + * this method and caching the result, but implementors are encouraged to + * write more efficient ad-hoc implementations. + * + * @return a set view of the keys of this map; it may be safely cast to a type-specific interface. + */ + public IntSet keySet() { + return new AbstractIntSet () { + public boolean contains( final int k ) { return containsKey( k ); } + public int size() { return AbstractInt2ObjectMap.this.size(); } + public void clear() { AbstractInt2ObjectMap.this.clear(); } + public IntIterator iterator() { + return new AbstractIntIterator () { + final ObjectIterator> i = entrySet().iterator(); + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public int nextInt() { return ((Int2ObjectMap.Entry )i.next()).getIntKey(); }; + public boolean hasNext() { return i.hasNext(); } + }; + } + }; + } + /** Returns a type-specific-set view of the values of this map. + * + *

The view is backed by the set returned by {@link #entrySet()}. Note that + * no attempt is made at caching the result of this method, as this would + * require adding some attributes that lightweight implementations would + * not need. Subclasses may easily override this policy by calling + * this method and caching the result, but implementors are encouraged to + * write more efficient ad-hoc implementations. + * + * @return a set view of the values of this map; it may be safely cast to a type-specific interface. + */ + public ObjectCollection values() { + return new AbstractObjectCollection () { + public boolean contains( final Object k ) { return containsValue( k ); } + public int size() { return AbstractInt2ObjectMap.this.size(); } + public void clear() { AbstractInt2ObjectMap.this.clear(); } + public ObjectIterator iterator() { + return new AbstractObjectIterator () { + final ObjectIterator> i = entrySet().iterator(); + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public V next() { return ((Int2ObjectMap.Entry )i.next()).getValue(); }; + public boolean hasNext() { return i.hasNext(); } + }; + } + }; + } + @SuppressWarnings({ "unchecked", "rawtypes" }) + public ObjectSet> entrySet() { + return (ObjectSet)int2ObjectEntrySet(); + } + /** Returns a hash code for this map. + * + * The hash code of a map is computed by summing the hash codes of its entries. + * + * @return a hash code for this map. + */ + public int hashCode() { + int h = 0, n = size(); + final ObjectIterator> i = entrySet().iterator(); + while( n-- != 0 ) h += i.next().hashCode(); + return h; + } + public boolean equals(Object o) { + if ( o == this ) return true; + if ( ! ( o instanceof Map ) ) return false; + Map m = (Map)o; + if ( m.size() != size() ) return false; + return entrySet().containsAll( m.entrySet() ); + } + public String toString() { + final StringBuilder s = new StringBuilder(); + final ObjectIterator> i = entrySet().iterator(); + int n = size(); + Int2ObjectMap.Entry e; + boolean first = true; + s.append("{"); + while(n-- != 0) { + if (first) first = false; + else s.append(", "); + e = (Int2ObjectMap.Entry )i.next(); + s.append(String.valueOf(e.getIntKey())); + s.append("=>"); + if (this == e.getValue()) s.append("(this map)"); else + s.append(String.valueOf(e.getValue())); + } + s.append("}"); + return s.toString(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/AbstractInt2ObjectSortedMap.java b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractInt2ObjectSortedMap.java new file mode 100644 index 0000000..4b4191b --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractInt2ObjectSortedMap.java @@ -0,0 +1,193 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectIterator; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; +import it.unimi.dsi.fastutil.objects.ObjectSortedSet; +import java.util.Map; +/** An abstract class providing basic methods for sorted maps implementing a type-specific interface. */ +public abstract class AbstractInt2ObjectSortedMap extends AbstractInt2ObjectMap implements Int2ObjectSortedMap { + private static final long serialVersionUID = -1773560792952436569L; + protected AbstractInt2ObjectSortedMap() {} + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Int2ObjectSortedMap headMap( final Integer to ) { + return headMap( ((to).intValue()) ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Int2ObjectSortedMap tailMap( final Integer from ) { + return tailMap( ((from).intValue()) ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Int2ObjectSortedMap subMap( final Integer from, final Integer to ) { + return subMap( ((from).intValue()), ((to).intValue()) ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer firstKey() { + return (Integer.valueOf(firstIntKey())); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer lastKey() { + return (Integer.valueOf(lastIntKey())); + } + /** Returns a type-specific-sorted-set view of the keys of this map. + * + *

The view is backed by the sorted set returned by {@link #entrySet()}. Note that + * no attempt is made at caching the result of this method, as this would + * require adding some attributes that lightweight implementations would + * not need. Subclasses may easily override this policy by calling + * this method and caching the result, but implementors are encouraged to + * write more efficient ad-hoc implementations. + * + * @return a sorted set view of the keys of this map; it may be safely cast to a type-specific interface. + */ + public IntSortedSet keySet() { + return new KeySet(); + } + /** A wrapper exhibiting the keys of a map. */ + protected class KeySet extends AbstractIntSortedSet { + public boolean contains( final int k ) { return containsKey( k ); } + public int size() { return AbstractInt2ObjectSortedMap.this.size(); } + public void clear() { AbstractInt2ObjectSortedMap.this.clear(); } + public IntComparator comparator() { return AbstractInt2ObjectSortedMap.this.comparator(); } + public int firstInt() { return firstIntKey(); } + public int lastInt() { return lastIntKey(); } + public IntSortedSet headSet( final int to ) { return headMap( to ).keySet(); } + public IntSortedSet tailSet( final int from ) { return tailMap( from ).keySet(); } + public IntSortedSet subSet( final int from, final int to ) { return subMap( from, to ).keySet(); } + public IntBidirectionalIterator iterator( final int from ) { return new KeySetIterator ( entrySet().iterator( new BasicEntry ( from, (null) ) ) ); } + public IntBidirectionalIterator iterator() { return new KeySetIterator ( entrySet().iterator() ); } + } + /** A wrapper exhibiting a map iterator as an iterator on keys. + * + *

To provide an iterator on keys, just create an instance of this + * class using the corresponding iterator on entries. + */ + protected static class KeySetIterator extends AbstractIntBidirectionalIterator { + protected final ObjectBidirectionalIterator> i; + public KeySetIterator( ObjectBidirectionalIterator> i ) { + this.i = i; + } + public int nextInt() { return ((i.next().getKey()).intValue()); }; + public int previousInt() { return ((i.previous().getKey()).intValue()); }; + public boolean hasNext() { return i.hasNext(); } + public boolean hasPrevious() { return i.hasPrevious(); } + } + /** Returns a type-specific collection view of the values contained in this map. + * + *

The view is backed by the sorted set returned by {@link #entrySet()}. Note that + * no attempt is made at caching the result of this method, as this would + * require adding some attributes that lightweight implementations would + * not need. Subclasses may easily override this policy by calling + * this method and caching the result, but implementors are encouraged to + * write more efficient ad-hoc implementations. + * + * @return a type-specific collection view of the values contained in this map. + */ + public ObjectCollection values() { + return new ValuesCollection(); + } + /** A wrapper exhibiting the values of a map. */ + protected class ValuesCollection extends AbstractObjectCollection { + public ObjectIterator iterator() { return new ValuesIterator ( entrySet().iterator() ); } + public boolean contains( final Object k ) { return containsValue( k ); } + public int size() { return AbstractInt2ObjectSortedMap.this.size(); } + public void clear() { AbstractInt2ObjectSortedMap.this.clear(); } + } + /** A wrapper exhibiting a map iterator as an iterator on values. + * + *

To provide an iterator on values, just create an instance of this + * class using the corresponding iterator on entries. + */ + protected static class ValuesIterator extends AbstractObjectIterator { + protected final ObjectBidirectionalIterator> i; + public ValuesIterator( ObjectBidirectionalIterator> i ) { + this.i = i; + } + public V next() { return (i.next().getValue()); }; + public boolean hasNext() { return i.hasNext(); } + } + @SuppressWarnings({ "unchecked", "rawtypes" }) + public ObjectSortedSet> entrySet() { + return (ObjectSortedSet)int2ObjectEntrySet(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntBidirectionalIterator.java b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntBidirectionalIterator.java new file mode 100644 index 0000000..ef90e23 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntBidirectionalIterator.java @@ -0,0 +1,95 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +/** An abstract class facilitating the creation of type-specific {@linkplain it.unimi.dsi.fastutil.BidirectionalIterator bidirectional iterators}. + * + *

To create a type-specific bidirectional iterator, besides what is needed + * for an iterator you need both a method returning the previous element as + * primitive type and a method returning the previous element as an + * object. However, if you inherit from this class you need just one (anyone). + * + *

This class implements also a trivial version of {@link #back(int)} that + * uses type-specific methods. + */ +public abstract class AbstractIntBidirectionalIterator extends AbstractIntIterator implements IntBidirectionalIterator { + protected AbstractIntBidirectionalIterator() {} + /** Delegates to the corresponding generic method. */ + public int previousInt() { return previous().intValue(); } + /** Delegates to the corresponding type-specific method. */ + public Integer previous() { return Integer.valueOf( previousInt() ); } + /** This method just iterates the type-specific version of {@link #previous()} for + * at most n times, stopping if {@link + * #hasPrevious()} becomes false. */ + public int back( final int n ) { + int i = n; + while( i-- != 0 && hasPrevious() ) previousInt(); + return n - i - 1; + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntCollection.java b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntCollection.java new file mode 100644 index 0000000..b704d10 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntCollection.java @@ -0,0 +1,271 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Iterator; +/** An abstract class providing basic methods for collections implementing a type-specific interface. + * + *

In particular, this class provide {@link #iterator()}, add(), {@link #remove(Object)} and + * {@link #contains(Object)} methods that just call the type-specific counterpart. + */ +public abstract class AbstractIntCollection extends AbstractCollection implements IntCollection { + protected AbstractIntCollection() {} + public int[] toArray( int a[] ) { + return toIntArray( a ); + } + public int[] toIntArray() { + return toIntArray( null ); + } + public int[] toIntArray( int a[] ) { + if ( a == null || a.length < size() ) a = new int[ size() ]; + IntIterators.unwrap( iterator(), a ); + return a; + } + /** Adds all elements of the given type-specific collection to this collection. + * + * @param c a type-specific collection. + * @return true if this collection changed as a result of the call. + */ + public boolean addAll( IntCollection c ) { + boolean retVal = false; + final IntIterator i = c.iterator(); + int n = c.size(); + while( n-- != 0 ) if ( add( i.nextInt() ) ) retVal = true; + return retVal; + } + /** Checks whether this collection contains all elements from the given type-specific collection. + * + * @param c a type-specific collection. + * @return true if this collection contains all elements of the argument. + */ + public boolean containsAll( IntCollection c ) { + final IntIterator i = c.iterator(); + int n = c.size(); + while( n-- != 0 ) if ( ! contains( i.nextInt() ) ) return false; + return true; + } + /** Retains in this collection only elements from the given type-specific collection. + * + * @param c a type-specific collection. + * @return true if this collection changed as a result of the call. + */ + public boolean retainAll( IntCollection c ) { + boolean retVal = false; + int n = size(); + final IntIterator i = iterator(); + while( n-- != 0 ) { + if ( ! c.contains( i.nextInt() ) ) { + i.remove(); + retVal = true; + } + } + return retVal; + } + /** Remove from this collection all elements in the given type-specific collection. + * + * @param c a type-specific collection. + * @return true if this collection changed as a result of the call. + */ + public boolean removeAll( IntCollection c ) { + boolean retVal = false; + int n = c.size(); + final IntIterator i = c.iterator(); + while( n-- != 0 ) if ( rem( i.nextInt() ) ) retVal = true; + return retVal; + } + public Object[] toArray() { + final Object[] a = new Object[ size() ]; + it.unimi.dsi.fastutil.objects.ObjectIterators.unwrap( iterator(), a ); + return a; + } + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + final int size = size(); + if ( a.length < size ) a = (T[])java.lang.reflect.Array.newInstance( a.getClass().getComponentType(), size ); + it.unimi.dsi.fastutil.objects.ObjectIterators.unwrap( iterator(), a ); + if ( size < a.length ) a[ size ] = null; + return a; + } + /** Adds all elements of the given collection to this collection. + * + * @param c a collection. + * @return true if this collection changed as a result of the call. + */ + public boolean addAll( Collection c ) { + boolean retVal = false; + final Iterator i = c.iterator(); + int n = c.size(); + while( n-- != 0 ) if ( add( i.next() ) ) retVal = true; + return retVal; + } + public boolean add( int k ) { + throw new UnsupportedOperationException(); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public IntIterator intIterator() { + return iterator(); + } + public abstract IntIterator iterator(); + /** Delegates to the type-specific rem() method. */ + public boolean remove( Object ok ) { + if ( ok == null ) return false; + return rem( ((((Integer)(ok)).intValue())) ); + } + /** Delegates to the corresponding type-specific method. */ + public boolean add( final Integer o ) { + return add( o.intValue() ); + } + /** Delegates to the corresponding type-specific method. */ + public boolean rem( final Object o ) { + if ( o == null ) return false; + return rem( ((((Integer)(o)).intValue())) ); + } + /** Delegates to the corresponding type-specific method. */ + public boolean contains( final Object o ) { + if ( o == null ) return false; + return contains( ((((Integer)(o)).intValue())) ); + } + public boolean contains( final int k ) { + final IntIterator iterator = iterator(); + while ( iterator.hasNext() ) if ( k == iterator.nextInt() ) return true; + return false; + } + public boolean rem( final int k ) { + final IntIterator iterator = iterator(); + while ( iterator.hasNext() ) + if ( k == iterator.nextInt() ) { + iterator.remove(); + return true; + } + return false; + } + /** Checks whether this collection contains all elements from the given collection. + * + * @param c a collection. + * @return true if this collection contains all elements of the argument. + */ + public boolean containsAll( Collection c ) { + int n = c.size(); + final Iterator i = c.iterator(); + while( n-- != 0 ) if ( ! contains( i.next() ) ) return false; + return true; + } + /** Retains in this collection only elements from the given collection. + * + * @param c a collection. + * @return true if this collection changed as a result of the call. + */ + public boolean retainAll( Collection c ) { + boolean retVal = false; + int n = size(); + final Iterator i = iterator(); + while( n-- != 0 ) { + if ( ! c.contains( i.next() ) ) { + i.remove(); + retVal = true; + } + } + return retVal; + } + /** Remove from this collection all elements in the given collection. + * If the collection is an instance of this class, it uses faster iterators. + * + * @param c a collection. + * @return true if this collection changed as a result of the call. + */ + public boolean removeAll( Collection c ) { + boolean retVal = false; + int n = c.size(); + final Iterator i = c.iterator(); + while( n-- != 0 ) if ( remove( i.next() ) ) retVal = true; + return retVal; + } + public boolean isEmpty() { + return size() == 0; + } + public String toString() { + final StringBuilder s = new StringBuilder(); + final IntIterator i = iterator(); + int n = size(); + int k; + boolean first = true; + s.append("{"); + while(n-- != 0) { + if (first) first = false; + else s.append(", "); + k = i.nextInt(); + s.append(String.valueOf(k)); + } + s.append("}"); + return s.toString(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntComparator.java b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntComparator.java new file mode 100644 index 0000000..2eb1121 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntComparator.java @@ -0,0 +1,87 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +/** An abstract class facilitating the creation of type-specific {@linkplain java.util.Comparator comparators}. + * + *

To create a type-specific comparator you need both a method comparing + * primitive types and a method comparing objects. However, if you have the + * first one you can just inherit from this class and get for free the second + * one. + * + * @see java.util.Comparator + */ +public abstract class AbstractIntComparator implements IntComparator , java.io.Serializable { + private static final long serialVersionUID = 0L; + protected AbstractIntComparator() {} + public int compare( Integer ok1, Integer ok2 ) { + return compare( ok1.intValue(), ok2.intValue() ); + } + public abstract int compare( int k1, int k2 ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntIterator.java b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntIterator.java new file mode 100644 index 0000000..4fc1be5 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntIterator.java @@ -0,0 +1,100 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +/** An abstract class facilitating the creation of type-specific iterators. + * + *

To create a type-specific iterator you need both a method returning the + * next element as primitive type and a method returning the next element as an + * object. However, if you inherit from this class you need just one (anyone). + * + *

This class implements also a trivial version of {@link #skip(int)} that uses + * type-specific methods; moreover, {@link #remove()} will throw an {@link + * UnsupportedOperationException}. + * + * @see java.util.Iterator + */ +public abstract class AbstractIntIterator implements IntIterator { + protected AbstractIntIterator() {} + /** Delegates to the corresponding generic method. */ + public int nextInt() { return next().intValue(); } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer next() { return Integer.valueOf( nextInt() ); } + /** This method just throws an {@link UnsupportedOperationException}. */ + public void remove() { throw new UnsupportedOperationException(); } + /** This method just iterates the type-specific version of {@link #next()} for at most + * n times, stopping if {@link #hasNext()} becomes false.*/ + public int skip( final int n ) { + int i = n; + while( i-- != 0 && hasNext() ) nextInt(); + return n - i - 1; + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntList.java b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntList.java new file mode 100644 index 0000000..4a32979 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntList.java @@ -0,0 +1,577 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.List; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.Collection; +import java.util.NoSuchElementException; +/** An abstract class providing basic methods for lists implementing a type-specific list interface. + * + *

As an additional bonus, this class implements on top of the list operations a type-specific stack. + */ +public abstract class AbstractIntList extends AbstractIntCollection implements IntList , IntStack { + protected AbstractIntList() {} + /** Ensures that the given index is nonnegative and not greater than the list size. + * + * @param index an index. + * @throws IndexOutOfBoundsException if the given index is negative or greater than the list size. + */ + protected void ensureIndex( final int index ) { + if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" ); + if ( index > size() ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than list size (" + ( size() ) + ")" ); + } + /** Ensures that the given index is nonnegative and smaller than the list size. + * + * @param index an index. + * @throws IndexOutOfBoundsException if the given index is negative or not smaller than the list size. + */ + protected void ensureRestrictedIndex( final int index ) { + if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" ); + if ( index >= size() ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + ( size() ) + ")" ); + } + public void add( final int index, final int k ) { + throw new UnsupportedOperationException(); + } + public boolean add( final int k ) { + add( size(), k ); + return true; + } + public int removeInt( int i ) { + throw new UnsupportedOperationException(); + } + public int set( final int index, final int k ) { + throw new UnsupportedOperationException(); + } + public boolean addAll( int index, final Collection c ) { + ensureIndex( index ); + int n = c.size(); + if ( n == 0 ) return false; + Iterator i = c.iterator(); + while( n-- != 0 ) add( index++, i.next() ); + return true; + } + /** Delegates to a more generic method. */ + public boolean addAll( final Collection c ) { + return addAll( size(), c ); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public IntListIterator intListIterator() { + return listIterator(); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public IntListIterator intListIterator( final int index ) { + return listIterator( index ); + } + public IntListIterator iterator() { + return listIterator(); + } + public IntListIterator listIterator() { + return listIterator( 0 ); + } + public IntListIterator listIterator( final int index ) { + ensureIndex( index ); + return new AbstractIntListIterator () { + int pos = index, last = -1; + public boolean hasNext() { return pos < AbstractIntList.this.size(); } + public boolean hasPrevious() { return pos > 0; } + public int nextInt() { if ( ! hasNext() ) throw new NoSuchElementException(); return AbstractIntList.this.getInt( last = pos++ ); } + public int previousInt() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return AbstractIntList.this.getInt( last = --pos ); } + public int nextIndex() { return pos; } + public int previousIndex() { return pos - 1; } + public void add( int k ) { + AbstractIntList.this.add( pos++, k ); + last = -1; + } + public void set( int k ) { + if ( last == -1 ) throw new IllegalStateException(); + AbstractIntList.this.set( last, k ); + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + AbstractIntList.this.removeInt( last ); + /* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */ + if ( last < pos ) pos--; + last = -1; + } + }; + } + public boolean contains( final int k ) { + return indexOf( k ) >= 0; + } + public int indexOf( final int k ) { + final IntListIterator i = listIterator(); + int e; + while( i.hasNext() ) { + e = i.nextInt(); + if ( ( (k) == (e) ) ) return i.previousIndex(); + } + return -1; + } + public int lastIndexOf( final int k ) { + IntListIterator i = listIterator( size() ); + int e; + while( i.hasPrevious() ) { + e = i.previousInt(); + if ( ( (k) == (e) ) ) return i.nextIndex(); + } + return -1; + } + public void size( final int size ) { + int i = size(); + if ( size > i ) while( i++ < size ) add( (0) ); + else while( i-- != size ) remove( i ); + } + public IntList subList( final int from, final int to ) { + ensureIndex( from ); + ensureIndex( to ); + if ( from > to ) throw new IndexOutOfBoundsException( "Start index (" + from + ") is greater than end index (" + to + ")" ); + return new IntSubList ( this, from, to ); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public IntList intSubList( final int from, final int to ) { + return subList( from, to ); + } + /** Removes elements of this type-specific list one-by-one. + * + *

This is a trivial iterator-based implementation. It is expected that + * implementations will override this method with a more optimized version. + * + * + * @param from the start index (inclusive). + * @param to the end index (exclusive). + */ + public void removeElements( final int from, final int to ) { + ensureIndex( to ); + IntListIterator i = listIterator( from ); + int n = to - from; + if ( n < 0 ) throw new IllegalArgumentException( "Start index (" + from + ") is greater than end index (" + to + ")" ); + while( n-- != 0 ) { + i.nextInt(); + i.remove(); + } + } + /** Adds elements to this type-specific list one-by-one. + * + *

This is a trivial iterator-based implementation. It is expected that + * implementations will override this method with a more optimized version. + * + * @param index the index at which to add elements. + * @param a the array containing the elements. + * @param offset the offset of the first element to add. + * @param length the number of elements to add. + */ + public void addElements( int index, final int a[], int offset, int length ) { + ensureIndex( index ); + if ( offset < 0 ) throw new ArrayIndexOutOfBoundsException( "Offset (" + offset + ") is negative" ); + if ( offset + length > a.length ) throw new ArrayIndexOutOfBoundsException( "End index (" + ( offset + length ) + ") is greater than array length (" + a.length + ")" ); + while( length-- != 0 ) add( index++, a[ offset++ ] ); + } + public void addElements( final int index, final int a[] ) { + addElements( index, a, 0, a.length ); + } + /** Copies element of this type-specific list into the given array one-by-one. + * + *

This is a trivial iterator-based implementation. It is expected that + * implementations will override this method with a more optimized version. + * + * @param from the start index (inclusive). + * @param a the destination array. + * @param offset the offset into the destination array where to store the first element copied. + * @param length the number of elements to be copied. + */ + public void getElements( final int from, final int a[], int offset, int length ) { + IntListIterator i = listIterator( from ); + if ( offset < 0 ) throw new ArrayIndexOutOfBoundsException( "Offset (" + offset + ") is negative" ); + if ( offset + length > a.length ) throw new ArrayIndexOutOfBoundsException( "End index (" + ( offset + length ) + ") is greater than array length (" + a.length + ")" ); + if ( from + length > size() ) throw new IndexOutOfBoundsException( "End index (" + ( from + length ) + ") is greater than list size (" + size() + ")" ); + while( length-- != 0 ) a[ offset++ ] = i.nextInt(); + } + private boolean valEquals( final Object a, final Object b ) { + return a == null ? b == null : a.equals( b ); + } + public boolean equals( final Object o ) { + if ( o == this ) return true; + if ( ! ( o instanceof List ) ) return false; + final List l = (List)o; + int s = size(); + if ( s != l.size() ) return false; + if ( l instanceof IntList ) { + final IntListIterator i1 = listIterator(), i2 = ((IntList )l).listIterator(); + while( s-- != 0 ) if ( i1.nextInt() != i2.nextInt() ) return false; + return true; + } + final ListIterator i1 = listIterator(), i2 = l.listIterator(); + while( s-- != 0 ) if ( ! valEquals( i1.next(), i2.next() ) ) return false; + return true; + } + /** Compares this list to another object. If the + * argument is a {@link java.util.List}, this method performs a lexicographical comparison; otherwise, + * it throws a ClassCastException. + * + * @param l a list. + * @return if the argument is a {@link java.util.List}, a negative integer, + * zero, or a positive integer as this list is lexicographically less than, equal + * to, or greater than the argument. + * @throws ClassCastException if the argument is not a list. + */ + + public int compareTo( final List l ) { + if ( l == this ) return 0; + if ( l instanceof IntList ) { + final IntListIterator i1 = listIterator(), i2 = ((IntList )l).listIterator(); + int r; + int e1, e2; + while( i1.hasNext() && i2.hasNext() ) { + e1 = i1.nextInt(); + e2 = i2.nextInt(); + if ( ( r = ( Integer.compare((e1),(e2)) ) ) != 0 ) return r; + } + return i2.hasNext() ? -1 : ( i1.hasNext() ? 1 : 0 ); + } + ListIterator i1 = listIterator(), i2 = l.listIterator(); + int r; + while( i1.hasNext() && i2.hasNext() ) { + if ( ( r = ((Comparable)i1.next()).compareTo( i2.next() ) ) != 0 ) return r; + } + return i2.hasNext() ? -1 : ( i1.hasNext() ? 1 : 0 ); + } + /** Returns the hash code for this list, which is identical to {@link java.util.List#hashCode()}. + * + * @return the hash code for this list. + */ + public int hashCode() { + IntIterator i = iterator(); + int h = 1, s = size(); + while ( s-- != 0 ) { + int k = i.nextInt(); + h = 31 * h + (k); + } + return h; + } + public void push( int o ) { + add( o ); + } + public int popInt() { + if ( isEmpty() ) throw new NoSuchElementException(); + return removeInt( size() - 1 ); + } + public int topInt() { + if ( isEmpty() ) throw new NoSuchElementException(); + return getInt( size() - 1 ); + } + public int peekInt( int i ) { + return getInt( size() - 1 - i ); + } + public boolean rem( int k ) { + int index = indexOf( k ); + if ( index == -1 ) return false; + removeInt( index ); + return true; + } + /** Delegates to rem(). */ + public boolean remove( final Object o ) { + return rem( ((((Integer)(o)).intValue())) ); + } + /** Delegates to a more generic method. */ + public boolean addAll( final int index, final IntCollection c ) { + return addAll( index, (Collection)c ); + } + /** Delegates to a more generic method. */ + public boolean addAll( final int index, final IntList l ) { + return addAll( index, (IntCollection)l ); + } + public boolean addAll( final IntCollection c ) { + return addAll( size(), c ); + } + public boolean addAll( final IntList l ) { + return addAll( size(), l ); + } + /** Delegates to the corresponding type-specific method. */ + public void add( final int index, final Integer ok ) { + add( index, ok.intValue() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer set( final int index, final Integer ok ) { + return (Integer.valueOf(set( index, ok.intValue() ))); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer get( final int index ) { + return (Integer.valueOf(getInt( index ))); + } + /** Delegates to the corresponding type-specific method. */ + public int indexOf( final Object ok) { + return indexOf( ((((Integer)(ok)).intValue())) ); + } + /** Delegates to the corresponding type-specific method. */ + public int lastIndexOf( final Object ok ) { + return lastIndexOf( ((((Integer)(ok)).intValue())) ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer remove( final int index ) { + return (Integer.valueOf(removeInt( index ))); + } + /** Delegates to the corresponding type-specific method. */ + public void push( Integer o ) { + push( o.intValue() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer pop() { + return Integer.valueOf( popInt() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer top() { + return Integer.valueOf( topInt() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer peek( int i ) { + return Integer.valueOf( peekInt( i ) ); + } + public String toString() { + final StringBuilder s = new StringBuilder(); + final IntIterator i = iterator(); + int n = size(); + int k; + boolean first = true; + s.append("["); + while( n-- != 0 ) { + if (first) first = false; + else s.append(", "); + k = i.nextInt(); + s.append( String.valueOf( k ) ); + } + s.append("]"); + return s.toString(); + } + public static class IntSubList extends AbstractIntList implements java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + /** The list this sublist restricts. */ + protected final IntList l; + /** Initial (inclusive) index of this sublist. */ + protected final int from; + /** Final (exclusive) index of this sublist. */ + protected int to; + private static final boolean ASSERTS = false; + public IntSubList( final IntList l, final int from, final int to ) { + this.l = l; + this.from = from; + this.to = to; + } + private void assertRange() { + if ( ASSERTS ) { + assert from <= l.size(); + assert to <= l.size(); + assert to >= from; + } + } + public boolean add( final int k ) { + l.add( to, k ); + to++; + if ( ASSERTS ) assertRange(); + return true; + } + public void add( final int index, final int k ) { + ensureIndex( index ); + l.add( from + index, k ); + to++; + if ( ASSERTS ) assertRange(); + } + public boolean addAll( final int index, final Collection c ) { + ensureIndex( index ); + to += c.size(); + if ( ASSERTS ) { + boolean retVal = l.addAll( from + index, c ); + assertRange(); + return retVal; + } + return l.addAll( from + index, c ); + } + public int getInt( int index ) { + ensureRestrictedIndex( index ); + return l.getInt( from + index ); + } + public int removeInt( int index ) { + ensureRestrictedIndex( index ); + to--; + return l.removeInt( from + index ); + } + public int set( int index, int k ) { + ensureRestrictedIndex( index ); + return l.set( from + index, k ); + } + public void clear() { + removeElements( 0, size() ); + if ( ASSERTS ) assertRange(); + } + public int size() { + return to - from; + } + public void getElements( final int from, final int[] a, final int offset, final int length ) { + ensureIndex( from ); + if ( from + length > size() ) throw new IndexOutOfBoundsException( "End index (" + from + length + ") is greater than list size (" + size() + ")" ); + l.getElements( this.from + from, a, offset, length ); + } + public void removeElements( final int from, final int to ) { + ensureIndex( from ); + ensureIndex( to ); + l.removeElements( this.from + from, this.from + to ); + this.to -= ( to - from ); + if ( ASSERTS ) assertRange(); + } + public void addElements( int index, final int a[], int offset, int length ) { + ensureIndex( index ); + l.addElements( this.from + index, a, offset, length ); + this.to += length; + if ( ASSERTS ) assertRange(); + } + public IntListIterator listIterator( final int index ) { + ensureIndex( index ); + return new AbstractIntListIterator () { + int pos = index, last = -1; + public boolean hasNext() { return pos < size(); } + public boolean hasPrevious() { return pos > 0; } + public int nextInt() { if ( ! hasNext() ) throw new NoSuchElementException(); return l.getInt( from + ( last = pos++ ) ); } + public int previousInt() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return l.getInt( from + ( last = --pos ) ); } + public int nextIndex() { return pos; } + public int previousIndex() { return pos - 1; } + public void add( int k ) { + if ( last == -1 ) throw new IllegalStateException(); + IntSubList.this.add( pos++, k ); + last = -1; + if ( ASSERTS ) assertRange(); + } + public void set( int k ) { + if ( last == -1 ) throw new IllegalStateException(); + IntSubList.this.set( last, k ); + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + IntSubList.this.removeInt( last ); + /* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */ + if ( last < pos ) pos--; + last = -1; + if ( ASSERTS ) assertRange(); + } + }; + } + public IntList subList( final int from, final int to ) { + ensureIndex( from ); + ensureIndex( to ); + if ( from > to ) throw new IllegalArgumentException( "Start index (" + from + ") is greater than end index (" + to + ")" ); + return new IntSubList ( this, from, to ); + } + public boolean rem( int k ) { + int index = indexOf( k ); + if ( index == -1 ) return false; + to--; + l.removeInt( from + index ); + if ( ASSERTS ) assertRange(); + return true; + } + public boolean remove( final Object o ) { + return rem( ((((Integer)(o)).intValue())) ); + } + public boolean addAll( final int index, final IntCollection c ) { + ensureIndex( index ); + to += c.size(); + if ( ASSERTS ) { + boolean retVal = l.addAll( from + index, c ); + assertRange(); + return retVal; + } + return l.addAll( from + index, c ); + } + public boolean addAll( final int index, final IntList l ) { + ensureIndex( index ); + to += l.size(); + if ( ASSERTS ) { + boolean retVal = this.l.addAll( from + index, l ); + assertRange(); + return retVal; + } + return this.l.addAll( from + index, l ); + } + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntListIterator.java b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntListIterator.java new file mode 100644 index 0000000..981123f --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntListIterator.java @@ -0,0 +1,92 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +/** An abstract class facilitating the creation of type-specific {@linkplain java.util.ListIterator list iterators}. + * + *

This class provides trivial type-specific implementations of {@link + * java.util.ListIterator#set(Object) set()} and {@link java.util.ListIterator#add(Object) add()} which + * throw an {@link UnsupportedOperationException}. For primitive types, it also + * provides a trivial implementation of {@link java.util.ListIterator#set(Object) set()} and {@link + * java.util.ListIterator#add(Object) add()} that just invokes the type-specific one. + * + * + * @see java.util.ListIterator + */ +public abstract class AbstractIntListIterator extends AbstractIntBidirectionalIterator implements IntListIterator { + protected AbstractIntListIterator() {} + /** Delegates to the corresponding type-specific method. */ + public void set( Integer ok ) { set( ok.intValue() ); } + /** Delegates to the corresponding type-specific method. */ + public void add( Integer ok ) { add( ok.intValue() ); } + /** This method just throws an {@link UnsupportedOperationException}. */ + public void set( int k ) { throw new UnsupportedOperationException(); } + /** This method just throws an {@link UnsupportedOperationException}. */ + public void add( int k ) { throw new UnsupportedOperationException(); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntPriorityQueue.java new file mode 100644 index 0000000..b3bc90f --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntPriorityQueue.java @@ -0,0 +1,95 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.AbstractPriorityQueue; +/** An abstract class providing basic methods for priority queues implementing a type-specific interface. + * + */ +public abstract class AbstractIntPriorityQueue extends AbstractPriorityQueue implements java.io.Serializable, IntPriorityQueue { + private static final long serialVersionUID = 1L; + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public void enqueue( final Integer x ) { enqueue( x.intValue() ); } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer dequeue() { return (Integer.valueOf(dequeueInt())); } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer first() { return (Integer.valueOf(firstInt())); } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer last() { return (Integer.valueOf(lastInt())); } + /** Throws an {@link UnsupportedOperationException}. */ + public int lastInt() { throw new UnsupportedOperationException(); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntSet.java b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntSet.java new file mode 100644 index 0000000..97f3bff --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntSet.java @@ -0,0 +1,115 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.Set; +/** An abstract class providing basic methods for sets implementing a type-specific interface. */ +public abstract class AbstractIntSet extends AbstractIntCollection implements Cloneable, IntSet { + protected AbstractIntSet() {} + public abstract IntIterator iterator(); + public boolean equals( final Object o ) { + if ( o == this ) return true; + if ( !( o instanceof Set ) ) return false; + Set s = (Set) o; + if ( s.size() != size() ) return false; + return containsAll(s); + } + /** Returns a hash code for this set. + * + * The hash code of a set is computed by summing the hash codes of + * its elements. + * + * @return a hash code for this set. + */ + public int hashCode() { + int h = 0, n = size(); + IntIterator i = iterator(); + int k; + while( n-- != 0 ) { + k = i.nextInt(); // We need k because KEY2JAVAHASH() is a macro with repeated evaluation. + h += (k); + } + return h; + } + public boolean remove( int k ) { + throw new UnsupportedOperationException(); + } + /** Delegates to remove(). + * + * @param k the element to be removed. + * @return true if the set was modified. + */ + public boolean rem( int k ) { + return remove( k ); + } + /** Delegates to the corresponding type-specific method. */ + public boolean remove( final Object o ) { + return remove( ((((Integer)(o)).intValue())) ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntSortedSet.java b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntSortedSet.java new file mode 100644 index 0000000..fb55816 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntSortedSet.java @@ -0,0 +1,110 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +/** An abstract class providing basic methods for sorted sets implementing a type-specific interface. */ +public abstract class AbstractIntSortedSet extends AbstractIntSet implements IntSortedSet { + protected AbstractIntSortedSet() {} + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public IntSortedSet headSet( final Integer to ) { + return headSet( to.intValue() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public IntSortedSet tailSet( final Integer from ) { + return tailSet( from.intValue() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public IntSortedSet subSet( final Integer from, final Integer to ) { + return subSet( from.intValue(), to.intValue() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer first() { + return (Integer.valueOf(firstInt())); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer last() { + return (Integer.valueOf(lastInt())); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public IntBidirectionalIterator intIterator() { + return iterator(); + } + public abstract IntBidirectionalIterator iterator(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntStack.java b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntStack.java new file mode 100644 index 0000000..ba0a282 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/AbstractIntStack.java @@ -0,0 +1,112 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.AbstractStack; +/** An abstract class providing basic methods for implementing a type-specific stack interface. + * + *

To create a type-specific stack, you need both object methods and + * primitive-type methods. However, if you inherit from this class you need + * just one (anyone). + */ +public abstract class AbstractIntStack extends AbstractStack implements IntStack { + protected AbstractIntStack() {} + /** Delegates to the corresponding type-specific method. */ + public void push( Integer o ) { + push( o.intValue() ); + } + /** Delegates to the corresponding type-specific method. */ + public Integer pop() { + return Integer.valueOf( popInt() ); + } + /** Delegates to the corresponding type-specific method. */ + public Integer top() { + return Integer.valueOf( topInt() ); + } + /** Delegates to the corresponding type-specific method. */ + public Integer peek( int i ) { + return Integer.valueOf( peekInt( i ) ); + } + /** Delegates to the corresponding generic method. */ + public void push( int k ) { + push( Integer.valueOf( k ) ); + } + /** Delegates to the corresponding generic method. */ + public int popInt() { + return pop().intValue(); + } + /** Delegates to the corresponding generic method. */ + public int topInt() { + return top().intValue(); + } + /** Delegates to the corresponding generic method. */ + public int peekInt( int i ) { + return peek( i ).intValue(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectAVLTreeMap.java b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectAVLTreeMap.java new file mode 100644 index 0000000..fec4cdc --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectAVLTreeMap.java @@ -0,0 +1,1655 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.objects.AbstractObjectSortedSet; +import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; +import it.unimi.dsi.fastutil.objects.ObjectListIterator; +import it.unimi.dsi.fastutil.objects.ObjectSortedSet; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import java.util.Comparator; +import java.util.Iterator; +import java.util.Map; +import java.util.SortedMap; +import java.util.NoSuchElementException; +/** A type-specific AVL tree map with a fast, small-footprint implementation. + * + *

The iterators provided by the views of this class are type-specific {@linkplain + * it.unimi.dsi.fastutil.BidirectionalIterator bidirectional iterators}. + * Moreover, the iterator returned by iterator() can be safely cast + * to a type-specific {@linkplain java.util.ListIterator list iterator}. + */ +public class Int2ObjectAVLTreeMap extends AbstractInt2ObjectSortedMap implements java.io.Serializable, Cloneable { + /** A reference to the root entry. */ + protected transient Entry tree; + /** Number of entries in this map. */ + protected int count; + /** The first key in this map. */ + protected transient Entry firstEntry; + /** The last key in this map. */ + protected transient Entry lastEntry; + /** Cached set of entries. */ + protected transient ObjectSortedSet > entries; + /** Cached set of keys. */ + protected transient IntSortedSet keys; + /** Cached collection of values. */ + protected transient ObjectCollection values; + /** The value of this variable remembers, after a put() + * or a remove(), whether the domain of the map + * has been modified. */ + protected transient boolean modified; + /** This map's comparator, as provided in the constructor. */ + protected Comparator storedComparator; + /** This map's actual comparator; it may differ from {@link #storedComparator} because it is + always a type-specific comparator, so it could be derived from the former by wrapping. */ + protected transient IntComparator actualComparator; + private static final long serialVersionUID = -7046029254386353129L; + private static final boolean ASSERTS = false; + { + allocatePaths(); + } + /** Creates a new empty tree map. + */ + public Int2ObjectAVLTreeMap() { + tree = null; + count = 0; + } + /** Generates the comparator that will be actually used. + * + *

When a specific {@link Comparator} is specified and stored in {@link + * #storedComparator}, we must check whether it is type-specific. If it is + * so, we can used directly, and we store it in {@link #actualComparator}. Otherwise, + * we generate on-the-fly an anonymous class that wraps the non-specific {@link Comparator} + * and makes it into a type-specific one. + */ + private void setActualComparator() { + /* If the provided comparator is already type-specific, we use it. Otherwise, + we use a wrapper anonymous class to fake that it is type-specific. */ + if ( storedComparator == null || storedComparator instanceof IntComparator ) actualComparator = (IntComparator)storedComparator; + else actualComparator = new IntComparator () { + public int compare( int k1, int k2 ) { + return storedComparator.compare( (Integer.valueOf(k1)), (Integer.valueOf(k2)) ); + } + public int compare( Integer ok1, Integer ok2 ) { + return storedComparator.compare( ok1, ok2 ); + } + }; + } + /** Creates a new empty tree map with the given comparator. + * + * @param c a (possibly type-specific) comparator. + */ + public Int2ObjectAVLTreeMap( final Comparator c ) { + this(); + storedComparator = c; + setActualComparator(); + } + /** Creates a new tree map copying a given map. + * + * @param m a {@link Map} to be copied into the new tree map. + */ + public Int2ObjectAVLTreeMap( final Map m ) { + this(); + putAll( m ); + } + /** Creates a new tree map copying a given sorted map (and its {@link Comparator}). + * + * @param m a {@link SortedMap} to be copied into the new tree map. + */ + public Int2ObjectAVLTreeMap( final SortedMap m ) { + this( m.comparator() ); + putAll( m ); + } + /** Creates a new tree map copying a given map. + * + * @param m a type-specific map to be copied into the new tree map. + */ + public Int2ObjectAVLTreeMap( final Int2ObjectMap m ) { + this(); + putAll( m ); + } + /** Creates a new tree map copying a given sorted map (and its {@link Comparator}). + * + * @param m a type-specific sorted map to be copied into the new tree map. + */ + public Int2ObjectAVLTreeMap( final Int2ObjectSortedMap m ) { + this( m.comparator() ); + putAll( m ); + } + /** Creates a new tree map using the elements of two parallel arrays and the given comparator. + * + * @param k the array of keys of the new tree map. + * @param v the array of corresponding values in the new tree map. + * @param c a (possibly type-specific) comparator. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Int2ObjectAVLTreeMap( final int[] k, final V v[], final Comparator c ) { + this( c ); + if ( k.length != v.length ) throw new IllegalArgumentException( "The key array and the value array have different lengths (" + k.length + " and " + v.length + ")" ); + for( int i = 0; i < k.length; i++ ) this.put( k[ i ], v[ i ] ); + } + /** Creates a new tree map using the elements of two parallel arrays. + * + * @param k the array of keys of the new tree map. + * @param v the array of corresponding values in the new tree map. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Int2ObjectAVLTreeMap( final int[] k, final V v[] ) { + this( k, v, null ); + } + /* + * The following methods implements some basic building blocks used by + * all accessors. They are (and should be maintained) identical to those used in AVLTreeSet.drv. + * + * The put()/remove() code is derived from Ben Pfaff's GNU libavl + * (http://www.msu.edu/~pfaffben/avl/). If you want to understand what's + * going on, you should have a look at the literate code contained therein + * first. + */ + /** Compares two keys in the right way. + * + *

This method uses the {@link #actualComparator} if it is non-null. + * Otherwise, it resorts to primitive type comparisons or to {@link Comparable#compareTo(Object) compareTo()}. + * + * @param k1 the first key. + * @param k2 the second key. + * @return a number smaller than, equal to or greater than 0, as usual + * (i.e., when k1 < k2, k1 = k2 or k1 > k2, respectively). + */ + + final int compare( final int k1, final int k2 ) { + return actualComparator == null ? ( Integer.compare((k1),(k2)) ) : actualComparator.compare( k1, k2 ); + } + /** Returns the entry corresponding to the given key, if it is in the tree; null, otherwise. + * + * @param k the key to search for. + * @return the corresponding entry, or null if no entry with the given key exists. + */ + final Entry findKey( final int k ) { + Entry e = tree; + int cmp; + while ( e != null && ( cmp = compare( k, e.key ) ) != 0 ) e = cmp < 0 ? e.left() : e.right(); + return e; + } + /** Locates a key. + * + * @param k a key. + * @return the last entry on a search for the given key; this will be + * the given key, if it present; otherwise, it will be either the smallest greater key or the greatest smaller key. + */ + final Entry locateKey( final int k ) { + Entry e = tree, last = tree; + int cmp = 0; + while ( e != null && ( cmp = compare( k, e.key ) ) != 0 ) { + last = e; + e = cmp < 0 ? e.left() : e.right(); + } + return cmp == 0 ? e : last; + } + /** This vector remembers the directions followed during + * the current insertion. It suffices for about 232 entries. */ + private transient boolean dirPath[]; + private void allocatePaths() { + dirPath = new boolean[ 48 ]; + } + public V put( final int k, final V v ) { + Entry e = add( k ); + final V oldValue = e.value; + e.value = v; + return oldValue; + } + /** Returns a node with key k in the balanced tree, creating one with defRetValue if necessary. + * + * @param k the key + * @return a node with key k. If a node with key k already exists, then that node is returned, + * otherwise a new node with defRetValue is created ensuring that the tree is balanced + after creation of the node. + */ + private Entry add( final int k ) { + /* After execution of this method, modified is true iff a new entry has + been inserted. */ + modified = false; + Entry e = null; + if ( tree == null ) { // The case of the empty tree is treated separately. + count++; + e = tree = lastEntry = firstEntry = new Entry ( k, defRetValue ); + modified = true; + } + else { + Entry p = tree, q = null, y = tree, z = null, w = null; + int cmp, i = 0; + while( true ) { + if ( ( cmp = compare( k, p.key ) ) == 0 ) { + return p; + } + if ( p.balance() != 0 ) { + i = 0; + z = q; + y = p; + } + if ( dirPath[ i++ ] = cmp > 0 ) { + if ( p.succ() ) { + count++; + e = new Entry ( k, defRetValue ); + modified = true; + if ( p.right == null ) lastEntry = e; + e.left = p; + e.right = p.right; + p.right( e ); + break; + } + q = p; + p = p.right; + } + else { + if ( p.pred() ) { + count++; + e = new Entry ( k, defRetValue ); + modified = true; + if ( p.left == null ) firstEntry = e; + e.right = p; + e.left = p.left; + p.left( e ); + break; + } + q = p; + p = p.left; + } + } + p = y; + i = 0; + while( p != e ) { + if ( dirPath[ i ] ) p.incBalance(); + else p.decBalance(); + p = dirPath[ i++ ] ? p.right : p.left; + } + if ( y.balance() == -2 ) { + Entry x = y.left; + if ( x.balance() == -1 ) { + w = x; + if ( x.succ() ) { + x.succ( false ); + y.pred( x ); + } + else y.left = x.right; + x.right = y; + x.balance( 0 ); + y.balance( 0 ); + } + else { + if ( ASSERTS ) assert x.balance() == 1; + w = x.right; + x.right = w.left; + w.left = x; + y.left = w.right; + w.right = y; + if ( w.balance() == -1 ) { + x.balance( 0 ); + y.balance( 1 ); + } + else if ( w.balance() == 0 ) { + x.balance( 0 ); + y.balance( 0 ); + } + else { + x.balance( -1 ); + y.balance( 0 ); + } + w.balance( 0 ); + if ( w.pred() ) { + x.succ( w ); + w.pred( false ); + } + if ( w.succ() ) { + y.pred( w ); + w.succ( false ); + } + } + } + else if ( y.balance() == +2 ) { + Entry x = y.right; + if ( x.balance() == 1 ) { + w = x; + if ( x.pred() ) { + x.pred( false ); + y.succ( x ); + } + else y.right = x.left; + x.left = y; + x.balance( 0 ); + y.balance( 0 ); + } + else { + if ( ASSERTS ) assert x.balance() == -1; + w = x.left; + x.left = w.right; + w.right = x; + y.right = w.left; + w.left = y; + if ( w.balance() == 1 ) { + x.balance( 0 ); + y.balance( -1 ); + } + else if ( w.balance() == 0 ) { + x.balance( 0 ); + y.balance( 0 ); + } + else { + x.balance( 1 ); + y.balance( 0 ); + } + w.balance( 0 ); + if ( w.pred() ) { + y.succ( w ); + w.pred( false ); + } + if ( w.succ() ) { + x.pred( w ); + w.succ( false ); + } + } + } + else return e; + if ( z == null ) tree = w; + else { + if ( z.left == y ) z.left = w; + else z.right = w; + } + } + if ( ASSERTS ) checkTree( tree ); + return e; + } + /** Finds the parent of an entry. + * + * @param e a node of the tree. + * @return the parent of the given node, or null for the root. + */ + private Entry parent( final Entry e ) { + if ( e == tree ) return null; + Entry x, y, p; + x = y = e; + while( true ) { + if ( y.succ() ) { + p = y.right; + if ( p == null || p.left != e ) { + while( ! x.pred() ) x = x.left; + p = x.left; + } + return p; + } + else if ( x.pred() ) { + p = x.left; + if ( p == null || p.right != e ) { + while( ! y.succ() ) y = y.right; + p = y.right; + } + return p; + } + x = x.left; + y = y.right; + } + } + /* After execution of this method, {@link #modified} is true iff an entry + has been deleted. */ + + public V remove( final int k ) { + modified = false; + if ( tree == null ) return defRetValue; + int cmp; + Entry p = tree, q = null; + boolean dir = false; + final int kk = k; + while( true ) { + if ( ( cmp = compare( kk, p.key ) ) == 0 ) break; + else if ( dir = cmp > 0 ) { + q = p; + if ( ( p = p.right() ) == null ) return defRetValue; + } + else { + q = p; + if ( ( p = p.left() ) == null ) return defRetValue; + } + } + if ( p.left == null ) firstEntry = p.next(); + if ( p.right == null ) lastEntry = p.prev(); + if ( p.succ() ) { + if ( p.pred() ) { + if ( q != null ) { + if ( dir ) q.succ( p.right ); + else q.pred( p.left ); + } + else tree = dir ? p.right : p.left; + } + else { + p.prev().right = p.right; + if ( q != null ) { + if ( dir ) q.right = p.left; + else q.left = p.left; + } + else tree = p.left; + } + } + else { + Entry r = p.right; + if ( r.pred() ) { + r.left = p.left; + r.pred( p.pred() ); + if ( ! r.pred() ) r.prev().right = r; + if ( q != null ) { + if ( dir ) q.right = r; + else q.left = r; + } + else tree = r; + r.balance( p.balance() ); + q = r; + dir = true; + } + else { + Entry s; + while( true ) { + s = r.left; + if ( s.pred() ) break; + r = s; + } + if ( s.succ() ) r.pred( s ); + else r.left = s.right; + s.left = p.left; + if ( ! p.pred() ) { + p.prev().right = s; + s.pred( false ); + } + s.right = p.right; + s.succ( false ); + if ( q != null ) { + if ( dir ) q.right = s; + else q.left = s; + } + else tree = s; + s.balance( p.balance() ); + q = r; + dir = false; + } + } + Entry y; + while( q != null ) { + y = q; + q = parent( y ); + if ( ! dir ) { + dir = q != null && q.left != y; + y.incBalance(); + if ( y.balance() == 1 ) break; + else if ( y.balance() == 2 ) { + Entry x = y.right; + if ( ASSERTS ) assert x != null; + if ( x.balance() == -1 ) { + Entry w; + if ( ASSERTS ) assert x.balance() == -1; + w = x.left; + x.left = w.right; + w.right = x; + y.right = w.left; + w.left = y; + if ( w.balance() == 1 ) { + x.balance( 0 ); + y.balance( -1 ); + } + else if ( w.balance() == 0 ) { + x.balance( 0 ); + y.balance( 0 ); + } + else { + if ( ASSERTS ) assert w.balance() == -1; + x.balance( 1 ); + y.balance( 0 ); + } + w.balance( 0 ); + if ( w.pred() ) { + y.succ( w ); + w.pred( false ); + } + if ( w.succ() ) { + x.pred( w ); + w.succ( false ); + } + if ( q != null ) { + if ( dir ) q.right = w; + else q.left = w; + } + else tree = w; + } + else { + if ( q != null ) { + if ( dir ) q.right = x; + else q.left = x; + } + else tree = x; + if ( x.balance() == 0 ) { + y.right = x.left; + x.left = y; + x.balance( -1 ); + y.balance( +1 ); + break; + } + if ( ASSERTS ) assert x.balance() == 1; + if ( x.pred() ) { + y.succ( true ); + x.pred( false ); + } + else y.right = x.left; + x.left = y; + y.balance( 0 ); + x.balance( 0 ); + } + } + } + else { + dir = q != null && q.left != y; + y.decBalance(); + if ( y.balance() == -1 ) break; + else if ( y.balance() == -2 ) { + Entry x = y.left; + if ( ASSERTS ) assert x != null; + if ( x.balance() == 1 ) { + Entry w; + if ( ASSERTS ) assert x.balance() == 1; + w = x.right; + x.right = w.left; + w.left = x; + y.left = w.right; + w.right = y; + if ( w.balance() == -1 ) { + x.balance( 0 ); + y.balance( 1 ); + } + else if ( w.balance() == 0 ) { + x.balance( 0 ); + y.balance( 0 ); + } + else { + if ( ASSERTS ) assert w.balance() == 1; + x.balance( -1 ); + y.balance( 0 ); + } + w.balance( 0 ); + if ( w.pred() ) { + x.succ( w ); + w.pred( false ); + } + if ( w.succ() ) { + y.pred( w ); + w.succ( false ); + } + if ( q != null ) { + if ( dir ) q.right = w; + else q.left = w; + } + else tree = w; + } + else { + if ( q != null ) { + if ( dir ) q.right = x; + else q.left = x; + } + else tree = x; + if ( x.balance() == 0 ) { + y.left = x.right; + x.right = y; + x.balance( +1 ); + y.balance( -1 ); + break; + } + if ( ASSERTS ) assert x.balance() == -1; + if ( x.succ() ) { + y.pred( true ); + x.succ( false ); + } + else y.left = x.right; + x.right = y; + y.balance( 0 ); + x.balance( 0 ); + } + } + } + } + modified = true; + count--; + if ( ASSERTS ) checkTree( tree ); + return p.value; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Integer ok, final V ov ) { + final V oldValue = put( ((ok).intValue()), (ov) ); + return modified ? (this.defRetValue) : (oldValue); + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V remove( final Object ok ) { + final V oldValue = remove( ((((Integer)(ok)).intValue())) ); + return modified ? (oldValue) : (this.defRetValue); + } + public boolean containsValue( final Object v ) { + final ValueIterator i = new ValueIterator(); + V ev; + int j = count; + while( j-- != 0 ) { + ev = i.next(); + if ( ( (ev) == null ? (v) == null : (ev).equals(v) ) ) return true; + } + return false; + } + public void clear() { + count = 0; + tree = null; + entries = null; + values = null; + keys = null; + firstEntry = lastEntry = null; + } + /** This class represent an entry in a tree map. + * + *

We use the only "metadata", i.e., {@link Entry#info}, to store + * information about balance, predecessor status and successor status. + * + *

Note that since the class is recursive, it can be + * considered equivalently a tree. + */ + private static final class Entry implements Cloneable, Int2ObjectMap.Entry { + /** If the bit in this mask is true, {@link #right} points to a successor. */ + private final static int SUCC_MASK = 1 << 31; + /** If the bit in this mask is true, {@link #left} points to a predecessor. */ + private final static int PRED_MASK = 1 << 30; + /** The bits in this mask hold the node balance info. You can get it just by casting to byte. */ + private final static int BALANCE_MASK = 0xFF; + /** The key of this entry. */ + int key; + /** The value of this entry. */ + V value; + /** The pointers to the left and right subtrees. */ + Entry left, right; + /** This integers holds different information in different bits (see {@link #SUCC_MASK}, {@link #PRED_MASK} and {@link #BALANCE_MASK}). */ + int info; + Entry() {} + /** Creates a new entry with the given key and value. + * + * @param k a key. + * @param v a value. + */ + Entry( final int k, final V v ) { + this.key = k; + this.value = v; + info = SUCC_MASK | PRED_MASK; + } + /** Returns the left subtree. + * + * @return the left subtree (null if the left + * subtree is empty). + */ + Entry left() { + return ( info & PRED_MASK ) != 0 ? null : left; + } + /** Returns the right subtree. + * + * @return the right subtree (null if the right + * subtree is empty). + */ + Entry right() { + return ( info & SUCC_MASK ) != 0 ? null : right; + } + /** Checks whether the left pointer is really a predecessor. + * @return true if the left pointer is a predecessor. + */ + boolean pred() { + return ( info & PRED_MASK ) != 0; + } + /** Checks whether the right pointer is really a successor. + * @return true if the right pointer is a successor. + */ + boolean succ() { + return ( info & SUCC_MASK ) != 0; + } + /** Sets whether the left pointer is really a predecessor. + * @param pred if true then the left pointer will be considered a predecessor. + */ + void pred( final boolean pred ) { + if ( pred ) info |= PRED_MASK; + else info &= ~PRED_MASK; + } + /** Sets whether the right pointer is really a successor. + * @param succ if true then the right pointer will be considered a successor. + */ + void succ( final boolean succ ) { + if ( succ ) info |= SUCC_MASK; + else info &= ~SUCC_MASK; + } + /** Sets the left pointer to a predecessor. + * @param pred the predecessr. + */ + void pred( final Entry pred ) { + info |= PRED_MASK; + left = pred; + } + /** Sets the right pointer to a successor. + * @param succ the successor. + */ + void succ( final Entry succ ) { + info |= SUCC_MASK; + right = succ; + } + /** Sets the left pointer to the given subtree. + * @param left the new left subtree. + */ + void left( final Entry left ) { + info &= ~PRED_MASK; + this.left = left; + } + /** Sets the right pointer to the given subtree. + * @param right the new right subtree. + */ + void right( final Entry right ) { + info &= ~SUCC_MASK; + this.right = right; + } + /** Returns the current level of the node. + * @return the current level of this node. + */ + int balance() { + return (byte)info; + } + /** Sets the level of this node. + * @param level the new level of this node. + */ + void balance( int level ) { + info &= ~BALANCE_MASK; + info |= ( level & BALANCE_MASK ); + } + /** Increments the level of this node. */ + void incBalance() { + info = info & ~BALANCE_MASK | ( (byte)info + 1 ) & 0xFF; + } + /** Decrements the level of this node. */ + protected void decBalance() { + info = info & ~BALANCE_MASK | ( (byte)info - 1 ) & 0xFF; + } + /** Computes the next entry in the set order. + * + * @return the next entry (null) if this is the last entry). + */ + Entry next() { + Entry next = this.right; + if ( ( info & SUCC_MASK ) == 0 ) while ( ( next.info & PRED_MASK ) == 0 ) next = next.left; + return next; + } + /** Computes the previous entry in the set order. + * + * @return the previous entry (null) if this is the first entry). + */ + Entry prev() { + Entry prev = this.left; + if ( ( info & PRED_MASK ) == 0 ) while ( ( prev.info & SUCC_MASK ) == 0 ) prev = prev.right; + return prev; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer getKey() { + return (Integer.valueOf(key)); + } + public int getIntKey() { + return key; + } + public V getValue() { + return (value); + } + public V setValue(final V value) { + final V oldValue = this.value; + this.value = value; + return oldValue; + } + @SuppressWarnings("unchecked") + public Entry clone() { + Entry c; + try { + c = (Entry )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.key = key; + c.value = value; + c.info = info; + return c; + } + @SuppressWarnings("unchecked") + public boolean equals( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + Map.Entry e = (Map.Entry)o; + return ( (key) == (((e.getKey()).intValue())) ) && ( (value) == null ? ((e.getValue())) == null : (value).equals((e.getValue())) ); + } + public int hashCode() { + return (key) ^ ( (value) == null ? 0 : (value).hashCode() ); + } + public String toString() { + return key + "=>" + value; + } + /* + public void prettyPrint() { + prettyPrint(0); + } + + public void prettyPrint(int level) { + if ( pred() ) { + for (int i = 0; i < level; i++) + System.err.print(" "); + System.err.println("pred: " + left ); + } + else if (left != null) + left.prettyPrint(level +1 ); + for (int i = 0; i < level; i++) + System.err.print(" "); + System.err.println(key + "=" + value + " (" + balance() + ")"); + if ( succ() ) { + for (int i = 0; i < level; i++) + System.err.print(" "); + System.err.println("succ: " + right ); + } + else if (right != null) + right.prettyPrint(level + 1); + } + */ + } + /* + public void prettyPrint() { + System.err.println("size: " + count); + if (tree != null) tree.prettyPrint(); + } + */ + + public boolean containsKey( final int k ) { + return findKey( k ) != null; + } + public int size() { + return count; + } + public boolean isEmpty() { + return count == 0; + } + + public V get( final int k ) { + final Entry e = findKey( k ); + return e == null ? defRetValue : e.value; + } + public int firstIntKey() { + if ( tree == null ) throw new NoSuchElementException(); + return firstEntry.key; + } + public int lastIntKey() { + if ( tree == null ) throw new NoSuchElementException(); + return lastEntry.key; + } + /** An abstract iterator on the whole range. + * + *

This class can iterate in both directions on a threaded tree. + */ + private class TreeIterator { + /** The entry that will be returned by the next call to {@link java.util.ListIterator#previous()} (or null if no previous entry exists). */ + Entry prev; + /** The entry that will be returned by the next call to {@link java.util.ListIterator#next()} (or null if no next entry exists). */ + Entry next; + /** The last entry that was returned (or null if we did not iterate or used {@link #remove()}). */ + Entry curr; + /** The current index (in the sense of a {@link java.util.ListIterator}). Note that this value is not meaningful when this {@link TreeIterator} has been created using the nonempty constructor.*/ + int index = 0; + TreeIterator() { + next = firstEntry; + } + TreeIterator( final int k ) { + if ( ( next = locateKey( k ) ) != null ) { + if ( compare( next.key, k ) <= 0 ) { + prev = next; + next = next.next(); + } + else prev = next.prev(); + } + } + public boolean hasNext() { return next != null; } + public boolean hasPrevious() { return prev != null; } + void updateNext() { + next = next.next(); + } + Entry nextEntry() { + if ( ! hasNext() ) throw new NoSuchElementException(); + curr = prev = next; + index++; + updateNext(); + return curr; + } + void updatePrevious() { + prev = prev.prev(); + } + Entry previousEntry() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + curr = next = prev; + index--; + updatePrevious(); + return curr; + } + public int nextIndex() { + return index; + } + public int previousIndex() { + return index - 1; + } + public void remove() { + if ( curr == null ) throw new IllegalStateException(); + /* If the last operation was a next(), we are removing an entry that preceeds + the current index, and thus we must decrement it. */ + if ( curr == prev ) index--; + next = prev = curr; + updatePrevious(); + updateNext(); + Int2ObjectAVLTreeMap.this.remove( curr.key ); + curr = null; + } + public int skip( final int n ) { + int i = n; + while( i-- != 0 && hasNext() ) nextEntry(); + return n - i - 1; + } + public int back( final int n ) { + int i = n; + while( i-- != 0 && hasPrevious() ) previousEntry(); + return n - i - 1; + } + } + /** An iterator on the whole range. + * + *

This class can iterate in both directions on a threaded tree. + */ + private class EntryIterator extends TreeIterator implements ObjectListIterator > { + EntryIterator() {} + EntryIterator( final int k ) { + super( k ); + } + public Int2ObjectMap.Entry next() { return nextEntry(); } + public Int2ObjectMap.Entry previous() { return previousEntry(); } + public void set( Int2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + public void add( Int2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + } + public ObjectSortedSet > int2ObjectEntrySet() { + if ( entries == null ) entries = new AbstractObjectSortedSet >() { + final Comparator > comparator = new Comparator > () { + public int compare( final Int2ObjectMap.Entry x, final Int2ObjectMap.Entry y ) { + return Int2ObjectAVLTreeMap.this.actualComparator.compare( x.getIntKey(), y.getIntKey() ); + } + }; + public Comparator > comparator() { + return comparator; + } + public ObjectBidirectionalIterator > iterator() { + return new EntryIterator(); + } + public ObjectBidirectionalIterator > iterator( final Int2ObjectMap.Entry from ) { + return new EntryIterator( from.getIntKey() ); + } + @SuppressWarnings("unchecked") + public boolean contains( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + final Map.Entry e = (Map.Entry )o; + if ( e.getKey() == null ) return false; + final Entry f = findKey( ((e.getKey()).intValue()) ); + return e.equals( f ); + } + @SuppressWarnings("unchecked") + public boolean remove( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + final Map.Entry e = (Map.Entry )o; + if ( e.getKey() == null ) return false; + final Entry f = findKey( ((e.getKey()).intValue()) ); + if ( f != null ) Int2ObjectAVLTreeMap.this.remove( f.key ); + return f != null; + } + public int size() { return count; } + public void clear() { Int2ObjectAVLTreeMap.this.clear(); } + public Int2ObjectMap.Entry first() { return firstEntry; } + public Int2ObjectMap.Entry last() { return lastEntry; } + public ObjectSortedSet > subSet( Int2ObjectMap.Entry from, Int2ObjectMap.Entry to ) { return subMap( from.getIntKey(), to.getIntKey() ).int2ObjectEntrySet(); } + public ObjectSortedSet > headSet( Int2ObjectMap.Entry to ) { return headMap( to.getIntKey() ).int2ObjectEntrySet(); } + public ObjectSortedSet > tailSet( Int2ObjectMap.Entry from ) { return tailMap( from.getIntKey() ).int2ObjectEntrySet(); } + }; + return entries; + } + /** An iterator on the whole range of keys. + * + *

This class can iterate in both directions on the keys of a threaded tree. We + * simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods (and possibly + * their type-specific counterparts) so that they return keys instead of entries. + */ + private final class KeyIterator extends TreeIterator implements IntListIterator { + public KeyIterator() {} + public KeyIterator( final int k ) { super( k ); } + public int nextInt() { return nextEntry().key; } + public int previousInt() { return previousEntry().key; } + public void set( int k ) { throw new UnsupportedOperationException(); } + public void add( int k ) { throw new UnsupportedOperationException(); } + public Integer next() { return (Integer.valueOf(nextEntry().key)); } + public Integer previous() { return (Integer.valueOf(previousEntry().key)); } + public void set( Integer ok ) { throw new UnsupportedOperationException(); } + public void add( Integer ok ) { throw new UnsupportedOperationException(); } + }; + /** A keyset implementation using a more direct implementation for iterators. */ + private class KeySet extends AbstractInt2ObjectSortedMap .KeySet { + public IntBidirectionalIterator iterator() { return new KeyIterator(); } + public IntBidirectionalIterator iterator( final int from ) { return new KeyIterator( from ); } + } + /** Returns a type-specific sorted set view of the keys contained in this map. + * + *

In addition to the semantics of {@link java.util.Map#keySet()}, you can + * safely cast the set returned by this call to a type-specific sorted + * set interface. + * + * @return a type-specific sorted set view of the keys contained in this map. + */ + public IntSortedSet keySet() { + if ( keys == null ) keys = new KeySet(); + return keys; + } + /** An iterator on the whole range of values. + * + *

This class can iterate in both directions on the values of a threaded tree. We + * simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods (and possibly + * their type-specific counterparts) so that they return values instead of entries. + */ + private final class ValueIterator extends TreeIterator implements ObjectListIterator { + public V next() { return nextEntry().value; } + public V previous() { return previousEntry().value; } + public void set( V v ) { throw new UnsupportedOperationException(); } + public void add( V v ) { throw new UnsupportedOperationException(); } + }; + /** Returns a type-specific collection view of the values contained in this map. + * + *

In addition to the semantics of {@link java.util.Map#values()}, you can + * safely cast the collection returned by this call to a type-specific collection + * interface. + * + * @return a type-specific collection view of the values contained in this map. + */ + public ObjectCollection values() { + if ( values == null ) values = new AbstractObjectCollection () { + public ObjectIterator iterator() { + return new ValueIterator(); + } + public boolean contains( final Object k ) { + return containsValue( k ); + } + public int size() { + return count; + } + public void clear() { + Int2ObjectAVLTreeMap.this.clear(); + } + }; + return values; + } + public IntComparator comparator() { + return actualComparator; + } + public Int2ObjectSortedMap headMap( int to ) { + return new Submap( (0), true, to, false ); + } + public Int2ObjectSortedMap tailMap( int from ) { + return new Submap( from, false, (0), true ); + } + public Int2ObjectSortedMap subMap( int from, int to ) { + return new Submap( from, false, to, false ); + } + /** A submap with given range. + * + *

This class represents a submap. One has to specify the left/right + * limits (which can be set to -∞ or ∞). Since the submap is a + * view on the map, at a given moment it could happen that the limits of + * the range are not any longer in the main map. Thus, things such as + * {@link java.util.SortedMap#firstKey()} or {@link java.util.Collection#size()} must be always computed + * on-the-fly. + */ + private final class Submap extends AbstractInt2ObjectSortedMap implements java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + /** The start of the submap range, unless {@link #bottom} is true. */ + int from; + /** The end of the submap range, unless {@link #top} is true. */ + int to; + /** If true, the submap range starts from -∞. */ + boolean bottom; + /** If true, the submap range goes to ∞. */ + boolean top; + /** Cached set of entries. */ + @SuppressWarnings("hiding") + protected transient ObjectSortedSet > entries; + /** Cached set of keys. */ + @SuppressWarnings("hiding") + protected transient IntSortedSet keys; + /** Cached collection of values. */ + @SuppressWarnings("hiding") + protected transient ObjectCollection values; + /** Creates a new submap with given key range. + * + * @param from the start of the submap range. + * @param bottom if true, the first parameter is ignored and the range starts from -∞. + * @param to the end of the submap range. + * @param top if true, the third parameter is ignored and the range goes to ∞. + */ + public Submap( final int from, final boolean bottom, final int to, final boolean top ) { + if ( ! bottom && ! top && Int2ObjectAVLTreeMap.this.compare( from, to ) > 0 ) throw new IllegalArgumentException( "Start key (" + from + ") is larger than end key (" + to + ")" ); + this.from = from; + this.bottom = bottom; + this.to = to; + this.top = top; + this.defRetValue = Int2ObjectAVLTreeMap.this.defRetValue; + } + public void clear() { + final SubmapIterator i = new SubmapIterator(); + while( i.hasNext() ) { + i.nextEntry(); + i.remove(); + } + } + /** Checks whether a key is in the submap range. + * @param k a key. + * @return true if is the key is in the submap range. + */ + final boolean in( final int k ) { + return ( bottom || Int2ObjectAVLTreeMap.this.compare( k, from ) >= 0 ) && + ( top || Int2ObjectAVLTreeMap.this.compare( k, to ) < 0 ); + } + public ObjectSortedSet > int2ObjectEntrySet() { + if ( entries == null ) entries = new AbstractObjectSortedSet >() { + public ObjectBidirectionalIterator > iterator() { + return new SubmapEntryIterator(); + } + public ObjectBidirectionalIterator > iterator( final Int2ObjectMap.Entry from ) { + return new SubmapEntryIterator( from.getIntKey() ); + } + public Comparator > comparator() { return Int2ObjectAVLTreeMap.this.entrySet().comparator(); } + @SuppressWarnings("unchecked") + public boolean contains( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + final Map.Entry e = (Map.Entry )o; + final Int2ObjectAVLTreeMap.Entry f = findKey( ((e.getKey()).intValue()) ); + return f != null && in( f.key ) && e.equals( f ); + } + @SuppressWarnings("unchecked") + public boolean remove( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + final Map.Entry e = (Map.Entry )o; + final Int2ObjectAVLTreeMap.Entry f = findKey( ((e.getKey()).intValue()) ); + if ( f != null && in( f.key ) ) Submap.this.remove( f.key ); + return f != null; + } + public int size() { + int c = 0; + for( Iterator i = iterator(); i.hasNext(); i.next() ) c++; + return c; + } + public boolean isEmpty() { + return ! new SubmapIterator().hasNext(); + } + public void clear() { + Submap.this.clear(); + } + public Int2ObjectMap.Entry first() { return firstEntry(); } + public Int2ObjectMap.Entry last() { return lastEntry(); } + public ObjectSortedSet > subSet( Int2ObjectMap.Entry from, Int2ObjectMap.Entry to ) { return subMap( from.getIntKey(), to.getIntKey() ).int2ObjectEntrySet(); } + public ObjectSortedSet > headSet( Int2ObjectMap.Entry to ) { return headMap( to.getIntKey() ).int2ObjectEntrySet(); } + public ObjectSortedSet > tailSet( Int2ObjectMap.Entry from ) { return tailMap( from.getIntKey() ).int2ObjectEntrySet(); } + }; + return entries; + } + private class KeySet extends AbstractInt2ObjectSortedMap .KeySet { + public IntBidirectionalIterator iterator() { return new SubmapKeyIterator(); } + public IntBidirectionalIterator iterator( final int from ) { return new SubmapKeyIterator( from ); } + } + public IntSortedSet keySet() { + if ( keys == null ) keys = new KeySet(); + return keys; + } + public ObjectCollection values() { + if ( values == null ) values = new AbstractObjectCollection () { + public ObjectIterator iterator() { + return new SubmapValueIterator(); + } + public boolean contains( final Object k ) { + return containsValue( k ); + } + public int size() { + return Submap.this.size(); + } + public void clear() { + Submap.this.clear(); + } + }; + return values; + } + + public boolean containsKey( final int k ) { + return in( k ) && Int2ObjectAVLTreeMap.this.containsKey( k ); + } + public boolean containsValue( final Object v ) { + final SubmapIterator i = new SubmapIterator(); + Object ev; + while( i.hasNext() ) { + ev = i.nextEntry().value; + if ( ( (ev) == null ? (v) == null : (ev).equals(v) ) ) return true; + } + return false; + } + + public V get(final int k) { + final Int2ObjectAVLTreeMap.Entry e; + final int kk = k; + return in( kk ) && ( e = findKey( kk ) ) != null ? e.value : this.defRetValue; + } + public V put(final int k, final V v) { + modified = false; + if ( ! in( k ) ) throw new IllegalArgumentException( "Key (" + k + ") out of range [" + ( bottom ? "-" : String.valueOf( from ) ) + ", " + ( top ? "-" : String.valueOf( to ) ) + ")" ); + final V oldValue = Int2ObjectAVLTreeMap.this.put( k, v ); + return modified ? this.defRetValue : oldValue; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Integer ok, final V ov ) { + final V oldValue = put( ((ok).intValue()), (ov) ); + return modified ? (this.defRetValue) : (oldValue); + } + + public V remove( final int k ) { + modified = false; + if ( ! in( k ) ) return this.defRetValue; + final V oldValue = Int2ObjectAVLTreeMap.this.remove( k ); + return modified ? oldValue : this.defRetValue; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V remove( final Object ok ) { + final V oldValue = remove( ((((Integer)(ok)).intValue())) ); + return modified ? (oldValue) : (this.defRetValue); + } + public int size() { + final SubmapIterator i = new SubmapIterator(); + int n = 0; + while( i.hasNext() ) { + n++; + i.nextEntry(); + } + return n; + } + public boolean isEmpty() { + return ! new SubmapIterator().hasNext(); + } + public IntComparator comparator() { + return actualComparator; + } + public Int2ObjectSortedMap headMap( final int to ) { + if ( top ) return new Submap( from, bottom, to, false ); + return compare( to, this.to ) < 0 ? new Submap( from, bottom, to, false ) : this; + } + public Int2ObjectSortedMap tailMap( final int from ) { + if ( bottom ) return new Submap( from, false, to, top ); + return compare( from, this.from ) > 0 ? new Submap( from, false, to, top ) : this; + } + public Int2ObjectSortedMap subMap( int from, int to ) { + if ( top && bottom ) return new Submap( from, false, to, false ); + if ( ! top ) to = compare( to, this.to ) < 0 ? to : this.to; + if ( ! bottom ) from = compare( from, this.from ) > 0 ? from : this.from; + if ( ! top && ! bottom && from == this.from && to == this.to ) return this; + return new Submap( from, false, to, false ); + } + /** Locates the first entry. + * + * @return the first entry of this submap, or null if the submap is empty. + */ + public Int2ObjectAVLTreeMap.Entry firstEntry() { + if ( tree == null ) return null; + // If this submap goes to -infinity, we return the main map first entry; otherwise, we locate the start of the map. + Int2ObjectAVLTreeMap.Entry e; + if ( bottom ) e = firstEntry; + else { + e = locateKey( from ); + // If we find either the start or something greater we're OK. + if ( compare( e.key, from ) < 0 ) e = e.next(); + } + // Finally, if this subset doesn't go to infinity, we check that the resulting key isn't greater than the end. + if ( e == null || ! top && compare( e.key, to ) >= 0 ) return null; + return e; + } + /** Locates the last entry. + * + * @return the last entry of this submap, or null if the submap is empty. + */ + public Int2ObjectAVLTreeMap.Entry lastEntry() { + if ( tree == null ) return null; + // If this submap goes to infinity, we return the main map last entry; otherwise, we locate the end of the map. + Int2ObjectAVLTreeMap.Entry e; + if ( top ) e = lastEntry; + else { + e = locateKey( to ); + // If we find something smaller than the end we're OK. + if ( compare( e.key, to ) >= 0 ) e = e.prev(); + } + // Finally, if this subset doesn't go to -infinity, we check that the resulting key isn't smaller than the start. + if ( e == null || ! bottom && compare( e.key, from ) < 0 ) return null; + return e; + } + public int firstIntKey() { + Int2ObjectAVLTreeMap.Entry e = firstEntry(); + if ( e == null ) throw new NoSuchElementException(); + return e.key; + } + public int lastIntKey() { + Int2ObjectAVLTreeMap.Entry e = lastEntry(); + if ( e == null ) throw new NoSuchElementException(); + return e.key; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Integer firstKey() { + Int2ObjectAVLTreeMap.Entry e = firstEntry(); + if ( e == null ) throw new NoSuchElementException(); + return e.getKey(); + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Integer lastKey() { + Int2ObjectAVLTreeMap.Entry e = lastEntry(); + if ( e == null ) throw new NoSuchElementException(); + return e.getKey(); + } + /** An iterator for subranges. + * + *

This class inherits from {@link TreeIterator}, but overrides the methods that + * update the pointer after a {@link java.util.ListIterator#next()} or {@link java.util.ListIterator#previous()}. If we would + * move out of the range of the submap we just overwrite the next or previous + * entry with null. + */ + private class SubmapIterator extends TreeIterator { + SubmapIterator() { + next = firstEntry(); + } + SubmapIterator( final int k ) { + this(); + if ( next != null ) { + if ( ! bottom && compare( k, next.key ) < 0 ) prev = null; + else if ( ! top && compare( k, ( prev = lastEntry() ).key ) >= 0 ) next = null; + else { + next = locateKey( k ); + if ( compare( next.key, k ) <= 0 ) { + prev = next; + next = next.next(); + } + else prev = next.prev(); + } + } + } + void updatePrevious() { + prev = prev.prev(); + if ( ! bottom && prev != null && Int2ObjectAVLTreeMap.this.compare( prev.key, from ) < 0 ) prev = null; + } + void updateNext() { + next = next.next(); + if ( ! top && next != null && Int2ObjectAVLTreeMap.this.compare( next.key, to ) >= 0 ) next = null; + } + } + private class SubmapEntryIterator extends SubmapIterator implements ObjectListIterator > { + SubmapEntryIterator() {} + SubmapEntryIterator( final int k ) { + super( k ); + } + public Int2ObjectMap.Entry next() { return nextEntry(); } + public Int2ObjectMap.Entry previous() { return previousEntry(); } + public void set( Int2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + public void add( Int2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + } + /** An iterator on a subrange of keys. + * + *

This class can iterate in both directions on a subrange of the + * keys of a threaded tree. We simply override the {@link + * java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods (and possibly their + * type-specific counterparts) so that they return keys instead of + * entries. + */ + private final class SubmapKeyIterator extends SubmapIterator implements IntListIterator { + public SubmapKeyIterator() { super(); } + public SubmapKeyIterator( int from ) { super( from ); } + public int nextInt() { return nextEntry().key; } + public int previousInt() { return previousEntry().key; } + public void set( int k ) { throw new UnsupportedOperationException(); } + public void add( int k ) { throw new UnsupportedOperationException(); } + public Integer next() { return (Integer.valueOf(nextEntry().key)); } + public Integer previous() { return (Integer.valueOf(previousEntry().key)); } + public void set( Integer ok ) { throw new UnsupportedOperationException(); } + public void add( Integer ok ) { throw new UnsupportedOperationException(); } + }; + /** An iterator on a subrange of values. + * + *

This class can iterate in both directions on the values of a + * subrange of the keys of a threaded tree. We simply override the + * {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods (and possibly their + * type-specific counterparts) so that they return values instead of + * entries. + */ + private final class SubmapValueIterator extends SubmapIterator implements ObjectListIterator { + public V next() { return nextEntry().value; } + public V previous() { return previousEntry().value; } + public void set( V v ) { throw new UnsupportedOperationException(); } + public void add( V v ) { throw new UnsupportedOperationException(); } + }; + } + /** Returns a deep copy of this tree map. + * + *

This method performs a deep copy of this tree map; the data stored in the + * set, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this tree map. + */ + @SuppressWarnings("unchecked") + public Int2ObjectAVLTreeMap clone() { + Int2ObjectAVLTreeMap c; + try { + c = (Int2ObjectAVLTreeMap )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.keys = null; + c.values = null; + c.entries = null; + c.allocatePaths(); + if ( count != 0 ) { + // Also this apparently unfathomable code is derived from GNU libavl. + Entry e, p, q, rp = new Entry (), rq = new Entry (); + p = rp; + rp.left( tree ); + q = rq; + rq.pred( null ); + while( true ) { + if ( ! p.pred() ) { + e = p.left.clone(); + e.pred( q.left ); + e.succ( q ); + q.left( e ); + p = p.left; + q = q.left; + } + else { + while( p.succ() ) { + p = p.right; + if ( p == null ) { + q.right = null; + c.tree = rq.left; + c.firstEntry = c.tree; + while( c.firstEntry.left != null ) c.firstEntry = c.firstEntry.left; + c.lastEntry = c.tree; + while( c.lastEntry.right != null ) c.lastEntry = c.lastEntry.right; + return c; + } + q = q.right; + } + p = p.right; + q = q.right; + } + if ( ! p.succ() ) { + e = p.right.clone(); + e.succ( q.right ); + e.pred( q ); + q.right( e ); + } + } + } + return c; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + int n = count; + EntryIterator i = new EntryIterator(); + Entry e; + s.defaultWriteObject(); + while(n-- != 0) { + e = i.nextEntry(); + s.writeInt( e.key ); + s.writeObject( e.value ); + } + } + /** Reads the given number of entries from the input stream, returning the corresponding tree. + * + * @param s the input stream. + * @param n the (positive) number of entries to read. + * @param pred the entry containing the key that preceeds the first key in the tree. + * @param succ the entry containing the key that follows the last key in the tree. + */ + @SuppressWarnings("unchecked") + private Entry readTree( final java.io.ObjectInputStream s, final int n, final Entry pred, final Entry succ ) throws java.io.IOException, ClassNotFoundException { + if ( n == 1 ) { + final Entry top = new Entry ( s.readInt(), (V) s.readObject() ); + top.pred( pred ); + top.succ( succ ); + return top; + } + if ( n == 2 ) { + /* We handle separately this case so that recursion will + *always* be on nonempty subtrees. */ + final Entry top = new Entry ( s.readInt(), (V) s.readObject() ); + top.right( new Entry ( s.readInt(), (V) s.readObject() ) ); + top.right.pred( top ); + top.balance( 1 ); + top.pred( pred ); + top.right.succ( succ ); + return top; + } + // The right subtree is the largest one. + final int rightN = n / 2, leftN = n - rightN - 1; + final Entry top = new Entry (); + top.left( readTree( s, leftN, pred, top ) ); + top.key = s.readInt(); + top.value = (V) s.readObject(); + top.right( readTree( s, rightN, top, succ ) ); + if ( n == ( n & -n ) ) top.balance( 1 ); // Quick test for determining whether n is a power of 2. + return top; + } + private void readObject( java.io.ObjectInputStream s ) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + /* The storedComparator is now correctly set, but we must restore + on-the-fly the actualComparator. */ + setActualComparator(); + allocatePaths(); + if ( count != 0 ) { + tree = readTree( s, count, null, null ); + Entry e; + e = tree; + while( e.left() != null ) e = e.left(); + firstEntry = e; + e = tree; + while( e.right() != null ) e = e.right(); + lastEntry = e; + } + if ( ASSERTS ) checkTree( tree ); + } + private static int checkTree( @SuppressWarnings("unused") Entry e ) { return 0; } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectArrayMap.java b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectArrayMap.java new file mode 100644 index 0000000..2b637a3 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectArrayMap.java @@ -0,0 +1,346 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2007-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.Map; +import java.util.NoSuchElementException; +import it.unimi.dsi.fastutil.objects.AbstractObjectIterator; +import it.unimi.dsi.fastutil.objects.AbstractObjectSet; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectCollections; +import it.unimi.dsi.fastutil.objects.ObjectArraySet; +import it.unimi.dsi.fastutil.objects.ObjectArrays; +/** A simple, brute-force implementation of a map based on two parallel backing arrays. + * + *

The main purpose of this + * implementation is that of wrapping cleanly the brute-force approach to the storage of a very + * small number of pairs: just put them into two parallel arrays and scan linearly to find an item. + */ +public class Int2ObjectArrayMap extends AbstractInt2ObjectMap implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = 1L; + /** The keys (valid up to {@link #size}, excluded). */ + private transient int[] key; + /** The values (parallel to {@link #key}). */ + private transient Object[] value; + /** The number of valid entries in {@link #key} and {@link #value}. */ + private int size; + /** Creates a new empty array map with given key and value backing arrays. The resulting map will have as many entries as the given arrays. + * + *

It is responsibility of the caller that the elements of key are distinct. + * + * @param key the key array. + * @param value the value array (it must have the same length as key). + */ + public Int2ObjectArrayMap( final int[] key, final Object[] value ) { + this.key = key; + this.value = value; + size = key.length; + if( key.length != value.length ) throw new IllegalArgumentException( "Keys and values have different lengths (" + key.length + ", " + value.length + ")" ); + } + /** Creates a new empty array map. + */ + public Int2ObjectArrayMap() { + this.key = IntArrays.EMPTY_ARRAY; + this.value = ObjectArrays.EMPTY_ARRAY; + } + /** Creates a new empty array map of given capacity. + * + * @param capacity the initial capacity. + */ + public Int2ObjectArrayMap( final int capacity ) { + this.key = new int[ capacity ]; + this.value = new Object[ capacity ]; + } + /** Creates a new empty array map copying the entries of a given map. + * + * @param m a map. + */ + public Int2ObjectArrayMap( final Int2ObjectMap m ) { + this( m.size() ); + putAll( m ); + } + /** Creates a new empty array map copying the entries of a given map. + * + * @param m a map. + */ + public Int2ObjectArrayMap( final Map m ) { + this( m.size() ); + putAll( m ); + } + /** Creates a new array map with given key and value backing arrays, using the given number of elements. + * + *

It is responsibility of the caller that the first size elements of key are distinct. + * + * @param key the key array. + * @param value the value array (it must have the same length as key). + * @param size the number of valid elements in key and value. + */ + public Int2ObjectArrayMap( final int[] key, final Object[] value, final int size ) { + this.key = key; + this.value = value; + this.size = size; + if( key.length != value.length ) throw new IllegalArgumentException( "Keys and values have different lengths (" + key.length + ", " + value.length + ")" ); + if ( size > key.length ) throw new IllegalArgumentException( "The provided size (" + size + ") is larger than or equal to the backing-arrays size (" + key.length + ")" ); + } + private final class EntrySet extends AbstractObjectSet > implements FastEntrySet { + @Override + public ObjectIterator > iterator() { + return new AbstractObjectIterator >() { + int curr = -1, next = 0; + public boolean hasNext() { + return next < size; + } + @SuppressWarnings("unchecked") + public Entry next() { + if ( ! hasNext() ) throw new NoSuchElementException(); + return new AbstractInt2ObjectMap.BasicEntry ( key[ curr = next ], (V) value[ next++ ] ); + } + public void remove() { + if ( curr == -1 ) throw new IllegalStateException(); + curr = -1; + final int tail = size-- - next--; + System.arraycopy( key, next + 1, key, next, tail ); + System.arraycopy( value, next + 1, value, next, tail ); + value[ size ] = null; + } + }; + } + public ObjectIterator > fastIterator() { + return new AbstractObjectIterator >() { + int next = 0, curr = -1; + final BasicEntry entry = new BasicEntry ( (0), (null) ); + public boolean hasNext() { + return next < size; + } + @SuppressWarnings("unchecked") + public Entry next() { + if ( ! hasNext() ) throw new NoSuchElementException(); + entry.key = key[ curr = next ]; + entry.value = (V) value[ next++ ]; + return entry; + } + public void remove() { + if ( curr == -1 ) throw new IllegalStateException(); + curr = -1; + final int tail = size-- - next--; + System.arraycopy( key, next + 1, key, next, tail ); + System.arraycopy( value, next + 1, value, next, tail ); + value[ size ] = null; + } + }; + } + public int size() { + return size; + } + @SuppressWarnings("unchecked") + public boolean contains( Object o ) { + if ( ! ( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final int k = ((e.getKey()).intValue()); + return Int2ObjectArrayMap.this.containsKey( k ) && ( (Int2ObjectArrayMap.this.get( k )) == null ? ((e.getValue())) == null : (Int2ObjectArrayMap.this.get( k )).equals((e.getValue())) ); + } + @SuppressWarnings("unchecked") + @Override + public boolean remove( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final int k = ((e.getKey()).intValue()); + final V v = (e.getValue()); + final int oldPos = Int2ObjectArrayMap.this.findKey( k ); + if ( oldPos == -1 || ! ( (v) == null ? (Int2ObjectArrayMap.this.value[ oldPos ]) == null : (v).equals(Int2ObjectArrayMap.this.value[ oldPos ]) ) ) return false; + final int tail = size - oldPos - 1; + System.arraycopy( Int2ObjectArrayMap.this.key, oldPos + 1, Int2ObjectArrayMap.this.key, oldPos, tail ); + System.arraycopy( Int2ObjectArrayMap.this.value, oldPos + 1, Int2ObjectArrayMap.this.value, oldPos, tail ); + Int2ObjectArrayMap.this.size--; + Int2ObjectArrayMap.this.value[ size ] = null; + return true; + } + } + public FastEntrySet int2ObjectEntrySet() { + return new EntrySet(); + } + private int findKey( final int k ) { + final int[] key = this.key; + for( int i = size; i-- != 0; ) if ( ( (key[ i ]) == (k) ) ) return i; + return -1; + } + @SuppressWarnings("unchecked") + public V get( final int k ) { + final int[] key = this.key; + for( int i = size; i-- != 0; ) if ( ( (key[ i ]) == (k) ) ) return (V) value[ i ]; + return defRetValue; + } + public int size() { + return size; + } + @Override + public void clear() { + for( int i = size; i-- != 0; ) { + value[ i ] = null; + } + size = 0; + } + @Override + public boolean containsKey( final int k ) { + return findKey( k ) != -1; + } + @Override + public boolean containsValue( Object v ) { + for( int i = size; i-- != 0; ) if ( ( (value[ i ]) == null ? (v) == null : (value[ i ]).equals(v) ) ) return true; + return false; + } + @Override + public boolean isEmpty() { + return size == 0; + } + @Override + @SuppressWarnings("unchecked") + public V put( int k, V v ) { + final int oldKey = findKey( k ); + if ( oldKey != -1 ) { + final V oldValue = (V) value[ oldKey ]; + value[ oldKey ] = v; + return oldValue; + } + if ( size == key.length ) { + final int[] newKey = new int[ size == 0 ? 2 : size * 2 ]; + final Object[] newValue = new Object[ size == 0 ? 2 : size * 2 ]; + for( int i = size; i-- != 0; ) { + newKey[ i ] = key[ i ]; + newValue[ i ] = value[ i ]; + } + key = newKey; + value = newValue; + } + key[ size ] = k; + value[ size ] = v; + size++; + return defRetValue; + } + @Override + @SuppressWarnings("unchecked") + public V remove( final int k ) { + final int oldPos = findKey( k ); + if ( oldPos == -1 ) return defRetValue; + final V oldValue = (V) value[ oldPos ]; + final int tail = size - oldPos - 1; + System.arraycopy( key, oldPos + 1, key, oldPos, tail ); + System.arraycopy( value, oldPos + 1, value, oldPos, tail ); + size--; + value[ size ] = null; + return oldValue; + } + @Override + public IntSet keySet() { + return new IntArraySet ( key, size ); + } + @Override + public ObjectCollection values() { + return ObjectCollections.unmodifiable( new ObjectArraySet ( value, size ) ); + } + /** Returns a deep copy of this map. + * + *

This method performs a deep copy of this hash map; the data stored in the + * map, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this map. + */ + @SuppressWarnings("unchecked") + public Int2ObjectArrayMap clone() { + Int2ObjectArrayMap c; + try { + c = (Int2ObjectArrayMap )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.key = key.clone(); + c.value = value.clone(); + return c; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + s.defaultWriteObject(); + for( int i = 0; i < size; i++ ) { + s.writeInt( key[ i ] ); + s.writeObject( value[ i ] ); + } + } + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + key = new int[ size ]; + value = new Object[ size ]; + for( int i = 0; i < size; i++ ) { + key[ i ] = s.readInt(); + value[ i ] = s.readObject(); + } + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectFunction.java b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectFunction.java new file mode 100644 index 0000000..489609b --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectFunction.java @@ -0,0 +1,137 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.Function; +/** A type-specific {@link Function}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Type-specific versions of get(), put() and + * remove() cannot rely on null to denote absence of + * a key. Rather, they return a {@linkplain #defaultReturnValue() default + * return value}, which is set to 0 cast to the return type (false + * for booleans) at creation, but can be changed using the + * defaultReturnValue() method. + * + *

For uniformity reasons, even maps returning objects implement the default + * return value (of course, in this case the default return value is + * initialized to null). + * + *

Warning: to fall in line as much as possible with the + * {@linkplain java.util.Map standard map interface}, it is strongly suggested + * that standard versions of get(), put() and + * remove() for maps with primitive-type values return + * null to denote missing keys rather than wrap the default + * return value in an object (of course, for maps with object keys and values + * this is not possible, as there is no type-specific version). + * + * @see Function + */ +public interface Int2ObjectFunction extends Function { + /** Adds a pair to the map. + * + * @param key the key. + * @param value the value. + * @return the old value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + * @see Function#put(Object,Object) + */ + V put( int key, V value ); + /** Returns the value to which the given key is mapped. + * + * @param key the key. + * @return the corresponding value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + * @see Function#get(Object) + */ + V get( int key ); + /** Removes the mapping with the given key. + * @param key the key. + * @return the old value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + * @see Function#remove(Object) + */ + V remove( int key ); + /** + * @see Function#containsKey(Object) + */ + boolean containsKey( int key ); + /** Sets the default return value. + * + * This value must be returned by type-specific versions of + * get(), put() and remove() to + * denote that the map does not contain the specified key. It must be + * 0/false/null by default. + * + * @param rv the new default return value. + * @see #defaultReturnValue() + */ + void defaultReturnValue( V rv ); + /** Gets the default return value. + * + * @return the current default return value. + */ + V defaultReturnValue(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectFunctions.java b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectFunctions.java new file mode 100644 index 0000000..d288c35 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectFunctions.java @@ -0,0 +1,224 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +/** A class providing static methods and objects that do useful things with type-specific functions. + * + * @see it.unimi.dsi.fastutil.Function + * @see java.util.Collections + */ +public class Int2ObjectFunctions { + private Int2ObjectFunctions() {} + /** An immutable class representing an empty type-specific function. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific function. + */ + public static class EmptyFunction extends AbstractInt2ObjectFunction implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptyFunction() {} + public V get( final int k ) { return (null); } + public boolean containsKey( final int k ) { return false; } + public V defaultReturnValue() { return (null); } + public void defaultReturnValue( final V defRetValue ) { throw new UnsupportedOperationException(); } + @Override + public V get( final Object k ) { return null; } + public int size() { return 0; } + public void clear() {} + private Object readResolve() { return EMPTY_FUNCTION; } + public Object clone() { return EMPTY_FUNCTION; } + } + /** An empty type-specific function (immutable). It is serializable and cloneable. */ + @SuppressWarnings("rawtypes") + public static final EmptyFunction EMPTY_FUNCTION = new EmptyFunction(); + /** An immutable class representing a type-specific singleton function. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific function. + */ + public static class Singleton extends AbstractInt2ObjectFunction implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected final int key; + protected final V value; + protected Singleton( final int key, final V value ) { + this.key = key; + this.value = value; + } + public boolean containsKey( final int k ) { return ( (key) == (k) ); } + public V get( final int k ) { if ( ( (key) == (k) ) ) return value; return defRetValue; } + public int size() { return 1; } + public Object clone() { return this; } + } + /** Returns a type-specific immutable function containing only the specified pair. The returned function is serializable and cloneable. + * + *

Note that albeit the returned function is immutable, its default return value may be changed. + * + * @param key the only key of the returned function. + * @param value the only value of the returned function. + * @return a type-specific immutable function containing just the pair <key,value>. + */ + public static Int2ObjectFunction singleton( final int key, V value ) { + return new Singleton ( key, value ); + } + /** Returns a type-specific immutable function containing only the specified pair. The returned function is serializable and cloneable. + * + *

Note that albeit the returned function is immutable, its default return value may be changed. + * + * @param key the only key of the returned function. + * @param value the only value of the returned function. + * @return a type-specific immutable function containing just the pair <key,value>. + */ + public static Int2ObjectFunction singleton( final Integer key, final V value ) { + return new Singleton ( ((key).intValue()), (value) ); + } + /** A synchronized wrapper class for functions. */ + public static class SynchronizedFunction extends AbstractInt2ObjectFunction implements java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final Int2ObjectFunction function; + protected final Object sync; + protected SynchronizedFunction( final Int2ObjectFunction f, final Object sync ) { + if ( f == null ) throw new NullPointerException(); + this.function = f; + this.sync = sync; + } + protected SynchronizedFunction( final Int2ObjectFunction f ) { + if ( f == null ) throw new NullPointerException(); + this.function = f; + this.sync = this; + } + public int size() { synchronized( sync ) { return function.size(); } } + public boolean containsKey( final int k ) { synchronized( sync ) { return function.containsKey( k ); } } + public V defaultReturnValue() { synchronized( sync ) { return function.defaultReturnValue(); } } + public void defaultReturnValue( final V defRetValue ) { synchronized( sync ) { function.defaultReturnValue( defRetValue ); } } + public V put( final int k, final V v ) { synchronized( sync ) { return function.put( k, v ); } } + public void clear() { synchronized( sync ) { function.clear(); } } + public String toString() { synchronized( sync ) { return function.toString(); } } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Integer k, final V v ) { synchronized( sync ) { return function.put( k, v ); } } + @Override + public V get( final Object k ) { synchronized( sync ) { return function.get( k ); } } + @Override + public V remove( final Object k ) { synchronized( sync ) { return function.remove( k ); } } + @Override + public V remove( final int k ) { synchronized( sync ) { return function.remove( k ); } } + @Override + public V get( final int k ) { synchronized( sync ) { return function.get( k ); } } + public boolean containsKey( final Object ok ) { synchronized( sync ) { return function.containsKey( ok ); } } + } + /** Returns a synchronized type-specific function backed by the given type-specific function. + * + * @param f the function to be wrapped in a synchronized function. + * @return a synchronized view of the specified function. + * @see java.util.Collections#synchronizedMap(java.util.Map) + */ + public static Int2ObjectFunction synchronize( final Int2ObjectFunction f ) { return new SynchronizedFunction ( f ); } + /** Returns a synchronized type-specific function backed by the given type-specific function, using an assigned object to synchronize. + * + * @param f the function to be wrapped in a synchronized function. + * @param sync an object that will be used to synchronize the access to the function. + * @return a synchronized view of the specified function. + * @see java.util.Collections#synchronizedMap(java.util.Map) + */ + public static Int2ObjectFunction synchronize( final Int2ObjectFunction f, final Object sync ) { return new SynchronizedFunction ( f, sync ); } + /** An unmodifiable wrapper class for functions. */ + public static class UnmodifiableFunction extends AbstractInt2ObjectFunction implements java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final Int2ObjectFunction function; + protected UnmodifiableFunction( final Int2ObjectFunction f ) { + if ( f == null ) throw new NullPointerException(); + this.function = f; + } + public int size() { return function.size(); } + public boolean containsKey( final int k ) { return function.containsKey( k ); } + public V defaultReturnValue() { return function.defaultReturnValue(); } + public void defaultReturnValue( final V defRetValue ) { throw new UnsupportedOperationException(); } + public V put( final int k, final V v ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + public String toString() { return function.toString(); } + @Override + public V remove( final int k ) { throw new UnsupportedOperationException(); } + @Override + public V get( final int k ) { return function.get( k ); } + public boolean containsKey( final Object ok ) { return function.containsKey( ok ); } + @Override + public V remove( final Object k ) { throw new UnsupportedOperationException(); } + @Override + public V get( final Object k ) { return function.get( k ); } + } + /** Returns an unmodifiable type-specific function backed by the given type-specific function. + * + * @param f the function to be wrapped in an unmodifiable function. + * @return an unmodifiable view of the specified function. + * @see java.util.Collections#unmodifiableMap(java.util.Map) + */ + public static Int2ObjectFunction unmodifiable( final Int2ObjectFunction f ) { return new UnmodifiableFunction ( f ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectLinkedOpenHashMap.java b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectLinkedOpenHashMap.java new file mode 100644 index 0000000..5564407 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectLinkedOpenHashMap.java @@ -0,0 +1,1444 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.HashCommon; +import static it.unimi.dsi.fastutil.HashCommon.arraySize; +import static it.unimi.dsi.fastutil.HashCommon.maxFill; +import java.util.Map; +import java.util.Arrays; +import java.util.NoSuchElementException; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import java.util.Comparator; +import it.unimi.dsi.fastutil.objects.AbstractObjectSortedSet; +import it.unimi.dsi.fastutil.objects.ObjectListIterator; +import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; +import it.unimi.dsi.fastutil.objects.ObjectSortedSet; +/** A type-specific linked hash map with with a fast, small-footprint implementation. + * + *

Instances of this class use a hash table to represent a map. The table is + * filled up to a specified load factor, and then doubled in size to + * accommodate new entries. If the table is emptied below one fourth + * of the load factor, it is halved in size. However, halving is + * not performed when deleting entries from an iterator, as it would interfere + * with the iteration process. + * + *

Note that {@link #clear()} does not modify the hash table size. + * Rather, a family of {@linkplain #trim() trimming + * methods} lets you control the size of the table; this is particularly useful + * if you reuse instances of this class. + * + *

Iterators generated by this map will enumerate pairs in the same order in which they + * have been added to the map (addition of pairs whose key is already present + * in the set does not change the iteration order). Note that this order has nothing in common with the natural + * order of the keys. The order is kept by means of a doubly linked list, represented + * via an array of longs parallel to the table. + * + *

This class implements the interface of a sorted map, so to allow easy + * access of the iteration order: for instance, you can get the first key + * in iteration order with {@code firstKey()} without having to create an + * iterator; however, this class partially violates the {@link java.util.SortedMap} + * contract because all submap methods throw an exception and {@link + * #comparator()} returns always null. + * + *

Additional methods, such as getAndMoveToFirst(), make it easy + * to use instances of this class as a cache (e.g., with LRU policy). + * + *

The iterators provided by the views of this class using are type-specific + * {@linkplain java.util.ListIterator list iterators}, and can be started at any + * element which is a key of the map, or + * a {@link NoSuchElementException} exception will be thrown. + * If, however, the provided element is not the first or last key in the + * set, the first access to the list index will require linear time, as in the worst case + * the entire key set must be scanned in iteration order to retrieve the positional + * index of the starting key. If you use just the methods of a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator}, + * however, all operations will be performed in constant time. + * + * @see Hash + * @see HashCommon + */ +public class Int2ObjectLinkedOpenHashMap extends AbstractInt2ObjectSortedMap implements java.io.Serializable, Cloneable, Hash { + private static final long serialVersionUID = 0L; + private static final boolean ASSERTS = false; + /** The array of keys. */ + protected transient int[] key; + /** The array of values. */ + protected transient V[] value; + /** The mask for wrapping a position counter. */ + protected transient int mask; + /** Whether this set contains the key zero. */ + protected transient boolean containsNullKey; + /** The index of the first entry in iteration order. It is valid iff {@link #size} is nonzero; otherwise, it contains -1. */ + protected transient int first = -1; + /** The index of the last entry in iteration order. It is valid iff {@link #size} is nonzero; otherwise, it contains -1. */ + protected transient int last = -1; + /** For each entry, the next and the previous entry in iteration order, + * stored as ((prev & 0xFFFFFFFFL) << 32) | (next & 0xFFFFFFFFL). + * The first entry contains predecessor -1, and the last entry + * contains successor -1. */ + protected transient long[] link; + /** The current table size. */ + protected transient int n; + /** Threshold after which we rehash. It must be the table size times {@link #f}. */ + protected transient int maxFill; + /** Number of entries in the set (including the key zero, if present). */ + protected int size; + /** The acceptable load factor. */ + protected final float f; + /** Cached set of entries. */ + protected transient FastSortedEntrySet entries; + /** Cached set of keys. */ + protected transient IntSortedSet keys; + /** Cached collection of values. */ + protected transient ObjectCollection values; + /** Creates a new hash map. + * + *

The actual table size will be the least power of two greater than expected/f. + * + * @param expected the expected number of elements in the hash set. + * @param f the load factor. + */ + @SuppressWarnings("unchecked") + public Int2ObjectLinkedOpenHashMap( final int expected, final float f ) { + if ( f <= 0 || f > 1 ) throw new IllegalArgumentException( "Load factor must be greater than 0 and smaller than or equal to 1" ); + if ( expected < 0 ) throw new IllegalArgumentException( "The expected number of elements must be nonnegative" ); + this.f = f; + n = arraySize( expected, f ); + mask = n - 1; + maxFill = maxFill( n, f ); + key = new int[ n + 1 ]; + value = (V[]) new Object[ n + 1 ]; + link = new long[ n + 1 ]; + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * + * @param expected the expected number of elements in the hash map. + */ + public Int2ObjectLinkedOpenHashMap( final int expected ) { + this( expected, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map with initial expected {@link Hash#DEFAULT_INITIAL_SIZE} entries + * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + */ + public Int2ObjectLinkedOpenHashMap() { + this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map copying a given one. + * + * @param m a {@link Map} to be copied into the new hash map. + * @param f the load factor. + */ + public Int2ObjectLinkedOpenHashMap( final Map m, final float f ) { + this( m.size(), f ); + putAll( m ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given one. + * + * @param m a {@link Map} to be copied into the new hash map. + */ + public Int2ObjectLinkedOpenHashMap( final Map m ) { + this( m, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map copying a given type-specific one. + * + * @param m a type-specific map to be copied into the new hash map. + * @param f the load factor. + */ + public Int2ObjectLinkedOpenHashMap( final Int2ObjectMap m, final float f ) { + this( m.size(), f ); + putAll( m ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given type-specific one. + * + * @param m a type-specific map to be copied into the new hash map. + */ + public Int2ObjectLinkedOpenHashMap( final Int2ObjectMap m ) { + this( m, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map using the elements of two parallel arrays. + * + * @param k the array of keys of the new hash map. + * @param v the array of corresponding values in the new hash map. + * @param f the load factor. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Int2ObjectLinkedOpenHashMap( final int[] k, final V[] v, final float f ) { + this( k.length, f ); + if ( k.length != v.length ) throw new IllegalArgumentException( "The key array and the value array have different lengths (" + k.length + " and " + v.length + ")" ); + for( int i = 0; i < k.length; i++ ) this.put( k[ i ], v[ i ] ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using the elements of two parallel arrays. + * + * @param k the array of keys of the new hash map. + * @param v the array of corresponding values in the new hash map. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Int2ObjectLinkedOpenHashMap( final int[] k, final V[] v ) { + this( k, v, DEFAULT_LOAD_FACTOR ); + } + private int realSize() { + return containsNullKey ? size - 1 : size; + } + private void ensureCapacity( final int capacity ) { + final int needed = arraySize( capacity, f ); + if ( needed > n ) rehash( needed ); + } + private void tryCapacity( final long capacity ) { + final int needed = (int)Math.min( 1 << 30, Math.max( 2, HashCommon.nextPowerOfTwo( (long)Math.ceil( capacity / f ) ) ) ); + if ( needed > n ) rehash( needed ); + } + private V removeEntry( final int pos ) { + final V oldValue = value[ pos ]; + value[ pos ] = null; + size--; + fixPointers( pos ); + shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return oldValue; + } + private V removeNullEntry() { + containsNullKey = false; + final V oldValue = value[ n ]; + value[ n ] = null; + size--; + fixPointers( n ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return oldValue; + } + /** {@inheritDoc} */ + public void putAll(Map m) { + if ( f <= .5 ) ensureCapacity( m.size() ); // The resulting map will be sized for m.size() elements + else tryCapacity( size() + m.size() ); // The resulting map will be tentatively sized for size() + m.size() elements + super.putAll( m ); + } + private int insert(final int k, final V v) { + int pos; + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) return n; + containsNullKey = true; + pos = n; + } + else { + int curr; + final int[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) { + if ( ( (curr) == (k) ) ) return pos; + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( (curr) == (k) ) ) return pos; + } + } + key[ pos ] = k; + value[ pos ] = v; + if ( size == 0 ) { + first = last = pos; + // Special case of SET_UPPER_LOWER( link[ pos ], -1, -1 ); + link[ pos ] = -1L; + } + else { + link[ last ] ^= ( ( link[ last ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ pos ] = ( ( last & 0xFFFFFFFFL ) << 32 ) | ( -1 & 0xFFFFFFFFL ); + last = pos; + } + if ( size++ >= maxFill ) rehash( arraySize( size + 1, f ) ); + if ( ASSERTS ) checkTable(); + return -1; + } + public V put(final int k, final V v) { + final int pos = insert( k, v ); + if ( pos < 0 ) return defRetValue; + final V oldValue = value[ pos ]; + value[ pos ] = v; + return oldValue; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Integer ok, final V ov ) { + final V v = (ov); + final int pos = insert( ((ok).intValue()), v ); + if ( pos < 0 ) return (this.defRetValue); + final V oldValue = value[ pos ]; + value[ pos ] = v; + return (oldValue); + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + protected final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + int curr; + final int[] key = this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + value[ last ] = null; + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( (curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + value[ last ] = value[ pos ]; + fixPointers( pos, last ); + } + } + + public V remove( final int k ) { + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) return removeNullEntry(); + return defRetValue; + } + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return removeEntry( pos ); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return removeEntry( pos ); + } + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + + public V remove( final Object ok ) { + final int k = ((((Integer)(ok)).intValue())); + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) return (removeNullEntry()); + return (this.defRetValue); + } + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (curr) == (k) ) ) return (removeEntry( pos )); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (curr) == (k) ) ) return (removeEntry( pos )); + } + } + private V setValue( final int pos, final V v ) { + final V oldValue = value[ pos ]; + value[ pos ] = v; + return oldValue; + } + /** Removes the mapping associated with the first key in iteration order. + * @return the value previously associated with the first key in iteration order. + * @throws NoSuchElementException is this map is empty. + */ + public V removeFirst() { + if ( size == 0 ) throw new NoSuchElementException(); + final int pos = first; + // Abbreviated version of fixPointers(pos) + first = (int) link[ pos ]; + if ( 0 <= first ) { + // Special case of SET_PREV( link[ first ], -1 ) + link[ first ] |= (-1 & 0xFFFFFFFFL) << 32; + } + size--; + final V v = value[ pos ]; + if ( pos == n ) { + containsNullKey = false; + value[ n ] = null; + } + else shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return v; + } + /** Removes the mapping associated with the last key in iteration order. + * @return the value previously associated with the last key in iteration order. + * @throws NoSuchElementException is this map is empty. + */ + public V removeLast() { + if ( size == 0 ) throw new NoSuchElementException(); + final int pos = last; + // Abbreviated version of fixPointers(pos) + last = (int) ( link[ pos ] >>> 32 ); + if ( 0 <= last ) { + // Special case of SET_NEXT( link[ last ], -1 ) + link[ last ] |= -1 & 0xFFFFFFFFL; + } + size--; + final V v = value[ pos ]; + if ( pos == n ) { + containsNullKey = false; + value[ n ] = null; + } + else shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return v; + } + private void moveIndexToFirst( final int i ) { + if ( size == 1 || first == i ) return; + if ( last == i ) { + last = (int) ( link[ i ] >>> 32 ); + // Special case of SET_NEXT( link[ last ], -1 ); + link[ last ] |= -1 & 0xFFFFFFFFL; + } + else { + final long linki = link[ i ]; + final int prev = (int) ( linki >>> 32 ); + final int next = (int) linki; + link[ prev ] ^= ( ( link[ prev ] ^ ( linki & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( linki & 0xFFFFFFFF00000000L ) ) & 0xFFFFFFFF00000000L ); + } + link[ first ] ^= ( ( link[ first ] ^ ( ( i & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ i ] = ( ( -1 & 0xFFFFFFFFL ) << 32 ) | ( first & 0xFFFFFFFFL ); + first = i; + } + private void moveIndexToLast( final int i ) { + if ( size == 1 || last == i ) return; + if ( first == i ) { + first = (int) link[ i ]; + // Special case of SET_PREV( link[ first ], -1 ); + link[ first ] |= (-1 & 0xFFFFFFFFL) << 32; + } + else { + final long linki = link[ i ]; + final int prev = (int) ( linki >>> 32 ); + final int next = (int) linki; + link[ prev ] ^= ( ( link[ prev ] ^ ( linki & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( linki & 0xFFFFFFFF00000000L ) ) & 0xFFFFFFFF00000000L ); + } + link[ last ] ^= ( ( link[ last ] ^ ( i & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ i ] = ( ( last & 0xFFFFFFFFL ) << 32 ) | ( -1 & 0xFFFFFFFFL ); + last = i; + } + /** Returns the value to which the given key is mapped; if the key is present, it is moved to the first position of the iteration order. + * + * @param k the key. + * @return the corresponding value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + */ + public V getAndMoveToFirst( final int k ) { + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) { + moveIndexToFirst( n ); + return value[ n ]; + } + return defRetValue; + } + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) { + moveIndexToFirst( pos ); + return value[ pos ]; + } + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) { + moveIndexToFirst( pos ); + return value[ pos ]; + } + } + } + /** Returns the value to which the given key is mapped; if the key is present, it is moved to the last position of the iteration order. + * + * @param k the key. + * @return the corresponding value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + */ + public V getAndMoveToLast( final int k ) { + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) { + moveIndexToLast( n ); + return value[ n ]; + } + return defRetValue; + } + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) { + moveIndexToLast( pos ); + return value[ pos ]; + } + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) { + moveIndexToLast( pos ); + return value[ pos ]; + } + } + } + /** Adds a pair to the map; if the key is already present, it is moved to the first position of the iteration order. + * + * @param k the key. + * @param v the value. + * @return the old value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + */ + public V putAndMoveToFirst( final int k, final V v ) { + int pos; + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) { + moveIndexToFirst( n ); + return setValue( n, v ); + } + containsNullKey = true; + pos = n; + } + else { + int curr; + final int[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) { + if ( ( (curr) == (k) ) ) { + moveIndexToFirst( pos ); + return setValue( pos, v ); + } + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( (curr) == (k) ) ) { + moveIndexToFirst( pos ); + return setValue( pos, v ); + } + } + } + key[ pos ] = k; + value[ pos ] = v; + if ( size == 0 ) { + first = last = pos; + // Special case of SET_UPPER_LOWER( link[ pos ], -1, -1 ); + link[ pos ] = -1L; + } + else { + link[ first ] ^= ( ( link[ first ] ^ ( ( pos & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ pos ] = ( ( -1 & 0xFFFFFFFFL ) << 32 ) | ( first & 0xFFFFFFFFL ); + first = pos; + } + if ( size++ >= maxFill ) rehash( arraySize( size, f ) ); + if ( ASSERTS ) checkTable(); + return defRetValue; + } + /** Adds a pair to the map; if the key is already present, it is moved to the last position of the iteration order. + * + * @param k the key. + * @param v the value. + * @return the old value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + */ + public V putAndMoveToLast( final int k, final V v ) { + int pos; + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) { + moveIndexToLast( n ); + return setValue( n, v ); + } + containsNullKey = true; + pos = n; + } + else { + int curr; + final int[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) { + if ( ( (curr) == (k) ) ) { + moveIndexToLast( pos ); + return setValue( pos, v ); + } + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( (curr) == (k) ) ) { + moveIndexToLast( pos ); + return setValue( pos, v ); + } + } + } + key[ pos ] = k; + value[ pos ] = v; + if ( size == 0 ) { + first = last = pos; + // Special case of SET_UPPER_LOWER( link[ pos ], -1, -1 ); + link[ pos ] = -1L; + } + else { + link[ last ] ^= ( ( link[ last ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ pos ] = ( ( last & 0xFFFFFFFFL ) << 32 ) | ( -1 & 0xFFFFFFFFL ); + last = pos; + } + if ( size++ >= maxFill ) rehash( arraySize( size, f ) ); + if ( ASSERTS ) checkTable(); + return defRetValue; + } + /** @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public V get( final Integer ok ) { + if ( ok == null ) return null; + final int k = ((ok).intValue()); + if ( ( (k) == (0) ) ) return containsNullKey ? (value[ n ]) : (this.defRetValue); + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (k) == (curr) ) ) return (value[ pos ]); + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (k) == (curr) ) ) return (value[ pos ]); + } + } + + public V get( final int k ) { + if ( ( (k) == (0) ) ) return containsNullKey ? value[ n ] : defRetValue; + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return value[ pos ]; + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return value[ pos ]; + } + } + + public boolean containsKey( final int k ) { + if ( ( (k) == (0) ) ) return containsNullKey; + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return true; + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return true; + } + } + public boolean containsValue( final Object v ) { + final V value[] = this.value; + final int key[] = this.key; + if ( containsNullKey && ( (value[ n ]) == null ? (v) == null : (value[ n ]).equals(v) ) ) return true; + for( int i = n; i-- != 0; ) if ( ! ( (key[ i ]) == (0) ) && ( (value[ i ]) == null ? (v) == null : (value[ i ]).equals(v) ) ) return true; + return false; + } + /* Removes all elements from this map. + * + *

To increase object reuse, this method does not change the table size. + * If you want to reduce the table size, you must use {@link #trim()}. + * + */ + public void clear() { + if ( size == 0 ) return; + size = 0; + containsNullKey = false; + Arrays.fill( key, (0) ); + Arrays.fill( value, null ); + first = last = -1; + } + public int size() { + return size; + } + public boolean isEmpty() { + return size == 0; + } + /** A no-op for backward compatibility. + * + * @param growthFactor unused. + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public void growthFactor( int growthFactor ) {} + /** Gets the growth factor (2). + * + * @return the growth factor of this set, which is fixed (2). + * @see #growthFactor(int) + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public int growthFactor() { + return 16; + } + /** The entry class for a hash map does not record key and value, but + * rather the position in the hash table of the corresponding entry. This + * is necessary so that calls to {@link java.util.Map.Entry#setValue(Object)} are reflected in + * the map */ + final class MapEntry implements Int2ObjectMap.Entry , Map.Entry { + // The table index this entry refers to, or -1 if this entry has been deleted. + int index; + MapEntry( final int index ) { + this.index = index; + } + MapEntry() {} + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer getKey() { + return (Integer.valueOf(key[ index ])); + } + public int getIntKey() { + return key[ index ]; + } + public V getValue() { + return (value[ index ]); + } + public V setValue( final V v ) { + final V oldValue = value[ index ]; + value[ index ] = v; + return oldValue; + } + @SuppressWarnings("unchecked") + public boolean equals( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + Map.Entry e = (Map.Entry)o; + return ( (key[ index ]) == (((e.getKey()).intValue())) ) && ( (value[ index ]) == null ? ((e.getValue())) == null : (value[ index ]).equals((e.getValue())) ); + } + public int hashCode() { + return (key[ index ]) ^ ( (value[ index ]) == null ? 0 : (value[ index ]).hashCode() ); + } + public String toString() { + return key[ index ] + "=>" + value[ index ]; + } + } + /** Modifies the {@link #link} vector so that the given entry is removed. + * This method will complete in constant time. + * + * @param i the index of an entry. + */ + protected void fixPointers( final int i ) { + if ( size == 0 ) { + first = last = -1; + return; + } + if ( first == i ) { + first = (int) link[ i ]; + if (0 <= first) { + // Special case of SET_PREV( link[ first ], -1 ) + link[ first ] |= (-1 & 0xFFFFFFFFL) << 32; + } + return; + } + if ( last == i ) { + last = (int) ( link[ i ] >>> 32 ); + if (0 <= last) { + // Special case of SET_NEXT( link[ last ], -1 ) + link[ last ] |= -1 & 0xFFFFFFFFL; + } + return; + } + final long linki = link[ i ]; + final int prev = (int) ( linki >>> 32 ); + final int next = (int) linki; + link[ prev ] ^= ( ( link[ prev ] ^ ( linki & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( linki & 0xFFFFFFFF00000000L ) ) & 0xFFFFFFFF00000000L ); + } + /** Modifies the {@link #link} vector for a shift from s to d. + *

This method will complete in constant time. + * + * @param s the source position. + * @param d the destination position. + */ + protected void fixPointers( int s, int d ) { + if ( size == 1 ) { + first = last = d; + // Special case of SET_UPPER_LOWER( link[ d ], -1, -1 ) + link[ d ] = -1L; + return; + } + if ( first == s ) { + first = d; + link[ (int) link[ s ] ] ^= ( ( link[ (int) link[ s ] ] ^ ( ( d & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ d ] = link[ s ]; + return; + } + if ( last == s ) { + last = d; + link[ (int) ( link[ s ] >>> 32 )] ^= ( ( link[ (int) ( link[ s ] >>> 32 )] ^ ( d & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ d ] = link[ s ]; + return; + } + final long links = link[ s ]; + final int prev = (int) ( links >>> 32 ); + final int next = (int) links; + link[ prev ] ^= ( ( link[ prev ] ^ ( d & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( ( d & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ d ] = links; + } + /** Returns the first key of this map in iteration order. + * + * @return the first key in iteration order. + */ + public int firstIntKey() { + if ( size == 0 ) throw new NoSuchElementException(); + return key[ first ]; + } + /** Returns the last key of this map in iteration order. + * + * @return the last key in iteration order. + */ + public int lastIntKey() { + if ( size == 0 ) throw new NoSuchElementException(); + return key[ last ]; + } + public IntComparator comparator() { return null; } + public Int2ObjectSortedMap tailMap( int from ) { throw new UnsupportedOperationException(); } + public Int2ObjectSortedMap headMap( int to ) { throw new UnsupportedOperationException(); } + public Int2ObjectSortedMap subMap( int from, int to ) { throw new UnsupportedOperationException(); } + /** A list iterator over a linked map. + * + *

This class provides a list iterator over a linked hash map. The constructor runs in constant time. + */ + private class MapIterator { + /** The entry that will be returned by the next call to {@link java.util.ListIterator#previous()} (or null if no previous entry exists). */ + int prev = -1; + /** The entry that will be returned by the next call to {@link java.util.ListIterator#next()} (or null if no next entry exists). */ + int next = -1; + /** The last entry that was returned (or -1 if we did not iterate or used {@link java.util.Iterator#remove()}). */ + int curr = -1; + /** The current index (in the sense of a {@link java.util.ListIterator}). Note that this value is not meaningful when this iterator has been created using the nonempty constructor.*/ + int index = -1; + private MapIterator() { + next = first; + index = 0; + } + private MapIterator( final int from ) { + if ( ( (from) == (0) ) ) { + if ( Int2ObjectLinkedOpenHashMap.this.containsNullKey ) { + next = (int) link[ n ]; + prev = n; + return; + } + else throw new NoSuchElementException( "The key " + from + " does not belong to this map." ); + } + if ( ( (key[ last ]) == (from) ) ) { + prev = last; + index = size; + return; + } + // The starting point. + int pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (from) ) ) & mask; + // There's always an unused entry. + while( ! ( (key[ pos ]) == (0) ) ) { + if ( ( (key[ pos ]) == (from) ) ) { + // Note: no valid index known. + next = (int) link[ pos ]; + prev = pos; + return; + } + pos = ( pos + 1 ) & mask; + } + throw new NoSuchElementException( "The key " + from + " does not belong to this map." ); + } + public boolean hasNext() { return next != -1; } + public boolean hasPrevious() { return prev != -1; } + private final void ensureIndexKnown() { + if ( index >= 0 ) return; + if ( prev == -1 ) { + index = 0; + return; + } + if ( next == -1 ) { + index = size; + return; + } + int pos = first; + index = 1; + while( pos != prev ) { + pos = (int) link[ pos ]; + index++; + } + } + public int nextIndex() { + ensureIndexKnown(); + return index; + } + public int previousIndex() { + ensureIndexKnown(); + return index - 1; + } + public int nextEntry() { + if ( ! hasNext() ) throw new NoSuchElementException(); + curr = next; + next = (int) link[ curr ]; + prev = curr; + if ( index >= 0 ) index++; + return curr; + } + public int previousEntry() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + curr = prev; + prev = (int) ( link[ curr ] >>> 32 ); + next = curr; + if ( index >= 0 ) index--; + return curr; + } + public void remove() { + ensureIndexKnown(); + if ( curr == -1 ) throw new IllegalStateException(); + if ( curr == prev ) { + /* If the last operation was a next(), we are removing an entry that preceeds + the current index, and thus we must decrement it. */ + index--; + prev = (int) ( link[ curr ] >>> 32 ); + } + else + next = (int) link[ curr ]; + size--; + /* Now we manually fix the pointers. Because of our knowledge of next + and prev, this is going to be faster than calling fixPointers(). */ + if ( prev == -1 ) first = next; + else + link[ prev ] ^= ( ( link[ prev ] ^ ( next & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + if ( next == -1 ) last = prev; + else + link[ next ] ^= ( ( link[ next ] ^ ( ( prev & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + int last, slot, pos = curr; + curr = -1; + if ( pos == n ) { + Int2ObjectLinkedOpenHashMap.this.containsNullKey = false; + value[ n ] = null; + } + else { + int curr; + final int[] key = Int2ObjectLinkedOpenHashMap.this.key; + // We have to horribly duplicate the shiftKeys() code because we need to update next/prev. + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + value[ last ] = null; + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( (curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + value[ last ] = value[ pos ]; + if ( next == pos ) next = last; + if ( prev == pos ) prev = last; + fixPointers( pos, last ); + } + } + } + public int skip( final int n ) { + int i = n; + while( i-- != 0 && hasNext() ) nextEntry(); + return n - i - 1; + } + public int back( final int n ) { + int i = n; + while( i-- != 0 && hasPrevious() ) previousEntry(); + return n - i - 1; + } + } + private class EntryIterator extends MapIterator implements ObjectListIterator > { + private MapEntry entry; + public EntryIterator() {} + public EntryIterator( int from ) { + super( from ); + } + public MapEntry next() { + return entry = new MapEntry( nextEntry() ); + } + public MapEntry previous() { + return entry = new MapEntry( previousEntry() ); + } + @Override + public void remove() { + super.remove(); + entry.index = -1; // You cannot use a deleted entry. + } + public void set( Int2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + public void add( Int2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + } + private class FastEntryIterator extends MapIterator implements ObjectListIterator > { + final MapEntry entry = new MapEntry(); + public FastEntryIterator() {} + public FastEntryIterator( int from ) { + super( from ); + } + public MapEntry next() { + entry.index = nextEntry(); + return entry; + } + public MapEntry previous() { + entry.index = previousEntry(); + return entry; + } + public void set( Int2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + public void add( Int2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + } + private final class MapEntrySet extends AbstractObjectSortedSet > implements FastSortedEntrySet { + public ObjectBidirectionalIterator > iterator() { + return new EntryIterator(); + } + public Comparator > comparator() { return null; } + public ObjectSortedSet > subSet( Int2ObjectMap.Entry fromElement, Int2ObjectMap.Entry toElement) { throw new UnsupportedOperationException(); } + public ObjectSortedSet > headSet( Int2ObjectMap.Entry toElement ) { throw new UnsupportedOperationException(); } + public ObjectSortedSet > tailSet( Int2ObjectMap.Entry fromElement ) { throw new UnsupportedOperationException(); } + public Int2ObjectMap.Entry first() { + if ( size == 0 ) throw new NoSuchElementException(); + return new MapEntry( Int2ObjectLinkedOpenHashMap.this.first ); + } + public Int2ObjectMap.Entry last() { + if ( size == 0 ) throw new NoSuchElementException(); + return new MapEntry( Int2ObjectLinkedOpenHashMap.this.last ); + } + @SuppressWarnings("unchecked") + public boolean contains( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final int k = ((e.getKey()).intValue()); + if ( ( (k) == (0) ) ) return ( Int2ObjectLinkedOpenHashMap.this.containsNullKey && ( (value[ n ]) == null ? ((e.getValue())) == null : (value[ n ]).equals((e.getValue())) ) ); + int curr; + final int[] key = Int2ObjectLinkedOpenHashMap.this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return ( (value[ pos ]) == null ? ((e.getValue())) == null : (value[ pos ]).equals((e.getValue())) ); + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return ( (value[ pos ]) == null ? ((e.getValue())) == null : (value[ pos ]).equals((e.getValue())) ); + } + } + @SuppressWarnings("unchecked") + public boolean remove( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final int k = ((e.getKey()).intValue()); + final V v = (e.getValue()); + if ( ( (k) == (0) ) ) { + if ( containsNullKey && ( (value[ n ]) == null ? (v) == null : (value[ n ]).equals(v) ) ) { + removeNullEntry(); + return true; + } + return false; + } + int curr; + final int[] key = Int2ObjectLinkedOpenHashMap.this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return false; + if ( ( (curr) == (k) ) ) { + if ( ( (value[ pos ]) == null ? (v) == null : (value[ pos ]).equals(v) ) ) { + removeEntry( pos ); + return true; + } + return false; + } + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (curr) == (k) ) ) { + if ( ( (value[ pos ]) == null ? (v) == null : (value[ pos ]).equals(v) ) ) { + removeEntry( pos ); + return true; + } + } + } + } + public int size() { + return size; + } + public void clear() { + Int2ObjectLinkedOpenHashMap.this.clear(); + } + public ObjectBidirectionalIterator > iterator( final Int2ObjectMap.Entry from ) { + return new EntryIterator( from.getIntKey() ); + } + public ObjectBidirectionalIterator > fastIterator() { + return new FastEntryIterator(); + } + public ObjectBidirectionalIterator > fastIterator( final Int2ObjectMap.Entry from ) { + return new FastEntryIterator( from.getIntKey() ); + } + } + public FastSortedEntrySet int2ObjectEntrySet() { + if ( entries == null ) entries = new MapEntrySet(); + return entries; + } + /** An iterator on keys. + * + *

We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods + * (and possibly their type-specific counterparts) so that they return keys + * instead of entries. + */ + private final class KeyIterator extends MapIterator implements IntListIterator { + public KeyIterator( final int k ) { super( k ); } + public int previousInt() { return key[ previousEntry() ]; } + public void set( int k ) { throw new UnsupportedOperationException(); } + public void add( int k ) { throw new UnsupportedOperationException(); } + public Integer previous() { return (Integer.valueOf(key[ previousEntry() ])); } + public void set( Integer ok ) { throw new UnsupportedOperationException(); } + public void add( Integer ok ) { throw new UnsupportedOperationException(); } + public KeyIterator() { super(); } + public int nextInt() { return key[ nextEntry() ]; } + public Integer next() { return (Integer.valueOf(key[ nextEntry() ])); } + } + private final class KeySet extends AbstractIntSortedSet { + public IntListIterator iterator( final int from ) { + return new KeyIterator( from ); + } + public IntListIterator iterator() { + return new KeyIterator(); + } + public int size() { + return size; + } + public boolean contains( int k ) { + return containsKey( k ); + } + public boolean remove( int k ) { + final int oldSize = size; + Int2ObjectLinkedOpenHashMap.this.remove( k ); + return size != oldSize; + } + public void clear() { + Int2ObjectLinkedOpenHashMap.this.clear(); + } + public int firstInt() { + if ( size == 0 ) throw new NoSuchElementException(); + return key[ first ]; + } + public int lastInt() { + if ( size == 0 ) throw new NoSuchElementException(); + return key[ last ]; + } + public IntComparator comparator() { return null; } + final public IntSortedSet tailSet( int from ) { throw new UnsupportedOperationException(); } + final public IntSortedSet headSet( int to ) { throw new UnsupportedOperationException(); } + final public IntSortedSet subSet( int from, int to ) { throw new UnsupportedOperationException(); } + } + public IntSortedSet keySet() { + if ( keys == null ) keys = new KeySet(); + return keys; + } + /** An iterator on values. + * + *

We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods + * (and possibly their type-specific counterparts) so that they return values + * instead of entries. + */ + private final class ValueIterator extends MapIterator implements ObjectListIterator { + public V previous() { return value[ previousEntry() ]; } + public void set( V v ) { throw new UnsupportedOperationException(); } + public void add( V v ) { throw new UnsupportedOperationException(); } + public ValueIterator() { super(); } + public V next() { return value[ nextEntry() ]; } + } + public ObjectCollection values() { + if ( values == null ) values = new AbstractObjectCollection () { + public ObjectIterator iterator() { + return new ValueIterator(); + } + public int size() { + return size; + } + public boolean contains( Object v ) { + return containsValue( v ); + } + public void clear() { + Int2ObjectLinkedOpenHashMap.this.clear(); + } + }; + return values; + } + /** A no-op for backward compatibility. The kind of tables implemented by + * this class never need rehashing. + * + *

If you need to reduce the table size to fit exactly + * this set, use {@link #trim()}. + * + * @return true. + * @see #trim() + * @deprecated A no-op. + */ + @Deprecated + public boolean rehash() { + return true; + } + /** Rehashes the map, making the table as small as possible. + * + *

This method rehashes the table to the smallest size satisfying the + * load factor. It can be used when the set will not be changed anymore, so + * to optimize access speed and size. + * + *

If the table size is already the minimum possible, this method + * does nothing. + * + * @return true if there was enough memory to trim the map. + * @see #trim(int) + */ + public boolean trim() { + final int l = arraySize( size, f ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch(OutOfMemoryError cantDoIt) { return false; } + return true; + } + /** Rehashes this map if the table is too large. + * + *

Let N be the smallest table size that can hold + * max(n,{@link #size()}) entries, still satisfying the load factor. If the current + * table size is smaller than or equal to N, this method does + * nothing. Otherwise, it rehashes this map in a table of size + * N. + * + *

This method is useful when reusing maps. {@linkplain #clear() Clearing a + * map} leaves the table size untouched. If you are reusing a map + * many times, you can call this method with a typical + * size to avoid keeping around a very large table just + * because of a few large transient maps. + * + * @param n the threshold for the trimming. + * @return true if there was enough memory to trim the map. + * @see #trim() + */ + public boolean trim( final int n ) { + final int l = HashCommon.nextPowerOfTwo( (int)Math.ceil( n / f ) ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch( OutOfMemoryError cantDoIt ) { return false; } + return true; + } + /** Rehashes the map. + * + *

This method implements the basic rehashing strategy, and may be + * overriden by subclasses implementing different rehashing strategies (e.g., + * disk-based rehashing). However, you should not override this method + * unless you understand the internal workings of this class. + * + * @param newN the new size + */ + @SuppressWarnings("unchecked") + protected void rehash( final int newN ) { + final int key[] = this.key; + final V value[] = this.value; + final int mask = newN - 1; // Note that this is used by the hashing macro + final int newKey[] = new int[ newN + 1 ]; + final V newValue[] = (V[]) new Object[ newN + 1 ]; + int i = first, prev = -1, newPrev = -1, t, pos; + final long link[] = this.link; + final long newLink[] = new long[ newN + 1 ]; + first = -1; + for( int j = size; j-- != 0; ) { + if ( ( (key[ i ]) == (0) ) ) pos = newN; + else { + pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (key[ i ]) ) ) & mask; + while ( ! ( (newKey[ pos ]) == (0) ) ) pos = ( pos + 1 ) & mask; + } + newKey[ pos ] = key[ i ]; + newValue[ pos ] = value[ i ]; + if ( prev != -1 ) { + newLink[ newPrev ] ^= ( ( newLink[ newPrev ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + newLink[ pos ] ^= ( ( newLink[ pos ] ^ ( ( newPrev & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + newPrev = pos; + } + else { + newPrev = first = pos; + // Special case of SET(newLink[ pos ], -1, -1); + newLink[ pos ] = -1L; + } + t = i; + i = (int) link[ i ]; + prev = t; + } + this.link = newLink; + this.last = newPrev; + if ( newPrev != -1 ) + // Special case of SET_NEXT( newLink[ newPrev ], -1 ); + newLink[ newPrev ] |= -1 & 0xFFFFFFFFL; + n = newN; + this.mask = mask; + maxFill = maxFill( n, f ); + this.key = newKey; + this.value = newValue; + } + /** Returns a deep copy of this map. + * + *

This method performs a deep copy of this hash map; the data stored in the + * map, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this map. + */ + @SuppressWarnings("unchecked") + public Int2ObjectLinkedOpenHashMap clone() { + Int2ObjectLinkedOpenHashMap c; + try { + c = (Int2ObjectLinkedOpenHashMap )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.keys = null; + c.values = null; + c.entries = null; + c.containsNullKey = containsNullKey; + c.key = key.clone(); + c.value = value.clone(); + c.link = link.clone(); + return c; + } + /** Returns a hash code for this map. + * + * This method overrides the generic method provided by the superclass. + * Since equals() is not overriden, it is important + * that the value returned by this method is the same value as + * the one returned by the overriden method. + * + * @return a hash code for this map. + */ + public int hashCode() { + int h = 0; + for( int j = realSize(), i = 0, t = 0; j-- != 0; ) { + while( ( (key[ i ]) == (0) ) ) i++; + t = (key[ i ]); + if ( this != value[ i ] ) + t ^= ( (value[ i ]) == null ? 0 : (value[ i ]).hashCode() ); + h += t; + i++; + } + // Zero / null keys have hash zero. + if ( containsNullKey ) h += ( (value[ n ]) == null ? 0 : (value[ n ]).hashCode() ); + return h; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + final int key[] = this.key; + final V value[] = this.value; + final MapIterator i = new MapIterator(); + s.defaultWriteObject(); + for( int j = size, e; j-- != 0; ) { + e = i.nextEntry(); + s.writeInt( key[ e ] ); + s.writeObject( value[ e ] ); + } + } + @SuppressWarnings("unchecked") + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + n = arraySize( size, f ); + maxFill = maxFill( n, f ); + mask = n - 1; + final int key[] = this.key = new int[ n + 1 ]; + final V value[] = this.value = (V[]) new Object[ n + 1 ]; + final long link[] = this.link = new long[ n + 1 ]; + int prev = -1; + first = last = -1; + int k; + V v; + for( int i = size, pos; i-- != 0; ) { + k = s.readInt(); + v = (V) s.readObject(); + if ( ( (k) == (0) ) ) { + pos = n; + containsNullKey = true; + } + else { + pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask; + while ( ! ( (key[ pos ]) == (0) ) ) pos = ( pos + 1 ) & mask; + } + key[ pos ] = k; + value[ pos ] = v; + if ( first != -1 ) { + link[ prev ] ^= ( ( link[ prev ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ pos ] ^= ( ( link[ pos ] ^ ( ( prev & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + prev = pos; + } + else { + prev = first = pos; + // Special case of SET_PREV( newLink[ pos ], -1 ); + link[ pos ] |= (-1L & 0xFFFFFFFFL) << 32; + } + } + last = prev; + if ( prev != -1 ) + // Special case of SET_NEXT( link[ prev ], -1 ); + link[ prev ] |= -1 & 0xFFFFFFFFL; + if ( ASSERTS ) checkTable(); + } + private void checkTable() {} +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectMap.java b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectMap.java new file mode 100644 index 0000000..b0cba54 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectMap.java @@ -0,0 +1,151 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectSet; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import java.util.Map; +/** A type-specific {@link Map}; provides some additional methods that use polymorphism to avoid (un)boxing, and handling of a default return value. + * + *

Besides extending the corresponding type-specific {@linkplain it.unimi.dsi.fastutil.Function function}, this interface strengthens {@link #entrySet()}, + * {@link #keySet()} and {@link #values()}. Maps returning entry sets of type {@link FastEntrySet} support also fast iteration. + * + *

A submap or subset may or may not have an + * independent default return value (which however must be initialized to the + * default return value of the originator). + * + * @see Map + */ +public interface Int2ObjectMap extends Int2ObjectFunction , Map { + /** An entry set providing fast iteration. + * + *

In some cases (e.g., hash-based classes) iteration over an entry set requires the creation + * of a large number of {@link java.util.Map.Entry} objects. Some fastutil + * maps might return {@linkplain #entrySet() entry set} objects of type FastEntrySet: in this case, {@link #fastIterator() fastIterator()} + * will return an iterator that is guaranteed not to create a large number of objects, possibly + * by returning always the same entry (of course, mutated). + */ + public interface FastEntrySet extends ObjectSet > { + /** Returns a fast iterator over this entry set; the iterator might return always the same entry object, suitably mutated. + * + * @return a fast iterator over this entry set; the iterator might return always the same {@link java.util.Map.Entry} object, suitably mutated. + */ + public ObjectIterator > fastIterator(); + } + /** Returns a set view of the mappings contained in this map. + *

Note that this specification strengthens the one given in {@link Map#entrySet()}. + * + * @return a set view of the mappings contained in this map. + * @see Map#entrySet() + */ + ObjectSet> entrySet(); + /** Returns a type-specific set view of the mappings contained in this map. + * + *

This method is necessary because there is no inheritance along + * type parameters: it is thus impossible to strengthen {@link #entrySet()} + * so that it returns an {@link it.unimi.dsi.fastutil.objects.ObjectSet} + * of type-specific entries (the latter makes it possible to + * access keys and values with type-specific methods). + * + * @return a type-specific set view of the mappings contained in this map. + * @see #entrySet() + */ + ObjectSet > int2ObjectEntrySet(); + /** Returns a set view of the keys contained in this map. + *

Note that this specification strengthens the one given in {@link Map#keySet()}. + * + * @return a set view of the keys contained in this map. + * @see Map#keySet() + */ + IntSet keySet(); + /** Returns a set view of the values contained in this map. + *

Note that this specification strengthens the one given in {@link Map#values()}. + * + * @return a set view of the values contained in this map. + * @see Map#values() + */ + ObjectCollection values(); + /** A type-specific {@link java.util.Map.Entry}; provides some additional methods + * that use polymorphism to avoid (un)boxing. + * + * @see java.util.Map.Entry + */ + interface Entry extends Map.Entry { + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + Integer getKey(); + /** + * @see java.util.Map.Entry#getKey() + */ + int getIntKey(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectMaps.java b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectMaps.java new file mode 100644 index 0000000..2c0741e --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectMaps.java @@ -0,0 +1,312 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.objects.ObjectSet; +import it.unimi.dsi.fastutil.objects.ObjectSets; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectCollections; +import java.util.Map; +/** A class providing static methods and objects that do useful things with type-specific maps. + * + * @see it.unimi.dsi.fastutil.Maps + * @see java.util.Collections + */ +public class Int2ObjectMaps { + private Int2ObjectMaps() {} + /** An immutable class representing an empty type-specific map. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific map. + */ + public static class EmptyMap extends Int2ObjectFunctions.EmptyFunction implements Int2ObjectMap , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptyMap() {} + public boolean containsValue( final Object v ) { return false; } + public void putAll( final Map m ) { throw new UnsupportedOperationException(); } + @SuppressWarnings("unchecked") + public ObjectSet > int2ObjectEntrySet() { return ObjectSets.EMPTY_SET; } + + public IntSet keySet() { return IntSets.EMPTY_SET; } + @SuppressWarnings("unchecked") + public ObjectCollection values() { return ObjectSets.EMPTY_SET; } + private Object readResolve() { return EMPTY_MAP; } + public Object clone() { return EMPTY_MAP; } + public boolean isEmpty() { return true; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + public ObjectSet> entrySet() { return (ObjectSet)int2ObjectEntrySet(); } + public int hashCode() { return 0; } + public boolean equals( final Object o ) { + if ( ! ( o instanceof Map ) ) return false; + return ((Map)o).isEmpty(); + } + public String toString() { return "{}"; } + } + /** An empty type-specific map (immutable). It is serializable and cloneable. + */ + @SuppressWarnings("rawtypes") + public static final EmptyMap EMPTY_MAP = new EmptyMap(); + /** Return an empty map (immutable). It is serializable and cloneable. + * + *

This method provides a typesafe access to {@link #EMPTY_MAP}. + * @return an empty map (immutable). + */ + @SuppressWarnings("unchecked") + public static Int2ObjectMap emptyMap() { + return EMPTY_MAP; + } + /** An immutable class representing a type-specific singleton map. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific map. + */ + public static class Singleton extends Int2ObjectFunctions.Singleton implements Int2ObjectMap , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected transient ObjectSet > entries; + protected transient IntSet keys; + protected transient ObjectCollection values; + protected Singleton( final int key, final V value ) { + super( key, value ); + } + public boolean containsValue( final Object v ) { return ( (value) == null ? (v) == null : (value).equals(v) ); } + public void putAll( final Map m ) { throw new UnsupportedOperationException(); } + public ObjectSet > int2ObjectEntrySet() { if ( entries == null ) entries = ObjectSets.singleton( (Int2ObjectMap.Entry )new SingletonEntry() ); return entries; } + public IntSet keySet() { if ( keys == null ) keys = IntSets.singleton( key ); return keys; } + public ObjectCollection values() { if ( values == null ) values = ObjectSets.singleton( value ); return values; } + protected class SingletonEntry implements Int2ObjectMap.Entry , Map.Entry { + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer getKey() { return (Integer.valueOf(Singleton.this.key)); } + public V getValue() { return (Singleton.this.value); } + public int getIntKey() { return Singleton.this.key; } + public V setValue( final V value ) { throw new UnsupportedOperationException(); } + public boolean equals( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + Map.Entry e = (Map.Entry)o; + return ( (Singleton.this.key) == (((((Integer)(e.getKey())).intValue()))) ) && ( (Singleton.this.value) == null ? ((e.getValue())) == null : (Singleton.this.value).equals((e.getValue())) ); + } + public int hashCode() { return (Singleton.this.key) ^ ( (Singleton.this.value) == null ? 0 : (Singleton.this.value).hashCode() ); } + public String toString() { return Singleton.this.key + "->" + Singleton.this.value; } + } + public boolean isEmpty() { return false; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + public ObjectSet> entrySet() { return (ObjectSet)int2ObjectEntrySet(); } + public int hashCode() { return (key) ^ ( (value) == null ? 0 : (value).hashCode() ); } + public boolean equals( final Object o ) { + if ( o == this ) return true; + if ( ! ( o instanceof Map ) ) return false; + Map m = (Map)o; + if ( m.size() != 1 ) return false; + return entrySet().iterator().next().equals( m.entrySet().iterator().next() ); + } + public String toString() { return "{" + key + "=>" + value + "}"; } + } + /** Returns a type-specific immutable map containing only the specified pair. The returned map is serializable and cloneable. + * + *

Note that albeit the returned map is immutable, its default return value may be changed. + * + * @param key the only key of the returned map. + * @param value the only value of the returned map. + * @return a type-specific immutable map containing just the pair <key,value>. + */ + public static Int2ObjectMap singleton( final int key, V value ) { + return new Singleton ( key, value ); + } + /** Returns a type-specific immutable map containing only the specified pair. The returned map is serializable and cloneable. + * + *

Note that albeit the returned map is immutable, its default return value may be changed. + * + * @param key the only key of the returned map. + * @param value the only value of the returned map. + * @return a type-specific immutable map containing just the pair <key,value>. + */ + public static Int2ObjectMap singleton( final Integer key, final V value ) { + return new Singleton ( ((key).intValue()), (value) ); + } + /** A synchronized wrapper class for maps. */ + public static class SynchronizedMap extends Int2ObjectFunctions.SynchronizedFunction implements Int2ObjectMap , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final Int2ObjectMap map; + protected transient ObjectSet > entries; + protected transient IntSet keys; + protected transient ObjectCollection values; + protected SynchronizedMap( final Int2ObjectMap m, final Object sync ) { + super( m, sync ); + this.map = m; + } + protected SynchronizedMap( final Int2ObjectMap m ) { + super( m ); + this.map = m; + } + public int size() { synchronized( sync ) { return map.size(); } } + public boolean containsKey( final int k ) { synchronized( sync ) { return map.containsKey( k ); } } + public boolean containsValue( final Object v ) { synchronized( sync ) { return map.containsValue( v ); } } + public V defaultReturnValue() { synchronized( sync ) { return map.defaultReturnValue(); } } + public void defaultReturnValue( final V defRetValue ) { synchronized( sync ) { map.defaultReturnValue( defRetValue ); } } + public V put( final int k, final V v ) { synchronized( sync ) { return map.put( k, v ); } } + //public void putAll( final MAP KEY_VALUE_EXTENDS_GENERIC c ) { synchronized( sync ) { map.putAll( c ); } } + public void putAll( final Map m ) { synchronized( sync ) { map.putAll( m ); } } + public ObjectSet > int2ObjectEntrySet() { if ( entries == null ) entries = ObjectSets.synchronize( map.int2ObjectEntrySet(), sync ); return entries; } + public IntSet keySet() { if ( keys == null ) keys = IntSets.synchronize( map.keySet(), sync ); return keys; } + public ObjectCollection values() { if ( values == null ) return ObjectCollections.synchronize( map.values(), sync ); return values; } + public void clear() { synchronized( sync ) { map.clear(); } } + public String toString() { synchronized( sync ) { return map.toString(); } } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Integer k, final V v ) { synchronized( sync ) { return map.put( k, v ); } } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V remove( final int k ) { synchronized( sync ) { return map.remove( k ); } } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V get( final int k ) { synchronized( sync ) { return map.get( k ); } } + public boolean containsKey( final Object ok ) { synchronized( sync ) { return map.containsKey( ok ); } } + public boolean isEmpty() { synchronized( sync ) { return map.isEmpty(); } } + public ObjectSet> entrySet() { synchronized( sync ) { return map.entrySet(); } } + public int hashCode() { synchronized( sync ) { return map.hashCode(); } } + public boolean equals( final Object o ) { synchronized( sync ) { return map.equals( o ); } } + } + /** Returns a synchronized type-specific map backed by the given type-specific map. + * + * @param m the map to be wrapped in a synchronized map. + * @return a synchronized view of the specified map. + * @see java.util.Collections#synchronizedMap(Map) + */ + public static Int2ObjectMap synchronize( final Int2ObjectMap m ) { return new SynchronizedMap ( m ); } + /** Returns a synchronized type-specific map backed by the given type-specific map, using an assigned object to synchronize. + * + * @param m the map to be wrapped in a synchronized map. + * @param sync an object that will be used to synchronize the access to the map. + * @return a synchronized view of the specified map. + * @see java.util.Collections#synchronizedMap(Map) + */ + public static Int2ObjectMap synchronize( final Int2ObjectMap m, final Object sync ) { return new SynchronizedMap ( m, sync ); } + /** An unmodifiable wrapper class for maps. */ + public static class UnmodifiableMap extends Int2ObjectFunctions.UnmodifiableFunction implements Int2ObjectMap , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final Int2ObjectMap map; + protected transient ObjectSet > entries; + protected transient IntSet keys; + protected transient ObjectCollection values; + protected UnmodifiableMap( final Int2ObjectMap m ) { + super( m ); + this.map = m; + } + public int size() { return map.size(); } + public boolean containsKey( final int k ) { return map.containsKey( k ); } + public boolean containsValue( final Object v ) { return map.containsValue( v ); } + public V defaultReturnValue() { throw new UnsupportedOperationException(); } + public void defaultReturnValue( final V defRetValue ) { throw new UnsupportedOperationException(); } + public V put( final int k, final V v ) { throw new UnsupportedOperationException(); } + //public void putAll( final MAP KEY_VALUE_EXTENDS_GENERIC c ) { throw new UnsupportedOperationException(); } + public void putAll( final Map m ) { throw new UnsupportedOperationException(); } + public ObjectSet > int2ObjectEntrySet() { if ( entries == null ) entries = ObjectSets.unmodifiable( map.int2ObjectEntrySet() ); return entries; } + public IntSet keySet() { if ( keys == null ) keys = IntSets.unmodifiable( map.keySet() ); return keys; } + public ObjectCollection values() { if ( values == null ) return ObjectCollections.unmodifiable( map.values() ); return values; } + public void clear() { throw new UnsupportedOperationException(); } + public String toString() { return map.toString(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V remove( final int k ) { throw new UnsupportedOperationException(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V get( final int k ) { return map.get( k ); } + public boolean containsKey( final Object ok ) { return map.containsKey( ok ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V remove( final Object k ) { throw new UnsupportedOperationException(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V get( final Object k ) { return map.get( k ); } + public boolean isEmpty() { return map.isEmpty(); } + public ObjectSet> entrySet() { return ObjectSets.unmodifiable( map.entrySet() ); } + } + /** Returns an unmodifiable type-specific map backed by the given type-specific map. + * + * @param m the map to be wrapped in an unmodifiable map. + * @return an unmodifiable view of the specified map. + * @see java.util.Collections#unmodifiableMap(Map) + */ + public static Int2ObjectMap unmodifiable( final Int2ObjectMap m ) { return new UnmodifiableMap ( m ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectOpenCustomHashMap.java b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectOpenCustomHashMap.java new file mode 100644 index 0000000..49bebcb --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectOpenCustomHashMap.java @@ -0,0 +1,922 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.HashCommon; +import static it.unimi.dsi.fastutil.HashCommon.arraySize; +import static it.unimi.dsi.fastutil.HashCommon.maxFill; +import java.util.Map; +import java.util.Arrays; +import java.util.NoSuchElementException; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.AbstractObjectSet; +/** A type-specific hash map with a fast, small-footprint implementation whose {@linkplain it.unimi.dsi.fastutil.Hash.Strategy hashing strategy} + * is specified at creation time. + * + *

Instances of this class use a hash table to represent a map. The table is + * filled up to a specified load factor, and then doubled in size to + * accommodate new entries. If the table is emptied below one fourth + * of the load factor, it is halved in size. However, halving is + * not performed when deleting entries from an iterator, as it would interfere + * with the iteration process. + * + *

Note that {@link #clear()} does not modify the hash table size. + * Rather, a family of {@linkplain #trim() trimming + * methods} lets you control the size of the table; this is particularly useful + * if you reuse instances of this class. + * + * @see Hash + * @see HashCommon + */ +public class Int2ObjectOpenCustomHashMap extends AbstractInt2ObjectMap implements java.io.Serializable, Cloneable, Hash { + private static final long serialVersionUID = 0L; + private static final boolean ASSERTS = false; + /** The array of keys. */ + protected transient int[] key; + /** The array of values. */ + protected transient V[] value; + /** The mask for wrapping a position counter. */ + protected transient int mask; + /** Whether this set contains the key zero. */ + protected transient boolean containsNullKey; + /** The hash strategy of this custom map. */ + protected it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy; + /** The current table size. */ + protected transient int n; + /** Threshold after which we rehash. It must be the table size times {@link #f}. */ + protected transient int maxFill; + /** Number of entries in the set (including the key zero, if present). */ + protected int size; + /** The acceptable load factor. */ + protected final float f; + /** Cached set of entries. */ + protected transient FastEntrySet entries; + /** Cached set of keys. */ + protected transient IntSet keys; + /** Cached collection of values. */ + protected transient ObjectCollection values; + /** Creates a new hash map. + * + *

The actual table size will be the least power of two greater than expected/f. + * + * @param expected the expected number of elements in the hash set. + * @param f the load factor. + * @param strategy the strategy. + */ + @SuppressWarnings("unchecked") + public Int2ObjectOpenCustomHashMap( final int expected, final float f, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this.strategy = strategy; + if ( f <= 0 || f > 1 ) throw new IllegalArgumentException( "Load factor must be greater than 0 and smaller than or equal to 1" ); + if ( expected < 0 ) throw new IllegalArgumentException( "The expected number of elements must be nonnegative" ); + this.f = f; + n = arraySize( expected, f ); + mask = n - 1; + maxFill = maxFill( n, f ); + key = new int[ n + 1 ]; + value = (V[]) new Object[ n + 1 ]; + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * + * @param expected the expected number of elements in the hash map. + * @param strategy the strategy. + */ + public Int2ObjectOpenCustomHashMap( final int expected, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( expected, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash map with initial expected {@link Hash#DEFAULT_INITIAL_SIZE} entries + * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * @param strategy the strategy. + */ + public Int2ObjectOpenCustomHashMap( final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash map copying a given one. + * + * @param m a {@link Map} to be copied into the new hash map. + * @param f the load factor. + * @param strategy the strategy. + */ + public Int2ObjectOpenCustomHashMap( final Map m, final float f, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( m.size(), f, strategy ); + putAll( m ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given one. + * + * @param m a {@link Map} to be copied into the new hash map. + * @param strategy the strategy. + */ + public Int2ObjectOpenCustomHashMap( final Map m, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( m, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash map copying a given type-specific one. + * + * @param m a type-specific map to be copied into the new hash map. + * @param f the load factor. + * @param strategy the strategy. + */ + public Int2ObjectOpenCustomHashMap( final Int2ObjectMap m, final float f, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( m.size(), f, strategy ); + putAll( m ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given type-specific one. + * + * @param m a type-specific map to be copied into the new hash map. + * @param strategy the strategy. + */ + public Int2ObjectOpenCustomHashMap( final Int2ObjectMap m, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( m, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash map using the elements of two parallel arrays. + * + * @param k the array of keys of the new hash map. + * @param v the array of corresponding values in the new hash map. + * @param f the load factor. + * @param strategy the strategy. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Int2ObjectOpenCustomHashMap( final int[] k, final V[] v, final float f, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( k.length, f, strategy ); + if ( k.length != v.length ) throw new IllegalArgumentException( "The key array and the value array have different lengths (" + k.length + " and " + v.length + ")" ); + for( int i = 0; i < k.length; i++ ) this.put( k[ i ], v[ i ] ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using the elements of two parallel arrays. + * + * @param k the array of keys of the new hash map. + * @param v the array of corresponding values in the new hash map. + * @param strategy the strategy. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Int2ObjectOpenCustomHashMap( final int[] k, final V[] v, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( k, v, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Returns the hashing strategy. + * + * @return the hashing strategy of this custom hash map. + */ + public it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy() { + return strategy; + } + private int realSize() { + return containsNullKey ? size - 1 : size; + } + private void ensureCapacity( final int capacity ) { + final int needed = arraySize( capacity, f ); + if ( needed > n ) rehash( needed ); + } + private void tryCapacity( final long capacity ) { + final int needed = (int)Math.min( 1 << 30, Math.max( 2, HashCommon.nextPowerOfTwo( (long)Math.ceil( capacity / f ) ) ) ); + if ( needed > n ) rehash( needed ); + } + private V removeEntry( final int pos ) { + final V oldValue = value[ pos ]; + value[ pos ] = null; + size--; + shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return oldValue; + } + private V removeNullEntry() { + containsNullKey = false; + final V oldValue = value[ n ]; + value[ n ] = null; + size--; + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return oldValue; + } + /** {@inheritDoc} */ + public void putAll(Map m) { + if ( f <= .5 ) ensureCapacity( m.size() ); // The resulting map will be sized for m.size() elements + else tryCapacity( size() + m.size() ); // The resulting map will be tentatively sized for size() + m.size() elements + super.putAll( m ); + } + private int insert(final int k, final V v) { + int pos; + if ( ( strategy.equals( (k), (0) ) ) ) { + if ( containsNullKey ) return n; + containsNullKey = true; + pos = n; + } + else { + int curr; + final int[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) { + if ( ( strategy.equals( (curr), (k) ) ) ) return pos; + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( strategy.equals( (curr), (k) ) ) ) return pos; + } + } + key[ pos ] = k; + value[ pos ] = v; + if ( size++ >= maxFill ) rehash( arraySize( size + 1, f ) ); + if ( ASSERTS ) checkTable(); + return -1; + } + public V put(final int k, final V v) { + final int pos = insert( k, v ); + if ( pos < 0 ) return defRetValue; + final V oldValue = value[ pos ]; + value[ pos ] = v; + return oldValue; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Integer ok, final V ov ) { + final V v = (ov); + final int pos = insert( ((ok).intValue()), v ); + if ( pos < 0 ) return (this.defRetValue); + final V oldValue = value[ pos ]; + value[ pos ] = v; + return (oldValue); + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + protected final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + int curr; + final int[] key = this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + value[ last ] = null; + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + value[ last ] = value[ pos ]; + } + } + + public V remove( final int k ) { + if ( ( strategy.equals( ( k), (0) ) ) ) { + if ( containsNullKey ) return removeNullEntry(); + return defRetValue; + } + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( strategy.equals( (k), (curr) ) ) ) return removeEntry( pos ); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( strategy.equals( (k), (curr) ) ) ) return removeEntry( pos ); + } + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + + public V remove( final Object ok ) { + final int k = ((((Integer)(ok)).intValue())); + if ( ( strategy.equals( (k), (0) ) ) ) { + if ( containsNullKey ) return (removeNullEntry()); + return (this.defRetValue); + } + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( strategy.equals( (curr), (k) ) ) ) return (removeEntry( pos )); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( strategy.equals( (curr), (k) ) ) ) return (removeEntry( pos )); + } + } + /** @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public V get( final Integer ok ) { + if ( ok == null ) return null; + final int k = ((ok).intValue()); + if ( ( strategy.equals( (k), (0) ) ) ) return containsNullKey ? (value[ n ]) : (this.defRetValue); + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( strategy.equals( (k), (curr) ) ) ) return (value[ pos ]); + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( strategy.equals( (k), (curr) ) ) ) return (value[ pos ]); + } + } + + public V get( final int k ) { + if ( ( strategy.equals( ( k), (0) ) ) ) return containsNullKey ? value[ n ] : defRetValue; + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( strategy.equals( (k), (curr) ) ) ) return value[ pos ]; + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( strategy.equals( (k), (curr) ) ) ) return value[ pos ]; + } + } + + public boolean containsKey( final int k ) { + if ( ( strategy.equals( ( k), (0) ) ) ) return containsNullKey; + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return true; + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return true; + } + } + public boolean containsValue( final Object v ) { + final V value[] = this.value; + final int key[] = this.key; + if ( containsNullKey && ( (value[ n ]) == null ? (v) == null : (value[ n ]).equals(v) ) ) return true; + for( int i = n; i-- != 0; ) if ( ! ( (key[ i ]) == (0) ) && ( (value[ i ]) == null ? (v) == null : (value[ i ]).equals(v) ) ) return true; + return false; + } + /* Removes all elements from this map. + * + *

To increase object reuse, this method does not change the table size. + * If you want to reduce the table size, you must use {@link #trim()}. + * + */ + public void clear() { + if ( size == 0 ) return; + size = 0; + containsNullKey = false; + Arrays.fill( key, (0) ); + Arrays.fill( value, null ); + } + public int size() { + return size; + } + public boolean isEmpty() { + return size == 0; + } + /** A no-op for backward compatibility. + * + * @param growthFactor unused. + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public void growthFactor( int growthFactor ) {} + /** Gets the growth factor (2). + * + * @return the growth factor of this set, which is fixed (2). + * @see #growthFactor(int) + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public int growthFactor() { + return 16; + } + /** The entry class for a hash map does not record key and value, but + * rather the position in the hash table of the corresponding entry. This + * is necessary so that calls to {@link java.util.Map.Entry#setValue(Object)} are reflected in + * the map */ + final class MapEntry implements Int2ObjectMap.Entry , Map.Entry { + // The table index this entry refers to, or -1 if this entry has been deleted. + int index; + MapEntry( final int index ) { + this.index = index; + } + MapEntry() {} + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer getKey() { + return (Integer.valueOf(key[ index ])); + } + public int getIntKey() { + return key[ index ]; + } + public V getValue() { + return (value[ index ]); + } + public V setValue( final V v ) { + final V oldValue = value[ index ]; + value[ index ] = v; + return oldValue; + } + @SuppressWarnings("unchecked") + public boolean equals( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + Map.Entry e = (Map.Entry)o; + return ( strategy.equals( (key[ index ]), (((e.getKey()).intValue())) ) ) && ( (value[ index ]) == null ? ((e.getValue())) == null : (value[ index ]).equals((e.getValue())) ); + } + public int hashCode() { + return ( strategy.hashCode(key[ index ]) ) ^ ( (value[ index ]) == null ? 0 : (value[ index ]).hashCode() ); + } + public String toString() { + return key[ index ] + "=>" + value[ index ]; + } + } + /** An iterator over a hash map. */ + private class MapIterator { + /** The index of the last entry returned, if positive or zero; initially, {@link #n}. If negative, the last + entry returned was that of the key of index {@code - pos - 1} from the {@link #wrapped} list. */ + int pos = n; + /** The index of the last entry that has been returned (more precisely, the value of {@link #pos} if {@link #pos} is positive, + or {@link Integer#MIN_VALUE} if {@link #pos} is negative). It is -1 if either + we did not return an entry yet, or the last returned entry has been removed. */ + int last = -1; + /** A downward counter measuring how many entries must still be returned. */ + int c = size; + /** A boolean telling us whether we should return the entry with the null key. */ + boolean mustReturnNullKey = Int2ObjectOpenCustomHashMap.this.containsNullKey; + /** A lazily allocated list containing keys of entries that have wrapped around the table because of removals. */ + IntArrayList wrapped; + public boolean hasNext() { + return c != 0; + } + public int nextEntry() { + if ( ! hasNext() ) throw new NoSuchElementException(); + c--; + if ( mustReturnNullKey ) { + mustReturnNullKey = false; + return last = n; + } + final int key[] = Int2ObjectOpenCustomHashMap.this.key; + for(;;) { + if ( --pos < 0 ) { + // We are just enumerating elements from the wrapped list. + last = Integer.MIN_VALUE; + final int k = wrapped.getInt( - pos - 1 ); + int p = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask; + while ( ! ( strategy.equals( (k), (key[ p ]) ) ) ) p = ( p + 1 ) & mask; + return p; + } + if ( ! ( (key[ pos ]) == (0) ) ) return last = pos; + } + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + private final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + int curr; + final int[] key = Int2ObjectOpenCustomHashMap.this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + value[ last ] = null; + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + if ( pos < last ) { // Wrapped entry. + if ( wrapped == null ) wrapped = new IntArrayList ( 2 ); + wrapped.add( key[ pos ] ); + } + key[ last ] = curr; + value[ last ] = value[ pos ]; + } + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + if ( last == n ) { + containsNullKey = false; + value[ n ] = null; + } + else if ( pos >= 0 ) shiftKeys( last ); + else { + // We're removing wrapped entries. + Int2ObjectOpenCustomHashMap.this.remove( wrapped.getInt( - pos - 1 ) ); + last = -1; // Note that we must not decrement size + return; + } + size--; + last = -1; // You can no longer remove this entry. + if ( ASSERTS ) checkTable(); + } + public int skip( final int n ) { + int i = n; + while( i-- != 0 && hasNext() ) nextEntry(); + return n - i - 1; + } + } + private class EntryIterator extends MapIterator implements ObjectIterator > { + private MapEntry entry; + public Int2ObjectMap.Entry next() { + return entry = new MapEntry( nextEntry() ); + } + @Override + public void remove() { + super.remove(); + entry.index = -1; // You cannot use a deleted entry. + } + } + private class FastEntryIterator extends MapIterator implements ObjectIterator > { + private final MapEntry entry = new MapEntry(); + public MapEntry next() { + entry.index = nextEntry(); + return entry; + } + } + private final class MapEntrySet extends AbstractObjectSet > implements FastEntrySet { + public ObjectIterator > iterator() { + return new EntryIterator(); + } + public ObjectIterator > fastIterator() { + return new FastEntryIterator(); + } + @SuppressWarnings("unchecked") + public boolean contains( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final int k = ((e.getKey()).intValue()); + if ( ( strategy.equals( (k), (0) ) ) ) return ( Int2ObjectOpenCustomHashMap.this.containsNullKey && ( (value[ n ]) == null ? ((e.getValue())) == null : (value[ n ]).equals((e.getValue())) ) ); + int curr; + final int[] key = Int2ObjectOpenCustomHashMap.this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return ( (value[ pos ]) == null ? ((e.getValue())) == null : (value[ pos ]).equals((e.getValue())) ); + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return ( (value[ pos ]) == null ? ((e.getValue())) == null : (value[ pos ]).equals((e.getValue())) ); + } + } + @SuppressWarnings("unchecked") + public boolean remove( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final int k = ((e.getKey()).intValue()); + final V v = (e.getValue()); + if ( ( strategy.equals( (k), (0) ) ) ) { + if ( containsNullKey && ( (value[ n ]) == null ? (v) == null : (value[ n ]).equals(v) ) ) { + removeNullEntry(); + return true; + } + return false; + } + int curr; + final int[] key = Int2ObjectOpenCustomHashMap.this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (curr), (k) ) ) ) { + if ( ( (value[ pos ]) == null ? (v) == null : (value[ pos ]).equals(v) ) ) { + removeEntry( pos ); + return true; + } + return false; + } + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (curr), (k) ) ) ) { + if ( ( (value[ pos ]) == null ? (v) == null : (value[ pos ]).equals(v) ) ) { + removeEntry( pos ); + return true; + } + } + } + } + public int size() { + return size; + } + public void clear() { + Int2ObjectOpenCustomHashMap.this.clear(); + } + } + public FastEntrySet int2ObjectEntrySet() { + if ( entries == null ) entries = new MapEntrySet(); + return entries; + } + /** An iterator on keys. + * + *

We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods + * (and possibly their type-specific counterparts) so that they return keys + * instead of entries. + */ + private final class KeyIterator extends MapIterator implements IntIterator { + public KeyIterator() { super(); } + public int nextInt() { return key[ nextEntry() ]; } + public Integer next() { return (Integer.valueOf(key[ nextEntry() ])); } + } + private final class KeySet extends AbstractIntSet { + public IntIterator iterator() { + return new KeyIterator(); + } + public int size() { + return size; + } + public boolean contains( int k ) { + return containsKey( k ); + } + public boolean remove( int k ) { + final int oldSize = size; + Int2ObjectOpenCustomHashMap.this.remove( k ); + return size != oldSize; + } + public void clear() { + Int2ObjectOpenCustomHashMap.this.clear(); + } + } + public IntSet keySet() { + if ( keys == null ) keys = new KeySet(); + return keys; + } + /** An iterator on values. + * + *

We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods + * (and possibly their type-specific counterparts) so that they return values + * instead of entries. + */ + private final class ValueIterator extends MapIterator implements ObjectIterator { + public ValueIterator() { super(); } + public V next() { return value[ nextEntry() ]; } + } + public ObjectCollection values() { + if ( values == null ) values = new AbstractObjectCollection () { + public ObjectIterator iterator() { + return new ValueIterator(); + } + public int size() { + return size; + } + public boolean contains( Object v ) { + return containsValue( v ); + } + public void clear() { + Int2ObjectOpenCustomHashMap.this.clear(); + } + }; + return values; + } + /** A no-op for backward compatibility. The kind of tables implemented by + * this class never need rehashing. + * + *

If you need to reduce the table size to fit exactly + * this set, use {@link #trim()}. + * + * @return true. + * @see #trim() + * @deprecated A no-op. + */ + @Deprecated + public boolean rehash() { + return true; + } + /** Rehashes the map, making the table as small as possible. + * + *

This method rehashes the table to the smallest size satisfying the + * load factor. It can be used when the set will not be changed anymore, so + * to optimize access speed and size. + * + *

If the table size is already the minimum possible, this method + * does nothing. + * + * @return true if there was enough memory to trim the map. + * @see #trim(int) + */ + public boolean trim() { + final int l = arraySize( size, f ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch(OutOfMemoryError cantDoIt) { return false; } + return true; + } + /** Rehashes this map if the table is too large. + * + *

Let N be the smallest table size that can hold + * max(n,{@link #size()}) entries, still satisfying the load factor. If the current + * table size is smaller than or equal to N, this method does + * nothing. Otherwise, it rehashes this map in a table of size + * N. + * + *

This method is useful when reusing maps. {@linkplain #clear() Clearing a + * map} leaves the table size untouched. If you are reusing a map + * many times, you can call this method with a typical + * size to avoid keeping around a very large table just + * because of a few large transient maps. + * + * @param n the threshold for the trimming. + * @return true if there was enough memory to trim the map. + * @see #trim() + */ + public boolean trim( final int n ) { + final int l = HashCommon.nextPowerOfTwo( (int)Math.ceil( n / f ) ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch( OutOfMemoryError cantDoIt ) { return false; } + return true; + } + /** Rehashes the map. + * + *

This method implements the basic rehashing strategy, and may be + * overriden by subclasses implementing different rehashing strategies (e.g., + * disk-based rehashing). However, you should not override this method + * unless you understand the internal workings of this class. + * + * @param newN the new size + */ + @SuppressWarnings("unchecked") + protected void rehash( final int newN ) { + final int key[] = this.key; + final V value[] = this.value; + final int mask = newN - 1; // Note that this is used by the hashing macro + final int newKey[] = new int[ newN + 1 ]; + final V newValue[] = (V[]) new Object[ newN + 1 ]; + int i = n, pos; + for( int j = realSize(); j-- != 0; ) { + while( ( (key[ --i ]) == (0) ) ); + if ( ! ( (newKey[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(key[ i ]) ) ) & mask ]) == (0) ) ) + while ( ! ( (newKey[ pos = ( pos + 1 ) & mask ]) == (0) ) ); + newKey[ pos ] = key[ i ]; + newValue[ pos ] = value[ i ]; + } + newValue[ newN ] = value[ n ]; + n = newN; + this.mask = mask; + maxFill = maxFill( n, f ); + this.key = newKey; + this.value = newValue; + } + /** Returns a deep copy of this map. + * + *

This method performs a deep copy of this hash map; the data stored in the + * map, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this map. + */ + @SuppressWarnings("unchecked") + public Int2ObjectOpenCustomHashMap clone() { + Int2ObjectOpenCustomHashMap c; + try { + c = (Int2ObjectOpenCustomHashMap )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.keys = null; + c.values = null; + c.entries = null; + c.containsNullKey = containsNullKey; + c.key = key.clone(); + c.value = value.clone(); + c.strategy = strategy; + return c; + } + /** Returns a hash code for this map. + * + * This method overrides the generic method provided by the superclass. + * Since equals() is not overriden, it is important + * that the value returned by this method is the same value as + * the one returned by the overriden method. + * + * @return a hash code for this map. + */ + public int hashCode() { + int h = 0; + for( int j = realSize(), i = 0, t = 0; j-- != 0; ) { + while( ( (key[ i ]) == (0) ) ) i++; + t = ( strategy.hashCode(key[ i ]) ); + if ( this != value[ i ] ) + t ^= ( (value[ i ]) == null ? 0 : (value[ i ]).hashCode() ); + h += t; + i++; + } + // Zero / null keys have hash zero. + if ( containsNullKey ) h += ( (value[ n ]) == null ? 0 : (value[ n ]).hashCode() ); + return h; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + final int key[] = this.key; + final V value[] = this.value; + final MapIterator i = new MapIterator(); + s.defaultWriteObject(); + for( int j = size, e; j-- != 0; ) { + e = i.nextEntry(); + s.writeInt( key[ e ] ); + s.writeObject( value[ e ] ); + } + } + @SuppressWarnings("unchecked") + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + n = arraySize( size, f ); + maxFill = maxFill( n, f ); + mask = n - 1; + final int key[] = this.key = new int[ n + 1 ]; + final V value[] = this.value = (V[]) new Object[ n + 1 ]; + int k; + V v; + for( int i = size, pos; i-- != 0; ) { + k = s.readInt(); + v = (V) s.readObject(); + if ( ( strategy.equals( (k), (0) ) ) ) { + pos = n; + containsNullKey = true; + } + else { + pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask; + while ( ! ( (key[ pos ]) == (0) ) ) pos = ( pos + 1 ) & mask; + } + key[ pos ] = k; + value[ pos ] = v; + } + if ( ASSERTS ) checkTable(); + } + private void checkTable() {} +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectOpenHashMap.java b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectOpenHashMap.java new file mode 100644 index 0000000..b392723 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectOpenHashMap.java @@ -0,0 +1,901 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.HashCommon; +import static it.unimi.dsi.fastutil.HashCommon.arraySize; +import static it.unimi.dsi.fastutil.HashCommon.maxFill; +import java.util.Map; +import java.util.Arrays; +import java.util.NoSuchElementException; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.AbstractObjectSet; +/** A type-specific hash map with a fast, small-footprint implementation. + * + *

Instances of this class use a hash table to represent a map. The table is + * filled up to a specified load factor, and then doubled in size to + * accommodate new entries. If the table is emptied below one fourth + * of the load factor, it is halved in size. However, halving is + * not performed when deleting entries from an iterator, as it would interfere + * with the iteration process. + * + *

Note that {@link #clear()} does not modify the hash table size. + * Rather, a family of {@linkplain #trim() trimming + * methods} lets you control the size of the table; this is particularly useful + * if you reuse instances of this class. + * + * @see Hash + * @see HashCommon + */ +public class Int2ObjectOpenHashMap extends AbstractInt2ObjectMap implements java.io.Serializable, Cloneable, Hash { + private static final long serialVersionUID = 0L; + private static final boolean ASSERTS = false; + /** The array of keys. */ + protected transient int[] key; + /** The array of values. */ + protected transient V[] value; + /** The mask for wrapping a position counter. */ + protected transient int mask; + /** Whether this set contains the key zero. */ + protected transient boolean containsNullKey; + /** The current table size. */ + protected transient int n; + /** Threshold after which we rehash. It must be the table size times {@link #f}. */ + protected transient int maxFill; + /** Number of entries in the set (including the key zero, if present). */ + protected int size; + /** The acceptable load factor. */ + protected final float f; + /** Cached set of entries. */ + protected transient FastEntrySet entries; + /** Cached set of keys. */ + protected transient IntSet keys; + /** Cached collection of values. */ + protected transient ObjectCollection values; + /** Creates a new hash map. + * + *

The actual table size will be the least power of two greater than expected/f. + * + * @param expected the expected number of elements in the hash set. + * @param f the load factor. + */ + @SuppressWarnings("unchecked") + public Int2ObjectOpenHashMap( final int expected, final float f ) { + if ( f <= 0 || f > 1 ) throw new IllegalArgumentException( "Load factor must be greater than 0 and smaller than or equal to 1" ); + if ( expected < 0 ) throw new IllegalArgumentException( "The expected number of elements must be nonnegative" ); + this.f = f; + n = arraySize( expected, f ); + mask = n - 1; + maxFill = maxFill( n, f ); + key = new int[ n + 1 ]; + value = (V[]) new Object[ n + 1 ]; + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * + * @param expected the expected number of elements in the hash map. + */ + public Int2ObjectOpenHashMap( final int expected ) { + this( expected, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map with initial expected {@link Hash#DEFAULT_INITIAL_SIZE} entries + * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + */ + public Int2ObjectOpenHashMap() { + this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map copying a given one. + * + * @param m a {@link Map} to be copied into the new hash map. + * @param f the load factor. + */ + public Int2ObjectOpenHashMap( final Map m, final float f ) { + this( m.size(), f ); + putAll( m ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given one. + * + * @param m a {@link Map} to be copied into the new hash map. + */ + public Int2ObjectOpenHashMap( final Map m ) { + this( m, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map copying a given type-specific one. + * + * @param m a type-specific map to be copied into the new hash map. + * @param f the load factor. + */ + public Int2ObjectOpenHashMap( final Int2ObjectMap m, final float f ) { + this( m.size(), f ); + putAll( m ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given type-specific one. + * + * @param m a type-specific map to be copied into the new hash map. + */ + public Int2ObjectOpenHashMap( final Int2ObjectMap m ) { + this( m, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map using the elements of two parallel arrays. + * + * @param k the array of keys of the new hash map. + * @param v the array of corresponding values in the new hash map. + * @param f the load factor. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Int2ObjectOpenHashMap( final int[] k, final V[] v, final float f ) { + this( k.length, f ); + if ( k.length != v.length ) throw new IllegalArgumentException( "The key array and the value array have different lengths (" + k.length + " and " + v.length + ")" ); + for( int i = 0; i < k.length; i++ ) this.put( k[ i ], v[ i ] ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using the elements of two parallel arrays. + * + * @param k the array of keys of the new hash map. + * @param v the array of corresponding values in the new hash map. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Int2ObjectOpenHashMap( final int[] k, final V[] v ) { + this( k, v, DEFAULT_LOAD_FACTOR ); + } + private int realSize() { + return containsNullKey ? size - 1 : size; + } + private void ensureCapacity( final int capacity ) { + final int needed = arraySize( capacity, f ); + if ( needed > n ) rehash( needed ); + } + private void tryCapacity( final long capacity ) { + final int needed = (int)Math.min( 1 << 30, Math.max( 2, HashCommon.nextPowerOfTwo( (long)Math.ceil( capacity / f ) ) ) ); + if ( needed > n ) rehash( needed ); + } + private V removeEntry( final int pos ) { + final V oldValue = value[ pos ]; + value[ pos ] = null; + size--; + shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return oldValue; + } + private V removeNullEntry() { + containsNullKey = false; + final V oldValue = value[ n ]; + value[ n ] = null; + size--; + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return oldValue; + } + /** {@inheritDoc} */ + public void putAll(Map m) { + if ( f <= .5 ) ensureCapacity( m.size() ); // The resulting map will be sized for m.size() elements + else tryCapacity( size() + m.size() ); // The resulting map will be tentatively sized for size() + m.size() elements + super.putAll( m ); + } + private int insert(final int k, final V v) { + int pos; + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) return n; + containsNullKey = true; + pos = n; + } + else { + int curr; + final int[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) { + if ( ( (curr) == (k) ) ) return pos; + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( (curr) == (k) ) ) return pos; + } + } + key[ pos ] = k; + value[ pos ] = v; + if ( size++ >= maxFill ) rehash( arraySize( size + 1, f ) ); + if ( ASSERTS ) checkTable(); + return -1; + } + public V put(final int k, final V v) { + final int pos = insert( k, v ); + if ( pos < 0 ) return defRetValue; + final V oldValue = value[ pos ]; + value[ pos ] = v; + return oldValue; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Integer ok, final V ov ) { + final V v = (ov); + final int pos = insert( ((ok).intValue()), v ); + if ( pos < 0 ) return (this.defRetValue); + final V oldValue = value[ pos ]; + value[ pos ] = v; + return (oldValue); + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + protected final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + int curr; + final int[] key = this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + value[ last ] = null; + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( (curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + value[ last ] = value[ pos ]; + } + } + + public V remove( final int k ) { + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) return removeNullEntry(); + return defRetValue; + } + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return removeEntry( pos ); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return removeEntry( pos ); + } + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + + public V remove( final Object ok ) { + final int k = ((((Integer)(ok)).intValue())); + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) return (removeNullEntry()); + return (this.defRetValue); + } + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (curr) == (k) ) ) return (removeEntry( pos )); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (curr) == (k) ) ) return (removeEntry( pos )); + } + } + /** @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public V get( final Integer ok ) { + if ( ok == null ) return null; + final int k = ((ok).intValue()); + if ( ( (k) == (0) ) ) return containsNullKey ? (value[ n ]) : (this.defRetValue); + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (k) == (curr) ) ) return (value[ pos ]); + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (k) == (curr) ) ) return (value[ pos ]); + } + } + + public V get( final int k ) { + if ( ( (k) == (0) ) ) return containsNullKey ? value[ n ] : defRetValue; + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return value[ pos ]; + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return value[ pos ]; + } + } + + public boolean containsKey( final int k ) { + if ( ( (k) == (0) ) ) return containsNullKey; + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return true; + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return true; + } + } + public boolean containsValue( final Object v ) { + final V value[] = this.value; + final int key[] = this.key; + if ( containsNullKey && ( (value[ n ]) == null ? (v) == null : (value[ n ]).equals(v) ) ) return true; + for( int i = n; i-- != 0; ) if ( ! ( (key[ i ]) == (0) ) && ( (value[ i ]) == null ? (v) == null : (value[ i ]).equals(v) ) ) return true; + return false; + } + /* Removes all elements from this map. + * + *

To increase object reuse, this method does not change the table size. + * If you want to reduce the table size, you must use {@link #trim()}. + * + */ + public void clear() { + if ( size == 0 ) return; + size = 0; + containsNullKey = false; + Arrays.fill( key, (0) ); + Arrays.fill( value, null ); + } + public int size() { + return size; + } + public boolean isEmpty() { + return size == 0; + } + /** A no-op for backward compatibility. + * + * @param growthFactor unused. + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public void growthFactor( int growthFactor ) {} + /** Gets the growth factor (2). + * + * @return the growth factor of this set, which is fixed (2). + * @see #growthFactor(int) + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public int growthFactor() { + return 16; + } + /** The entry class for a hash map does not record key and value, but + * rather the position in the hash table of the corresponding entry. This + * is necessary so that calls to {@link java.util.Map.Entry#setValue(Object)} are reflected in + * the map */ + final class MapEntry implements Int2ObjectMap.Entry , Map.Entry { + // The table index this entry refers to, or -1 if this entry has been deleted. + int index; + MapEntry( final int index ) { + this.index = index; + } + MapEntry() {} + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer getKey() { + return (Integer.valueOf(key[ index ])); + } + public int getIntKey() { + return key[ index ]; + } + public V getValue() { + return (value[ index ]); + } + public V setValue( final V v ) { + final V oldValue = value[ index ]; + value[ index ] = v; + return oldValue; + } + @SuppressWarnings("unchecked") + public boolean equals( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + Map.Entry e = (Map.Entry)o; + return ( (key[ index ]) == (((e.getKey()).intValue())) ) && ( (value[ index ]) == null ? ((e.getValue())) == null : (value[ index ]).equals((e.getValue())) ); + } + public int hashCode() { + return (key[ index ]) ^ ( (value[ index ]) == null ? 0 : (value[ index ]).hashCode() ); + } + public String toString() { + return key[ index ] + "=>" + value[ index ]; + } + } + /** An iterator over a hash map. */ + private class MapIterator { + /** The index of the last entry returned, if positive or zero; initially, {@link #n}. If negative, the last + entry returned was that of the key of index {@code - pos - 1} from the {@link #wrapped} list. */ + int pos = n; + /** The index of the last entry that has been returned (more precisely, the value of {@link #pos} if {@link #pos} is positive, + or {@link Integer#MIN_VALUE} if {@link #pos} is negative). It is -1 if either + we did not return an entry yet, or the last returned entry has been removed. */ + int last = -1; + /** A downward counter measuring how many entries must still be returned. */ + int c = size; + /** A boolean telling us whether we should return the entry with the null key. */ + boolean mustReturnNullKey = Int2ObjectOpenHashMap.this.containsNullKey; + /** A lazily allocated list containing keys of entries that have wrapped around the table because of removals. */ + IntArrayList wrapped; + public boolean hasNext() { + return c != 0; + } + public int nextEntry() { + if ( ! hasNext() ) throw new NoSuchElementException(); + c--; + if ( mustReturnNullKey ) { + mustReturnNullKey = false; + return last = n; + } + final int key[] = Int2ObjectOpenHashMap.this.key; + for(;;) { + if ( --pos < 0 ) { + // We are just enumerating elements from the wrapped list. + last = Integer.MIN_VALUE; + final int k = wrapped.getInt( - pos - 1 ); + int p = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask; + while ( ! ( (k) == (key[ p ]) ) ) p = ( p + 1 ) & mask; + return p; + } + if ( ! ( (key[ pos ]) == (0) ) ) return last = pos; + } + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + private final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + int curr; + final int[] key = Int2ObjectOpenHashMap.this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + value[ last ] = null; + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( (curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + if ( pos < last ) { // Wrapped entry. + if ( wrapped == null ) wrapped = new IntArrayList ( 2 ); + wrapped.add( key[ pos ] ); + } + key[ last ] = curr; + value[ last ] = value[ pos ]; + } + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + if ( last == n ) { + containsNullKey = false; + value[ n ] = null; + } + else if ( pos >= 0 ) shiftKeys( last ); + else { + // We're removing wrapped entries. + Int2ObjectOpenHashMap.this.remove( wrapped.getInt( - pos - 1 ) ); + last = -1; // Note that we must not decrement size + return; + } + size--; + last = -1; // You can no longer remove this entry. + if ( ASSERTS ) checkTable(); + } + public int skip( final int n ) { + int i = n; + while( i-- != 0 && hasNext() ) nextEntry(); + return n - i - 1; + } + } + private class EntryIterator extends MapIterator implements ObjectIterator > { + private MapEntry entry; + public Int2ObjectMap.Entry next() { + return entry = new MapEntry( nextEntry() ); + } + @Override + public void remove() { + super.remove(); + entry.index = -1; // You cannot use a deleted entry. + } + } + private class FastEntryIterator extends MapIterator implements ObjectIterator > { + private final MapEntry entry = new MapEntry(); + public MapEntry next() { + entry.index = nextEntry(); + return entry; + } + } + private final class MapEntrySet extends AbstractObjectSet > implements FastEntrySet { + public ObjectIterator > iterator() { + return new EntryIterator(); + } + public ObjectIterator > fastIterator() { + return new FastEntryIterator(); + } + @SuppressWarnings("unchecked") + public boolean contains( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final int k = ((e.getKey()).intValue()); + if ( ( (k) == (0) ) ) return ( Int2ObjectOpenHashMap.this.containsNullKey && ( (value[ n ]) == null ? ((e.getValue())) == null : (value[ n ]).equals((e.getValue())) ) ); + int curr; + final int[] key = Int2ObjectOpenHashMap.this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return ( (value[ pos ]) == null ? ((e.getValue())) == null : (value[ pos ]).equals((e.getValue())) ); + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return ( (value[ pos ]) == null ? ((e.getValue())) == null : (value[ pos ]).equals((e.getValue())) ); + } + } + @SuppressWarnings("unchecked") + public boolean remove( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final int k = ((e.getKey()).intValue()); + final V v = (e.getValue()); + if ( ( (k) == (0) ) ) { + if ( containsNullKey && ( (value[ n ]) == null ? (v) == null : (value[ n ]).equals(v) ) ) { + removeNullEntry(); + return true; + } + return false; + } + int curr; + final int[] key = Int2ObjectOpenHashMap.this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return false; + if ( ( (curr) == (k) ) ) { + if ( ( (value[ pos ]) == null ? (v) == null : (value[ pos ]).equals(v) ) ) { + removeEntry( pos ); + return true; + } + return false; + } + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (curr) == (k) ) ) { + if ( ( (value[ pos ]) == null ? (v) == null : (value[ pos ]).equals(v) ) ) { + removeEntry( pos ); + return true; + } + } + } + } + public int size() { + return size; + } + public void clear() { + Int2ObjectOpenHashMap.this.clear(); + } + } + public FastEntrySet int2ObjectEntrySet() { + if ( entries == null ) entries = new MapEntrySet(); + return entries; + } + /** An iterator on keys. + * + *

We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods + * (and possibly their type-specific counterparts) so that they return keys + * instead of entries. + */ + private final class KeyIterator extends MapIterator implements IntIterator { + public KeyIterator() { super(); } + public int nextInt() { return key[ nextEntry() ]; } + public Integer next() { return (Integer.valueOf(key[ nextEntry() ])); } + } + private final class KeySet extends AbstractIntSet { + public IntIterator iterator() { + return new KeyIterator(); + } + public int size() { + return size; + } + public boolean contains( int k ) { + return containsKey( k ); + } + public boolean remove( int k ) { + final int oldSize = size; + Int2ObjectOpenHashMap.this.remove( k ); + return size != oldSize; + } + public void clear() { + Int2ObjectOpenHashMap.this.clear(); + } + } + public IntSet keySet() { + if ( keys == null ) keys = new KeySet(); + return keys; + } + /** An iterator on values. + * + *

We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods + * (and possibly their type-specific counterparts) so that they return values + * instead of entries. + */ + private final class ValueIterator extends MapIterator implements ObjectIterator { + public ValueIterator() { super(); } + public V next() { return value[ nextEntry() ]; } + } + public ObjectCollection values() { + if ( values == null ) values = new AbstractObjectCollection () { + public ObjectIterator iterator() { + return new ValueIterator(); + } + public int size() { + return size; + } + public boolean contains( Object v ) { + return containsValue( v ); + } + public void clear() { + Int2ObjectOpenHashMap.this.clear(); + } + }; + return values; + } + /** A no-op for backward compatibility. The kind of tables implemented by + * this class never need rehashing. + * + *

If you need to reduce the table size to fit exactly + * this set, use {@link #trim()}. + * + * @return true. + * @see #trim() + * @deprecated A no-op. + */ + @Deprecated + public boolean rehash() { + return true; + } + /** Rehashes the map, making the table as small as possible. + * + *

This method rehashes the table to the smallest size satisfying the + * load factor. It can be used when the set will not be changed anymore, so + * to optimize access speed and size. + * + *

If the table size is already the minimum possible, this method + * does nothing. + * + * @return true if there was enough memory to trim the map. + * @see #trim(int) + */ + public boolean trim() { + final int l = arraySize( size, f ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch(OutOfMemoryError cantDoIt) { return false; } + return true; + } + /** Rehashes this map if the table is too large. + * + *

Let N be the smallest table size that can hold + * max(n,{@link #size()}) entries, still satisfying the load factor. If the current + * table size is smaller than or equal to N, this method does + * nothing. Otherwise, it rehashes this map in a table of size + * N. + * + *

This method is useful when reusing maps. {@linkplain #clear() Clearing a + * map} leaves the table size untouched. If you are reusing a map + * many times, you can call this method with a typical + * size to avoid keeping around a very large table just + * because of a few large transient maps. + * + * @param n the threshold for the trimming. + * @return true if there was enough memory to trim the map. + * @see #trim() + */ + public boolean trim( final int n ) { + final int l = HashCommon.nextPowerOfTwo( (int)Math.ceil( n / f ) ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch( OutOfMemoryError cantDoIt ) { return false; } + return true; + } + /** Rehashes the map. + * + *

This method implements the basic rehashing strategy, and may be + * overriden by subclasses implementing different rehashing strategies (e.g., + * disk-based rehashing). However, you should not override this method + * unless you understand the internal workings of this class. + * + * @param newN the new size + */ + @SuppressWarnings("unchecked") + protected void rehash( final int newN ) { + final int key[] = this.key; + final V value[] = this.value; + final int mask = newN - 1; // Note that this is used by the hashing macro + final int newKey[] = new int[ newN + 1 ]; + final V newValue[] = (V[]) new Object[ newN + 1 ]; + int i = n, pos; + for( int j = realSize(); j-- != 0; ) { + while( ( (key[ --i ]) == (0) ) ); + if ( ! ( (newKey[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (key[ i ]) ) ) & mask ]) == (0) ) ) + while ( ! ( (newKey[ pos = ( pos + 1 ) & mask ]) == (0) ) ); + newKey[ pos ] = key[ i ]; + newValue[ pos ] = value[ i ]; + } + newValue[ newN ] = value[ n ]; + n = newN; + this.mask = mask; + maxFill = maxFill( n, f ); + this.key = newKey; + this.value = newValue; + } + /** Returns a deep copy of this map. + * + *

This method performs a deep copy of this hash map; the data stored in the + * map, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this map. + */ + @SuppressWarnings("unchecked") + public Int2ObjectOpenHashMap clone() { + Int2ObjectOpenHashMap c; + try { + c = (Int2ObjectOpenHashMap )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.keys = null; + c.values = null; + c.entries = null; + c.containsNullKey = containsNullKey; + c.key = key.clone(); + c.value = value.clone(); + return c; + } + /** Returns a hash code for this map. + * + * This method overrides the generic method provided by the superclass. + * Since equals() is not overriden, it is important + * that the value returned by this method is the same value as + * the one returned by the overriden method. + * + * @return a hash code for this map. + */ + public int hashCode() { + int h = 0; + for( int j = realSize(), i = 0, t = 0; j-- != 0; ) { + while( ( (key[ i ]) == (0) ) ) i++; + t = (key[ i ]); + if ( this != value[ i ] ) + t ^= ( (value[ i ]) == null ? 0 : (value[ i ]).hashCode() ); + h += t; + i++; + } + // Zero / null keys have hash zero. + if ( containsNullKey ) h += ( (value[ n ]) == null ? 0 : (value[ n ]).hashCode() ); + return h; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + final int key[] = this.key; + final V value[] = this.value; + final MapIterator i = new MapIterator(); + s.defaultWriteObject(); + for( int j = size, e; j-- != 0; ) { + e = i.nextEntry(); + s.writeInt( key[ e ] ); + s.writeObject( value[ e ] ); + } + } + @SuppressWarnings("unchecked") + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + n = arraySize( size, f ); + maxFill = maxFill( n, f ); + mask = n - 1; + final int key[] = this.key = new int[ n + 1 ]; + final V value[] = this.value = (V[]) new Object[ n + 1 ]; + int k; + V v; + for( int i = size, pos; i-- != 0; ) { + k = s.readInt(); + v = (V) s.readObject(); + if ( ( (k) == (0) ) ) { + pos = n; + containsNullKey = true; + } + else { + pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask; + while ( ! ( (key[ pos ]) == (0) ) ) pos = ( pos + 1 ) & mask; + } + key[ pos ] = k; + value[ pos ] = v; + } + if ( ASSERTS ) checkTable(); + } + private void checkTable() {} +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectRBTreeMap.java b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectRBTreeMap.java new file mode 100644 index 0000000..dae82fa --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectRBTreeMap.java @@ -0,0 +1,1599 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.objects.AbstractObjectSortedSet; +import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; +import it.unimi.dsi.fastutil.objects.ObjectListIterator; +import it.unimi.dsi.fastutil.objects.ObjectSortedSet; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import java.util.Comparator; +import java.util.Iterator; +import java.util.Map; +import java.util.SortedMap; +import java.util.NoSuchElementException; +/** A type-specific red-black tree map with a fast, small-footprint implementation. + * + *

The iterators provided by the views of this class are type-specific {@linkplain + * it.unimi.dsi.fastutil.BidirectionalIterator bidirectional iterators}. + * Moreover, the iterator returned by iterator() can be safely cast + * to a type-specific {@linkplain java.util.ListIterator list iterator}. + * + */ +public class Int2ObjectRBTreeMap extends AbstractInt2ObjectSortedMap implements java.io.Serializable, Cloneable { + /** A reference to the root entry. */ + protected transient Entry tree; + /** Number of entries in this map. */ + protected int count; + /** The first key in this map. */ + protected transient Entry firstEntry; + /** The last key in this map. */ + protected transient Entry lastEntry; + /** Cached set of entries. */ + protected transient ObjectSortedSet > entries; + /** Cached set of keys. */ + protected transient IntSortedSet keys; + /** Cached collection of values. */ + protected transient ObjectCollection values; + /** The value of this variable remembers, after a put() + * or a remove(), whether the domain of the map + * has been modified. */ + protected transient boolean modified; + /** This map's comparator, as provided in the constructor. */ + protected Comparator storedComparator; + /** This map's actual comparator; it may differ from {@link #storedComparator} because it is + always a type-specific comparator, so it could be derived from the former by wrapping. */ + protected transient IntComparator actualComparator; + private static final long serialVersionUID = -7046029254386353129L; + private static final boolean ASSERTS = false; + { + allocatePaths(); + } + /** Creates a new empty tree map. + */ + public Int2ObjectRBTreeMap() { + tree = null; + count = 0; + } + /** Generates the comparator that will be actually used. + * + *

When a specific {@link Comparator} is specified and stored in {@link + * #storedComparator}, we must check whether it is type-specific. If it is + * so, we can used directly, and we store it in {@link #actualComparator}. Otherwise, + * we generate on-the-fly an anonymous class that wraps the non-specific {@link Comparator} + * and makes it into a type-specific one. + */ + private void setActualComparator() { + /* If the provided comparator is already type-specific, we use it. Otherwise, + we use a wrapper anonymous class to fake that it is type-specific. */ + if ( storedComparator == null || storedComparator instanceof IntComparator ) actualComparator = (IntComparator)storedComparator; + else actualComparator = new IntComparator () { + public int compare( int k1, int k2 ) { + return storedComparator.compare( (Integer.valueOf(k1)), (Integer.valueOf(k2)) ); + } + public int compare( Integer ok1, Integer ok2 ) { + return storedComparator.compare( ok1, ok2 ); + } + }; + } + /** Creates a new empty tree map with the given comparator. + * + * @param c a (possibly type-specific) comparator. + */ + public Int2ObjectRBTreeMap( final Comparator c ) { + this(); + storedComparator = c; + setActualComparator(); + } + /** Creates a new tree map copying a given map. + * + * @param m a {@link Map} to be copied into the new tree map. + */ + public Int2ObjectRBTreeMap( final Map m ) { + this(); + putAll( m ); + } + /** Creates a new tree map copying a given sorted map (and its {@link Comparator}). + * + * @param m a {@link SortedMap} to be copied into the new tree map. + */ + public Int2ObjectRBTreeMap( final SortedMap m ) { + this( m.comparator() ); + putAll( m ); + } + /** Creates a new tree map copying a given map. + * + * @param m a type-specific map to be copied into the new tree map. + */ + public Int2ObjectRBTreeMap( final Int2ObjectMap m ) { + this(); + putAll( m ); + } + /** Creates a new tree map copying a given sorted map (and its {@link Comparator}). + * + * @param m a type-specific sorted map to be copied into the new tree map. + */ + public Int2ObjectRBTreeMap( final Int2ObjectSortedMap m ) { + this( m.comparator() ); + putAll( m ); + } + /** Creates a new tree map using the elements of two parallel arrays and the given comparator. + * + * @param k the array of keys of the new tree map. + * @param v the array of corresponding values in the new tree map. + * @param c a (possibly type-specific) comparator. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Int2ObjectRBTreeMap( final int[] k, final V v[], final Comparator c ) { + this( c ); + if ( k.length != v.length ) throw new IllegalArgumentException( "The key array and the value array have different lengths (" + k.length + " and " + v.length + ")" ); + for( int i = 0; i < k.length; i++ ) this.put( k[ i ], v[ i ] ); + } + /** Creates a new tree map using the elements of two parallel arrays. + * + * @param k the array of keys of the new tree map. + * @param v the array of corresponding values in the new tree map. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Int2ObjectRBTreeMap( final int[] k, final V v[] ) { + this( k, v, null ); + } + /* + * The following methods implements some basic building blocks used by + * all accessors. They are (and should be maintained) identical to those used in RBTreeSet.drv. + * + * The put()/remove() code is derived from Ben Pfaff's GNU libavl + * (http://www.msu.edu/~pfaffben/avl/). If you want to understand what's + * going on, you should have a look at the literate code contained therein + * first. + */ + /** Compares two keys in the right way. + * + *

This method uses the {@link #actualComparator} if it is non-null. + * Otherwise, it resorts to primitive type comparisons or to {@link Comparable#compareTo(Object) compareTo()}. + * + * @param k1 the first key. + * @param k2 the second key. + * @return a number smaller than, equal to or greater than 0, as usual + * (i.e., when k1 < k2, k1 = k2 or k1 > k2, respectively). + */ + + final int compare( final int k1, final int k2 ) { + return actualComparator == null ? ( Integer.compare((k1),(k2)) ) : actualComparator.compare( k1, k2 ); + } + /** Returns the entry corresponding to the given key, if it is in the tree; null, otherwise. + * + * @param k the key to search for. + * @return the corresponding entry, or null if no entry with the given key exists. + */ + final Entry findKey( final int k ) { + Entry e = tree; + int cmp; + while ( e != null && ( cmp = compare( k, e.key ) ) != 0 ) e = cmp < 0 ? e.left() : e.right(); + return e; + } + /** Locates a key. + * + * @param k a key. + * @return the last entry on a search for the given key; this will be + * the given key, if it present; otherwise, it will be either the smallest greater key or the greatest smaller key. + */ + final Entry locateKey( final int k ) { + Entry e = tree, last = tree; + int cmp = 0; + while ( e != null && ( cmp = compare( k, e.key ) ) != 0 ) { + last = e; + e = cmp < 0 ? e.left() : e.right(); + } + return cmp == 0 ? e : last; + } + /** This vector remembers the path and the direction followed during the + * current insertion. It suffices for about 232 entries. */ + private transient boolean dirPath[]; + private transient Entry nodePath[]; + @SuppressWarnings("unchecked") + private void allocatePaths() { + dirPath = new boolean[ 64 ]; + nodePath = new Entry[ 64 ]; + } + public V put( final int k, final V v ) { + Entry e = add( k ); + final V oldValue = e.value; + e.value = v; + return oldValue; + } + /** Returns a node with key k in the balanced tree, creating one with defRetValue if necessary. + * + * @param k the key + * @return a node with key k. If a node with key k already exists, then that node is returned, + * otherwise a new node with defRetValue is created ensuring that the tree is balanced + after creation of the node. + */ + private Entry add( final int k ) { + /* After execution of this method, modified is true iff a new entry has + been inserted. */ + modified = false; + int maxDepth = 0; + Entry e; + if ( tree == null ) { // The case of the empty tree is treated separately. + count++; + e = tree = lastEntry = firstEntry = new Entry ( k, defRetValue ); + } + else { + Entry p = tree; + int cmp, i = 0; + while( true ) { + if ( ( cmp = compare( k, p.key ) ) == 0 ) { + // We clean up the node path, or we could have stale references later. + while( i-- != 0 ) nodePath[ i ] = null; + return p; + } + nodePath[ i ] = p; + if ( dirPath[ i++ ] = cmp > 0 ) { + if ( p.succ() ) { + count++; + e = new Entry ( k, defRetValue ); + if ( p.right == null ) lastEntry = e; + e.left = p; + e.right = p.right; + p.right( e ); + break; + } + p = p.right; + } + else { + if ( p.pred() ) { + count++; + e = new Entry ( k, defRetValue ); + if ( p.left == null ) firstEntry = e; + e.right = p; + e.left = p.left; + p.left( e ); + break; + } + p = p.left; + } + } + modified = true; + maxDepth = i--; + while( i > 0 && ! nodePath[ i ].black() ) { + if ( ! dirPath[ i - 1 ] ) { + Entry y = nodePath[ i - 1 ].right; + if ( ! nodePath[ i - 1 ].succ() && ! y.black() ) { + nodePath[ i ].black( true ); + y.black( true ); + nodePath[ i - 1 ].black( false ); + i -= 2; + } + else { + Entry x; + if ( ! dirPath[ i ] ) y = nodePath[ i ]; + else { + x = nodePath[ i ]; + y = x.right; + x.right = y.left; + y.left = x; + nodePath[ i - 1 ].left = y; + if ( y.pred() ) { + y.pred( false ); + x.succ( y ); + } + } + x = nodePath[ i - 1 ]; + x.black( false ); + y.black( true ); + x.left = y.right; + y.right = x; + if ( i < 2 ) tree = y; + else { + if ( dirPath[ i - 2 ] ) nodePath[ i - 2 ].right = y; + else nodePath[ i - 2 ].left = y; + } + if ( y.succ() ) { + y.succ( false ); + x.pred( y ); + } + break; + } + } + else { + Entry y = nodePath[ i - 1 ].left; + if ( ! nodePath[ i - 1 ].pred() && ! y.black() ) { + nodePath[ i ].black( true ); + y.black( true ); + nodePath[ i - 1 ].black( false ); + i -= 2; + } + else { + Entry x; + if ( dirPath[ i ] ) y = nodePath[ i ]; + else { + x = nodePath[ i ]; + y = x.left; + x.left = y.right; + y.right = x; + nodePath[ i - 1 ].right = y; + if ( y.succ() ) { + y.succ( false ); + x.pred( y ); + } + } + x = nodePath[ i - 1 ]; + x.black( false ); + y.black( true ); + x.right = y.left; + y.left = x; + if ( i < 2 ) tree = y; + else { + if ( dirPath[ i - 2 ] ) nodePath[ i - 2 ].right = y; + else nodePath[ i - 2 ].left = y; + } + if ( y.pred() ){ + y.pred( false ); + x.succ( y ); + } + break; + } + } + } + } + tree.black( true ); + // We clean up the node path, or we could have stale references later. + while( maxDepth-- != 0 ) nodePath[ maxDepth ] = null; + if ( ASSERTS ) { + checkNodePath(); + checkTree( tree, 0, -1 ); + } + return e; + } + /* After execution of this method, {@link #modified} is true iff an entry + has been deleted. */ + + public V remove( final int k ) { + modified = false; + if ( tree == null ) return defRetValue; + Entry p = tree; + int cmp; + int i = 0; + final int kk = k; + while( true ) { + if ( ( cmp = compare( kk, p.key ) ) == 0 ) break; + dirPath[ i ] = cmp > 0; + nodePath[ i ] = p; + if ( dirPath[ i++ ] ) { + if ( ( p = p.right() ) == null ) { + // We clean up the node path, or we could have stale references later. + while( i-- != 0 ) nodePath[ i ] = null; + return defRetValue; + } + } + else { + if ( ( p = p.left() ) == null ) { + // We clean up the node path, or we could have stale references later. + while( i-- != 0 ) nodePath[ i ] = null; + return defRetValue; + } + } + } + if ( p.left == null ) firstEntry = p.next(); + if ( p.right == null ) lastEntry = p.prev(); + if ( p.succ() ) { + if ( p.pred() ) { + if ( i == 0 ) tree = p.left; + else { + if ( dirPath[ i - 1 ] ) nodePath[ i - 1 ].succ( p.right ); + else nodePath[ i - 1 ].pred( p.left ); + } + } + else { + p.prev().right = p.right; + if ( i == 0 ) tree = p.left; + else { + if ( dirPath[ i - 1 ] ) nodePath[ i - 1 ].right = p.left; + else nodePath[ i - 1 ].left = p.left; + } + } + } + else { + boolean color; + Entry r = p.right; + if ( r.pred() ) { + r.left = p.left; + r.pred( p.pred() ); + if ( ! r.pred() ) r.prev().right = r; + if ( i == 0 ) tree = r; + else { + if ( dirPath[ i - 1 ] ) nodePath[ i - 1 ].right = r; + else nodePath[ i - 1 ].left = r; + } + color = r.black(); + r.black( p.black() ); + p.black( color ); + dirPath[ i ] = true; + nodePath[ i++ ] = r; + } + else { + Entry s; + int j = i++; + while( true ) { + dirPath[ i ] = false; + nodePath[ i++ ] = r; + s = r.left; + if ( s.pred() ) break; + r = s; + } + dirPath[ j ] = true; + nodePath[ j ] = s; + if ( s.succ() ) r.pred( s ); + else r.left = s.right; + s.left = p.left; + if ( ! p.pred() ) { + p.prev().right = s; + s.pred( false ); + } + s.right( p.right ); + color = s.black(); + s.black( p.black() ); + p.black( color ); + if ( j == 0 ) tree = s; + else { + if ( dirPath[ j - 1 ] ) nodePath[ j - 1 ].right = s; + else nodePath[ j - 1 ].left = s; + } + } + } + int maxDepth = i; + if ( p.black() ) { + for( ; i > 0; i-- ) { + if ( dirPath[ i - 1 ] && ! nodePath[ i - 1 ].succ() || + ! dirPath[ i - 1 ] && ! nodePath[ i - 1 ].pred() ) { + Entry x = dirPath[ i - 1 ] ? nodePath[ i - 1 ].right : nodePath[ i - 1 ].left; + if ( ! x.black() ) { + x.black( true ); + break; + } + } + if ( ! dirPath[ i - 1 ] ) { + Entry w = nodePath[ i - 1 ].right; + if ( ! w.black() ) { + w.black( true ); + nodePath[ i - 1 ].black( false ); + nodePath[ i - 1 ].right = w.left; + w.left = nodePath[ i - 1 ]; + if ( i < 2 ) tree = w; + else { + if ( dirPath[ i - 2 ] ) nodePath[ i - 2 ].right = w; + else nodePath[ i - 2 ].left = w; + } + nodePath[ i ] = nodePath[ i - 1 ]; + dirPath[ i ] = false; + nodePath[ i - 1 ] = w; + if ( maxDepth == i++ ) maxDepth++; + w = nodePath[ i - 1 ].right; + } + if ( ( w.pred() || w.left.black() ) && + ( w.succ() || w.right.black() ) ) { + w.black( false ); + } + else { + if ( w.succ() || w.right.black() ) { + Entry y = w.left; + y.black ( true ); + w.black( false ); + w.left = y.right; + y.right = w; + w = nodePath[ i - 1 ].right = y; + if ( w.succ() ) { + w.succ( false ); + w.right.pred( w ); + } + } + w.black( nodePath[ i - 1 ].black() ); + nodePath[ i - 1 ].black( true ); + w.right.black( true ); + nodePath[ i - 1 ].right = w.left; + w.left = nodePath[ i - 1 ]; + if ( i < 2 ) tree = w; + else { + if ( dirPath[ i - 2 ] ) nodePath[ i - 2 ].right = w; + else nodePath[ i - 2 ].left = w; + } + if ( w.pred() ) { + w.pred( false ); + nodePath[ i - 1 ].succ( w ); + } + break; + } + } + else { + Entry w = nodePath[ i - 1 ].left; + if ( ! w.black() ) { + w.black ( true ); + nodePath[ i - 1 ].black( false ); + nodePath[ i - 1 ].left = w.right; + w.right = nodePath[ i - 1 ]; + if ( i < 2 ) tree = w; + else { + if ( dirPath[ i - 2 ] ) nodePath[ i - 2 ].right = w; + else nodePath[ i - 2 ].left = w; + } + nodePath[ i ] = nodePath[ i - 1 ]; + dirPath[ i ] = true; + nodePath[ i - 1 ] = w; + if ( maxDepth == i++ ) maxDepth++; + w = nodePath[ i - 1 ].left; + } + if ( ( w.pred() || w.left.black() ) && + ( w.succ() || w.right.black() ) ) { + w.black( false ); + } + else { + if ( w.pred() || w.left.black() ) { + Entry y = w.right; + y.black( true ); + w.black ( false ); + w.right = y.left; + y.left = w; + w = nodePath[ i - 1 ].left = y; + if ( w.pred() ) { + w.pred( false ); + w.left.succ( w ); + } + } + w.black( nodePath[ i - 1 ].black() ); + nodePath[ i - 1 ].black( true ); + w.left.black( true ); + nodePath[ i - 1 ].left = w.right; + w.right = nodePath[ i - 1 ]; + if ( i < 2 ) tree = w; + else { + if ( dirPath[ i - 2 ] ) nodePath[ i - 2 ].right = w; + else nodePath[ i - 2 ].left = w; + } + if ( w.succ() ) { + w.succ( false ); + nodePath[ i - 1 ].pred( w ); + } + break; + } + } + } + if ( tree != null ) tree.black( true ); + } + modified = true; + count--; + // We clean up the node path, or we could have stale references later. + while( maxDepth-- != 0 ) nodePath[ maxDepth ] = null; + if ( ASSERTS ) { + checkNodePath(); + checkTree( tree, 0, -1 ); + } + return p.value; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Integer ok, final V ov ) { + final V oldValue = put( ((ok).intValue()), (ov) ); + return modified ? (this.defRetValue) : (oldValue); + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V remove( final Object ok ) { + final V oldValue = remove( ((((Integer)(ok)).intValue())) ); + return modified ? (oldValue) : (this.defRetValue); + } + public boolean containsValue( final Object v ) { + final ValueIterator i = new ValueIterator(); + Object ev; + int j = count; + while( j-- != 0 ) { + ev = i.next(); + if ( ( (ev) == null ? (v) == null : (ev).equals(v) ) ) return true; + } + return false; + } + public void clear() { + count = 0; + tree = null; + entries = null; + values = null; + keys = null; + firstEntry = lastEntry = null; + } + /** This class represent an entry in a tree map. + * + *

We use the only "metadata", i.e., {@link Entry#info}, to store + * information about color, predecessor status and successor status. + * + *

Note that since the class is recursive, it can be + * considered equivalently a tree. + */ + private static final class Entry implements Cloneable, Int2ObjectMap.Entry { + /** The the bit in this mask is true, the node is black. */ + private final static int BLACK_MASK = 1; + /** If the bit in this mask is true, {@link #right} points to a successor. */ + private final static int SUCC_MASK = 1 << 31; + /** If the bit in this mask is true, {@link #left} points to a predecessor. */ + private final static int PRED_MASK = 1 << 30; + /** The key of this entry. */ + int key; + /** The value of this entry. */ + V value; + /** The pointers to the left and right subtrees. */ + Entry left, right; + /** This integers holds different information in different bits (see {@link #SUCC_MASK} and {@link #PRED_MASK}. */ + int info; + Entry() {} + /** Creates a new entry with the given key and value. + * + * @param k a key. + * @param v a value. + */ + Entry( final int k, final V v ) { + this.key = k; + this.value = v; + info = SUCC_MASK | PRED_MASK; + } + /** Returns the left subtree. + * + * @return the left subtree (null if the left + * subtree is empty). + */ + Entry left() { + return ( info & PRED_MASK ) != 0 ? null : left; + } + /** Returns the right subtree. + * + * @return the right subtree (null if the right + * subtree is empty). + */ + Entry right() { + return ( info & SUCC_MASK ) != 0 ? null : right; + } + /** Checks whether the left pointer is really a predecessor. + * @return true if the left pointer is a predecessor. + */ + boolean pred() { + return ( info & PRED_MASK ) != 0; + } + /** Checks whether the right pointer is really a successor. + * @return true if the right pointer is a successor. + */ + boolean succ() { + return ( info & SUCC_MASK ) != 0; + } + /** Sets whether the left pointer is really a predecessor. + * @param pred if true then the left pointer will be considered a predecessor. + */ + void pred( final boolean pred ) { + if ( pred ) info |= PRED_MASK; + else info &= ~PRED_MASK; + } + /** Sets whether the right pointer is really a successor. + * @param succ if true then the right pointer will be considered a successor. + */ + void succ( final boolean succ ) { + if ( succ ) info |= SUCC_MASK; + else info &= ~SUCC_MASK; + } + /** Sets the left pointer to a predecessor. + * @param pred the predecessr. + */ + void pred( final Entry pred ) { + info |= PRED_MASK; + left = pred; + } + /** Sets the right pointer to a successor. + * @param succ the successor. + */ + void succ( final Entry succ ) { + info |= SUCC_MASK; + right = succ; + } + /** Sets the left pointer to the given subtree. + * @param left the new left subtree. + */ + void left( final Entry left ) { + info &= ~PRED_MASK; + this.left = left; + } + /** Sets the right pointer to the given subtree. + * @param right the new right subtree. + */ + void right( final Entry right ) { + info &= ~SUCC_MASK; + this.right = right; + } + /** Returns whether this node is black. + * @return true iff this node is black. + */ + boolean black() { + return ( info & BLACK_MASK ) != 0; + } + /** Sets whether this node is black. + * @param black if true, then this node becomes black; otherwise, it becomes red.. + */ + void black( final boolean black ) { + if ( black ) info |= BLACK_MASK; + else info &= ~BLACK_MASK; + } + /** Computes the next entry in the set order. + * + * @return the next entry (null) if this is the last entry). + */ + Entry next() { + Entry next = this.right; + if ( ( info & SUCC_MASK ) == 0 ) while ( ( next.info & PRED_MASK ) == 0 ) next = next.left; + return next; + } + /** Computes the previous entry in the set order. + * + * @return the previous entry (null) if this is the first entry). + */ + Entry prev() { + Entry prev = this.left; + if ( ( info & PRED_MASK ) == 0 ) while ( ( prev.info & SUCC_MASK ) == 0 ) prev = prev.right; + return prev; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer getKey() { + return (Integer.valueOf(key)); + } + public int getIntKey() { + return key; + } + public V getValue() { + return (value); + } + public V setValue(final V value) { + final V oldValue = this.value; + this.value = value; + return oldValue; + } + @SuppressWarnings("unchecked") + public Entry clone() { + Entry c; + try { + c = (Entry )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.key = key; + c.value = value; + c.info = info; + return c; + } + @SuppressWarnings("unchecked") + public boolean equals( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + Map.Entry e = (Map.Entry )o; + return ( (key) == (((e.getKey()).intValue())) ) && ( (value) == null ? ((e.getValue())) == null : (value).equals((e.getValue())) ); + } + public int hashCode() { + return (key) ^ ( (value) == null ? 0 : (value).hashCode() ); + } + public String toString() { + return key + "=>" + value; + } + /* + public void prettyPrint() { + prettyPrint(0); + } + + public void prettyPrint(int level) { + if ( pred() ) { + for (int i = 0; i < level; i++) + System.err.print(" "); + System.err.println("pred: " + left ); + } + else if (left != null) + left.prettyPrint(level +1 ); + for (int i = 0; i < level; i++) + System.err.print(" "); + System.err.println(key + "=" + value + " (" + balance() + ")"); + if ( succ() ) { + for (int i = 0; i < level; i++) + System.err.print(" "); + System.err.println("succ: " + right ); + } + else if (right != null) + right.prettyPrint(level + 1); + }*/ + } + /* + public void prettyPrint() { + System.err.println("size: " + count); + if (tree != null) tree.prettyPrint(); + }*/ + + public boolean containsKey( final int k ) { + return findKey( k ) != null; + } + public int size() { + return count; + } + public boolean isEmpty() { + return count == 0; + } + + public V get( final int k ) { + final Entry e = findKey( k ); + return e == null ? defRetValue : e.value; + } + public int firstIntKey() { + if ( tree == null ) throw new NoSuchElementException(); + return firstEntry.key; + } + public int lastIntKey() { + if ( tree == null ) throw new NoSuchElementException(); + return lastEntry.key; + } + /** An abstract iterator on the whole range. + * + *

This class can iterate in both directions on a threaded tree. + */ + private class TreeIterator { + /** The entry that will be returned by the next call to {@link java.util.ListIterator#previous()} (or null if no previous entry exists). */ + Entry prev; + /** The entry that will be returned by the next call to {@link java.util.ListIterator#next()} (or null if no next entry exists). */ + Entry next; + /** The last entry that was returned (or null if we did not iterate or used {@link #remove()}). */ + Entry curr; + /** The current index (in the sense of a {@link java.util.ListIterator}). Note that this value is not meaningful when this {@link TreeIterator} has been created using the nonempty constructor.*/ + int index = 0; + TreeIterator() { + next = firstEntry; + } + TreeIterator( final int k ) { + if ( ( next = locateKey( k ) ) != null ) { + if ( compare( next.key, k ) <= 0 ) { + prev = next; + next = next.next(); + } + else prev = next.prev(); + } + } + public boolean hasNext() { return next != null; } + public boolean hasPrevious() { return prev != null; } + void updateNext() { + next = next.next(); + } + Entry nextEntry() { + if ( ! hasNext() ) throw new NoSuchElementException(); + curr = prev = next; + index++; + updateNext(); + return curr; + } + void updatePrevious() { + prev = prev.prev(); + } + Entry previousEntry() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + curr = next = prev; + index--; + updatePrevious(); + return curr; + } + public int nextIndex() { + return index; + } + public int previousIndex() { + return index - 1; + } + public void remove() { + if ( curr == null ) throw new IllegalStateException(); + /* If the last operation was a next(), we are removing an entry that preceeds + the current index, and thus we must decrement it. */ + if ( curr == prev ) index--; + next = prev = curr; + updatePrevious(); + updateNext(); + Int2ObjectRBTreeMap.this.remove( curr.key ); + curr = null; + } + public int skip( final int n ) { + int i = n; + while( i-- != 0 && hasNext() ) nextEntry(); + return n - i - 1; + } + public int back( final int n ) { + int i = n; + while( i-- != 0 && hasPrevious() ) previousEntry(); + return n - i - 1; + } + } + /** An iterator on the whole range. + * + *

This class can iterate in both directions on a threaded tree. + */ + private class EntryIterator extends TreeIterator implements ObjectListIterator > { + EntryIterator() {} + EntryIterator( final int k ) { + super( k ); + } + public Int2ObjectMap.Entry next() { return nextEntry(); } + public Int2ObjectMap.Entry previous() { return previousEntry(); } + public void set( Int2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + public void add( Int2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + } + public ObjectSortedSet > int2ObjectEntrySet() { + if ( entries == null ) entries = new AbstractObjectSortedSet >() { + final Comparator > comparator = new Comparator > () { + public int compare( final Int2ObjectMap.Entry x, Int2ObjectMap.Entry y ) { + return Int2ObjectRBTreeMap.this.actualComparator.compare( x.getIntKey(), y.getIntKey() ); + } + }; + public Comparator > comparator() { + return comparator; + } + public ObjectBidirectionalIterator > iterator() { + return new EntryIterator(); + } + public ObjectBidirectionalIterator > iterator( final Int2ObjectMap.Entry from ) { + return new EntryIterator( from.getIntKey() ); + } + @SuppressWarnings("unchecked") + public boolean contains( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final Entry f = findKey( ((e.getKey()).intValue()) ); + return e.equals( f ); + } + @SuppressWarnings("unchecked") + public boolean remove( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final Entry f = findKey( ((e.getKey()).intValue()) ); + if ( f != null ) Int2ObjectRBTreeMap.this.remove( f.key ); + return f != null; + } + public int size() { return count; } + public void clear() { Int2ObjectRBTreeMap.this.clear(); } + public Int2ObjectMap.Entry first() { return firstEntry; } + public Int2ObjectMap.Entry last() { return lastEntry; } + public ObjectSortedSet > subSet( Int2ObjectMap.Entry from, Int2ObjectMap.Entry to ) { return subMap( from.getIntKey(), to.getIntKey() ).int2ObjectEntrySet(); } + public ObjectSortedSet > headSet( Int2ObjectMap.Entry to ) { return headMap( to.getIntKey() ).int2ObjectEntrySet(); } + public ObjectSortedSet > tailSet( Int2ObjectMap.Entry from ) { return tailMap( from.getIntKey() ).int2ObjectEntrySet(); } + }; + return entries; + } + /** An iterator on the whole range of keys. + * + *

This class can iterate in both directions on the keys of a threaded tree. We + * simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods (and possibly + * their type-specific counterparts) so that they return keys instead of entries. + */ + private final class KeyIterator extends TreeIterator implements IntListIterator { + public KeyIterator() {} + public KeyIterator( final int k ) { super( k ); } + public int nextInt() { return nextEntry().key; } + public int previousInt() { return previousEntry().key; } + public void set( int k ) { throw new UnsupportedOperationException(); } + public void add( int k ) { throw new UnsupportedOperationException(); } + public Integer next() { return (Integer.valueOf(nextEntry().key)); } + public Integer previous() { return (Integer.valueOf(previousEntry().key)); } + public void set( Integer ok ) { throw new UnsupportedOperationException(); } + public void add( Integer ok ) { throw new UnsupportedOperationException(); } + }; + /** A keyset implementation using a more direct implementation for iterators. */ + private class KeySet extends AbstractInt2ObjectSortedMap .KeySet { + public IntBidirectionalIterator iterator() { return new KeyIterator(); } + public IntBidirectionalIterator iterator( final int from ) { return new KeyIterator( from ); } + } + /** Returns a type-specific sorted set view of the keys contained in this map. + * + *

In addition to the semantics of {@link java.util.Map#keySet()}, you can + * safely cast the set returned by this call to a type-specific sorted + * set interface. + * + * @return a type-specific sorted set view of the keys contained in this map. + */ + public IntSortedSet keySet() { + if ( keys == null ) keys = new KeySet(); + return keys; + } + /** An iterator on the whole range of values. + * + *

This class can iterate in both directions on the values of a threaded tree. We + * simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods (and possibly + * their type-specific counterparts) so that they return values instead of entries. + */ + private final class ValueIterator extends TreeIterator implements ObjectListIterator { + public V next() { return nextEntry().value; } + public V previous() { return previousEntry().value; } + public void set( V v ) { throw new UnsupportedOperationException(); } + public void add( V v ) { throw new UnsupportedOperationException(); } + }; + /** Returns a type-specific collection view of the values contained in this map. + * + *

In addition to the semantics of {@link java.util.Map#values()}, you can + * safely cast the collection returned by this call to a type-specific collection + * interface. + * + * @return a type-specific collection view of the values contained in this map. + */ + public ObjectCollection values() { + if ( values == null ) values = new AbstractObjectCollection () { + public ObjectIterator iterator() { + return new ValueIterator(); + } + public boolean contains( final Object k ) { + return containsValue( k ); + } + public int size() { + return count; + } + public void clear() { + Int2ObjectRBTreeMap.this.clear(); + } + }; + return values; + } + public IntComparator comparator() { + return actualComparator; + } + public Int2ObjectSortedMap headMap( int to ) { + return new Submap( (0), true, to, false ); + } + public Int2ObjectSortedMap tailMap( int from ) { + return new Submap( from, false, (0), true ); + } + public Int2ObjectSortedMap subMap( int from, int to ) { + return new Submap( from, false, to, false ); + } + /** A submap with given range. + * + *

This class represents a submap. One has to specify the left/right + * limits (which can be set to -∞ or ∞). Since the submap is a + * view on the map, at a given moment it could happen that the limits of + * the range are not any longer in the main map. Thus, things such as + * {@link java.util.SortedMap#firstKey()} or {@link java.util.Collection#size()} must be always computed + * on-the-fly. + */ + private final class Submap extends AbstractInt2ObjectSortedMap implements java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + /** The start of the submap range, unless {@link #bottom} is true. */ + int from; + /** The end of the submap range, unless {@link #top} is true. */ + int to; + /** If true, the submap range starts from -∞. */ + boolean bottom; + /** If true, the submap range goes to ∞. */ + boolean top; + /** Cached set of entries. */ + @SuppressWarnings("hiding") + protected transient ObjectSortedSet > entries; + /** Cached set of keys. */ + @SuppressWarnings("hiding") + protected transient IntSortedSet keys; + /** Cached collection of values. */ + @SuppressWarnings("hiding") + protected transient ObjectCollection values; + /** Creates a new submap with given key range. + * + * @param from the start of the submap range. + * @param bottom if true, the first parameter is ignored and the range starts from -∞. + * @param to the end of the submap range. + * @param top if true, the third parameter is ignored and the range goes to ∞. + */ + public Submap( final int from, final boolean bottom, final int to, final boolean top ) { + if ( ! bottom && ! top && Int2ObjectRBTreeMap.this.compare( from, to ) > 0 ) throw new IllegalArgumentException( "Start key (" + from + ") is larger than end key (" + to + ")" ); + this.from = from; + this.bottom = bottom; + this.to = to; + this.top = top; + this.defRetValue = Int2ObjectRBTreeMap.this.defRetValue; + } + public void clear() { + final SubmapIterator i = new SubmapIterator(); + while( i.hasNext() ) { + i.nextEntry(); + i.remove(); + } + } + /** Checks whether a key is in the submap range. + * @param k a key. + * @return true if is the key is in the submap range. + */ + final boolean in( final int k ) { + return ( bottom || Int2ObjectRBTreeMap.this.compare( k, from ) >= 0 ) && + ( top || Int2ObjectRBTreeMap.this.compare( k, to ) < 0 ); + } + public ObjectSortedSet > int2ObjectEntrySet() { + if ( entries == null ) entries = new AbstractObjectSortedSet >() { + public ObjectBidirectionalIterator > iterator() { + return new SubmapEntryIterator(); + } + public ObjectBidirectionalIterator > iterator( final Int2ObjectMap.Entry from ) { + return new SubmapEntryIterator( from.getIntKey() ); + } + public Comparator > comparator() { return Int2ObjectRBTreeMap.this.int2ObjectEntrySet().comparator(); } + @SuppressWarnings("unchecked") + public boolean contains( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + final Map.Entry e = (Map.Entry)o; + final Int2ObjectRBTreeMap.Entry f = findKey( ((e.getKey()).intValue()) ); + return f != null && in( f.key ) && e.equals( f ); + } + @SuppressWarnings("unchecked") + public boolean remove( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + final Map.Entry e = (Map.Entry)o; + final Int2ObjectRBTreeMap.Entry f = findKey( ((e.getKey()).intValue()) ); + if ( f != null && in( f.key ) ) Submap.this.remove( f.key ); + return f != null; + } + public int size() { + int c = 0; + for( Iterator i = iterator(); i.hasNext(); i.next() ) c++; + return c; + } + public boolean isEmpty() { return ! new SubmapIterator().hasNext(); } + public void clear() { Submap.this.clear(); } + public Int2ObjectMap.Entry first() { return firstEntry(); } + public Int2ObjectMap.Entry last() { return lastEntry(); } + public ObjectSortedSet > subSet( Int2ObjectMap.Entry from, Int2ObjectMap.Entry to ) { return subMap( from.getIntKey(), to.getIntKey() ).int2ObjectEntrySet(); } + public ObjectSortedSet > headSet( Int2ObjectMap.Entry to ) { return headMap( to.getIntKey() ).int2ObjectEntrySet(); } + public ObjectSortedSet > tailSet( Int2ObjectMap.Entry from ) { return tailMap( from.getIntKey() ).int2ObjectEntrySet(); } + }; + return entries; + } + private class KeySet extends AbstractInt2ObjectSortedMap .KeySet { + public IntBidirectionalIterator iterator() { return new SubmapKeyIterator(); } + public IntBidirectionalIterator iterator( final int from ) { return new SubmapKeyIterator( from ); } + } + public IntSortedSet keySet() { + if ( keys == null ) keys = new KeySet(); + return keys; + } + public ObjectCollection values() { + if ( values == null ) values = new AbstractObjectCollection () { + public ObjectIterator iterator() { + return new SubmapValueIterator(); + } + public boolean contains( final Object k ) { + return containsValue( k ); + } + public int size() { + return Submap.this.size(); + } + public void clear() { + Submap.this.clear(); + } + }; + return values; + } + + public boolean containsKey( final int k ) { + return in( k ) && Int2ObjectRBTreeMap.this.containsKey( k ); + } + public boolean containsValue( final Object v ) { + final SubmapIterator i = new SubmapIterator(); + Object ev; + while( i.hasNext() ) { + ev = i.nextEntry().value; + if ( ( (ev) == null ? (v) == null : (ev).equals(v) ) ) return true; + } + return false; + } + + public V get(final int k) { + final Int2ObjectRBTreeMap.Entry e; + final int kk = k; + return in( kk ) && ( e = findKey( kk ) ) != null ? e.value : this.defRetValue; + } + public V put(final int k, final V v) { + modified = false; + if ( ! in( k ) ) throw new IllegalArgumentException( "Key (" + k + ") out of range [" + ( bottom ? "-" : String.valueOf( from ) ) + ", " + ( top ? "-" : String.valueOf( to ) ) + ")" ); + final V oldValue = Int2ObjectRBTreeMap.this.put( k, v ); + return modified ? this.defRetValue : oldValue; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Integer ok, final V ov ) { + final V oldValue = put( ((ok).intValue()), (ov) ); + return modified ? (this.defRetValue) : (oldValue); + } + + public V remove( final int k ) { + modified = false; + if ( ! in( k ) ) return this.defRetValue; + final V oldValue = Int2ObjectRBTreeMap.this.remove( k ); + return modified ? oldValue : this.defRetValue; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V remove( final Object ok ) { + final V oldValue = remove( ((((Integer)(ok)).intValue())) ); + return modified ? (oldValue) : (this.defRetValue); + } + public int size() { + final SubmapIterator i = new SubmapIterator(); + int n = 0; + while( i.hasNext() ) { + n++; + i.nextEntry(); + } + return n; + } + public boolean isEmpty() { + return ! new SubmapIterator().hasNext(); + } + public IntComparator comparator() { + return actualComparator; + } + public Int2ObjectSortedMap headMap( final int to ) { + if ( top ) return new Submap( from, bottom, to, false ); + return compare( to, this.to ) < 0 ? new Submap( from, bottom, to, false ) : this; + } + public Int2ObjectSortedMap tailMap( final int from ) { + if ( bottom ) return new Submap( from, false, to, top ); + return compare( from, this.from ) > 0 ? new Submap( from, false, to, top ) : this; + } + public Int2ObjectSortedMap subMap( int from, int to ) { + if ( top && bottom ) return new Submap( from, false, to, false ); + if ( ! top ) to = compare( to, this.to ) < 0 ? to : this.to; + if ( ! bottom ) from = compare( from, this.from ) > 0 ? from : this.from; + if ( ! top && ! bottom && from == this.from && to == this.to ) return this; + return new Submap( from, false, to, false ); + } + /** Locates the first entry. + * + * @return the first entry of this submap, or null if the submap is empty. + */ + public Int2ObjectRBTreeMap.Entry firstEntry() { + if ( tree == null ) return null; + // If this submap goes to -infinity, we return the main map first entry; otherwise, we locate the start of the map. + Int2ObjectRBTreeMap.Entry e; + if ( bottom ) e = firstEntry; + else { + e = locateKey( from ); + // If we find either the start or something greater we're OK. + if ( compare( e.key, from ) < 0 ) e = e.next(); + } + // Finally, if this submap doesn't go to infinity, we check that the resulting key isn't greater than the end. + if ( e == null || ! top && compare( e.key, to ) >= 0 ) return null; + return e; + } + /** Locates the last entry. + * + * @return the last entry of this submap, or null if the submap is empty. + */ + public Int2ObjectRBTreeMap.Entry lastEntry() { + if ( tree == null ) return null; + // If this submap goes to infinity, we return the main map last entry; otherwise, we locate the end of the map. + Int2ObjectRBTreeMap.Entry e; + if ( top ) e = lastEntry; + else { + e = locateKey( to ); + // If we find something smaller than the end we're OK. + if ( compare( e.key, to ) >= 0 ) e = e.prev(); + } + // Finally, if this submap doesn't go to -infinity, we check that the resulting key isn't smaller than the start. + if ( e == null || ! bottom && compare( e.key, from ) < 0 ) return null; + return e; + } + public int firstIntKey() { + Int2ObjectRBTreeMap.Entry e = firstEntry(); + if ( e == null ) throw new NoSuchElementException(); + return e.key; + } + public int lastIntKey() { + Int2ObjectRBTreeMap.Entry e = lastEntry(); + if ( e == null ) throw new NoSuchElementException(); + return e.key; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Integer firstKey() { + Int2ObjectRBTreeMap.Entry e = firstEntry(); + if ( e == null ) throw new NoSuchElementException(); + return e.getKey(); + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Integer lastKey() { + Int2ObjectRBTreeMap.Entry e = lastEntry(); + if ( e == null ) throw new NoSuchElementException(); + return e.getKey(); + } + /** An iterator for subranges. + * + *

This class inherits from {@link TreeIterator}, but overrides the methods that + * update the pointer after a {@link java.util.ListIterator#next()} or {@link java.util.ListIterator#previous()}. If we would + * move out of the range of the submap we just overwrite the next or previous + * entry with null. + */ + private class SubmapIterator extends TreeIterator { + SubmapIterator() { + next = firstEntry(); + } + SubmapIterator( final int k ) { + this(); + if ( next != null ) { + if ( ! bottom && compare( k, next.key ) < 0 ) prev = null; + else if ( ! top && compare( k, ( prev = lastEntry() ).key ) >= 0 ) next = null; + else { + next = locateKey( k ); + if ( compare( next.key, k ) <= 0 ) { + prev = next; + next = next.next(); + } + else prev = next.prev(); + } + } + } + void updatePrevious() { + prev = prev.prev(); + if ( ! bottom && prev != null && Int2ObjectRBTreeMap.this.compare( prev.key, from ) < 0 ) prev = null; + } + void updateNext() { + next = next.next(); + if ( ! top && next != null && Int2ObjectRBTreeMap.this.compare( next.key, to ) >= 0 ) next = null; + } + } + private class SubmapEntryIterator extends SubmapIterator implements ObjectListIterator > { + SubmapEntryIterator() {} + SubmapEntryIterator( final int k ) { + super( k ); + } + public Int2ObjectMap.Entry next() { return nextEntry(); } + public Int2ObjectMap.Entry previous() { return previousEntry(); } + public void set( Int2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + public void add( Int2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + } + /** An iterator on a subrange of keys. + * + *

This class can iterate in both directions on a subrange of the + * keys of a threaded tree. We simply override the {@link + * java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods (and possibly their + * type-specific counterparts) so that they return keys instead of + * entries. + */ + private final class SubmapKeyIterator extends SubmapIterator implements IntListIterator { + public SubmapKeyIterator() { super(); } + public SubmapKeyIterator( int from ) { super( from ); } + public int nextInt() { return nextEntry().key; } + public int previousInt() { return previousEntry().key; } + public void set( int k ) { throw new UnsupportedOperationException(); } + public void add( int k ) { throw new UnsupportedOperationException(); } + public Integer next() { return (Integer.valueOf(nextEntry().key)); } + public Integer previous() { return (Integer.valueOf(previousEntry().key)); } + public void set( Integer ok ) { throw new UnsupportedOperationException(); } + public void add( Integer ok ) { throw new UnsupportedOperationException(); } + }; + /** An iterator on a subrange of values. + * + *

This class can iterate in both directions on the values of a + * subrange of the keys of a threaded tree. We simply override the + * {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods (and possibly their + * type-specific counterparts) so that they return values instead of + * entries. + */ + private final class SubmapValueIterator extends SubmapIterator implements ObjectListIterator { + public V next() { return nextEntry().value; } + public V previous() { return previousEntry().value; } + public void set( V v ) { throw new UnsupportedOperationException(); } + public void add( V v ) { throw new UnsupportedOperationException(); } + }; + } + /** Returns a deep copy of this tree map. + * + *

This method performs a deep copy of this tree map; the data stored in the + * set, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this tree map. + */ + @SuppressWarnings("unchecked") + public Int2ObjectRBTreeMap clone() { + Int2ObjectRBTreeMap c; + try { + c = (Int2ObjectRBTreeMap )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.keys = null; + c.values = null; + c.entries = null; + c.allocatePaths(); + if ( count != 0 ) { + // Also this apparently unfathomable code is derived from GNU libavl. + Entry e, p, q, rp = new Entry (), rq = new Entry (); + p = rp; + rp.left( tree ); + q = rq; + rq.pred( null ); + while( true ) { + if ( ! p.pred() ) { + e = p.left.clone(); + e.pred( q.left ); + e.succ( q ); + q.left( e ); + p = p.left; + q = q.left; + } + else { + while( p.succ() ) { + p = p.right; + if ( p == null ) { + q.right = null; + c.tree = rq.left; + c.firstEntry = c.tree; + while( c.firstEntry.left != null ) c.firstEntry = c.firstEntry.left; + c.lastEntry = c.tree; + while( c.lastEntry.right != null ) c.lastEntry = c.lastEntry.right; + return c; + } + q = q.right; + } + p = p.right; + q = q.right; + } + if ( ! p.succ() ) { + e = p.right.clone(); + e.succ( q.right ); + e.pred( q ); + q.right( e ); + } + } + } + return c; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + int n = count; + EntryIterator i = new EntryIterator(); + Entry e; + s.defaultWriteObject(); + while(n-- != 0) { + e = i.nextEntry(); + s.writeInt( e.key ); + s.writeObject( e.value ); + } + } + /** Reads the given number of entries from the input stream, returning the corresponding tree. + * + * @param s the input stream. + * @param n the (positive) number of entries to read. + * @param pred the entry containing the key that preceeds the first key in the tree. + * @param succ the entry containing the key that follows the last key in the tree. + */ + @SuppressWarnings("unchecked") + private Entry readTree( final java.io.ObjectInputStream s, final int n, final Entry pred, final Entry succ ) throws java.io.IOException, ClassNotFoundException { + if ( n == 1 ) { + final Entry top = new Entry ( s.readInt(), (V) s.readObject() ); + top.pred( pred ); + top.succ( succ ); + top.black( true ); + return top; + } + if ( n == 2 ) { + /* We handle separately this case so that recursion will + *always* be on nonempty subtrees. */ + final Entry top = new Entry ( s.readInt(), (V) s.readObject() ); + top.black( true ); + top.right( new Entry ( s.readInt(), (V) s.readObject() ) ); + top.right.pred( top ); + top.pred( pred ); + top.right.succ( succ ); + return top; + } + // The right subtree is the largest one. + final int rightN = n / 2, leftN = n - rightN - 1; + final Entry top = new Entry (); + top.left( readTree( s, leftN, pred, top ) ); + top.key = s.readInt(); + top.value = (V) s.readObject(); + top.black( true ); + top.right( readTree( s, rightN, top, succ ) ); + if ( n + 2 == ( ( n + 2 ) & -( n + 2 ) ) ) top.right.black( false ); // Quick test for determining whether n + 2 is a power of 2. + return top; + } + private void readObject( java.io.ObjectInputStream s ) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + /* The storedComparator is now correctly set, but we must restore + on-the-fly the actualComparator. */ + setActualComparator(); + allocatePaths(); + if ( count != 0 ) { + tree = readTree( s, count, null, null ); + Entry e; + e = tree; + while( e.left() != null ) e = e.left(); + firstEntry = e; + e = tree; + while( e.right() != null ) e = e.right(); + lastEntry = e; + } + if ( ASSERTS ) checkTree( tree, 0, -1 ); + } + private void checkNodePath() {} + @SuppressWarnings("unused") + private static int checkTree( Entry e, int d, int D ) { return 0; } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectSortedMap.java b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectSortedMap.java new file mode 100644 index 0000000..04fbc68 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectSortedMap.java @@ -0,0 +1,181 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectSortedSet; +import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; +import java.util.Map; +import java.util.SortedMap; +/** A type-specific {@link SortedMap}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Additionally, this interface strengthens {@link #entrySet()}, + * {@link #keySet()}, {@link #values()}, + * {@link #comparator()}, {@link SortedMap#subMap(Object,Object)}, {@link SortedMap#headMap(Object)} and {@link SortedMap#tailMap(Object)}. + * + * @see SortedMap + */ +public interface Int2ObjectSortedMap extends Int2ObjectMap , SortedMap { + /** A sorted entry set providing fast iteration. + * + *

In some cases (e.g., hash-based classes) iteration over an entry set requires the creation + * of a large number of entry objects. Some fastutil + * maps might return {@linkplain #entrySet() entry set} objects of type FastSortedEntrySet: in this case, {@link #fastIterator() fastIterator()} + * will return an iterator that is guaranteed not to create a large number of objects, possibly + * by returning always the same entry (of course, mutated). + */ + public interface FastSortedEntrySet extends ObjectSortedSet >, FastEntrySet { + /** Returns a fast iterator over this sorted entry set; the iterator might return always the same entry object, suitably mutated. + * + * @return a fast iterator over this sorted entry set; the iterator might return always the same entry object, suitably mutated. + */ + public ObjectBidirectionalIterator > fastIterator( Int2ObjectMap.Entry from ); + } + /** Returns a sorted-set view of the mappings contained in this map. + * Note that this specification strengthens the one given in the + * corresponding type-specific unsorted map. + * + * @return a sorted-set view of the mappings contained in this map. + * @see Map#entrySet() + */ + ObjectSortedSet> entrySet(); + /** Returns a type-specific sorted-set view of the mappings contained in this map. + * Note that this specification strengthens the one given in the + * corresponding type-specific unsorted map. + * + * @return a type-specific sorted-set view of the mappings contained in this map. + * @see #entrySet() + */ + ObjectSortedSet > int2ObjectEntrySet(); + /** Returns a sorted-set view of the keys contained in this map. + * Note that this specification strengthens the one given in the + * corresponding type-specific unsorted map. + * + * @return a sorted-set view of the keys contained in this map. + * @see Map#keySet() + */ + IntSortedSet keySet(); + /** Returns a set view of the values contained in this map. + *

Note that this specification strengthens the one given in {@link Map#values()}, + * which was already strengthened in the corresponding type-specific class, + * but was weakened by the fact that this interface extends {@link SortedMap}. + * + * @return a set view of the values contained in this map. + * @see Map#values() + */ + ObjectCollection values(); + /** Returns the comparator associated with this sorted set, or null if it uses its keys' natural ordering. + * + *

Note that this specification strengthens the one given in {@link SortedMap#comparator()}. + * + * @see SortedMap#comparator() + */ + IntComparator comparator(); + /** Returns a view of the portion of this sorted map whose keys range from fromKey, inclusive, to toKey, exclusive. + * + *

Note that this specification strengthens the one given in {@link SortedMap#subMap(Object,Object)}. + * + * @see SortedMap#subMap(Object,Object) + */ + Int2ObjectSortedMap subMap(Integer fromKey, Integer toKey); + /** Returns a view of the portion of this sorted map whose keys are strictly less than toKey. + * + *

Note that this specification strengthens the one given in {@link SortedMap#headMap(Object)}. + * + * @see SortedMap#headMap(Object) + */ + Int2ObjectSortedMap headMap(Integer toKey); + /** Returns a view of the portion of this sorted map whose keys are greater than or equal to fromKey. + * + *

Note that this specification strengthens the one given in {@link SortedMap#tailMap(Object)}. + * + * @see SortedMap#tailMap(Object) + */ + Int2ObjectSortedMap tailMap(Integer fromKey); + /** Returns a view of the portion of this sorted map whose keys range from fromKey, inclusive, to toKey, exclusive. + * @see SortedMap#subMap(Object,Object) + */ + Int2ObjectSortedMap subMap(int fromKey, int toKey); + /** Returns a view of the portion of this sorted map whose keys are strictly less than toKey. + * @see SortedMap#headMap(Object) + */ + Int2ObjectSortedMap headMap(int toKey); + /** Returns a view of the portion of this sorted map whose keys are greater than or equal to fromKey. + * @see SortedMap#tailMap(Object) + */ + Int2ObjectSortedMap tailMap(int fromKey); + /** + * @see SortedMap#firstKey() + */ + int firstIntKey(); + /** + * @see SortedMap#lastKey() + */ + int lastIntKey(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectSortedMaps.java b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectSortedMaps.java new file mode 100644 index 0000000..49e4cc7 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/Int2ObjectSortedMaps.java @@ -0,0 +1,326 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.objects.ObjectSortedSet; +import it.unimi.dsi.fastutil.objects.ObjectSortedSets; +import java.util.Comparator; +import java.util.Map; +import java.util.SortedMap; +import java.util.NoSuchElementException; +/** A class providing static methods and objects that do useful things with type-specific sorted maps. + * + * @see java.util.Collections + */ +public class Int2ObjectSortedMaps { + private Int2ObjectSortedMaps() {} + /** Returns a comparator for entries based on a given comparator on keys. + * + * @param comparator a comparator on keys. + * @return the associated comparator on entries. + */ + public static Comparator> entryComparator( final IntComparator comparator ) { + return new Comparator>() { + public int compare( Map.Entry x, Map.Entry y ) { + return comparator.compare( x.getKey(), y.getKey() ); + } + }; + } + /** An immutable class representing an empty type-specific sorted map. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific sorted map. + */ + public static class EmptySortedMap extends Int2ObjectMaps.EmptyMap implements Int2ObjectSortedMap , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptySortedMap() {} + public IntComparator comparator() { return null; } + @SuppressWarnings("unchecked") + public ObjectSortedSet > int2ObjectEntrySet() { return ObjectSortedSets.EMPTY_SET; } + @SuppressWarnings("unchecked") + public ObjectSortedSet> entrySet() { return ObjectSortedSets.EMPTY_SET; } + + public IntSortedSet keySet() { return IntSortedSets.EMPTY_SET; } + @SuppressWarnings("unchecked") + public Int2ObjectSortedMap subMap( final int from, final int to ) { return EMPTY_MAP; } + @SuppressWarnings("unchecked") + public Int2ObjectSortedMap headMap( final int to ) { return EMPTY_MAP; } + @SuppressWarnings("unchecked") + public Int2ObjectSortedMap tailMap( final int from ) { return EMPTY_MAP; } + public int firstIntKey() { throw new NoSuchElementException(); } + public int lastIntKey() { throw new NoSuchElementException(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Int2ObjectSortedMap headMap( Integer oto ) { return headMap( ((oto).intValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Int2ObjectSortedMap tailMap( Integer ofrom ) { return tailMap( ((ofrom).intValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Int2ObjectSortedMap subMap( Integer ofrom, Integer oto ) { return subMap( ((ofrom).intValue()), ((oto).intValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer firstKey() { return (Integer.valueOf(firstIntKey())); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer lastKey() { return (Integer.valueOf(lastIntKey())); } + } + /** An empty sorted map (immutable). It is serializable and cloneable. + */ + @SuppressWarnings("rawtypes") + public static final EmptySortedMap EMPTY_MAP = new EmptySortedMap(); + /** Return an empty sorted map (immutable). It is serializable and cloneable. + * + *

This method provides a typesafe access to {@link #EMPTY_MAP}. + * @return an empty sorted map (immutable). + */ + @SuppressWarnings("unchecked") + public static Int2ObjectSortedMap emptyMap() { + return EMPTY_MAP; + } + /** An immutable class representing a type-specific singleton sorted map. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific sorted map. + */ + public static class Singleton extends Int2ObjectMaps.Singleton implements Int2ObjectSortedMap , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected final IntComparator comparator; + protected Singleton( final int key, final V value, IntComparator comparator ) { + super( key, value ); + this.comparator = comparator; + } + protected Singleton( final int key, final V value ) { + this( key, value, null ); + } + + final int compare( final int k1, final int k2 ) { + return comparator == null ? ( Integer.compare((k1),(k2)) ) : comparator.compare( k1, k2 ); + } + public IntComparator comparator() { return comparator; } + + public ObjectSortedSet > int2ObjectEntrySet() { if ( entries == null ) entries = ObjectSortedSets.singleton( (Int2ObjectMap.Entry )new SingletonEntry(), (Comparator >)entryComparator( comparator ) ); return (ObjectSortedSet >)entries; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + public ObjectSortedSet> entrySet() { return (ObjectSortedSet)int2ObjectEntrySet(); } + public IntSortedSet keySet() { if ( keys == null ) keys = IntSortedSets.singleton( key, comparator ); return (IntSortedSet )keys; } + @SuppressWarnings("unchecked") + public Int2ObjectSortedMap subMap( final int from, final int to ) { if ( compare( from, key ) <= 0 && compare( key, to ) < 0 ) return this; return EMPTY_MAP; } + @SuppressWarnings("unchecked") + public Int2ObjectSortedMap headMap( final int to ) { if ( compare( key, to ) < 0 ) return this; return EMPTY_MAP; } + @SuppressWarnings("unchecked") + public Int2ObjectSortedMap tailMap( final int from ) { if ( compare( from, key ) <= 0 ) return this; return EMPTY_MAP; } + public int firstIntKey() { return key; } + public int lastIntKey() { return key; } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Int2ObjectSortedMap headMap( Integer oto ) { return headMap( ((oto).intValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Int2ObjectSortedMap tailMap( Integer ofrom ) { return tailMap( ((ofrom).intValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Int2ObjectSortedMap subMap( Integer ofrom, Integer oto ) { return subMap( ((ofrom).intValue()), ((oto).intValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer firstKey() { return (Integer.valueOf(firstIntKey())); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer lastKey() { return (Integer.valueOf(lastIntKey())); } + } + /** Returns a type-specific immutable sorted map containing only the specified pair. The returned sorted map is serializable and cloneable. + * + *

Note that albeit the returned map is immutable, its default return value may be changed. + * + * @param key the only key of the returned sorted map. + * @param value the only value of the returned sorted map. + * @return a type-specific immutable sorted map containing just the pair <key,value>. + */ + public static Int2ObjectSortedMap singleton( final Integer key, V value ) { + return new Singleton ( ((key).intValue()), (value) ); + } + /** RETURNS a type-specific immutable sorted map containing only the specified pair. The returned sorted map is serializable and cloneable. + * + *

Note that albeit the returned map is immutable, its default return value may be changed. + * + * @param key the only key of the returned sorted map. + * @param value the only value of the returned sorted map. + * @param comparator the comparator to use in the returned sorted map. + * @return a type-specific immutable sorted map containing just the pair <key,value>. + */ + public static Int2ObjectSortedMap singleton( final Integer key, V value, IntComparator comparator ) { + return new Singleton ( ((key).intValue()), (value), comparator ); + } + /** Returns a type-specific immutable sorted map containing only the specified pair. The returned sorted map is serializable and cloneable. + * + *

Note that albeit the returned map is immutable, its default return value may be changed. + * + * @param key the only key of the returned sorted map. + * @param value the only value of the returned sorted map. + * @return a type-specific immutable sorted map containing just the pair <key,value>. + */ + public static Int2ObjectSortedMap singleton( final int key, final V value ) { + return new Singleton ( key, value ); + } + /** Returns a type-specific immutable sorted map containing only the specified pair. The returned sorted map is serializable and cloneable. + * + *

Note that albeit the returned map is immutable, its default return value may be changed. + * + * @param key the only key of the returned sorted map. + * @param value the only value of the returned sorted map. + * @param comparator the comparator to use in the returned sorted map. + * @return a type-specific immutable sorted map containing just the pair <key,value>. + */ + public static Int2ObjectSortedMap singleton( final int key, final V value, IntComparator comparator ) { + return new Singleton ( key, value, comparator ); + } + /** A synchronized wrapper class for sorted maps. */ + public static class SynchronizedSortedMap extends Int2ObjectMaps.SynchronizedMap implements Int2ObjectSortedMap , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final Int2ObjectSortedMap sortedMap; + protected SynchronizedSortedMap( final Int2ObjectSortedMap m, final Object sync ) { + super( m, sync ); + sortedMap = m; + } + protected SynchronizedSortedMap( final Int2ObjectSortedMap m ) { + super( m ); + sortedMap = m; + } + public IntComparator comparator() { synchronized( sync ) { return sortedMap.comparator(); } } + public ObjectSortedSet > int2ObjectEntrySet() { if ( entries == null ) entries = ObjectSortedSets.synchronize( sortedMap.int2ObjectEntrySet(), sync ); return (ObjectSortedSet >)entries; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + public ObjectSortedSet> entrySet() { return (ObjectSortedSet)int2ObjectEntrySet(); } + public IntSortedSet keySet() { if ( keys == null ) keys = IntSortedSets.synchronize( sortedMap.keySet(), sync ); return (IntSortedSet )keys; } + public Int2ObjectSortedMap subMap( final int from, final int to ) { return new SynchronizedSortedMap ( sortedMap.subMap( from, to ), sync ); } + public Int2ObjectSortedMap headMap( final int to ) { return new SynchronizedSortedMap ( sortedMap.headMap( to ), sync ); } + public Int2ObjectSortedMap tailMap( final int from ) { return new SynchronizedSortedMap ( sortedMap.tailMap( from ), sync ); } + public int firstIntKey() { synchronized( sync ) { return sortedMap.firstIntKey(); } } + public int lastIntKey() { synchronized( sync ) { return sortedMap.lastIntKey(); } } + public Integer firstKey() { synchronized( sync ) { return sortedMap.firstKey(); } } + public Integer lastKey() { synchronized( sync ) { return sortedMap.lastKey(); } } + public Int2ObjectSortedMap subMap( final Integer from, final Integer to ) { return new SynchronizedSortedMap ( sortedMap.subMap( from, to ), sync ); } + public Int2ObjectSortedMap headMap( final Integer to ) { return new SynchronizedSortedMap ( sortedMap.headMap( to ), sync ); } + public Int2ObjectSortedMap tailMap( final Integer from ) { return new SynchronizedSortedMap ( sortedMap.tailMap( from ), sync ); } + } + /** Returns a synchronized type-specific sorted map backed by the given type-specific sorted map. + * + * @param m the sorted map to be wrapped in a synchronized sorted map. + * @return a synchronized view of the specified sorted map. + * @see java.util.Collections#synchronizedSortedMap(SortedMap) + */ + public static Int2ObjectSortedMap synchronize( final Int2ObjectSortedMap m ) { return new SynchronizedSortedMap ( m ); } + /** Returns a synchronized type-specific sorted map backed by the given type-specific sorted map, using an assigned object to synchronize. + * + * @param m the sorted map to be wrapped in a synchronized sorted map. + * @param sync an object that will be used to synchronize the access to the sorted sorted map. + * @return a synchronized view of the specified sorted map. + * @see java.util.Collections#synchronizedSortedMap(SortedMap) + */ + public static Int2ObjectSortedMap synchronize( final Int2ObjectSortedMap m, final Object sync ) { return new SynchronizedSortedMap ( m, sync ); } + /** An unmodifiable wrapper class for sorted maps. */ + public static class UnmodifiableSortedMap extends Int2ObjectMaps.UnmodifiableMap implements Int2ObjectSortedMap , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final Int2ObjectSortedMap sortedMap; + protected UnmodifiableSortedMap( final Int2ObjectSortedMap m ) { + super( m ); + sortedMap = m; + } + public IntComparator comparator() { return sortedMap.comparator(); } + public ObjectSortedSet > int2ObjectEntrySet() { if ( entries == null ) entries = ObjectSortedSets.unmodifiable( sortedMap.int2ObjectEntrySet() ); return (ObjectSortedSet >)entries; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + public ObjectSortedSet> entrySet() { return (ObjectSortedSet)int2ObjectEntrySet(); } + public IntSortedSet keySet() { if ( keys == null ) keys = IntSortedSets.unmodifiable( sortedMap.keySet() ); return (IntSortedSet )keys; } + public Int2ObjectSortedMap subMap( final int from, final int to ) { return new UnmodifiableSortedMap ( sortedMap.subMap( from, to ) ); } + public Int2ObjectSortedMap headMap( final int to ) { return new UnmodifiableSortedMap ( sortedMap.headMap( to ) ); } + public Int2ObjectSortedMap tailMap( final int from ) { return new UnmodifiableSortedMap ( sortedMap.tailMap( from ) ); } + public int firstIntKey() { return sortedMap.firstIntKey(); } + public int lastIntKey() { return sortedMap.lastIntKey(); } + public Integer firstKey() { return sortedMap.firstKey(); } + public Integer lastKey() { return sortedMap.lastKey(); } + public Int2ObjectSortedMap subMap( final Integer from, final Integer to ) { return new UnmodifiableSortedMap ( sortedMap.subMap( from, to ) ); } + public Int2ObjectSortedMap headMap( final Integer to ) { return new UnmodifiableSortedMap ( sortedMap.headMap( to ) ); } + public Int2ObjectSortedMap tailMap( final Integer from ) { return new UnmodifiableSortedMap ( sortedMap.tailMap( from ) ); } + } + /** Returns an unmodifiable type-specific sorted map backed by the given type-specific sorted map. + * + * @param m the sorted map to be wrapped in an unmodifiable sorted map. + * @return an unmodifiable view of the specified sorted map. + * @see java.util.Collections#unmodifiableSortedMap(SortedMap) + */ + public static Int2ObjectSortedMap unmodifiable( final Int2ObjectSortedMap m ) { return new UnmodifiableSortedMap ( m ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntArrayFIFOQueue.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntArrayFIFOQueue.java new file mode 100644 index 0000000..d6835e9 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntArrayFIFOQueue.java @@ -0,0 +1,226 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2010-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.io.Serializable; +import it.unimi.dsi.fastutil.HashCommon; +import java.util.NoSuchElementException; +/** A type-specific array-based FIFO queue, supporting also deque operations. + * + *

Instances of this class represent a FIFO queue using a backing + * array in a circular way. The array is enlarged and shrunk as needed. You can use the {@link #trim()} method + * to reduce its memory usage, if necessary. + * + *

This class provides additional methods that implement a deque (double-ended queue). + */ +public class IntArrayFIFOQueue extends AbstractIntPriorityQueue implements Serializable { + private static final long serialVersionUID = 0L; + /** The standard initial capacity of a queue. */ + public final static int INITIAL_CAPACITY = 4; + /** The backing array. */ + protected transient int array[]; + /** The current (cached) length of {@link #array}. */ + protected transient int length; + /** The start position in {@link #array}. It is always strictly smaller than {@link #length}.*/ + protected transient int start; + /** The end position in {@link #array}. It is always strictly smaller than {@link #length}. + * Might be actually smaller than {@link #start} because {@link #array} is used cyclically. */ + protected transient int end; + /** Creates a new empty queue with given capacity. + * + * @param capacity the initial capacity of this queue. + */ + + public IntArrayFIFOQueue( final int capacity ) { + if ( capacity < 0 ) throw new IllegalArgumentException( "Initial capacity (" + capacity + ") is negative" ); + array = new int[ Math.max( 1, capacity ) ]; // Never build a queue with zero-sized backing array. + length = array.length; + } + /** Creates a new empty queue with standard {@linkplain #INITIAL_CAPACITY initial capacity}. + */ + public IntArrayFIFOQueue() { + this( INITIAL_CAPACITY ); + } + /** Returns null (FIFO queues have no comparator). + * @return null. + */ + @Override + public IntComparator comparator() { + return null; + } + @Override + public int dequeueInt() { + if ( start == end ) throw new NoSuchElementException(); + final int t = array[ start ]; + if ( ++start == length ) start = 0; + reduce(); + return t; + } + /** Dequeues the last element from the queue. + * + * @return the dequeued element. + * @throws NoSuchElementException if the queue is empty. + */ + public int dequeueLastInt() { + if ( start == end ) throw new NoSuchElementException(); + if ( end == 0 ) end = length; + final int t = array[ --end ]; + reduce(); + return t; + } + + private final void resize( final int size, final int newLength ) { + final int[] newArray = new int[ newLength ]; + if ( start >= end ) { + if ( size != 0 ) { + System.arraycopy( array, start, newArray, 0, length - start ); + System.arraycopy( array, 0, newArray, length - start, end ); + } + } + else System.arraycopy( array, start, newArray, 0, end - start ); + start = 0; + end = size; + array = newArray; + length = newLength; + } + private final void expand() { + resize( length, (int)Math.min( it.unimi.dsi.fastutil.Arrays.MAX_ARRAY_SIZE, 2L * length ) ); + } + private final void reduce() { + final int size = size(); + if ( length > INITIAL_CAPACITY && size <= length / 4 ) resize( size, length / 2 ); + } + @Override + public void enqueue( int x ) { + array[ end++ ] = x; + if ( end == length ) end = 0; + if ( end == start ) expand(); + } + /** Enqueues a new element as the first element (in dequeuing order) of the queue. + */ + public void enqueueFirst( int x ) { + if ( start == 0 ) start = length; + array[ --start ] = x; + if ( end == start ) expand(); + } + /** Returns the first element of the queue. + * @return the first element of the queue. + */ + public int firstInt() { + if ( start == end ) throw new NoSuchElementException(); + return array[ start ]; + } + /** Returns the last element of the queue. + * @return the last element of the queue. + */ + public int lastInt() { + if ( start == end ) throw new NoSuchElementException(); + return array[ ( end == 0 ? length : end ) - 1 ]; + } + @Override + public void clear() { + start = end = 0; + } + /** Trims the queue to the smallest possible size. */ + + public void trim() { + final int size = size(); + final int[] newArray = + new int[ size + 1 ]; + if ( start <= end ) System.arraycopy( array, start, newArray, 0, end - start ); + else { + System.arraycopy( array, start, newArray, 0, length - start ); + System.arraycopy( array, 0, newArray, length - start, end ); + } + start = 0; + length = ( end = size ) + 1; + array = newArray; + } + @Override + public int size() { + final int apparentLength = end - start; + return apparentLength >= 0 ? apparentLength : length + apparentLength; + } + private void writeObject( java.io.ObjectOutputStream s ) throws java.io.IOException { + s.defaultWriteObject(); + int size = size(); + s.writeInt( size ); + for( int i = start; size-- != 0; ) { + s.writeInt( array[ i++ ] ); + if ( i == length ) i = 0; + } + } + + private void readObject( java.io.ObjectInputStream s ) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + end = s.readInt(); + array = new int[ length = HashCommon.nextPowerOfTwo( end + 1 ) ]; + for( int i = 0; i < end; i++ ) array[ i ] = s.readInt(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntArrayIndirectPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntArrayIndirectPriorityQueue.java new file mode 100644 index 0000000..34bf5c0 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntArrayIndirectPriorityQueue.java @@ -0,0 +1,295 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.ints.IntArrays; +import it.unimi.dsi.fastutil.AbstractIndirectPriorityQueue; +import java.util.NoSuchElementException; +/** A type-specific array-based semi-indirect priority queue. + * + *

Instances of this class use as reference list a reference array, + * which must be provided to each constructor, and represent a priority queue + * using a backing array of integer indices—all operations are performed + * directly on the array. The array is enlarged as needed, but it is never + * shrunk. Use the {@link #trim()} method to reduce its size, if necessary. + * + *

This implementation is extremely inefficient, but it is difficult to beat + * when the size of the queue is very small. Moreover, it allows to enqueue several + * time the same index, without limitations. + */ +public class IntArrayIndirectPriorityQueue extends AbstractIndirectPriorityQueue implements IntIndirectPriorityQueue { + /** The reference array. */ + protected int refArray[]; + /** The backing array. */ + protected int array[] = IntArrays.EMPTY_ARRAY; + /** The number of elements in this queue. */ + protected int size; + /** The type-specific comparator used in this queue. */ + protected IntComparator c; + /** The first index, cached, if {@link #firstIndexValid} is true. */ + protected int firstIndex; + /** Whether {@link #firstIndex} contains a valid value. */ + protected boolean firstIndexValid; + /** Creates a new empty queue without elements with a given capacity and comparator. + * + * @param refArray the reference array. + * @param capacity the initial capacity of this queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntArrayIndirectPriorityQueue( int[] refArray, int capacity, IntComparator c ) { + if ( capacity > 0 ) this.array = new int[ capacity ]; + this.refArray = refArray; + this.c = c; + } + /** Creates a new empty queue with given capacity and using the natural order. + * + * @param refArray the reference array. + * @param capacity the initial capacity of this queue. + */ + public IntArrayIndirectPriorityQueue( int[] refArray, int capacity ) { + this( refArray, capacity, null ); + } + /** Creates a new empty queue with capacity equal to the length of the reference array and a given comparator. + * + * @param refArray the reference array. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntArrayIndirectPriorityQueue( int[] refArray, IntComparator c ) { + this( refArray, refArray.length, c ); + } + /** Creates a new empty queue with capacity equal to the length of the reference array and using the natural order. + * @param refArray the reference array. + */ + public IntArrayIndirectPriorityQueue( int[] refArray ) { + this( refArray, refArray.length, null ); + } + /** Wraps a given array in a queue using a given comparator. + * + *

The queue returned by this method will be backed by the given array. + * + * @param refArray the reference array. + * @param a an array of indices into refArray. + * @param size the number of elements to be included in the queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntArrayIndirectPriorityQueue( final int[] refArray, final int[] a, int size, final IntComparator c ) { + this( refArray, 0, c ); + this.array = a; + this.size = size; + } + /** Wraps a given array in a queue using a given comparator. + * + *

The queue returned by this method will be backed by the given array. + * + * @param refArray the reference array. + * @param a an array of indices into refArray. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntArrayIndirectPriorityQueue( final int[] refArray, final int[] a, final IntComparator c ) { + this( refArray, a, a.length, c ); + } + /** Wraps a given array in a queue using the natural order. + * + *

The queue returned by this method will be backed by the given array. + * + * @param refArray the reference array. + * @param a an array of indices into refArray. + * @param size the number of elements to be included in the queue. + */ + public IntArrayIndirectPriorityQueue( final int[] refArray, final int[] a, int size ) { + this( refArray, a, size, null ); + } + /** Wraps a given array in a queue using the natural order. + * + *

The queue returned by this method will be backed by the given array. + * + * @param refArray the reference array. + * @param a an array of indices into refArray. + */ + public IntArrayIndirectPriorityQueue( final int[] refArray, final int[] a ) { + this( refArray, a, a.length ); + } + /** Returns the index (in {@link #array}) of the smallest element. */ + + private int findFirst() { + if ( firstIndexValid ) return this.firstIndex; + firstIndexValid = true; + int i = size; + int firstIndex = --i; + int first = refArray[ array[ firstIndex ] ]; + if ( c == null ) while( i-- != 0 ) { if ( ( (refArray[ array[ i ] ]) < (first) ) ) first = refArray[ array[ firstIndex = i ] ]; } + else while( i-- != 0 ) { if ( c.compare( refArray[ array[ i ] ], first ) < 0 ) first = refArray[ array[ firstIndex = i ] ]; } + return this.firstIndex = firstIndex; + } + /** Returns the index (in {@link #array}) of the largest element. */ + + private int findLast() { + int i = size; + int lastIndex = --i; + int last = refArray[ array[ lastIndex ] ]; + if ( c == null ) { while( i-- != 0 ) if ( ( (last) < (refArray[ array[ i ] ]) ) ) last = refArray[ array[ lastIndex = i ] ]; } + else { while( i-- != 0 ) if ( c.compare( last, refArray[ array[ i ] ] ) < 0 ) last = refArray[ array[ lastIndex = i ] ]; } + return lastIndex; + } + protected final void ensureNonEmpty() { + if ( size == 0 ) throw new NoSuchElementException(); + } + /** Ensures that the given index is a firstIndexValid reference. + * + * @param index an index in the reference array. + * @throws IndexOutOfBoundsException if the given index is negative or larger than the reference array length. + */ + protected void ensureElement( final int index ) { + if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" ); + if ( index >= refArray.length ) throw new IndexOutOfBoundsException( "Index (" + index + ") is larger than or equal to reference array size (" + refArray.length + ")" ); + } + /** Enqueues a new element. + * + *

Note that for efficiency reasons this method will not throw an exception + * when x is already in the queue. However, the queue state will become + * inconsistent and the following behaviour will not be predictable. + */ + + public void enqueue( int x ) { + ensureElement( x ); + if ( size == array.length ) array = IntArrays.grow( array, size + 1 ); + if ( firstIndexValid ) { + if ( c == null ) { if ( ( (refArray[ x ]) < (refArray[ array[ firstIndex ] ]) ) ) firstIndex = size; } + else if ( c.compare( refArray[ x ], refArray[ array[ firstIndex ] ] ) < 0 ) firstIndex = size; + } + else firstIndexValid = false; + array[ size++ ] = x; + } + public int dequeue() { + ensureNonEmpty(); + final int firstIndex = findFirst(); + final int result = array[ firstIndex ]; + if ( --size != 0 ) System.arraycopy( array, firstIndex + 1, array, firstIndex, size - firstIndex ); + firstIndexValid = false; + return result; + } + public int first() { + ensureNonEmpty(); + return array[ findFirst() ]; + } + public int last() { + ensureNonEmpty(); + return array[ findLast() ]; + } + public void changed() { + ensureNonEmpty(); + firstIndexValid = false; + } + /** {@inheritDoc} + * + *

Note that for efficiency reasons this method will not throw an exception + * when index is not in the queue. + */ + public void changed( int index ) { + ensureElement( index ); + if ( index == firstIndex ) firstIndexValid = false; + } + public void allChanged() { + firstIndexValid = false; + } + public boolean remove( int index ) { + ensureElement( index ); + final int[] a = array; + int i = size; + while( i-- != 0 ) if ( a[ i ] == index ) break; + if ( i < 0 ) return false; + firstIndexValid = false; + if ( --size != 0 ) System.arraycopy( a, i + 1, a, i, size - i ); + return true; + } + public int front( int[] a ) { + final int top = refArray[ array[ findFirst() ] ]; + int i = size, c = 0; + while( i-- != 0 ) if ( ( (top) == (refArray[ array[ i ] ]) ) ) a[ c++ ] = array[ i ]; + return c; + } + public int size() { return size; } + public void clear() { size = 0; firstIndexValid = false; } + /** Trims the backing array so that it has exactly {@link #size()} elements. + */ + public void trim() { + array = IntArrays.trim( array, size ); + } + public IntComparator comparator() { return c; } + public String toString() { + StringBuffer s = new StringBuffer(); + s.append( "[" ); + for ( int i = 0; i < size; i++ ) { + if ( i != 0 ) s.append( ", " ); + s.append( refArray[ array [ i ] ] ); + } + s.append( "]" ); + return s.toString(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntArrayList.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntArrayList.java new file mode 100644 index 0000000..ec18eae --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntArrayList.java @@ -0,0 +1,501 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.RandomAccess; +import java.util.NoSuchElementException; +/** A type-specific array-based list; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

This class implements a lightweight, fast, open, optimized, + * reuse-oriented version of array-based lists. Instances of this class + * represent a list with an array that is enlarged as needed when new entries + * are created (by doubling its current length), but is + * never made smaller (even on a {@link #clear()}). A family of + * {@linkplain #trim() trimming methods} lets you control the size of the + * backing array; this is particularly useful if you reuse instances of this class. + * Range checks are equivalent to those of {@link java.util}'s classes, but + * they are delayed as much as possible. The backing array is exposed by the + * {@link #elements()} method. + * + *

This class implements the bulk methods removeElements(), + * addElements() and getElements() using + * high-performance system calls (e.g., {@link + * System#arraycopy(Object,int,Object,int,int) System.arraycopy()} instead of + * expensive loops. + * + * @see java.util.ArrayList + */ +public class IntArrayList extends AbstractIntList implements RandomAccess, Cloneable, java.io.Serializable { + private static final long serialVersionUID = -7046029254386353130L; + /** The initial default capacity of an array list. */ + public final static int DEFAULT_INITIAL_CAPACITY = 16; + /** The backing array. */ + protected transient int a[]; + /** The current actual size of the list (never greater than the backing-array length). */ + protected int size; + private static final boolean ASSERTS = false; + /** Creates a new array list using a given array. + * + *

This constructor is only meant to be used by the wrapping methods. + * + * @param a the array that will be used to back this array list. + */ + @SuppressWarnings("unused") + protected IntArrayList( final int a[], boolean dummy ) { + this.a = a; + } + /** Creates a new array list with given capacity. + * + * @param capacity the initial capacity of the array list (may be 0). + */ + + public IntArrayList( final int capacity ) { + if ( capacity < 0 ) throw new IllegalArgumentException( "Initial capacity (" + capacity + ") is negative" ); + a = new int[ capacity ]; + } + /** Creates a new array list with {@link #DEFAULT_INITIAL_CAPACITY} capacity. + */ + public IntArrayList() { + this( DEFAULT_INITIAL_CAPACITY ); + } + /** Creates a new array list and fills it with a given collection. + * + * @param c a collection that will be used to fill the array list. + */ + public IntArrayList( final Collection c ) { + this( c.size() ); + size = IntIterators.unwrap( IntIterators.asIntIterator( c.iterator() ), a ); + } + /** Creates a new array list and fills it with a given type-specific collection. + * + * @param c a type-specific collection that will be used to fill the array list. + */ + public IntArrayList( final IntCollection c ) { + this( c.size() ); + size = IntIterators.unwrap( c.iterator(), a ); + } + /** Creates a new array list and fills it with a given type-specific list. + * + * @param l a type-specific list that will be used to fill the array list. + */ + public IntArrayList( final IntList l ) { + this( l.size() ); + l.getElements( 0, a, 0, size = l.size() ); + } + /** Creates a new array list and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the array list. + */ + public IntArrayList( final int a[] ) { + this( a, 0, a.length ); + } + /** Creates a new array list and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the array list. + * @param offset the first element to use. + * @param length the number of elements to use. + */ + public IntArrayList( final int a[], final int offset, final int length ) { + this( length ); + System.arraycopy( a, offset, this.a, 0, length ); + size = length; + } + /** Creates a new array list and fills it with the elements returned by an iterator.. + * + * @param i an iterator whose returned elements will fill the array list. + */ + public IntArrayList( final Iterator i ) { + this(); + while( i.hasNext() ) this.add( i.next() ); + } + /** Creates a new array list and fills it with the elements returned by a type-specific iterator.. + * + * @param i a type-specific iterator whose returned elements will fill the array list. + */ + public IntArrayList( final IntIterator i ) { + this(); + while( i.hasNext() ) this.add( i.nextInt() ); + } + /** Returns the backing array of this list. + * + * @return the backing array. + */ + public int[] elements() { + return a; + } + /** Wraps a given array into an array list of given size. + * + *

Note it is guaranteed + * that the type of the array returned by {@link #elements()} will be the same + * (see the comments in the class documentation). + * + * @param a an array to wrap. + * @param length the length of the resulting array list. + * @return a new array list of the given size, wrapping the given array. + */ + public static IntArrayList wrap( final int a[], final int length ) { + if ( length > a.length ) throw new IllegalArgumentException( "The specified length (" + length + ") is greater than the array size (" + a.length + ")" ); + final IntArrayList l = new IntArrayList ( a, false ); + l.size = length; + return l; + } + /** Wraps a given array into an array list. + * + *

Note it is guaranteed + * that the type of the array returned by {@link #elements()} will be the same + * (see the comments in the class documentation). + * + * @param a an array to wrap. + * @return a new array list wrapping the given array. + */ + public static IntArrayList wrap( final int a[] ) { + return wrap( a, a.length ); + } + /** Ensures that this array list can contain the given number of entries without resizing. + * + * @param capacity the new minimum capacity for this array list. + */ + + public void ensureCapacity( final int capacity ) { + a = IntArrays.ensureCapacity( a, capacity, size ); + if ( ASSERTS ) assert size <= a.length; + } + /** Grows this array list, ensuring that it can contain the given number of entries without resizing, + * and in case enlarging it at least by a factor of two. + * + * @param capacity the new minimum capacity for this array list. + */ + + private void grow( final int capacity ) { + a = IntArrays.grow( a, capacity, size ); + if ( ASSERTS ) assert size <= a.length; + } + public void add( final int index, final int k ) { + ensureIndex( index ); + grow( size + 1 ); + if ( index != size ) System.arraycopy( a, index, a, index + 1, size - index ); + a[ index ] = k; + size++; + if ( ASSERTS ) assert size <= a.length; + } + public boolean add( final int k ) { + grow( size + 1 ); + a[ size++ ] = k; + if ( ASSERTS ) assert size <= a.length; + return true; + } + public int getInt( final int index ) { + if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" ); + return a[ index ]; + } + public int indexOf( final int k ) { + for( int i = 0; i < size; i++ ) if ( ( (k) == (a[ i ]) ) ) return i; + return -1; + } + public int lastIndexOf( final int k ) { + for( int i = size; i-- != 0; ) if ( ( (k) == (a[ i ]) ) ) return i; + return -1; + } + public int removeInt( final int index ) { + if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" ); + final int old = a[ index ]; + size--; + if ( index != size ) System.arraycopy( a, index + 1, a, index, size - index ); + if ( ASSERTS ) assert size <= a.length; + return old; + } + public boolean rem( final int k ) { + int index = indexOf( k ); + if ( index == -1 ) return false; + removeInt( index ); + if ( ASSERTS ) assert size <= a.length; + return true; + } + public int set( final int index, final int k ) { + if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" ); + int old = a[ index ]; + a[ index ] = k; + return old; + } + public void clear() { + size = 0; + if ( ASSERTS ) assert size <= a.length; + } + public int size() { + return size; + } + public void size( final int size ) { + if ( size > a.length ) ensureCapacity( size ); + if ( size > this.size ) Arrays.fill( a, this.size, size, (0) ); + this.size = size; + } + public boolean isEmpty() { + return size == 0; + } + /** Trims this array list so that the capacity is equal to the size. + * + * @see java.util.ArrayList#trimToSize() + */ + public void trim() { + trim( 0 ); + } + /** Trims the backing array if it is too large. + * + * If the current array length is smaller than or equal to + * n, this method does nothing. Otherwise, it trims the + * array length to the maximum between n and {@link #size()}. + * + *

This method is useful when reusing lists. {@linkplain #clear() Clearing a + * list} leaves the array length untouched. If you are reusing a list + * many times, you can call this method with a typical + * size to avoid keeping around a very large array just + * because of a few large transient lists. + * + * @param n the threshold for the trimming. + */ + + public void trim( final int n ) { + // TODO: use Arrays.trim() and preserve type only if necessary + if ( n >= a.length || size == a.length ) return; + final int t[] = new int[ Math.max( n, size ) ]; + System.arraycopy( a, 0, t, 0, size ); + a = t; + if ( ASSERTS ) assert size <= a.length; + } + /** Copies element of this type-specific list into the given array using optimized system calls. + * + * @param from the start index (inclusive). + * @param a the destination array. + * @param offset the offset into the destination array where to store the first element copied. + * @param length the number of elements to be copied. + */ + public void getElements( final int from, final int[] a, final int offset, final int length ) { + IntArrays.ensureOffsetLength( a, offset, length ); + System.arraycopy( this.a, from, a, offset, length ); + } + /** Removes elements of this type-specific list using optimized system calls. + * + * @param from the start index (inclusive). + * @param to the end index (exclusive). + */ + public void removeElements( final int from, final int to ) { + it.unimi.dsi.fastutil.Arrays.ensureFromTo( size, from, to ); + System.arraycopy( a, to, a, from, size - to ); + size -= ( to - from ); + } + /** Adds elements to this type-specific list using optimized system calls. + * + * @param index the index at which to add elements. + * @param a the array containing the elements. + * @param offset the offset of the first element to add. + * @param length the number of elements to add. + */ + public void addElements( final int index, final int a[], final int offset, final int length ) { + ensureIndex( index ); + IntArrays.ensureOffsetLength( a, offset, length ); + grow( size + length ); + System.arraycopy( this.a, index, this.a, index + length, size - index ); + System.arraycopy( a, offset, this.a, index, length ); + size += length; + } + public int[] toIntArray( int a[] ) { + if ( a == null || a.length < size ) a = new int[ size ]; + System.arraycopy( this.a, 0, a, 0, size ); + return a; + } + public boolean addAll( int index, final IntCollection c ) { + ensureIndex( index ); + int n = c.size(); + if ( n == 0 ) return false; + grow( size + n ); + if ( index != size ) System.arraycopy( a, index, a, index + n, size - index ); + final IntIterator i = c.iterator(); + size += n; + while( n-- != 0 ) a[ index++ ] = i.nextInt(); + if ( ASSERTS ) assert size <= a.length; + return true; + } + public boolean addAll( final int index, final IntList l ) { + ensureIndex( index ); + final int n = l.size(); + if ( n == 0 ) return false; + grow( size + n ); + if ( index != size ) System.arraycopy( a, index, a, index + n, size - index ); + l.getElements( 0, a, index, n ); + size += n; + if ( ASSERTS ) assert size <= a.length; + return true; + } + @Override + public boolean removeAll( final IntCollection c ) { + final int[] a = this.a; + int j = 0; + for( int i = 0; i < size; i++ ) + if ( ! c.contains( a[ i ] ) ) a[ j++ ] = a[ i ]; + final boolean modified = size != j; + size = j; + return modified; + } + @Override + public boolean removeAll( final Collection c ) { + final int[] a = this.a; + int j = 0; + for( int i = 0; i < size; i++ ) + if ( ! c.contains( (Integer.valueOf(a[ i ])) ) ) a[ j++ ] = a[ i ]; + final boolean modified = size != j; + size = j; + return modified; + } + public IntListIterator listIterator( final int index ) { + ensureIndex( index ); + return new AbstractIntListIterator () { + int pos = index, last = -1; + public boolean hasNext() { return pos < size; } + public boolean hasPrevious() { return pos > 0; } + public int nextInt() { if ( ! hasNext() ) throw new NoSuchElementException(); return a[ last = pos++ ]; } + public int previousInt() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return a[ last = --pos ]; } + public int nextIndex() { return pos; } + public int previousIndex() { return pos - 1; } + public void add( int k ) { + IntArrayList.this.add( pos++, k ); + last = -1; + } + public void set( int k ) { + if ( last == -1 ) throw new IllegalStateException(); + IntArrayList.this.set( last, k ); + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + IntArrayList.this.removeInt( last ); + /* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */ + if ( last < pos ) pos--; + last = -1; + } + }; + } + public IntArrayList clone() { + IntArrayList c = new IntArrayList ( size ); + System.arraycopy( a, 0, c.a, 0, size ); + c.size = size; + return c; + } + /** Compares this type-specific array list to another one. + * + *

This method exists only for sake of efficiency. The implementation + * inherited from the abstract implementation would already work. + * + * @param l a type-specific array list. + * @return true if the argument contains the same elements of this type-specific array list. + */ + public boolean equals( final IntArrayList l ) { + if ( l == this ) return true; + int s = size(); + if ( s != l.size() ) return false; + final int[] a1 = a; + final int[] a2 = l.a; + while( s-- != 0 ) if ( a1[ s ] != a2[ s ] ) return false; + return true; + } + /** Compares this array list to another array list. + * + *

This method exists only for sake of efficiency. The implementation + * inherited from the abstract implementation would already work. + * + * @param l an array list. + * @return a negative integer, + * zero, or a positive integer as this list is lexicographically less than, equal + * to, or greater than the argument. + */ + + public int compareTo( final IntArrayList l ) { + final int s1 = size(), s2 = l.size(); + final int a1[] = a, a2[] = l.a; + int e1, e2; + int r, i; + for( i = 0; i < s1 && i < s2; i++ ) { + e1 = a1[ i ]; + e2 = a2[ i ]; + if ( ( r = ( Integer.compare((e1),(e2)) ) ) != 0 ) return r; + } + return i < s2 ? -1 : ( i < s1 ? 1 : 0 ); + } + private void writeObject( java.io.ObjectOutputStream s ) throws java.io.IOException { + s.defaultWriteObject(); + for( int i = 0; i < size; i++ ) s.writeInt( a[ i ] ); + } + + private void readObject( java.io.ObjectInputStream s ) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + a = new int[ size ]; + for( int i = 0; i < size; i++ ) a[ i ] = s.readInt(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntArrayPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntArrayPriorityQueue.java new file mode 100644 index 0000000..dcf704d --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntArrayPriorityQueue.java @@ -0,0 +1,229 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.NoSuchElementException; +/** A type-specific array-based priority queue. + * + *

Instances of this class represent a priority queue using a backing + * array—all operations are performed directly on the array. The array is + * enlarged as needed, but it is never shrunk. Use the {@link #trim()} method + * to reduce its size, if necessary. + * + *

This implementation is extremely inefficient, but it is difficult to beat + * when the size of the queue is very small. + */ +public class IntArrayPriorityQueue extends AbstractIntPriorityQueue implements java.io.Serializable { + private static final long serialVersionUID = 1L; + /** The backing array. */ + + protected transient int array[] = IntArrays.EMPTY_ARRAY; + /** The number of elements in this queue. */ + protected int size; + /** The type-specific comparator used in this queue. */ + protected IntComparator c; + /** The first index, cached, if {@link #firstIndexValid} is true. */ + transient protected int firstIndex; + /** Whether {@link #firstIndex} contains a valid value. */ + transient protected boolean firstIndexValid; + /** Creates a new empty queue with a given capacity and comparator. + * + * @param capacity the initial capacity of this queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + + public IntArrayPriorityQueue( int capacity, IntComparator c ) { + if ( capacity > 0 ) this.array = new int[ capacity ]; + this.c = c; + } + /** Creates a new empty queue with a given capacity and using the natural order. + * + * @param capacity the initial capacity of this queue. + */ + public IntArrayPriorityQueue( int capacity ) { + this( capacity, null ); + } + /** Creates a new empty queue with a given comparator. + * + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntArrayPriorityQueue( IntComparator c ) { + this( 0, c ); + } + /** Creates a new empty queue using the natural order. + */ + public IntArrayPriorityQueue() { + this( 0, null ); + } + /** Wraps a given array in a queue using a given comparator. + * + *

The queue returned by this method will be backed by the given array. + * + * @param a an array. + * @param size the number of elements to be included in the queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntArrayPriorityQueue( final int[] a, int size, final IntComparator c ) { + this( c ); + this.array = a; + this.size = size; + } + /** Wraps a given array in a queue using a given comparator. + * + *

The queue returned by this method will be backed by the given array. + * + * @param a an array. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntArrayPriorityQueue( final int[] a, final IntComparator c ) { + this( a, a.length, c ); + } + /** Wraps a given array in a queue using the natural order. + * + *

The queue returned by this method will be backed by the given array. + * + * @param a an array. + * @param size the number of elements to be included in the queue. + */ + public IntArrayPriorityQueue( final int[] a, int size ) { + this( a, size, null ); + } + /** Wraps a given array in a queue using the natural order. + * + *

The queue returned by this method will be backed by the given array. + * + * @param a an array. + */ + public IntArrayPriorityQueue( final int[] a ) { + this( a, a.length ); + } + /** Returns the index of the smallest element. */ + + private int findFirst() { + if ( firstIndexValid ) return this.firstIndex; + firstIndexValid = true; + int i = size; + int firstIndex = --i; + int first = array[ firstIndex ]; + if ( c == null ) { while( i-- != 0 ) if ( ( (array[ i ]) < (first) ) ) first = array[ firstIndex = i ]; } + else while( i-- != 0 ) { if ( c.compare( array[ i ], first ) < 0 ) first = array[ firstIndex = i ]; } + return this.firstIndex = firstIndex; + } + private void ensureNonEmpty() { + if ( size == 0 ) throw new NoSuchElementException(); + } + + public void enqueue( int x ) { + if ( size == array.length ) array = IntArrays.grow( array, size + 1 ); + if ( firstIndexValid ) { + if ( c == null ) { if ( ( (x) < (array[ firstIndex ]) ) ) firstIndex = size; } + else if ( c.compare( x, array[ firstIndex ] ) < 0 ) firstIndex = size; + } + else firstIndexValid = false; + array[ size++ ] = x; + } + public int dequeueInt() { + ensureNonEmpty(); + final int first = findFirst(); + final int result = array[ first ]; + System.arraycopy( array, first + 1, array, first, --size - first ); + firstIndexValid = false; + return result; + } + public int firstInt() { + ensureNonEmpty(); + return array[ findFirst() ]; + } + public void changed() { + ensureNonEmpty(); + firstIndexValid = false; + } + public int size() { return size; } + public void clear() { + size = 0; + firstIndexValid = false; + } + /** Trims the underlying array so that it has exactly {@link #size()} elements. + */ + public void trim() { + array = IntArrays.trim( array, size ); + } + public IntComparator comparator() { return c; } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + s.defaultWriteObject(); + s.writeInt( array.length ); + for( int i = 0; i < size; i++ ) s.writeInt( array[ i ] ); + } + + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + array = new int[ s.readInt() ]; + for( int i = 0; i < size; i++ ) array[ i ] = s.readInt(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntArraySet.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntArraySet.java new file mode 100644 index 0000000..af8014d --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntArraySet.java @@ -0,0 +1,218 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2007-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.Collection; +import java.util.NoSuchElementException; +/** A simple, brute-force implementation of a set based on a backing array. + * + *

The main purpose of this + * implementation is that of wrapping cleanly the brute-force approach to the storage of a very + * small number of items: just put them into an array and scan linearly to find an item. + */ +public class IntArraySet extends AbstractIntSet implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = 1L; + /** The backing array (valid up to {@link #size}, excluded). */ + private transient int[] a; + /** The number of valid entries in {@link #a}. */ + private int size; + /** Creates a new array set using the given backing array. The resulting set will have as many elements as the array. + * + *

It is responsibility of the caller that the elements of a are distinct. + * + * @param a the backing array. + */ + public IntArraySet( final int[] a ) { + this.a = a; + size = a.length; + } + /** Creates a new empty array set. + */ + public IntArraySet() { + this.a = IntArrays.EMPTY_ARRAY; + } + /** Creates a new empty array set of given initial capacity. + * + * @param capacity the initial capacity. + */ + public IntArraySet( final int capacity ) { + this.a = new int[ capacity ]; + } + /** Creates a new array set copying the contents of a given collection. + * @param c a collection. + */ + public IntArraySet( IntCollection c ) { + this( c.size () ); + addAll( c ); + } + /** Creates a new array set copying the contents of a given set. + * @param c a collection. + */ + public IntArraySet( final Collection c ) { + this( c.size() ); + addAll( c ); + } + /** Creates a new array set using the given backing array and the given number of elements of the array. + * + *

It is responsibility of the caller that the first size elements of a are distinct. + * + * @param a the backing array. + * @param size the number of valid elements in a. + */ + public IntArraySet( final int[] a, final int size ) { + this.a = a; + this.size = size; + if ( size > a.length ) throw new IllegalArgumentException( "The provided size (" + size + ") is larger than or equal to the array size (" + a.length + ")" ); + } + private int findKey( final int o ) { + for( int i = size; i-- != 0; ) if ( ( (a[ i ]) == (o) ) ) return i; + return -1; + } + @Override + + public IntIterator iterator() { + return new AbstractIntIterator () { + int next = 0; + public boolean hasNext() { + return next < size; + } + public int nextInt() { + if ( ! hasNext() ) throw new NoSuchElementException(); + return a[ next++ ]; + } + public void remove() { + final int tail = size-- - next--; + System.arraycopy( a, next + 1, a, next, tail ); + } + }; + } + public boolean contains( final int k ) { + return findKey( k ) != -1; + } + public int size() { + return size; + } + @Override + public boolean remove( final int k ) { + final int pos = findKey( k ); + if ( pos == -1 ) return false; + final int tail = size - pos - 1; + for( int i = 0; i < tail; i++ ) a[ pos + i ] = a[ pos + i + 1 ]; + size--; + return true; + } + @Override + public boolean add( final int k ) { + final int pos = findKey( k ); + if ( pos != -1 ) return false; + if ( size == a.length ) { + final int[] b = new int[ size == 0 ? 2 : size * 2 ]; + for( int i = size; i-- != 0; ) b[ i ] = a[ i ]; + a = b; + } + a[ size++ ] = k; + return true; + } + @Override + public void clear() { + size = 0; + } + @Override + public boolean isEmpty() { + return size == 0; + } + /** Returns a deep copy of this set. + * + *

This method performs a deep copy of this hash set; the data stored in the + * set, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this set. + */ + + public IntArraySet clone() { + IntArraySet c; + try { + c = (IntArraySet )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.a = a.clone(); + return c; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + s.defaultWriteObject(); + for( int i = 0; i < size; i++ ) s.writeInt( a[ i ] ); + } + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + a = new int[ size ]; + for( int i = 0; i < size; i++ ) a[ i ] = s.readInt(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntArrays.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntArrays.java new file mode 100644 index 0000000..e9d8586 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntArrays.java @@ -0,0 +1,2462 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * + * For the sorting and binary search code: + * + * Copyright (C) 1999 CERN - European Organization for Nuclear Research. + * + * Permission to use, copy, modify, distribute and sell this software and + * its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation. CERN makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without expressed or implied warranty. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.Arrays; +import it.unimi.dsi.fastutil.Hash; +import java.util.Random; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.RecursiveAction; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorCompletionService; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; +/** A class providing static methods and objects that do useful things with type-specific arrays. + * + *

In particular, the ensureCapacity(), grow(), + * trim() and setLength() methods allow to handle + * arrays much like array lists. This can be very useful when efficiency (or + * syntactic simplicity) reasons make array lists unsuitable. + * + *

Note that {@link it.unimi.dsi.fastutil.io.BinIO} and {@link it.unimi.dsi.fastutil.io.TextIO} + * contain several methods make it possible to load and save arrays of primitive types as sequences + * of elements in {@link java.io.DataInput} format (i.e., not as objects) or as sequences of lines of text. + * + *

Sorting

+ * + *

There are several sorting methods available. The main theme is that of letting you choose + * the sorting algorithm you prefer (i.e., trading stability of mergesort for no memory allocation in quicksort). + * Several algorithms provide a parallel version, that will use the {@linkplain Runtime#availableProcessors() number of cores available}. + * Some algorithms also provide an explicit indirect sorting facility, which makes it possible + * to sort an array using the values in another array as comparator. + * + *

All comparison-based algorithm have an implementation based on a type-specific comparator. + * + *

As a general rule, sequential radix sort is significantly faster than quicksort or mergesort, in particular + * on random-looking data. In + * the parallel case, up to a few cores parallel radix sort is still the fastest, but at some point quicksort + * exploits parallelism better. + * + *

If you are fine with not knowing exactly which algorithm will be run (in particular, not knowing exactly whether a support array will be allocated), + * the dual-pivot parallel sorts in {@link java.util.Arrays} + * are about 50% faster than the classical single-pivot implementation used here. + * + *

In any case, if sorting time is important I suggest that you benchmark your sorting load + * with your data distribution and on your architecture. + * + * @see java.util.Arrays + */ +public class IntArrays { + private IntArrays() {} + /** A static, final, empty array. */ + public final static int[] EMPTY_ARRAY = {}; + /** Ensures that an array can contain the given number of entries. + * + *

If you cannot foresee whether this array will need again to be + * enlarged, you should probably use grow() instead. + * + * @param array an array. + * @param length the new minimum length for this array. + * @return array, if it contains length entries or more; otherwise, + * an array with length entries whose first array.length + * entries are the same as those of array. + */ + public static int[] ensureCapacity( final int[] array, final int length ) { + if ( length > array.length ) { + final int t[] = + new int[ length ]; + System.arraycopy( array, 0, t, 0, array.length ); + return t; + } + return array; + } + /** Ensures that an array can contain the given number of entries, preserving just a part of the array. + * + * @param array an array. + * @param length the new minimum length for this array. + * @param preserve the number of elements of the array that must be preserved in case a new allocation is necessary. + * @return array, if it can contain length entries or more; otherwise, + * an array with length entries whose first preserve + * entries are the same as those of array. + */ + public static int[] ensureCapacity( final int[] array, final int length, final int preserve ) { + if ( length > array.length ) { + final int t[] = + new int[ length ]; + System.arraycopy( array, 0, t, 0, preserve ); + return t; + } + return array; + } + /** Grows the given array to the maximum between the given length and + * the current length multiplied by two, provided that the given + * length is larger than the current length. + * + *

If you want complete control on the array growth, you + * should probably use ensureCapacity() instead. + * + * @param array an array. + * @param length the new minimum length for this array. + * @return array, if it can contain length + * entries; otherwise, an array with + * max(length,array.length/φ) entries whose first + * array.length entries are the same as those of array. + * */ + public static int[] grow( final int[] array, final int length ) { + if ( length > array.length ) { + final int newLength = (int)Math.max( Math.min( 2L * array.length, Arrays.MAX_ARRAY_SIZE ), length ); + final int t[] = + new int[ newLength ]; + System.arraycopy( array, 0, t, 0, array.length ); + return t; + } + return array; + } + /** Grows the given array to the maximum between the given length and + * the current length multiplied by two, provided that the given + * length is larger than the current length, preserving just a part of the array. + * + *

If you want complete control on the array growth, you + * should probably use ensureCapacity() instead. + * + * @param array an array. + * @param length the new minimum length for this array. + * @param preserve the number of elements of the array that must be preserved in case a new allocation is necessary. + * @return array, if it can contain length + * entries; otherwise, an array with + * max(length,array.length/φ) entries whose first + * preserve entries are the same as those of array. + * */ + public static int[] grow( final int[] array, final int length, final int preserve ) { + if ( length > array.length ) { + final int newLength = (int)Math.max( Math.min( 2L * array.length, Arrays.MAX_ARRAY_SIZE ), length ); + final int t[] = + new int[ newLength ]; + System.arraycopy( array, 0, t, 0, preserve ); + return t; + } + return array; + } + /** Trims the given array to the given length. + * + * @param array an array. + * @param length the new maximum length for the array. + * @return array, if it contains length + * entries or less; otherwise, an array with + * length entries whose entries are the same as + * the first length entries of array. + * + */ + public static int[] trim( final int[] array, final int length ) { + if ( length >= array.length ) return array; + final int t[] = + length == 0 ? EMPTY_ARRAY : new int[ length ]; + System.arraycopy( array, 0, t, 0, length ); + return t; + } + /** Sets the length of the given array. + * + * @param array an array. + * @param length the new length for the array. + * @return array, if it contains exactly length + * entries; otherwise, if it contains more than + * length entries, an array with length entries + * whose entries are the same as the first length entries of + * array; otherwise, an array with length entries + * whose first array.length entries are the same as those of + * array. + * + */ + public static int[] setLength( final int[] array, final int length ) { + if ( length == array.length ) return array; + if ( length < array.length ) return trim( array, length ); + return ensureCapacity( array, length ); + } + /** Returns a copy of a portion of an array. + * + * @param array an array. + * @param offset the first element to copy. + * @param length the number of elements to copy. + * @return a new array containing length elements of array starting at offset. + */ + public static int[] copy( final int[] array, final int offset, final int length ) { + ensureOffsetLength( array, offset, length ); + final int[] a = + length == 0 ? EMPTY_ARRAY : new int[ length ]; + System.arraycopy( array, offset, a, 0, length ); + return a; + } + /** Returns a copy of an array. + * + * @param array an array. + * @return a copy of array. + */ + public static int[] copy( final int[] array ) { + return array.clone(); + } + /** Fills the given array with the given value. + * + * @param array an array. + * @param value the new value for all elements of the array. + * @deprecated Please use the corresponding {@link java.util.Arrays} method. + */ + @Deprecated + public static void fill( final int[] array, final int value ) { + int i = array.length; + while( i-- != 0 ) array[ i ] = value; + } + /** Fills a portion of the given array with the given value. + * + * @param array an array. + * @param from the starting index of the portion to fill (inclusive). + * @param to the end index of the portion to fill (exclusive). + * @param value the new value for all elements of the specified portion of the array. + * @deprecated Please use the corresponding {@link java.util.Arrays} method. + */ + @Deprecated + public static void fill( final int[] array, final int from, int to, final int value ) { + ensureFromTo( array, from, to ); + if ( from == 0 ) while( to-- != 0 ) array[ to ] = value; + else for( int i = from; i < to; i++ ) array[ i ] = value; + } + /** Returns true if the two arrays are elementwise equal. + * + * @param a1 an array. + * @param a2 another array. + * @return true if the two arrays are of the same length, and their elements are equal. + * @deprecated Please use the corresponding {@link java.util.Arrays} method, which is intrinsified in recent JVMs. + */ + @Deprecated + public static boolean equals( final int[] a1, final int a2[] ) { + int i = a1.length; + if ( i != a2.length ) return false; + while( i-- != 0 ) if (! ( (a1[ i ]) == (a2[ i ]) ) ) return false; + return true; + } + /** Ensures that a range given by its first (inclusive) and last (exclusive) elements fits an array. + * + *

This method may be used whenever an array range check is needed. + * + * @param a an array. + * @param from a start index (inclusive). + * @param to an end index (exclusive). + * @throws IllegalArgumentException if from is greater than to. + * @throws ArrayIndexOutOfBoundsException if from or to are greater than the array length or negative. + */ + public static void ensureFromTo( final int[] a, final int from, final int to ) { + Arrays.ensureFromTo( a.length, from, to ); + } + /** Ensures that a range given by an offset and a length fits an array. + * + *

This method may be used whenever an array range check is needed. + * + * @param a an array. + * @param offset a start index. + * @param length a length (the number of elements in the range). + * @throws IllegalArgumentException if length is negative. + * @throws ArrayIndexOutOfBoundsException if offset is negative or offset+length is greater than the array length. + */ + public static void ensureOffsetLength( final int[] a, final int offset, final int length ) { + Arrays.ensureOffsetLength( a.length, offset, length ); + } + /** Ensures that two arrays are of the same length. + * + * @param a an array. + * @param b another array. + * @throws IllegalArgumentException if the two argument arrays are not of the same length. + */ + public static void ensureSameLength( final int[] a, final int[] b ) { + if ( a.length != b.length ) throw new IllegalArgumentException( "Array size mismatch: " + a.length + " != " + b.length ); + } + private static final int QUICKSORT_NO_REC = 16; + private static final int PARALLEL_QUICKSORT_NO_FORK = 8192; + private static final int QUICKSORT_MEDIAN_OF_9 = 128; + private static final int MERGESORT_NO_REC = 16; + /** Swaps two elements of an anrray. + * + * @param x an array. + * @param a a position in {@code x}. + * @param b another position in {@code x}. + */ + public static void swap( final int x[], final int a, final int b ) { + final int t = x[ a ]; + x[ a ] = x[ b ]; + x[ b ] = t; + } + /** Swaps two sequences of elements of an array. + * + * @param x an array. + * @param a a position in {@code x}. + * @param b another position in {@code x}. + * @param n the number of elements to exchange starting at {@code a} and {@code b}. + */ + public static void swap( final int[] x, int a, int b, final int n ) { + for( int i = 0; i < n; i++, a++, b++ ) swap( x, a, b ); + } + private static int med3( final int x[], final int a, final int b, final int c, IntComparator comp ) { + final int ab = comp.compare( x[ a ], x[ b ] ); + final int ac = comp.compare( x[ a ], x[ c ] ); + final int bc = comp.compare( x[ b ], x[ c ] ); + return ( ab < 0 ? + ( bc < 0 ? b : ac < 0 ? c : a ) : + ( bc > 0 ? b : ac > 0 ? c : a ) ); + } + private static void selectionSort( final int[] a, final int from, final int to, final IntComparator comp ) { + for( int i = from; i < to - 1; i++ ) { + int m = i; + for( int j = i + 1; j < to; j++ ) if ( comp.compare( a[ j ], a[ m ] ) < 0 ) m = j; + if ( m != i ) { + final int u = a[ i ]; + a[ i ] = a[ m ]; + a[ m ] = u; + } + } + } + private static void insertionSort( final int[] a, final int from, final int to, final IntComparator comp ) { + for ( int i = from; ++i < to; ) { + int t = a[ i ]; + int j = i; + for ( int u = a[ j - 1 ]; comp.compare( t, u ) < 0; u = a[ --j - 1 ] ) { + a[ j ] = u; + if ( from == j - 1 ) { + --j; + break; + } + } + a[ j ] = t; + } + } + /** Sorts the specified range of elements according to the order induced by the specified + * comparator using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param comp the comparator to determine the sorting order. + * + */ + public static void quickSort( final int[] x, final int from, final int to, final IntComparator comp ) { + final int len = to - from; + // Selection sort on smallest arrays + if ( len < QUICKSORT_NO_REC ) { + selectionSort( x, from, to, comp ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9 + int s = len / 8; + l = med3( x, l, l + s, l + 2 * s, comp ); + m = med3( x, m - s, m, m + s, comp ); + n = med3( x, n - 2 * s, n - s, n, comp ); + } + m = med3( x, l, m, n, comp ); // Mid-size, med of 3 + final int v = x[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while( true ) { + int comparison; + while ( b <= c && ( comparison = comp.compare( x[ b ], v ) ) <= 0 ) { + if ( comparison == 0 ) swap( x, a++, b ); + b++; + } + while ( c >= b && ( comparison = comp.compare( x[ c ], v ) ) >=0 ) { + if ( comparison == 0 ) swap( x, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, b++, c-- ); + } + // Swap partition elements back to middle + int s; + s = Math.min( a - from, b - a ); + swap( x, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, b, to - s, s ); + // Recursively sort non-partition-elements + if ( ( s = b - a ) > 1 ) quickSort( x, from, from + s, comp ); + if ( ( s = d - c ) > 1 ) quickSort( x, to - s, to, comp ); + } + /** Sorts an array 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. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param x the array to be sorted. + * @param comp the comparator to determine the sorting order. + * + */ + public static void quickSort( final int[] x, final IntComparator comp ) { + quickSort( x, 0, x.length, comp ); + } + protected static class ForkJoinQuickSortComp extends RecursiveAction { + private static final long serialVersionUID = 1L; + private final int from; + private final int to; + private final int[] x; + private final IntComparator comp; + public ForkJoinQuickSortComp( final int[] x , final int from , final int to, final IntComparator comp ) { + this.from = from; + this.to = to; + this.x = x; + this.comp = comp; + } + @Override + protected void compute() { + final int[] x = this.x; + final int len = to - from; + if ( len < PARALLEL_QUICKSORT_NO_FORK ) { + quickSort( x, from, to, comp ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + int s = len / 8; + l = med3( x, l, l + s, l + 2 * s ); + m = med3( x, m - s, m, m + s ); + n = med3( x, n - 2 * s, n - s, n ); + m = med3( x, l, m, n ); + final int v = x[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison; + while ( b <= c && ( comparison = comp.compare( x[ b ], v ) ) <= 0 ) { + if ( comparison == 0 ) swap( x, a++, b ); + b++; + } + while ( c >= b && ( comparison = comp.compare( x[ c ], v ) ) >= 0 ) { + if ( comparison == 0 ) swap( x, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, b++, c-- ); + } + // Swap partition elements back to middle + int t; + s = Math.min( a - from, b - a ); + swap( x, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, b, to - s, s ); + // Recursively sort non-partition-elements + s = b - a; + t = d - c; + if ( s > 1 && t > 1 ) invokeAll( new ForkJoinQuickSortComp ( x, from, from + s, comp ), new ForkJoinQuickSortComp ( x, to - t, to, comp ) ); + else if ( s > 1 ) invokeAll( new ForkJoinQuickSortComp ( x, from, from + s, comp ) ); + else invokeAll( new ForkJoinQuickSortComp ( x, to - t, to, comp ) ); + } + } + /** Sorts the specified range of elements according to the order induced by the specified + * comparator using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param comp the comparator to determine the sorting order. + */ + public static void parallelQuickSort( final int[] x, final int from, final int to, final IntComparator comp ) { + if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSort( x, from, to, comp ); + else { + final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() ); + pool.invoke( new ForkJoinQuickSortComp ( x, from, to, comp ) ); + pool.shutdown(); + } + } + /** Sorts an array according to the order induced by the specified + * comparator using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the array to be sorted. + * @param comp the comparator to determine the sorting order. + */ + public static void parallelQuickSort( final int[] x, final IntComparator comp ) { + parallelQuickSort( x, 0, x.length, comp ); + } + + private static int med3( final int x[], final int a, final int b, final int c ) { + final int ab = ( Integer.compare((x[ a ]),(x[ b ])) ); + final int ac = ( Integer.compare((x[ a ]),(x[ c ])) ); + final int bc = ( Integer.compare((x[ b ]),(x[ c ])) ); + return ( ab < 0 ? + ( bc < 0 ? b : ac < 0 ? c : a ) : + ( bc > 0 ? b : ac > 0 ? c : a ) ); + } + + private static void selectionSort( final int[] a, final int from, final int to ) { + for( int i = from; i < to - 1; i++ ) { + int m = i; + for( int j = i + 1; j < to; j++ ) if ( ( (a[ j ]) < (a[ m ]) ) ) m = j; + if ( m != i ) { + final int u = a[ i ]; + a[ i ] = a[ m ]; + a[ m ] = u; + } + } + } + + private static void insertionSort( final int[] a, final int from, final int to ) { + for ( int i = from; ++i < to; ) { + int t = a[ i ]; + int j = i; + for ( int u = a[ j - 1 ]; ( (t) < (u) ); u = a[ --j - 1 ] ) { + a[ j ] = u; + if ( from == j - 1 ) { + --j; + break; + } + } + a[ j ] = t; + } + } + /** Sorts the specified range of elements according to the natural ascending order using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + + public static void quickSort( final int[] x, final int from, final int to ) { + final int len = to - from; + // Selection sort on smallest arrays + if ( len < QUICKSORT_NO_REC ) { + selectionSort( x, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9 + int s = len / 8; + l = med3( x, l, l + s, l + 2 * s ); + m = med3( x, m - s, m, m + s ); + n = med3( x, n - 2 * s, n - s, n ); + } + m = med3( x, l, m, n ); // Mid-size, med of 3 + final int v = x[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while(true) { + int comparison; + while ( b <= c && ( comparison = ( Integer.compare((x[ b ]),(v)) ) ) <= 0 ) { + if ( comparison == 0 ) swap( x, a++, b ); + b++; + } + while (c >= b && ( comparison = ( Integer.compare((x[ c ]),(v)) ) ) >=0 ) { + if ( comparison == 0 ) swap( x, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, b++, c-- ); + } + // Swap partition elements back to middle + int s; + s = Math.min( a - from, b - a ); + swap( x, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, b, to - s, s ); + // Recursively sort non-partition-elements + if ( ( s = b - a ) > 1 ) quickSort( x, from, from + s ); + if ( ( s = d - c ) > 1 ) quickSort( x, to - s, to ); + } + /** Sorts an array according to the natural ascending order using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param x the array to be sorted. + * + */ + public static void quickSort( final int[] x ) { + quickSort( x, 0, x.length ); + } + protected static class ForkJoinQuickSort extends RecursiveAction { + private static final long serialVersionUID = 1L; + private final int from; + private final int to; + private final int[] x; + public ForkJoinQuickSort( final int[] x , final int from , final int to ) { + this.from = from; + this.to = to; + this.x = x; + } + @Override + + protected void compute() { + final int[] x = this.x; + final int len = to - from; + if ( len < PARALLEL_QUICKSORT_NO_FORK ) { + quickSort( x, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + int s = len / 8; + l = med3( x, l, l + s, l + 2 * s ); + m = med3( x, m - s, m, m + s ); + n = med3( x, n - 2 * s, n - s, n ); + m = med3( x, l, m, n ); + final int v = x[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison; + while ( b <= c && ( comparison = ( Integer.compare((x[ b ]),(v)) ) ) <= 0 ) { + if ( comparison == 0 ) swap( x, a++, b ); + b++; + } + while ( c >= b && ( comparison = ( Integer.compare((x[ c ]),(v)) ) ) >= 0 ) { + if ( comparison == 0 ) swap( x, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, b++, c-- ); + } + // Swap partition elements back to middle + int t; + s = Math.min( a - from, b - a ); + swap( x, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, b, to - s, s ); + // Recursively sort non-partition-elements + s = b - a; + t = d - c; + if ( s > 1 && t > 1 ) invokeAll( new ForkJoinQuickSort ( x, from, from + s ), new ForkJoinQuickSort ( x, to - t, to ) ); + else if ( s > 1 ) invokeAll( new ForkJoinQuickSort ( x, from, from + s ) ); + else invokeAll( new ForkJoinQuickSort ( x, to - t, to ) ); + } + } + /** Sorts the specified range of elements according to the natural ascending order using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void parallelQuickSort( final int[] x, final int from, final int to ) { + if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSort( x, from, to ); + else { + final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() ); + pool.invoke( new ForkJoinQuickSort ( x, from, to ) ); + pool.shutdown(); + } + } + /** Sorts an array according to the natural ascending order using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the array to be sorted. + * + */ + public static void parallelQuickSort( final int[] x ) { + parallelQuickSort( x, 0, x.length ); + } + + private static int med3Indirect( final int perm[], final int x[], final int a, final int b, final int c ) { + final int aa = x[ perm[ a ] ]; + final int bb = x[ perm[ b ] ]; + final int cc = x[ perm[ c ] ]; + final int ab = ( Integer.compare((aa),(bb)) ); + final int ac = ( Integer.compare((aa),(cc)) ); + final int bc = ( Integer.compare((bb),(cc)) ); + return ( ab < 0 ? + ( bc < 0 ? b : ac < 0 ? c : a ) : + ( bc > 0 ? b : ac > 0 ? c : a ) ); + } + + private static void insertionSortIndirect( final int[] perm, final int[] a, final int from, final int to ) { + for ( int i = from; ++i < to; ) { + int t = perm[ i ]; + int j = i; + for ( int u = perm[ j - 1 ]; ( (a[ t ]) < (a[ u ]) ); u = perm[ --j - 1 ] ) { + perm[ j ] = u; + if ( from == j - 1 ) { + --j; + break; + } + } + perm[ j ] = t; + } + } + /** Sorts the specified range of elements according to the natural ascending order using indirect quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param perm a permutation array indexing {@code x}. + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + + public static void quickSortIndirect( final int[] perm, final int[] x, final int from, final int to ) { + final int len = to - from; + // Selection sort on smallest arrays + if ( len < QUICKSORT_NO_REC ) { + insertionSortIndirect( perm, x, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9 + int s = len / 8; + l = med3Indirect( perm, x, l, l + s, l + 2 * s ); + m = med3Indirect( perm, x, m - s, m, m + s ); + n = med3Indirect( perm, x, n - 2 * s, n - s, n ); + } + m = med3Indirect( perm, x, l, m, n ); // Mid-size, med of 3 + final int v = x[ perm[ m ] ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while(true) { + int comparison; + while ( b <= c && ( comparison = ( Integer.compare((x[ perm[ b ] ]),(v)) ) ) <= 0 ) { + if ( comparison == 0 ) IntArrays.swap( perm, a++, b ); + b++; + } + while (c >= b && ( comparison = ( Integer.compare((x[ perm[ c ] ]),(v)) ) ) >=0 ) { + if ( comparison == 0 ) IntArrays.swap( perm, c, d-- ); + c--; + } + if ( b > c ) break; + IntArrays.swap( perm, b++, c-- ); + } + // Swap partition elements back to middle + int s; + s = Math.min( a - from, b - a ); + IntArrays.swap( perm, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + IntArrays.swap( perm, b, to - s, s ); + // Recursively sort non-partition-elements + if ( ( s = b - a ) > 1 ) quickSortIndirect( perm, x, from, from + s ); + if ( ( s = d - c ) > 1 ) quickSortIndirect( perm, x, to - s, to ); + } + /** Sorts an array according to the natural ascending order using indirect quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param perm a permutation array indexing {@code x}. + * @param x the array to be sorted. + */ + public static void quickSortIndirect( final int perm[], final int[] x ) { + quickSortIndirect( perm, x, 0, x.length ); + } + protected static class ForkJoinQuickSortIndirect extends RecursiveAction { + private static final long serialVersionUID = 1L; + private final int from; + private final int to; + private final int[] perm; + private final int[] x; + public ForkJoinQuickSortIndirect( final int perm[], final int[] x , final int from , final int to ) { + this.from = from; + this.to = to; + this.x = x; + this.perm = perm; + } + @Override + + protected void compute() { + final int[] x = this.x; + final int len = to - from; + if ( len < PARALLEL_QUICKSORT_NO_FORK ) { + quickSortIndirect( perm, x, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + int s = len / 8; + l = med3Indirect( perm, x, l, l + s, l + 2 * s ); + m = med3Indirect( perm, x, m - s, m, m + s ); + n = med3Indirect( perm, x, n - 2 * s, n - s, n ); + m = med3Indirect( perm, x, l, m, n ); + final int v = x[ perm[ m ] ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison; + while ( b <= c && ( comparison = ( Integer.compare((x[ perm[ b ] ]),(v)) ) ) <= 0 ) { + if ( comparison == 0 ) IntArrays.swap( perm, a++, b ); + b++; + } + while ( c >= b && ( comparison = ( Integer.compare((x[ perm[ c ] ]),(v)) ) ) >= 0 ) { + if ( comparison == 0 ) IntArrays.swap( perm, c, d-- ); + c--; + } + if ( b > c ) break; + IntArrays.swap( perm, b++, c-- ); + } + // Swap partition elements back to middle + int t; + s = Math.min( a - from, b - a ); + IntArrays.swap( perm, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + IntArrays.swap( perm, b, to - s, s ); + // Recursively sort non-partition-elements + s = b - a; + t = d - c; + if ( s > 1 && t > 1 ) invokeAll( new ForkJoinQuickSortIndirect ( perm, x, from, from + s ), new ForkJoinQuickSortIndirect ( perm, x, to - t, to ) ); + else if ( s > 1 ) invokeAll( new ForkJoinQuickSortIndirect ( perm, x, from, from + s ) ); + else invokeAll( new ForkJoinQuickSortIndirect ( perm, x, to - t, to ) ); + } + } + /** Sorts the specified range of elements according to the natural ascending order using a parallel indirect quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param perm a permutation array indexing {@code x}. + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void parallelQuickSortIndirect( final int[] perm, final int[] x, final int from, final int to ) { + if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSortIndirect( perm, x, from, to ); + else { + final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() ); + pool.invoke( new ForkJoinQuickSortIndirect ( perm, x, from, to ) ); + pool.shutdown(); + } + } + /** Sorts an array according to the natural ascending order using a parallel indirect quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param perm a permutation array indexing {@code x}. + * @param x the array to be sorted. + * + */ + public static void parallelQuickSortIndirect( final int perm[], final int[] x ) { + parallelQuickSortIndirect( perm, x, 0, x.length ); + } + /** Stabilizes a permutation. + * + *

This method can be used to stabilize the permutation generated by an indirect sorting, assuming that + * initially the permutation array was in ascending order (e.g., the identity, as usually happens). This method + * scans the permutation, and for each non-singleton block of elements with the same associated values in {@code x}, + * permutes them in ascending order. The resulting permutation corresponds to a stable sort. + * + *

Usually combining an unstable indirect sort and this method is more efficient than using a stable sort, + * as most stable sort algorithms require a support array. + * + *

More precisely, assuming that x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ], after + * stabilization we will also have that x[ perm[ i ] ] = x[ perm[ i + 1 ] ] implies + * perm[ i ] ≤ perm[ i + 1 ]. + * + * @param perm a permutation array indexing {@code x} so that it is sorted. + * @param x the sorted array to be stabilized. + * @param from the index of the first element (inclusive) to be stabilized. + * @param to the index of the last element (exclusive) to be stabilized. + */ + public static void stabilize( final int perm[], final int[] x, final int from, final int to ) { + int curr = from; + for( int i = from + 1; i < to; i++ ) { + if ( x[ perm[ i ] ] != x[ perm[ curr ] ] ) { + if ( i - curr > 1 ) IntArrays.parallelQuickSort( perm, curr, i ); + curr = i; + } + } + if ( to - curr > 1 ) IntArrays.parallelQuickSort( perm, curr, to ); + } + /** Stabilizes a permutation. + * + *

This method can be used to stabilize the permutation generated by an indirect sorting, assuming that + * initially the permutation array was in ascending order (e.g., the identity, as usually happens). This method + * scans the permutation, and for each non-singleton block of elements with the same associated values in {@code x}, + * permutes them in ascending order. The resulting permutation corresponds to a stable sort. + * + *

Usually combining an unstable indirect sort and this method is more efficient than using a stable sort, + * as most stable sort algorithms require a support array. + * + *

More precisely, assuming that x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ], after + * stabilization we will also have that x[ perm[ i ] ] = x[ perm[ i + 1 ] ] implies + * perm[ i ] ≤ perm[ i + 1 ]. + * + * @param perm a permutation array indexing {@code x} so that it is sorted. + * @param x the sorted array to be stabilized. + */ + public static void stabilize( final int perm[], final int[] x ) { + stabilize( perm, x, 0, perm.length ); + } + + private static int med3( final int x[], final int[] y, final int a, final int b, final int c ) { + int t; + final int ab = ( t = ( Integer.compare((x[ a ]),(x[ b ])) ) ) == 0 ? ( Integer.compare((y[ a ]),(y[ b ])) ) : t; + final int ac = ( t = ( Integer.compare((x[ a ]),(x[ c ])) ) ) == 0 ? ( Integer.compare((y[ a ]),(y[ c ])) ) : t; + final int bc = ( t = ( Integer.compare((x[ b ]),(x[ c ])) ) ) == 0 ? ( Integer.compare((y[ b ]),(y[ c ])) ) : t; + return ( ab < 0 ? + ( bc < 0 ? b : ac < 0 ? c : a ) : + ( bc > 0 ? b : ac > 0 ? c : a ) ); + } + private static void swap( final int x[], final int[] y, final int a, final int b ) { + final int t = x[ a ]; + final int u = y[ a ]; + x[ a ] = x[ b ]; + y[ a ] = y[ b ]; + x[ b ] = t; + y[ b ] = u; + } + private static void swap( final int[] x, final int[] y, int a, int b, final int n ) { + for ( int i = 0; i < n; i++, a++, b++ ) swap( x, y, a, b ); + } + + private static void selectionSort( final int[] a, final int[] b, final int from, final int to ) { + for( int i = from; i < to - 1; i++ ) { + int m = i, u; + for( int j = i + 1; j < to; j++ ) + if ( ( u = ( Integer.compare((a[ j ]),(a[ m ])) ) ) < 0 || u == 0 && ( (b[ j ]) < (b[ m ]) ) ) m = j; + if ( m != i ) { + int t = a[ i ]; + a[ i ] = a[ m ]; + a[ m ] = t; + t = b[ i ]; + b[ i ] = b[ m ]; + b[ m ] = t; + } + } + } + /** Sorts the specified range of elements of two arrays according to the natural lexicographical + * ascending order using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implements a lexicographical sorting of the arguments. Pairs of + * elements in the same position in the two provided arrays will be considered a single key, and + * permuted accordingly. In the end, either x[ i ] < x[ i + 1 ] or x[ i ] + * == x[ i + 1 ] and y[ i ] ≤ y[ i + 1 ]. + * + * @param x the first array to be sorted. + * @param y the second array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + + public static void quickSort( final int[] x, final int[] y, final int from, final int to ) { + final int len = to - from; + if ( len < QUICKSORT_NO_REC ) { + selectionSort( x, y, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9 + int s = len / 8; + l = med3( x, y, l, l + s, l + 2 * s ); + m = med3( x, y, m - s, m, m + s ); + n = med3( x, y, n - 2 * s, n - s, n ); + } + m = med3( x, y, l, m, n ); // Mid-size, med of 3 + final int v = x[ m ], w = y[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison, t; + while ( b <= c && ( comparison = ( t = ( Integer.compare((x[ b ]),(v)) ) ) == 0 ? ( Integer.compare((y[ b ]),(w)) ) : t ) <= 0 ) { + if ( comparison == 0 ) swap( x, y, a++, b ); + b++; + } + while ( c >= b && ( comparison = ( t = ( Integer.compare((x[ c ]),(v)) ) ) == 0 ? ( Integer.compare((y[ c ]),(w)) ) : t ) >= 0 ) { + if ( comparison == 0 ) swap( x, y, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, y, b++, c-- ); + } + // Swap partition elements back to middle + int s; + s = Math.min( a - from, b - a ); + swap( x, y, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, y, b, to - s, s ); + // Recursively sort non-partition-elements + if ( ( s = b - a ) > 1 ) quickSort( x, y, from, from + s ); + if ( ( s = d - c ) > 1 ) quickSort( x, y, to - s, to ); + } + /** Sorts two arrays according to the natural lexicographical ascending order using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implements a lexicographical sorting of the arguments. Pairs of + * elements in the same position in the two provided arrays will be considered a single key, and + * permuted accordingly. In the end, either x[ i ] < x[ i + 1 ] or x[ i ] + * == x[ i + 1 ] and y[ i ] ≤ y[ i + 1 ]. + * + * @param x the first array to be sorted. + * @param y the second array to be sorted. + */ + public static void quickSort( final int[] x, final int[] y ) { + ensureSameLength( x, y ); + quickSort( x, y, 0, x.length ); + } + protected static class ForkJoinQuickSort2 extends RecursiveAction { + private static final long serialVersionUID = 1L; + private final int from; + private final int to; + private final int[] x, y; + public ForkJoinQuickSort2( final int[] x, final int[] y, final int from , final int to ) { + this.from = from; + this.to = to; + this.x = x; + this.y = y; + } + @Override + + protected void compute() { + final int[] x = this.x; + final int[] y = this.y; + final int len = to - from; + if ( len < PARALLEL_QUICKSORT_NO_FORK ) { + quickSort( x, y, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + int s = len / 8; + l = med3( x, y, l, l + s, l + 2 * s ); + m = med3( x, y, m - s, m, m + s ); + n = med3( x, y, n - 2 * s, n - s, n ); + m = med3( x, y, l, m, n ); + final int v = x[ m ], w = y[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison, t; + while ( b <= c && ( comparison = ( t = ( Integer.compare((x[ b ]),(v)) ) ) == 0 ? ( Integer.compare((y[ b ]),(w)) ) : t ) <= 0 ) { + if ( comparison == 0 ) swap( x, y, a++, b ); + b++; + } + while ( c >= b && ( comparison = ( t = ( Integer.compare((x[ c ]),(v)) ) ) == 0 ? ( Integer.compare((y[ c ]),(w)) ) : t ) >= 0 ) { + if ( comparison == 0 ) swap( x, y, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, y, b++, c-- ); + } + // Swap partition elements back to middle + int t; + s = Math.min( a - from, b - a ); + swap( x, y, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, y, b, to - s, s ); + s = b - a; + t = d - c; + // Recursively sort non-partition-elements + if ( s > 1 && t > 1 ) invokeAll( new ForkJoinQuickSort2 ( x, y, from, from + s ), new ForkJoinQuickSort2 ( x, y, to - t, to ) ); + else if ( s > 1 ) invokeAll( new ForkJoinQuickSort2 ( x, y, from, from + s ) ); + else invokeAll( new ForkJoinQuickSort2 ( x, y, to - t, to ) ); + } + } + /** Sorts the specified range of elements of two arrays according to the natural lexicographical + * ascending order using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implements a lexicographical sorting of the arguments. Pairs of + * elements in the same position in the two provided arrays will be considered a single key, and + * permuted accordingly. In the end, either x[ i ] < x[ i + 1 ] or x[ i ] + * == x[ i + 1 ] and y[ i ] ≤ y[ i + 1 ]. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the first array to be sorted. + * @param y the second array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void parallelQuickSort( final int[] x, final int[] y, final int from, final int to ) { + if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSort( x, y, from, to ); + final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() ); + pool.invoke( new ForkJoinQuickSort2 ( x, y, from, to ) ); + pool.shutdown(); + } + /** Sorts two arrays according to the natural lexicographical + * ascending order using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implements a lexicographical sorting of the arguments. Pairs of + * elements in the same position in the two provided arrays will be considered a single key, and + * permuted accordingly. In the end, either x[ i ] < x[ i + 1 ] or x[ i ] + * == x[ i + 1 ] and y[ i ] ≤ y[ i + 1 ]. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the first array to be sorted. + * @param y the second array to be sorted. + */ + public static void parallelQuickSort( final int[] x, final int[] y ) { + ensureSameLength( x, y ); + parallelQuickSort( x, y, 0, x.length ); + } + /** Sorts the specified range of elements according to the natural ascending order using mergesort, using a given pre-filled support array. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. Moreover, no support arrays will be allocated. + + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param supp a support array containing at least to elements, and whose entries are identical to those + * of {@code a} in the specified range. + */ + + public static void mergeSort( final int a[], final int from, final int to, final int supp[] ) { + int len = to - from; + // Insertion sort on smallest arrays + if ( len < MERGESORT_NO_REC ) { + insertionSort( a, from, to ); + return; + } + // Recursively sort halves of a into supp + final int mid = ( from + to ) >>> 1; + mergeSort( supp, from, mid, a ); + mergeSort( supp, mid, to, a ); + // If list is already sorted, just copy from supp to a. This is an + // optimization that results in faster sorts for nearly ordered lists. + if ( ( (supp[ mid - 1 ]) <= (supp[ mid ]) ) ) { + System.arraycopy( supp, from, a, from, len ); + return; + } + // Merge sorted halves (now in supp) into a + for( int i = from, p = from, q = mid; i < to; i++ ) { + if ( q >= to || p < mid && ( (supp[ p ]) <= (supp[ q ]) ) ) a[ i ] = supp[ p++ ]; + else a[ i ] = supp[ q++ ]; + } + } + /** Sorts the specified range of elements according to the natural ascending order using mergesort. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. An array as large as a will be allocated by this method. + + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void mergeSort( final int a[], final int from, final int to ) { + mergeSort( a, from, to, a.clone() ); + } + /** Sorts an array according to the natural ascending order using mergesort. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. An array as large as a will be allocated by this method. + + * @param a the array to be sorted. + */ + public static void mergeSort( final int a[] ) { + mergeSort( a, 0, a.length ); + } + /** Sorts the specified range of elements according to the order induced by the specified + * comparator using mergesort, using a given pre-filled support array. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. Moreover, no support arrays will be allocated. + + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param comp the comparator to determine the sorting order. + * @param supp a support array containing at least to elements, and whose entries are identical to those + * of {@code a} in the specified range. + */ + public static void mergeSort( final int a[], final int from, final int to, IntComparator comp, final int supp[] ) { + int len = to - from; + // Insertion sort on smallest arrays + if ( len < MERGESORT_NO_REC ) { + insertionSort( a, from, to, comp ); + return; + } + // Recursively sort halves of a into supp + final int mid = ( from + to ) >>> 1; + mergeSort( supp, from, mid, comp, a ); + mergeSort( supp, mid, to, comp, a ); + // If list is already sorted, just copy from supp to a. This is an + // optimization that results in faster sorts for nearly ordered lists. + if ( comp.compare( supp[ mid - 1 ], supp[ mid ] ) <= 0 ) { + System.arraycopy( supp, from, a, from, len ); + return; + } + // Merge sorted halves (now in supp) into a + for( int i = from, p = from, q = mid; i < to; i++ ) { + if ( q >= to || p < mid && comp.compare( supp[ p ], supp[ q ] ) <= 0 ) a[ i ] = supp[ p++ ]; + else a[ i ] = supp[ q++ ]; + } + } + /** Sorts the specified range of elements according to the order induced by the specified + * comparator using mergesort. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. An array as large as a will be allocated by this method. + * + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param comp the comparator to determine the sorting order. + */ + public static void mergeSort( final int a[], final int from, final int to, IntComparator comp ) { + mergeSort( a, from, to, comp, a.clone() ); + } + /** Sorts an array 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. An array as large as a will be allocated by this method. + + * @param a the array to be sorted. + * @param comp the comparator to determine the sorting order. + */ + public static void mergeSort( final int a[], IntComparator comp ) { + mergeSort( a, 0, a.length, comp ); + } + /** + * Searches a range of the specified array for the specified value using + * the binary search algorithm. The range must be sorted prior to making this call. + * If it is not sorted, the results are undefined. If the range contains multiple elements with + * the specified value, there is no guarantee which one will be found. + * + * @param a the array to be searched. + * @param from the index of the first element (inclusive) to be searched. + * @param to the index of the last element (exclusive) to be searched. + * @param key the value to be searched for. + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The insertion + * point is defined as the the point at which the value would + * be inserted into the array: the index of the first + * element greater than the key, or the length of the array, if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be ≥ 0 if + * and only if the key is found. + * @see java.util.Arrays + */ + + public static int binarySearch( final int[] a, int from, int to, final int key ) { + int midVal; + to--; + while (from <= to) { + final int mid = (from + to) >>> 1; + midVal = a[ mid ]; + if (midVal < key) from = mid + 1; + else if (midVal > key) to = mid - 1; + else return mid; + } + return -( from + 1 ); + } + /** + * Searches an array for the specified value using + * the binary search algorithm. The range must be sorted prior to making this call. + * If it is not sorted, the results are undefined. If the range contains multiple elements with + * the specified value, there is no guarantee which one will be found. + * + * @param a the array to be searched. + * @param key the value to be searched for. + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The insertion + * point is defined as the the point at which the value would + * be inserted into the array: the index of the first + * element greater than the key, or the length of the array, if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be ≥ 0 if + * and only if the key is found. + * @see java.util.Arrays + */ + public static int binarySearch( final int[] a, final int key ) { + return binarySearch( a, 0, a.length, key ); + } + /** + * Searches a range of the specified array for the specified value using + * the binary search algorithm and a specified comparator. The range must be sorted following the comparator prior to making this call. + * If it is not sorted, the results are undefined. If the range contains multiple elements with + * the specified value, there is no guarantee which one will be found. + * + * @param a the array to be searched. + * @param from the index of the first element (inclusive) to be searched. + * @param to the index of the last element (exclusive) to be searched. + * @param key the value to be searched for. + * @param c a comparator. + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The insertion + * point is defined as the the point at which the value would + * be inserted into the array: the index of the first + * element greater than the key, or the length of the array, if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be ≥ 0 if + * and only if the key is found. + * @see java.util.Arrays + */ + public static int binarySearch( final int[] a, int from, int to, final int key, final IntComparator c ) { + int midVal; + to--; + while (from <= to) { + final int mid = (from + to) >>> 1; + midVal = a[ mid ]; + final int cmp = c.compare( midVal, key ); + if ( cmp < 0 ) from = mid + 1; + else if (cmp > 0) to = mid - 1; + else return mid; // key found + } + return -( from + 1 ); + } + /** + * Searches an array for the specified value using + * the binary search algorithm and a specified comparator. The range must be sorted following the comparator prior to making this call. + * If it is not sorted, the results are undefined. If the range contains multiple elements with + * the specified value, there is no guarantee which one will be found. + * + * @param a the array to be searched. + * @param key the value to be searched for. + * @param c a comparator. + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The insertion + * point is defined as the the point at which the value would + * be inserted into the array: the index of the first + * element greater than the key, or the length of the array, if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be ≥ 0 if + * and only if the key is found. + * @see java.util.Arrays + */ + public static int binarySearch( final int[] a, final int key, final IntComparator c ) { + return binarySearch( a, 0, a.length, key, c ); + } + /** The size of a digit used during radix sort (must be a power of 2). */ + private static final int DIGIT_BITS = 8; + /** The mask to extract a digit of {@link #DIGIT_BITS} bits. */ + private static final int DIGIT_MASK = ( 1 << DIGIT_BITS ) - 1; + /** The number of digits per element. */ + private static final int DIGITS_PER_ELEMENT = Integer.SIZE / DIGIT_BITS; + private static final int RADIXSORT_NO_REC = 1024; + private static final int PARALLEL_RADIXSORT_NO_FORK = 1024; + /** This method fixes negative numbers so that the combination exponent/significand is lexicographically sorted. */ + /** Sorts the specified array using radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This implementation is significantly faster than quicksort + * already at small sizes (say, more than 10000 elements), but it can only + * sort in ascending order. + * + * @param a the array to be sorted. + */ + public static void radixSort( final int[] a ) { + radixSort( a, 0, a.length ); + } + /** Sorts the specified range of an array using radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This implementation is significantly faster than quicksort + * already at small sizes (say, more than 10000 elements), but it can only + * sort in ascending order. + * + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void radixSort( final int[] a, final int from, final int to ) { + if ( to - from < RADIXSORT_NO_REC ) { + quickSort( a, from, to ); + return; + } + final int maxLevel = DIGITS_PER_ELEMENT - 1; + final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( DIGITS_PER_ELEMENT - 1 ) + 1; + int stackPos = 0; + final int[] offsetStack = new int[ stackSize ]; + final int[] lengthStack = new int[ stackSize ]; + final int[] levelStack = new int[ stackSize ]; + offsetStack[ stackPos ] = from; + lengthStack[ stackPos ] = to - from; + levelStack[ stackPos++ ] = 0; + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + while( stackPos > 0 ) { + final int first = offsetStack[ --stackPos ]; + final int length = lengthStack[ stackPos ]; + final int level = levelStack[ stackPos ]; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ ((a[ i ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + int t = a[ i ]; + c = ((t) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while ( ( d = --pos[ c ] ) > i ) { + final int z = t; + t = a[ d ]; + a[ d ] = z; + c = ((t) >>> shift & DIGIT_MASK ^ signMask); + } + a[ i ] = t; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < RADIXSORT_NO_REC ) quickSort( a, i, i + count[ c ] ); + else { + offsetStack[ stackPos ] = i; + lengthStack[ stackPos ] = count[ c ]; + levelStack[ stackPos++ ] = level + 1; + } + } + } + } + } + protected final static class Segment { + protected final int offset, length, level; + protected Segment( final int offset, final int length, final int level ) { + this.offset = offset; + this.length = length; + this.level = level; + } + @Override + public String toString() { + return "Segment [offset=" + offset + ", length=" + length + ", level=" + level + "]"; + } + } + protected final static Segment POISON_PILL = new Segment( -1, -1, -1 ); + /** Sorts the specified range of an array using parallel radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This implementation uses a pool of {@link Runtime#availableProcessors()} threads. + * + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void parallelRadixSort( final int[] a, final int from, final int to ) { + if ( to - from < PARALLEL_RADIXSORT_NO_FORK ) { + quickSort( a, from, to ); + return; + } + final int maxLevel = DIGITS_PER_ELEMENT - 1; + final LinkedBlockingQueue queue = new LinkedBlockingQueue(); + queue.add( new Segment( from, to - from, 0 ) ); + final AtomicInteger queueSize = new AtomicInteger( 1 ); + final int numberOfThreads = Runtime.getRuntime().availableProcessors(); + final ExecutorService executorService = Executors.newFixedThreadPool( numberOfThreads, Executors.defaultThreadFactory() ); + final ExecutorCompletionService executorCompletionService = new ExecutorCompletionService( executorService ); + for( int i = numberOfThreads; i-- != 0; ) executorCompletionService.submit( new Callable() { + public Void call() throws Exception { + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + for(;;) { + if ( queueSize.get() == 0 ) for( int i = numberOfThreads; i-- != 0; ) queue.add( POISON_PILL ); + final Segment segment = queue.take(); + if ( segment == POISON_PILL ) return null; + final int first = segment.offset; + final int length = segment.length; + final int level = segment.level; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ ((a[ i ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + int t = a[ i ]; + c = ((t) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { + while( ( d = --pos[ c ] ) > i ) { + final int z = t; + t = a[ d ]; + a[ d ] = z; + c = ((t) >>> shift & DIGIT_MASK ^ signMask); + } + a[ i ] = t; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < PARALLEL_RADIXSORT_NO_FORK ) quickSort( a, i, i + count[ c ] ); + else { + queueSize.incrementAndGet(); + queue.add( new Segment( i, count[ c ], level + 1 ) ); + } + } + } + queueSize.decrementAndGet(); + } + } + } ); + Throwable problem = null; + for( int i = numberOfThreads; i-- != 0; ) + try { + executorCompletionService.take().get(); + } + catch( Exception e ) { + problem = e.getCause(); // We keep only the last one. They will be logged anyway. + } + executorService.shutdown(); + if ( problem != null ) throw ( problem instanceof RuntimeException ) ? (RuntimeException)problem : new RuntimeException( problem ); + } + /** Sorts the specified array using parallel radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This implementation uses a pool of {@link Runtime#availableProcessors()} threads. + * + * @param a the array to be sorted. + */ + public static void parallelRadixSort( final int[] a ) { + parallelRadixSort( a, 0, a.length ); + } + /** Sorts the specified array using indirect radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]. + * + *

This implementation will allocate, in the stable case, a support array as large as perm (note that the stable + * version is slightly faster). + * + * @param perm a permutation array indexing a. + * @param a the array to be sorted. + * @param stable whether the sorting algorithm should be stable. + */ + public static void radixSortIndirect( final int[] perm, final int[] a, final boolean stable ) { + radixSortIndirect( perm, a, 0, perm.length, stable ); + } + /** Sorts the specified array using indirect radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]. + * + *

This implementation will allocate, in the stable case, a support array as large as perm (note that the stable + * version is slightly faster). + * + * @param perm a permutation array indexing a. + * @param a the array to be sorted. + * @param from the index of the first element of perm (inclusive) to be permuted. + * @param to the index of the last element of perm (exclusive) to be permuted. + * @param stable whether the sorting algorithm should be stable. + */ + public static void radixSortIndirect( final int[] perm, final int[] a, final int from, final int to, final boolean stable ) { + if ( to - from < RADIXSORT_NO_REC ) { + insertionSortIndirect( perm, a, from, to ); + return; + } + final int maxLevel = DIGITS_PER_ELEMENT - 1; + final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( DIGITS_PER_ELEMENT - 1 ) + 1; + int stackPos = 0; + final int[] offsetStack = new int[ stackSize ]; + final int[] lengthStack = new int[ stackSize ]; + final int[] levelStack = new int[ stackSize ]; + offsetStack[ stackPos ] = from; + lengthStack[ stackPos ] = to - from; + levelStack[ stackPos++ ] = 0; + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + final int[] support = stable ? new int[ perm.length ] : null; + while( stackPos > 0 ) { + final int first = offsetStack[ --stackPos ]; + final int length = lengthStack[ stackPos ]; + final int level = levelStack[ stackPos ]; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ ((a[ perm[ i ] ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = stable ? 0 : first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + if ( stable ) { + for( int i = first + length; i-- != first; ) support[ --pos[ ((a[ perm[ i ] ]) >>> shift & DIGIT_MASK ^ signMask) ] ] = perm[ i ]; + System.arraycopy( support, 0, perm, first, length ); + for( int i = 0, p = first; i <= lastUsed; i++ ) { + if ( level < maxLevel && count[ i ] > 1 ) { + if ( count[ i ] < RADIXSORT_NO_REC ) insertionSortIndirect( perm, a, p, p + count[ i ] ); + else { + offsetStack[ stackPos ] = p; + lengthStack[ stackPos ] = count[ i ]; + levelStack[ stackPos++ ] = level + 1; + } + } + p += count[ i ]; + } + java.util.Arrays.fill( count, 0 ); + } + else { + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + int t = perm[ i ]; + c = ((a[ t ]) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while( ( d = --pos[ c ] ) > i ) { + final int z = t; + t = perm[ d ]; + perm[ d ] = z; + c = ((a[ t ]) >>> shift & DIGIT_MASK ^ signMask); + } + perm[ i ] = t; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < RADIXSORT_NO_REC ) insertionSortIndirect( perm, a, i, i + count[ c ] ); + else { + offsetStack[ stackPos ] = i; + lengthStack[ stackPos ] = count[ c ]; + levelStack[ stackPos++ ] = level + 1; + } + } + } + } + } + } + /** Sorts the specified range of an array using parallel indirect radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]. + * + *

This implementation uses a pool of {@link Runtime#availableProcessors()} threads. + * + * @param perm a permutation array indexing a. + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param stable whether the sorting algorithm should be stable. + */ + public static void parallelRadixSortIndirect( final int perm[], final int[] a, final int from, final int to, final boolean stable ) { + if ( to - from < PARALLEL_RADIXSORT_NO_FORK ) { + radixSortIndirect( perm, a, from, to, stable ); + return; + } + final int maxLevel = DIGITS_PER_ELEMENT - 1; + final LinkedBlockingQueue queue = new LinkedBlockingQueue(); + queue.add( new Segment( from, to - from, 0 ) ); + final AtomicInteger queueSize = new AtomicInteger( 1 ); + final int numberOfThreads = Runtime.getRuntime().availableProcessors(); + final ExecutorService executorService = Executors.newFixedThreadPool( numberOfThreads, Executors.defaultThreadFactory() ); + final ExecutorCompletionService executorCompletionService = new ExecutorCompletionService( executorService ); + final int[] support = stable ? new int[ perm.length ] : null; + for( int i = numberOfThreads; i-- != 0; ) executorCompletionService.submit( new Callable() { + public Void call() throws Exception { + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + for(;;) { + if ( queueSize.get() == 0 ) for( int i = numberOfThreads; i-- != 0; ) queue.add( POISON_PILL ); + final Segment segment = queue.take(); + if ( segment == POISON_PILL ) return null; + final int first = segment.offset; + final int length = segment.length; + final int level = segment.level; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ ((a[ perm[ i ] ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + if ( stable ) { + for( int i = first + length; i-- != first; ) support[ --pos[ ((a[ perm[ i ] ]) >>> shift & DIGIT_MASK ^ signMask) ] ] = perm[ i ]; + System.arraycopy( support, first, perm, first, length ); + for( int i = 0, p = first; i <= lastUsed; i++ ) { + if ( level < maxLevel && count[ i ] > 1 ) { + if ( count[ i ] < PARALLEL_RADIXSORT_NO_FORK ) radixSortIndirect( perm, a, p, p + count[ i ], stable ); + else { + queueSize.incrementAndGet(); + queue.add( new Segment( p, count[ i ], level + 1 ) ); + } + } + p += count[ i ]; + } + java.util.Arrays.fill( count, 0 ); + } + else { + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + int t = perm[ i ]; + c = ((a[ t ]) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while( ( d = --pos[ c ] ) > i ) { + final int z = t; + t = perm[ d ]; + perm[ d ] = z; + c = ((a[ t ]) >>> shift & DIGIT_MASK ^ signMask); + } + perm[ i ] = t; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < PARALLEL_RADIXSORT_NO_FORK ) radixSortIndirect( perm, a, i, i + count[ c ], stable ); + else { + queueSize.incrementAndGet(); + queue.add( new Segment( i, count[ c ], level + 1 ) ); + } + } + } + } + queueSize.decrementAndGet(); + } + } + } ); + Throwable problem = null; + for( int i = numberOfThreads; i-- != 0; ) + try { + executorCompletionService.take().get(); + } + catch( Exception e ) { + problem = e.getCause(); // We keep only the last one. They will be logged anyway. + } + executorService.shutdown(); + if ( problem != null ) throw ( problem instanceof RuntimeException ) ? (RuntimeException)problem : new RuntimeException( problem ); + } + /** Sorts the specified array using parallel indirect radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]. + * + *

This implementation uses a pool of {@link Runtime#availableProcessors()} threads. + * + * @param perm a permutation array indexing a. + * @param a the array to be sorted. + * @param stable whether the sorting algorithm should be stable. + */ + public static void parallelRadixSortIndirect( final int perm[], final int[] a, final boolean stable ) { + parallelRadixSortIndirect( perm, a, 0, a.length, stable ); + } + /** Sorts the specified pair of arrays lexicographically using radix sort. + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implements a lexicographical sorting of the arguments. Pairs of elements + * in the same position in the two provided arrays will be considered a single key, and permuted + * accordingly. In the end, either a[ i ] < a[ i + 1 ] or a[ i ] == a[ i + 1 ] and b[ i ] ≤ b[ i + 1 ]. + * + * @param a the first array to be sorted. + * @param b the second array to be sorted. + */ + public static void radixSort( final int[] a, final int[] b ) { + ensureSameLength( a, b ); + radixSort( a, b, 0, a.length ); + } + /** Sorts the specified range of elements of two arrays using radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implements a lexicographical sorting of the arguments. Pairs of elements + * in the same position in the two provided arrays will be considered a single key, and permuted + * accordingly. In the end, either a[ i ] < a[ i + 1 ] or a[ i ] == a[ i + 1 ] and b[ i ] ≤ b[ i + 1 ]. + * + * @param a the first array to be sorted. + * @param b the second array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void radixSort( final int[] a, final int[] b, final int from, final int to ) { + if ( to - from < RADIXSORT_NO_REC ) { + selectionSort( a, b, from, to ); + return; + } + final int layers = 2; + final int maxLevel = DIGITS_PER_ELEMENT * layers - 1; + final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( layers * DIGITS_PER_ELEMENT - 1 ) + 1; + int stackPos = 0; + final int[] offsetStack = new int[ stackSize ]; + final int[] lengthStack = new int[ stackSize ]; + final int[] levelStack = new int[ stackSize ]; + offsetStack[ stackPos ] = from; + lengthStack[ stackPos ] = to - from; + levelStack[ stackPos++ ] = 0; + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + while( stackPos > 0 ) { + final int first = offsetStack[ --stackPos ]; + final int length = lengthStack[ stackPos ]; + final int level = levelStack[ stackPos ]; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final int[] k = level < DIGITS_PER_ELEMENT ? a : b; // This is the key array + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ ((k[ i ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + int t = a[ i ]; + int u = b[ i ]; + c = ((k[ i ]) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while( ( d = --pos[ c ] ) > i ) { + c = ((k[ d ]) >>> shift & DIGIT_MASK ^ signMask); + int z = t; + t = a[ d ]; + a[ d ] = z; + z = u; + u = b[ d ]; + b[ d ] = z; + } + a[ i ] = t; + b[ i ] = u; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < RADIXSORT_NO_REC ) selectionSort( a, b, i, i + count[ c ] ); + else { + offsetStack[ stackPos ] = i; + lengthStack[ stackPos ] = count[ c ]; + levelStack[ stackPos++ ] = level + 1; + } + } + } + } + } + /** Sorts the specified range of elements of two arrays using a parallel radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implements a lexicographical sorting of the arguments. Pairs of elements + * in the same position in the two provided arrays will be considered a single key, and permuted + * accordingly. In the end, either a[ i ] < a[ i + 1 ] or a[ i ] == a[ i + 1 ] and b[ i ] ≤ b[ i + 1 ]. + * + *

This implementation uses a pool of {@link Runtime#availableProcessors()} threads. + * + * @param a the first array to be sorted. + * @param b the second array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void parallelRadixSort( final int[] a, final int[] b, final int from, final int to ) { + if ( to - from < PARALLEL_RADIXSORT_NO_FORK ) { + quickSort( a, b, from, to ); + return; + } + final int layers = 2; + if ( a.length != b.length ) throw new IllegalArgumentException( "Array size mismatch." ); + final int maxLevel = DIGITS_PER_ELEMENT * layers - 1; + final LinkedBlockingQueue queue = new LinkedBlockingQueue(); + queue.add( new Segment( from, to - from, 0 ) ); + final AtomicInteger queueSize = new AtomicInteger( 1 ); + final int numberOfThreads = Runtime.getRuntime().availableProcessors(); + final ExecutorService executorService = Executors.newFixedThreadPool( numberOfThreads, Executors.defaultThreadFactory() ); + final ExecutorCompletionService executorCompletionService = new ExecutorCompletionService( executorService ); + for ( int i = numberOfThreads; i-- != 0; ) + executorCompletionService.submit( new Callable() { + public Void call() throws Exception { + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + for ( ;; ) { + if ( queueSize.get() == 0 ) for ( int i = numberOfThreads; i-- != 0; ) + queue.add( POISON_PILL ); + final Segment segment = queue.take(); + if ( segment == POISON_PILL ) return null; + final int first = segment.offset; + final int length = segment.length; + final int level = segment.level; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final int[] k = level < DIGITS_PER_ELEMENT ? a : b; // This is the key array + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; + // Count keys. + for ( int i = first + length; i-- != first; ) + count[ ((k[ i ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + final int end = first + length - count[ lastUsed ]; + for ( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + int t = a[ i ]; + int u = b[ i ]; + c = ((k[ i ]) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while ( ( d = --pos[ c ] ) > i ) { + c = ((k[ d ]) >>> shift & DIGIT_MASK ^ signMask); + final int z = t; + final int w = u; + t = a[ d ]; + u = b[ d ]; + a[ d ] = z; + b[ d ] = w; + } + a[ i ] = t; + b[ i ] = u; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < PARALLEL_RADIXSORT_NO_FORK ) quickSort( a, b, i, i + count[ c ] ); + else { + queueSize.incrementAndGet(); + queue.add( new Segment( i, count[ c ], level + 1 ) ); + } + } + } + queueSize.decrementAndGet(); + } + } + } ); + Throwable problem = null; + for ( int i = numberOfThreads; i-- != 0; ) + try { + executorCompletionService.take().get(); + } + catch ( Exception e ) { + problem = e.getCause(); // We keep only the last one. They will be logged anyway. + } + executorService.shutdown(); + if ( problem != null ) throw ( problem instanceof RuntimeException ) ? (RuntimeException)problem : new RuntimeException( problem ); + } + /** Sorts two arrays using a parallel radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implements a lexicographical sorting of the arguments. Pairs of elements + * in the same position in the two provided arrays will be considered a single key, and permuted + * accordingly. In the end, either a[ i ] < a[ i + 1 ] or a[ i ] == a[ i + 1 ] and b[ i ] ≤ b[ i + 1 ]. + * + *

This implementation uses a pool of {@link Runtime#availableProcessors()} threads. + * + * @param a the first array to be sorted. + * @param b the second array to be sorted. + */ + public static void parallelRadixSort( final int[] a, final int[] b ) { + ensureSameLength( a, b ); + parallelRadixSort( a, b, 0, a.length ); + } + private static void insertionSortIndirect( final int[] perm, final int[] a, final int[] b, final int from, final int to ) { + for ( int i = from; ++i < to; ) { + int t = perm[ i ]; + int j = i; + for ( int u = perm[ j - 1 ]; ( (a[ t ]) < (a[ u ]) ) || ( (a[ t ]) == (a[ u ]) ) && ( (b[ t ]) < (b[ u ]) ); u = perm[ --j - 1 ] ) { + perm[ j ] = u; + if ( from == j - 1 ) { + --j; + break; + } + } + perm[ j ] = t; + } + } + /** Sorts the specified pair of arrays lexicographically using indirect radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]. + * + *

This implementation will allocate, in the stable case, a further support array as large as perm (note that the stable + * version is slightly faster). + * + * @param perm a permutation array indexing a. + * @param a the array to be sorted. + * @param b the second array to be sorted. + * @param stable whether the sorting algorithm should be stable. + */ + public static void radixSortIndirect( final int[] perm, final int[] a, final int[] b, final boolean stable ) { + ensureSameLength( a, b ); + radixSortIndirect( perm, a, b, 0, a.length, stable ); + } + /** Sorts the specified pair of arrays lexicographically using indirect radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]. + * + *

This implementation will allocate, in the stable case, a further support array as large as perm (note that the stable + * version is slightly faster). + * + * @param perm a permutation array indexing a. + * @param a the array to be sorted. + * @param b the second array to be sorted. + * @param from the index of the first element of perm (inclusive) to be permuted. + * @param to the index of the last element of perm (exclusive) to be permuted. + * @param stable whether the sorting algorithm should be stable. + */ + public static void radixSortIndirect( final int[] perm, final int[] a, final int[] b, final int from, final int to, final boolean stable ) { + if ( to - from < RADIXSORT_NO_REC ) { + insertionSortIndirect( perm, a, b, from, to ); + return; + } + final int layers = 2; + final int maxLevel = DIGITS_PER_ELEMENT * layers - 1; + final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( layers * DIGITS_PER_ELEMENT - 1 ) + 1; + int stackPos = 0; + final int[] offsetStack = new int[ stackSize ]; + final int[] lengthStack = new int[ stackSize ]; + final int[] levelStack = new int[ stackSize ]; + offsetStack[ stackPos ] = from; + lengthStack[ stackPos ] = to - from; + levelStack[ stackPos++ ] = 0; + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + final int[] support = stable ? new int[ perm.length ] : null; + while( stackPos > 0 ) { + final int first = offsetStack[ --stackPos ]; + final int length = lengthStack[ stackPos ]; + final int level = levelStack[ stackPos ]; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final int[] k = level < DIGITS_PER_ELEMENT ? a : b; // This is the key array + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ ((k[ perm[ i ] ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = stable ? 0 : first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + if ( stable ) { + for( int i = first + length; i-- != first; ) support[ --pos[ ((k[ perm[ i ] ]) >>> shift & DIGIT_MASK ^ signMask) ] ] = perm[ i ]; + System.arraycopy( support, 0, perm, first, length ); + for( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( level < maxLevel && count[ i ] > 1 ) { + if ( count[ i ] < RADIXSORT_NO_REC ) insertionSortIndirect( perm, a, b, p, p + count[ i ] ); + else { + offsetStack[ stackPos ] = p; + lengthStack[ stackPos ] = count[ i ]; + levelStack[ stackPos++ ] = level + 1; + } + } + p += count[ i ]; + } + java.util.Arrays.fill( count, 0 ); + } + else { + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + int t = perm[ i ]; + c = ((k[ t ]) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while( ( d = --pos[ c ] ) > i ) { + final int z = t; + t = perm[ d ]; + perm[ d ] = z; + c = ((k[ t ]) >>> shift & DIGIT_MASK ^ signMask); + } + perm[ i ] = t; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < RADIXSORT_NO_REC ) insertionSortIndirect( perm, a, b, i, i + count[ c ] ); + else { + offsetStack[ stackPos ] = i; + lengthStack[ stackPos ] = count[ c ]; + levelStack[ stackPos++ ] = level + 1; + } + } + } + } + } + } + private static void selectionSort( final int[][] a, final int from, final int to, final int level ) { + final int layers = a.length; + final int firstLayer = level / DIGITS_PER_ELEMENT; + for( int i = from; i < to - 1; i++ ) { + int m = i; + for( int j = i + 1; j < to; j++ ) { + for( int p = firstLayer; p < layers; p++ ) { + if ( a[ p ][ j ] < a[ p ][ m ] ) { + m = j; + break; + } + else if ( a[ p ][ j ] > a[ p ][ m ] ) break; + } + } + if ( m != i ) { + for( int p = layers; p-- != 0; ) { + final int u = a[ p ][ i ]; + a[ p ][ i ] = a[ p ][ m ]; + a[ p ][ m ] = u; + } + } + } + } + /** Sorts the specified array of arrays lexicographically using radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implements a lexicographical sorting of the provided arrays. Tuples of elements + * in the same position will be considered a single key, and permuted + * accordingly. + * + * @param a an array containing arrays of equal length to be sorted lexicographically in parallel. + */ + public static void radixSort( final int[][] a ) { + radixSort( a, 0, a[ 0 ].length ); + } + /** Sorts the specified array of arrays lexicographically using radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implements a lexicographical sorting of the provided arrays. Tuples of elements + * in the same position will be considered a single key, and permuted + * accordingly. + * + * @param a an array containing arrays of equal length to be sorted lexicographically in parallel. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void radixSort( final int[][] a, final int from, final int to ) { + if ( to - from < RADIXSORT_NO_REC ) { + selectionSort( a, from, to, 0 ); + return; + } + final int layers = a.length; + final int maxLevel = DIGITS_PER_ELEMENT * layers - 1; + for( int p = layers, l = a[ 0 ].length; p-- != 0; ) if ( a[ p ].length != l ) throw new IllegalArgumentException( "The array of index " + p + " has not the same length of the array of index 0." ); + final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( layers * DIGITS_PER_ELEMENT - 1 ) + 1; + int stackPos = 0; + final int[] offsetStack = new int[ stackSize ]; + final int[] lengthStack = new int[ stackSize ]; + final int[] levelStack = new int[ stackSize ]; + offsetStack[ stackPos ] = from; + lengthStack[ stackPos ] = to - from; + levelStack[ stackPos++ ] = 0; + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + final int[] t = new int[ layers ]; + while( stackPos > 0 ) { + final int first = offsetStack[ --stackPos ]; + final int length = lengthStack[ stackPos ]; + final int level = levelStack[ stackPos ]; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final int[] k = a[ level / DIGITS_PER_ELEMENT ]; // This is the key array + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ ((k[ i ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + for( int p = layers; p-- != 0; ) t[ p ] = a[ p ][ i ]; + c = ((k[ i ]) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while( ( d = --pos[ c ] ) > i ) { + c = ((k[ d ]) >>> shift & DIGIT_MASK ^ signMask); + for( int p = layers; p-- != 0; ) { + final int u = t[ p ]; + t[ p ] = a[ p ][ d ]; + a[ p ][ d ] = u; + } + } + for( int p = layers; p-- != 0; ) a[ p ][ i ] = t[ p ]; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < RADIXSORT_NO_REC ) selectionSort( a, i, i + count[ c ], level + 1 ); + else { + offsetStack[ stackPos ] = i; + lengthStack[ stackPos ] = count[ c ]; + levelStack[ stackPos++ ] = level + 1; + } + } + } + } + } + /** Shuffles the specified array fragment using the specified pseudorandom number generator. + * + * @param a the array to be shuffled. + * @param from the index of the first element (inclusive) to be shuffled. + * @param to the index of the last element (exclusive) to be shuffled. + * @param random a pseudorandom number generator (please use a XorShift* generator). + * @return a. + */ + public static int[] shuffle( final int[] a, final int from, final int to, final Random random ) { + for( int i = to - from; i-- != 0; ) { + final int p = random.nextInt( i + 1 ); + final int t = a[ from + i ]; + a[ from + i ] = a[ from + p ]; + a[ from + p ] = t; + } + return a; + } + /** Shuffles the specified array using the specified pseudorandom number generator. + * + * @param a the array to be shuffled. + * @param random a pseudorandom number generator (please use a XorShift* generator). + * @return a. + */ + public static int[] shuffle( final int[] a, final Random random ) { + for( int i = a.length; i-- != 0; ) { + final int p = random.nextInt( i + 1 ); + final int t = a[ i ]; + a[ i ] = a[ p ]; + a[ p ] = t; + } + return a; + } + /** Reverses the order of the elements in the specified array. + * + * @param a the array to be reversed. + * @return a. + */ + public static int[] reverse( final int[] a ) { + final int length = a.length; + for( int i = length / 2; i-- != 0; ) { + final int t = a[ length - i - 1 ]; + a[ length - i - 1 ] = a[ i ]; + a[ i ] = t; + } + return a; + } + /** Reverses the order of the elements in the specified array fragment. + * + * @param a the array to be reversed. + * @param from the index of the first element (inclusive) to be reversed. + * @param to the index of the last element (exclusive) to be reversed. + * @return a. + */ + public static int[] reverse( final int[] a, final int from, final int to ) { + final int length = to - from; + for( int i = length / 2; i-- != 0; ) { + final int t = a[ from + length - i - 1 ]; + a[ from + length - i - 1 ] = a[ from + i ]; + a[ from + i ] = t; + } + return a; + } + /** A type-specific content-based hash strategy for arrays. */ + private static final class ArrayHashStrategy implements Hash.Strategy, java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + public int hashCode( final int[] o ) { + return java.util.Arrays.hashCode( o ); + } + public boolean equals( final int[] a, final int[] b ) { + return java.util.Arrays.equals( a, b ); + } + } + /** A type-specific content-based hash strategy for arrays. + * + *

This hash strategy may be used in custom hash collections whenever keys are + * arrays, and they must be considered equal by content. This strategy + * will handle null correctly, and it is serializable. + */ + public final static Hash.Strategy HASH_STRATEGY = new ArrayHashStrategy(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntBidirectionalIterator.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntBidirectionalIterator.java new file mode 100644 index 0000000..04df663 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntBidirectionalIterator.java @@ -0,0 +1,97 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.BidirectionalIterator; +import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; +/** A type-specific bidirectional iterator; provides an additional method to avoid (un)boxing, + * and the possibility to skip elements backwards. + * + * @see BidirectionalIterator + */ +public interface IntBidirectionalIterator extends IntIterator , ObjectBidirectionalIterator { + /** + * Returns the previous element as a primitive type. + * + * @return the previous element in the iteration. + * @see java.util.ListIterator#previous() + */ + int previousInt(); + /** Moves back for the given number of elements. + * + *

The effect of this call is exactly the same as that of + * calling {@link #previous()} for n times (possibly stopping + * if {@link #hasPrevious()} becomes false). + * + * @param n the number of elements to skip back. + * @return the number of elements actually skipped. + * @see java.util.Iterator#next() + */ + int back( int n ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntCollection.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntCollection.java new file mode 100644 index 0000000..56a2d21 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntCollection.java @@ -0,0 +1,169 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.Collection; +/** A type-specific {@link Collection}; provides some additional methods + * that use polymorphism to avoid (un)boxing. + * + *

Additionally, this class defines strengthens (again) {@link #iterator()} and defines + * a slightly different semantics for {@link #toArray(Object[])}. + * + * @see Collection + */ +public interface IntCollection extends Collection, IntIterable { + /** Returns a type-specific iterator on the elements of this collection. + * + *

Note that this specification strengthens the one given in + * {@link java.lang.Iterable#iterator()}, which was already + * strengthened in the corresponding type-specific class, + * but was weakened by the fact that this interface extends {@link Collection}. + * + * @return a type-specific iterator on the elements of this collection. + */ + IntIterator iterator(); + /** Returns a type-specific iterator on this elements of this collection. + * + * @see #iterator() + * @deprecated As of fastutil 5, replaced by {@link #iterator()}. + */ + @Deprecated + IntIterator intIterator(); + /** Returns an containing the items of this collection; + * the runtime type of the returned array is that of the specified array. + * + *

Warning: Note that, contrarily to {@link Collection#toArray(Object[])}, this + * methods just writes all elements of this collection: no special + * value will be added after the last one. + * + * @param a if this array is big enough, it will be used to store this collection. + * @return a primitive type array containing the items of this collection. + * @see Collection#toArray(Object[]) + */ + T[] toArray(T[] a); + /** + * @see Collection#contains(Object) + */ + boolean contains( int key ); + /** Returns a primitive type array containing the items of this collection. + * @return a primitive type array containing the items of this collection. + * @see Collection#toArray() + */ + int[] toIntArray(); + /** Returns a primitive type array containing the items of this collection. + * + *

Note that, contrarily to {@link Collection#toArray(Object[])}, this + * methods just writes all elements of this collection: no special + * value will be added after the last one. + * + * @param a if this array is big enough, it will be used to store this collection. + * @return a primitive type array containing the items of this collection. + * @see Collection#toArray(Object[]) + */ + int[] toIntArray( int a[] ); + /** Returns a primitive type array containing the items of this collection. + * + *

Note that, contrarily to {@link Collection#toArray(Object[])}, this + * methods just writes all elements of this collection: no special + * value will be added after the last one. + * + * @param a if this array is big enough, it will be used to store this collection. + * @return a primitive type array containing the items of this collection. + * @see Collection#toArray(Object[]) + */ + int[] toArray( int a[] ); + /** + * @see Collection#add(Object) + */ + boolean add( int key ); + /** Note that this method should be called {@link java.util.Collection#remove(Object) remove()}, but the clash + * with the similarly named index-based method in the {@link java.util.List} interface + * forces us to use a distinguished name. For simplicity, the set interfaces reinstates + * remove(). + * + * @see Collection#remove(Object) + */ + boolean rem( int key ); + /** + * @see Collection#addAll(Collection) + */ + boolean addAll( IntCollection c ); + /** + * @see Collection#containsAll(Collection) + */ + boolean containsAll( IntCollection c ); + /** + * @see Collection#removeAll(Collection) + */ + boolean removeAll( IntCollection c ); + /** + * @see Collection#retainAll(Collection) + */ + boolean retainAll( IntCollection c ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntCollections.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntCollections.java new file mode 100644 index 0000000..fbf2c95 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntCollections.java @@ -0,0 +1,237 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.Collection; +import it.unimi.dsi.fastutil.objects.ObjectArrays; +/** A class providing static methods and objects that do useful things with type-specific collections. + * + * @see java.util.Collections + */ +public class IntCollections { + private IntCollections() {} + /** An immutable class representing an empty type-specific collection. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific collection. + */ + public abstract static class EmptyCollection extends AbstractIntCollection { + protected EmptyCollection() {} + public boolean add( int k ) { throw new UnsupportedOperationException(); } + public boolean contains( int k ) { return false; } + public Object[] toArray() { return ObjectArrays.EMPTY_ARRAY; } + public int[] toIntArray( int[] a ) { return a; } + public int[] toIntArray() { return IntArrays.EMPTY_ARRAY; } + public boolean rem( int k ) { throw new UnsupportedOperationException(); } + public boolean addAll( IntCollection c ) { throw new UnsupportedOperationException(); } + public boolean removeAll( IntCollection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( IntCollection c ) { throw new UnsupportedOperationException(); } + public boolean containsAll( IntCollection c ) { return c.isEmpty(); } + + public IntBidirectionalIterator iterator() { return IntIterators.EMPTY_ITERATOR; } + public int size() { return 0; } + public void clear() {} + public int hashCode() { return 0; } + public boolean equals( Object o ) { + if ( o == this ) return true; + if ( ! ( o instanceof Collection ) ) return false; + return ((Collection)o).isEmpty(); + } + } + /** A synchronized wrapper class for collections. */ + public static class SynchronizedCollection implements IntCollection , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final IntCollection collection; + protected final Object sync; + protected SynchronizedCollection( final IntCollection c, final Object sync ) { + if ( c == null ) throw new NullPointerException(); + this.collection = c; + this.sync = sync; + } + protected SynchronizedCollection( final IntCollection c ) { + if ( c == null ) throw new NullPointerException(); + this.collection = c; + this.sync = this; + } + public int size() { synchronized( sync ) { return collection.size(); } } + public boolean isEmpty() { synchronized( sync ) { return collection.isEmpty(); } } + public boolean contains( final int o ) { synchronized( sync ) { return collection.contains( o ); } } + public int[] toIntArray() { synchronized( sync ) { return collection.toIntArray(); } } + public Object[] toArray() { synchronized( sync ) { return collection.toArray(); } } + public int[] toIntArray( final int[] a ) { synchronized( sync ) { return collection.toIntArray( a ); } } + public int[] toArray( final int[] a ) { synchronized( sync ) { return collection.toIntArray( a ); } } + public boolean addAll( final IntCollection c ) { synchronized( sync ) { return collection.addAll( c ); } } + public boolean containsAll( final IntCollection c ) { synchronized( sync ) { return collection.containsAll( c ); } } + public boolean removeAll( final IntCollection c ) { synchronized( sync ) { return collection.removeAll( c ); } } + public boolean retainAll( final IntCollection c ) { synchronized( sync ) { return collection.retainAll( c ); } } + public boolean add( final Integer k ) { synchronized( sync ) { return collection.add( k ); } } + public boolean contains( final Object k ) { synchronized( sync ) { return collection.contains( k ); } } + public T[] toArray( final T[] a ) { synchronized( sync ) { return collection.toArray( a ); } } + public IntIterator iterator() { return collection.iterator(); } + @Deprecated + public IntIterator intIterator() { return iterator(); } + public boolean add( final int k ) { synchronized( sync ) { return collection.add( k ); } } + public boolean rem( final int k ) { synchronized( sync ) { return collection.rem( k ); } } + public boolean remove( final Object ok ) { synchronized( sync ) { return collection.remove( ok ); } } + public boolean addAll( final Collection c ) { synchronized( sync ) { return collection.addAll( c ); } } + public boolean containsAll( final Collection c ) { synchronized( sync ) { return collection.containsAll( c ); } } + public boolean removeAll( final Collection c ) { synchronized( sync ) { return collection.removeAll( c ); } } + public boolean retainAll( final Collection c ) { synchronized( sync ) { return collection.retainAll( c ); } } + public void clear() { synchronized( sync ) { collection.clear(); } } + public String toString() { synchronized( sync ) { return collection.toString(); } } + } + /** Returns a synchronized collection backed by the specified collection. + * + * @param c the collection to be wrapped in a synchronized collection. + * @return a synchronized view of the specified collection. + * @see java.util.Collections#synchronizedCollection(Collection) + */ + public static IntCollection synchronize( final IntCollection c ) { return new SynchronizedCollection ( c ); } + /** Returns a synchronized collection backed by the specified collection, using an assigned object to synchronize. + * + * @param c the collection to be wrapped in a synchronized collection. + * @param sync an object that will be used to synchronize the list access. + * @return a synchronized view of the specified collection. + * @see java.util.Collections#synchronizedCollection(Collection) + */ + public static IntCollection synchronize( final IntCollection c, final Object sync ) { return new SynchronizedCollection ( c, sync ); } + /** An unmodifiable wrapper class for collections. */ + public static class UnmodifiableCollection implements IntCollection , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final IntCollection collection; + protected UnmodifiableCollection( final IntCollection c ) { + if ( c == null ) throw new NullPointerException(); + this.collection = c; + } + public int size() { return collection.size(); } + public boolean isEmpty() { return collection.isEmpty(); } + public boolean contains( final int o ) { return collection.contains( o ); } + public IntIterator iterator() { return IntIterators.unmodifiable( collection.iterator() ); } + @Deprecated + public IntIterator intIterator() { return iterator(); } + public boolean add( final int k ) { throw new UnsupportedOperationException(); } + public boolean remove( final Object ok ) { throw new UnsupportedOperationException(); } + public boolean addAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean containsAll( final Collection c ) { return collection.containsAll( c ); } + public boolean removeAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( final Collection c ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + public String toString() { return collection.toString(); } + public T[] toArray( final T[] a ) { return collection.toArray( a ); } + public Object[] toArray() { return collection.toArray(); } + public int[] toIntArray() { return collection.toIntArray(); } + public int[] toIntArray( final int[] a ) { return collection.toIntArray( a ); } + public int[] toArray( final int[] a ) { return collection.toArray( a ); } + public boolean rem( final int k ) { throw new UnsupportedOperationException(); } + public boolean addAll( final IntCollection c ) { throw new UnsupportedOperationException(); } + public boolean containsAll( final IntCollection c ) { return collection.containsAll( c ); } + public boolean removeAll( final IntCollection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( final IntCollection c ) { throw new UnsupportedOperationException(); } + public boolean add( final Integer k ) { throw new UnsupportedOperationException(); } + public boolean contains( final Object k ) { return collection.contains( k ); } + } + /** Returns an unmodifiable collection backed by the specified collection. + * + * @param c the collection to be wrapped in an unmodifiable collection. + * @return an unmodifiable view of the specified collection. + * @see java.util.Collections#unmodifiableCollection(Collection) + */ + public static IntCollection unmodifiable( final IntCollection c ) { return new UnmodifiableCollection ( c ); } + /** A collection wrapper class for iterables. */ + public static class IterableCollection extends AbstractIntCollection implements java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final IntIterable iterable; + protected IterableCollection( final IntIterable iterable ) { + if ( iterable == null ) throw new NullPointerException(); + this.iterable = iterable; + } + public int size() { + int c = 0; + final IntIterator iterator = iterator(); + while( iterator.hasNext() ) { + iterator.next(); + c++; + } + return c; + } + public boolean isEmpty() { return iterable.iterator().hasNext(); } + public IntIterator iterator() { return iterable.iterator(); } + @Deprecated + public IntIterator intIterator() { return iterator(); } + } + /** Returns an unmodifiable collection backed by the specified iterable. + * + * @param iterable the iterable object to be wrapped in an unmodifiable collection. + * @return an unmodifiable collection view of the specified iterable. + */ + public static IntCollection asCollection( final IntIterable iterable ) { + if ( iterable instanceof IntCollection ) return (IntCollection )iterable; + return new IterableCollection ( iterable ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntComparator.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntComparator.java new file mode 100644 index 0000000..cb84b48 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntComparator.java @@ -0,0 +1,90 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.Comparator; +/** A type-specific {@link Comparator}; provides methods to compare two primitive types both as objects + * and as primitive types. + * + *

Note that fastutil provides a corresponding abstract class that + * can be used to implement this interface just by specifying the type-specific + * comparator. + * + * @see Comparator + */ +public interface IntComparator extends Comparator { + /** Compares the given primitive types. + * + * @see java.util.Comparator + * @return A positive integer, zero, or a negative integer if the first + * argument is greater than, equal to, or smaller than, respectively, the + * second one. + */ + public int compare( int k1, int k2 ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntComparators.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntComparators.java new file mode 100644 index 0000000..04e7ce7 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntComparators.java @@ -0,0 +1,113 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +/** A class providing static methods and objects that do useful things with comparators. + */ +public class IntComparators { + private IntComparators() {} + /** A type-specific comparator mimicking the natural order. */ + protected static class NaturalImplicitComparator extends AbstractIntComparator implements java.io.Serializable { + private static final long serialVersionUID = 1L; + public final int compare( final int a, final int b ) { + return ( Integer.compare((a),(b)) ); + } + private Object readResolve() { return NATURAL_COMPARATOR; } + }; + + public static final IntComparator NATURAL_COMPARATOR = new NaturalImplicitComparator(); + /** A type-specific comparator mimicking the opposite of the natural order. */ + protected static class OppositeImplicitComparator extends AbstractIntComparator implements java.io.Serializable { + private static final long serialVersionUID = 1L; + public final int compare( final int a, final int b ) { + return - ( Integer.compare((a),(b)) ); + } + private Object readResolve() { return OPPOSITE_COMPARATOR; } + }; + + public static final IntComparator OPPOSITE_COMPARATOR = new OppositeImplicitComparator(); + protected static class OppositeComparator extends AbstractIntComparator implements java.io.Serializable { + private static final long serialVersionUID = 1L; + private final IntComparator comparator; + protected OppositeComparator( final IntComparator c ) { + comparator = c; + } + public final int compare( final int a, final int b ) { + return comparator.compare( b, a ); + } + }; + /** Returns a comparator representing the opposite order of the given comparator. + * + * @param c a comparator. + * @return a comparator representing the opposite order of c. + */ + public static IntComparator oppositeComparator( final IntComparator c ) { + return new OppositeComparator ( c ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntHash.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntHash.java new file mode 100644 index 0000000..7b7753e --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntHash.java @@ -0,0 +1,96 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.Hash; +/** A type-specific {@link Hash} interface. + * + * @see Hash + */ +public interface IntHash { + /** A type-specific hash strategy. + * + * @see it.unimi.dsi.fastutil.Hash.Strategy + */ + public interface Strategy { + /** Returns the hash code of the specified element with respect to this hash strategy. + * + * @param e an element. + * @return the hash code of the given element with respect to this hash strategy. + */ + public int hashCode( int e ); + /** Returns true if the given elements are equal with respect to this hash strategy. + * + * @param a an element. + * @param b another element. + * @return true if the two specified elements are equal with respect to this hash strategy. + */ + public boolean equals( int a, int b ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntHeapIndirectPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntHeapIndirectPriorityQueue.java new file mode 100644 index 0000000..94da704 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntHeapIndirectPriorityQueue.java @@ -0,0 +1,227 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.ints.IntArrays; +import java.util.Arrays; +import java.util.NoSuchElementException; +/** A type-specific heap-based indirect priority queue. + * + *

Instances of this class use an additional inversion array, of the same length of the reference array, + * to keep track of the heap position containing a given element of the reference array. The priority queue is + * represented using a heap. The heap is enlarged as needed, but it is never + * shrunk. Use the {@link #trim()} method to reduce its size, if necessary. + * + *

This implementation does not allow one to enqueue several times the same index. + */ +public class IntHeapIndirectPriorityQueue extends IntHeapSemiIndirectPriorityQueue { + /** The inversion array. */ + protected final int inv[]; + /** Creates a new empty queue with a given capacity and comparator. + * + * @param refArray the reference array. + * @param capacity the initial capacity of this queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntHeapIndirectPriorityQueue( int[] refArray, int capacity, IntComparator c ) { + super( refArray, capacity, c ); + if ( capacity > 0 ) this.heap = new int[ capacity ]; + this.c = c; + this.inv = new int[ refArray.length ]; + Arrays.fill( inv, -1 ); + } + /** Creates a new empty queue with a given capacity and using the natural order. + * + * @param refArray the reference array. + * @param capacity the initial capacity of this queue. + */ + public IntHeapIndirectPriorityQueue( int[] refArray, int capacity ) { + this( refArray, capacity, null ); + } + /** Creates a new empty queue with capacity equal to the length of the reference array and a given comparator. + * + * @param refArray the reference array. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntHeapIndirectPriorityQueue( int[] refArray, IntComparator c ) { + this( refArray, refArray.length, c ); + } + /** Creates a new empty queue with capacity equal to the length of the reference array and using the natural order. + * @param refArray the reference array. + */ + public IntHeapIndirectPriorityQueue( int[] refArray ) { + this( refArray, refArray.length, null ); + } + /** Wraps a given array in a queue using a given comparator. + * + *

The queue returned by this method will be backed by the given array. + * The first size element of the array will be rearranged so to form a heap (this is + * more efficient than enqueing the elements of a one by one). + * + * @param refArray the reference array. + * @param a an array of indices into refArray. + * @param size the number of elements to be included in the queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntHeapIndirectPriorityQueue( final int[] refArray, final int[] a, final int size, final IntComparator c ) { + this( refArray, 0, c ); + this.heap = a; + this.size = size; + int i = size; + while( i-- != 0 ) { + if ( inv[ a[ i ] ] != -1 ) throw new IllegalArgumentException( "Index " + a[ i ] + " appears twice in the heap" ); + inv[ a[ i ] ] = i; + } + IntIndirectHeaps.makeHeap( refArray, a, inv, size, c ); + } + /** Wraps a given array in a queue using a given comparator. + * + *

The queue returned by this method will be backed by the given array. + * The elements of the array will be rearranged so to form a heap (this is + * more efficient than enqueing the elements of a one by one). + * + * @param refArray the reference array. + * @param a an array of indices into refArray. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntHeapIndirectPriorityQueue( final int[] refArray, final int[] a, final IntComparator c ) { + this( refArray, a, a.length, c ); + } + /** Wraps a given array in a queue using the natural order. + * + *

The queue returned by this method will be backed by the given array. + * The first size element of the array will be rearranged so to form a heap (this is + * more efficient than enqueing the elements of a one by one). + * + * @param refArray the reference array. + * @param a an array of indices into refArray. + * @param size the number of elements to be included in the queue. + */ + public IntHeapIndirectPriorityQueue( final int[] refArray, final int[] a, int size ) { + this( refArray, a, size, null ); + } + /** Wraps a given array in a queue using the natural order. + * + *

The queue returned by this method will be backed by the given array. + * The elements of the array will be rearranged so to form a heap (this is + * more efficient than enqueing the elements of a one by one). + * + * @param refArray the reference array. + * @param a an array of indices into refArray. + */ + public IntHeapIndirectPriorityQueue( final int[] refArray, final int[] a ) { + this( refArray, a, a.length ); + } + public void enqueue( final int x ) { + if ( inv[ x ] >= 0 ) throw new IllegalArgumentException( "Index " + x + " belongs to the queue" ); + if ( size == heap.length ) heap = IntArrays.grow( heap, size + 1 ); + inv[ heap[ size ] = x ] = size++; + IntIndirectHeaps.upHeap( refArray, heap, inv, size, size - 1, c ); + } + public boolean contains( final int index ) { + return inv[ index ] >= 0; + } + public int dequeue() { + if ( size == 0 ) throw new NoSuchElementException(); + final int result = heap[ 0 ]; + if ( --size != 0 ) inv[ heap[ 0 ] = heap[ size ] ] = 0; + inv[ result ] = -1; + if ( size != 0 ) IntIndirectHeaps.downHeap( refArray, heap, inv, size, 0, c ); + return result; + } + public void changed() { + IntIndirectHeaps.downHeap( refArray, heap, inv, size, 0, c ); + } + public void changed( final int index ) { + final int pos = inv[ index ]; + if ( pos < 0 ) throw new IllegalArgumentException( "Index " + index + " does not belong to the queue" ); + final int newPos = IntIndirectHeaps.upHeap( refArray, heap, inv, size, pos, c ); + IntIndirectHeaps.downHeap( refArray, heap, inv, size, newPos, c ); + } + /** Rebuilds this heap in a bottom-up fashion. + */ + public void allChanged() { + IntIndirectHeaps.makeHeap( refArray, heap, inv, size, c ); + } + public boolean remove( final int index ) { + final int result = inv[ index ]; + if ( result < 0 ) return false; + inv[ index ] = -1; + if ( result < --size ) { + inv[ heap[ result ] = heap[ size ] ] = result; + final int newPos = IntIndirectHeaps.upHeap( refArray, heap, inv, size, result, c ); + IntIndirectHeaps.downHeap( refArray, heap, inv, size, newPos, c ); + } + return true; + } + public void clear() { + size = 0; + Arrays.fill( inv, -1 ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntHeapPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntHeapPriorityQueue.java new file mode 100644 index 0000000..b9f9796 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntHeapPriorityQueue.java @@ -0,0 +1,251 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.Iterator; +import java.util.Collection; +import java.util.NoSuchElementException; +/** A type-specific heap-based priority queue. + * + *

Instances of this class represent a priority queue using a heap. The heap is enlarged as needed, but + * it is never shrunk. Use the {@link #trim()} method to reduce its size, if necessary. + */ +public class IntHeapPriorityQueue extends AbstractIntPriorityQueue implements java.io.Serializable { + private static final long serialVersionUID = 1L; + /** The heap array. */ + + protected transient int[] heap = IntArrays.EMPTY_ARRAY; + /** The number of elements in this queue. */ + protected int size; + /** The type-specific comparator used in this queue. */ + protected IntComparator c; + /** Creates a new empty queue with a given capacity and comparator. + * + * @param capacity the initial capacity of this queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + + public IntHeapPriorityQueue( int capacity, IntComparator c ) { + if ( capacity > 0 ) this.heap = new int[ capacity ]; + this.c = c; + } + /** Creates a new empty queue with a given capacity and using the natural order. + * + * @param capacity the initial capacity of this queue. + */ + public IntHeapPriorityQueue( int capacity ) { + this( capacity, null ); + } + /** Creates a new empty queue with a given comparator. + * + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntHeapPriorityQueue( IntComparator c ) { + this( 0, c ); + } + /** Creates a new empty queue using the natural order. + */ + public IntHeapPriorityQueue() { + this( 0, null ); + } + /** Wraps a given array in a queue using a given comparator. + * + *

The queue returned by this method will be backed by the given array. + * The first size element of the array will be rearranged so to form a heap (this is + * more efficient than enqueing the elements of a one by one). + * + * @param a an array. + * @param size the number of elements to be included in the queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntHeapPriorityQueue( final int[] a, int size, final IntComparator c ) { + this( c ); + this.heap = a; + this.size = size; + IntHeaps.makeHeap( a, size, c ); + } + /** Wraps a given array in a queue using a given comparator. + * + *

The queue returned by this method will be backed by the given array. + * The elements of the array will be rearranged so to form a heap (this is + * more efficient than enqueing the elements of a one by one). + * + * @param a an array. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntHeapPriorityQueue( final int[] a, final IntComparator c ) { + this( a, a.length, c ); + } + /** Wraps a given array in a queue using the natural order. + * + *

The queue returned by this method will be backed by the given array. + * The first size element of the array will be rearranged so to form a heap (this is + * more efficient than enqueing the elements of a one by one). + * + * @param a an array. + * @param size the number of elements to be included in the queue. + */ + public IntHeapPriorityQueue( final int[] a, int size ) { + this( a, size, null ); + } + /** Wraps a given array in a queue using the natural order. + * + *

The queue returned by this method will be backed by the given array. + * The elements of the array will be rearranged so to form a heap (this is + * more efficient than enqueing the elements of a one by one). + * + * @param a an array. + */ + public IntHeapPriorityQueue( final int[] a ) { + this( a, a.length ); + } + /** Creates a queue using the elements in a type-specific collection using a given comparator. + * + *

This constructor is more efficient than enqueing the elements of collection one by one. + * + * @param collection a collection; its elements will be used to initialize the queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntHeapPriorityQueue( final IntCollection collection, final IntComparator c ) { + this( collection.toIntArray(), c ); + } + /** Creates a queue using the elements in a type-specific collection using the natural order. + * + *

This constructor is + * more efficient than enqueing the elements of collection one by one. + * + * @param collection a collection; its elements will be used to initialize the queue. + */ + public IntHeapPriorityQueue( final IntCollection collection ) { + this( collection, null ); + } + /** Creates a queue using the elements in a collection using a given comparator. + * + *

This constructor is more efficient than enqueing the elements of collection one by one. + * + * @param collection a collection; its elements will be used to initialize the queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntHeapPriorityQueue( final Collection collection, final IntComparator c ) { + this( collection.size(), c ); + final Iterator iterator = collection.iterator(); + final int size = collection.size(); + for( int i = 0 ; i < size; i++ ) heap[ i ] = ((((Integer)(iterator.next())).intValue())); + } + /** Creates a queue using the elements in a collection using the natural order. + * + *

This constructor is + * more efficient than enqueing the elements of collection one by one. + * + * @param collection a collection; its elements will be used to initialize the queue. + */ + public IntHeapPriorityQueue( final Collection collection ) { + this( collection, null ); + } + public void enqueue( int x ) { + if ( size == heap.length ) heap = IntArrays.grow( heap, size + 1 ); + heap[ size++ ] = x; + IntHeaps.upHeap( heap, size, size - 1, c ); + } + public int dequeueInt() { + if ( size == 0 ) throw new NoSuchElementException(); + final int result = heap[ 0 ]; + heap[ 0 ] = heap[ --size ]; + if ( size != 0 ) IntHeaps.downHeap( heap, size, 0, c ); + return result; + } + public int firstInt() { + if ( size == 0 ) throw new NoSuchElementException(); + return heap[ 0 ]; + } + public void changed() { + IntHeaps.downHeap( heap, size, 0, c ); + } + public int size() { return size; } + public void clear() { + size = 0; + } + /** Trims the underlying heap array so that it has exactly {@link #size()} elements. + */ + public void trim() { + heap = IntArrays.trim( heap, size ); + } + public IntComparator comparator() { return c; } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + s.defaultWriteObject(); + s.writeInt( heap.length ); + for( int i = 0; i < size; i++ ) s.writeInt( heap[ i ] ); + } + + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + heap = new int[ s.readInt() ]; + for( int i = 0; i < size; i++ ) heap[ i ] = s.readInt(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntHeapSemiIndirectPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntHeapSemiIndirectPriorityQueue.java new file mode 100644 index 0000000..f294993 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntHeapSemiIndirectPriorityQueue.java @@ -0,0 +1,243 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.NoSuchElementException; +import it.unimi.dsi.fastutil.ints.IntArrays; +import it.unimi.dsi.fastutil.AbstractIndirectPriorityQueue; +/** A type-specific heap-based semi-indirect priority queue. + * + *

Instances of this class use as reference list a reference array, + * which must be provided to each constructor. The priority queue is + * represented using a heap. The heap is enlarged as needed, but it is never + * shrunk. Use the {@link #trim()} method to reduce its size, if necessary. + * + *

This implementation allows one to enqueue several time the same index, but + * you must be careful when calling {@link #changed()}. + */ +public class IntHeapSemiIndirectPriorityQueue extends AbstractIndirectPriorityQueue implements IntIndirectPriorityQueue { + /** The reference array. */ + protected final int refArray[]; + /** The semi-indirect heap. */ + protected int heap[] = IntArrays.EMPTY_ARRAY; + /** The number of elements in this queue. */ + protected int size; + /** The type-specific comparator used in this queue. */ + protected IntComparator c; + /** Creates a new empty queue without elements with a given capacity and comparator. + * + * @param refArray the reference array. + * @param capacity the initial capacity of this queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntHeapSemiIndirectPriorityQueue( int[] refArray, int capacity, IntComparator c ) { + if ( capacity > 0 ) this.heap = new int[ capacity ]; + this.refArray = refArray; + this.c = c; + } + /** Creates a new empty queue with given capacity and using the natural order. + * + * @param refArray the reference array. + * @param capacity the initial capacity of this queue. + */ + public IntHeapSemiIndirectPriorityQueue( int[] refArray, int capacity ) { + this( refArray, capacity, null ); + } + /** Creates a new empty queue with capacity equal to the length of the reference array and a given comparator. + * + * @param refArray the reference array. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntHeapSemiIndirectPriorityQueue( int[] refArray, IntComparator c ) { + this( refArray, refArray.length, c ); + } + /** Creates a new empty queue with capacity equal to the length of the reference array and using the natural order. + * @param refArray the reference array. + */ + public IntHeapSemiIndirectPriorityQueue( final int[] refArray ) { + this( refArray, refArray.length, null ); + } + /** Wraps a given array in a queue using a given comparator. + * + *

The queue returned by this method will be backed by the given array. + * The first size element of the array will be rearranged so to form a heap (this is + * more efficient than enqueing the elements of a one by one). + * + * @param refArray the reference array. + * @param a an array of indices into refArray. + * @param size the number of elements to be included in the queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntHeapSemiIndirectPriorityQueue( final int[] refArray, final int[] a, int size, final IntComparator c ) { + this( refArray, 0, c ); + this.heap = a; + this.size = size; + IntSemiIndirectHeaps.makeHeap( refArray, a, size, c ); + } + /** Wraps a given array in a queue using a given comparator. + * + *

The queue returned by this method will be backed by the given array. + * The elements of the array will be rearranged so to form a heap (this is + * more efficient than enqueing the elements of a one by one). + * + * @param refArray the reference array. + * @param a an array of indices into refArray. + * @param c the comparator used in this queue, or null for the natural order. + */ + public IntHeapSemiIndirectPriorityQueue( final int[] refArray, final int[] a, final IntComparator c ) { + this( refArray, a, a.length, c ); + } + /** Wraps a given array in a queue using the natural order. + * + *

The queue returned by this method will be backed by the given array. + * The first size element of the array will be rearranged so to form a heap (this is + * more efficient than enqueing the elements of a one by one). + * + * @param refArray the reference array. + * @param a an array of indices into refArray. + * @param size the number of elements to be included in the queue. + */ + public IntHeapSemiIndirectPriorityQueue( final int[] refArray, final int[] a, int size ) { + this( refArray, a, size, null ); + } + /** Wraps a given array in a queue using the natural order. + * + *

The queue returned by this method will be backed by the given array. + * The elements of the array will be rearranged so to form a heap (this is + * more efficient than enqueing the elements of a one by one). + * + * @param refArray the reference array. + * @param a an array of indices into refArray. + */ + public IntHeapSemiIndirectPriorityQueue( final int[] refArray, final int[] a ) { + this( refArray, a, a.length ); + } + /** Ensures that the given index is a valid reference. + * + * @param index an index in the reference array. + * @throws IndexOutOfBoundsException if the given index is negative or larger than the reference array length. + */ + protected void ensureElement( final int index ) { + if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" ); + if ( index >= refArray.length ) throw new IndexOutOfBoundsException( "Index (" + index + ") is larger than or equal to reference array size (" + refArray.length + ")" ); + } + public void enqueue( int x ) { + ensureElement( x ); + if ( size == heap.length ) heap = IntArrays.grow( heap, size + 1 ); + heap[ size++ ] = x; + IntSemiIndirectHeaps.upHeap( refArray, heap, size, size - 1, c ); + } + public int dequeue() { + if ( size == 0 ) throw new NoSuchElementException(); + final int result = heap[ 0 ]; + heap[ 0 ] = heap[ --size ]; + if ( size != 0 ) IntSemiIndirectHeaps.downHeap( refArray, heap, size, 0, c ); + return result; + } + public int first() { + if ( size == 0 ) throw new NoSuchElementException(); + return heap[ 0 ]; + } + /** {@inheritDoc} + * + *

The caller must guarantee that when this method is called the + * index of the first element appears just once in the queue. Failure to do so + * will bring the queue in an inconsistent state, and will cause + * unpredictable behaviour. + */ + public void changed() { + IntSemiIndirectHeaps.downHeap( refArray, heap, size, 0, c ); + } + /** Rebuilds this heap in a bottom-up fashion. + */ + public void allChanged() { + IntSemiIndirectHeaps.makeHeap( refArray, heap, size, c ); + } + public int size() { return size; } + public void clear() { size = 0; } + /** Trims the backing array so that it has exactly {@link #size()} elements. + */ + public void trim() { + heap = IntArrays.trim( heap, size ); + } + public IntComparator comparator() { return c; } + public int front( final int[] a ) { + return c == null ? IntSemiIndirectHeaps.front( refArray, heap, size, a ) : IntSemiIndirectHeaps.front( refArray, heap, size, a, c ); + } + public String toString() { + StringBuffer s = new StringBuffer(); + s.append( "[" ); + for ( int i = 0; i < size; i++ ) { + if ( i != 0 ) s.append( ", " ); + s.append( refArray[ heap [ i ] ] ); + } + s.append( "]" ); + return s.toString(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntHeaps.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntHeaps.java new file mode 100644 index 0000000..ab987b7 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntHeaps.java @@ -0,0 +1,155 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +/** A class providing static methods and objects that do useful things with heaps. + * + *

The static methods of this class allow to treat arrays as 0-based heaps. They + * are used in the implementation of heap-based queues, but they may be also used + * directly. + * + */ +public class IntHeaps { + private IntHeaps() {} + /** Moves the given element down into the heap until it reaches the lowest possible position. + * + * @param heap the heap (starting at 0). + * @param size the number of elements in the heap. + * @param i the index of the element that must be moved down. + * @param c a type-specific comparator, or null for the natural order. + * @return the new position of the element of index i. + */ + + public static int downHeap( final int[] heap, final int size, int i, final IntComparator c ) { + assert i < size; + final int e = heap[ i ]; + int child; + if ( c == null ) + while ( ( child = ( i << 1 ) + 1 ) < size ) { + int t = heap[ child ]; + final int right = child + 1; + if ( right < size && ( (heap[ right ]) < (t) ) ) t = heap[ child = right ]; + if ( ( (e) <= (t) ) ) break; + heap[ i ] = t; + i = child; + } + else + while ( ( child = ( i << 1 ) + 1 ) < size ) { + int t = heap[ child ]; + final int right = child + 1; + if ( right < size && c.compare( heap[ right ], t ) < 0 ) t = heap[ child = right ]; + if ( c.compare( e, t ) <= 0 ) break; + heap[ i ] = t; + i = child; + } + heap[ i ] = e; + return i; + } + /** Moves the given element up in the heap until it reaches the highest possible position. + * + * @param heap the heap (starting at 0). + * @param size the number of elements in the heap. + * @param i the index of the element that must be moved up. + * @param c a type-specific comparator, or null for the natural order. + * @return the new position of the element of index i. + */ + + public static int upHeap( final int[] heap, final int size, int i, final IntComparator c ) { + assert i < size; + final int e = heap[ i ]; + if ( c == null ) + while ( i != 0 ) { + final int parent = ( i - 1 ) >>> 1; + final int t = heap[ parent ]; + if ( ( (t) <= (e) ) ) break; + heap[ i ] = t; + i = parent; + } + else + while ( i != 0 ) { + final int parent = ( i - 1 ) >>> 1; + final int t = heap[ parent ]; + if ( c.compare( t, e ) <= 0 ) break; + heap[ i ] = t; + i = parent; + } + heap[ i ] = e; + return i; + } + /** Makes an array into a heap. + * + * @param heap the heap (starting at 0). + * @param size the number of elements in the heap. + * @param c a type-specific comparator, or null for the natural order. + */ + public static void makeHeap( final int[] heap, final int size, final IntComparator c ) { + int i = size >>> 1; + while( i-- != 0 ) downHeap( heap, size, i, c ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntIndirectHeaps.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntIndirectHeaps.java new file mode 100644 index 0000000..53f3e35 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntIndirectHeaps.java @@ -0,0 +1,191 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.Arrays; +/** A class providing static methods and objects that do useful things with indirect heaps. + * + *

An indirect heap is an extension of a semi-indirect heap using also an + * inversion array of the same length as the reference array, + * satisfying the relation heap[inv[i]]==i when + * inv[i]>=0, and inv[heap[i]]==i for all elements in the heap. + */ +public class IntIndirectHeaps { + private IntIndirectHeaps() {} + /** Moves the given element down into the indirect heap until it reaches the lowest possible position. + * + * @param refArray the reference array. + * @param heap the indirect heap (starting at 0). + * @param inv the inversion array. + * @param size the number of elements in the heap. + * @param i the index in the heap of the element to be moved down. + * @param c a type-specific comparator, or null for the natural order. + * @return the new position in the heap of the element of heap index i. + */ + + public static int downHeap( final int[] refArray, final int[] heap, final int[] inv, final int size, int i, final IntComparator c ) { + assert i < size; + final int e = heap[ i ]; + final int E = refArray[ e ]; + int child; + if ( c == null ) + while ( ( child = ( i << 1 ) + 1 ) < size ) { + int t = heap[ child ]; + final int right = child + 1; + if ( right < size && ( (refArray[ heap[ right ] ]) < (refArray[ t ]) ) ) t = heap[ child = right ]; + if ( ( (E) <= (refArray[ t ]) ) ) break; + heap[ i ] = t; + inv[ heap[ i ] ] = i; + i = child; + } + else + while ( ( child = ( i << 1 ) + 1 ) < size ) { + int t = heap[ child ]; + final int right = child + 1; + if ( right < size && c.compare( refArray[ heap[ right ] ], refArray[ t ] ) < 0 ) t = heap[ child = right ]; + if ( c.compare( E, refArray[ t ] ) <= 0 ) break; + heap[ i ] = t; + inv[ heap[ i ] ] = i; + i = child; + } + heap[ i ] = e; + inv[ e ] = i; + return i; + } + /** Moves the given element up in the indirect heap until it reaches the highest possible position. + * + * Note that in principle after this call the heap property may be violated. + * + * @param refArray the reference array. + * @param heap the indirect heap (starting at 0). + * @param inv the inversion array. + * @param size the number of elements in the heap. + * @param i the index in the heap of the element to be moved up. + * @param c a type-specific comparator, or null for the natural order. + * @return the new position in the heap of the element of heap index i. + */ + + public static int upHeap( final int[] refArray, final int[] heap, final int[] inv, final int size, int i, final IntComparator c ) { + assert i < size; + final int e = heap[ i ]; + final int E = refArray[ e ]; + if ( c == null ) + while ( i != 0 ) { + final int parent = ( i - 1 ) >>> 1; + final int t = heap[ parent ]; + if ( ( (refArray[ t ]) <= (E) ) ) break; + heap[ i ] = t; + inv[ heap[ i ] ] = i; + i = parent; + } + else + while ( i != 0 ) { + final int parent = ( i - 1 ) >>> 1; + final int t = heap[ parent ]; + if ( c.compare( refArray[ t ], E ) <= 0 ) break; + heap[ i ] = t; + inv[ heap[ i ] ] = i; + i = parent; + } + heap[ i ] = e; + inv[ e ] = i; + return i; + } + /** Creates an indirect heap in the given array. + * + * @param refArray the reference array. + * @param offset the first element of the reference array to be put in the heap. + * @param length the number of elements to be put in the heap. + * @param heap the array where the heap is to be created. + * @param inv the inversion array. + * @param c a type-specific comparator, or null for the natural order. + */ + public static void makeHeap( final int[] refArray, final int offset, final int length, final int[] heap, final int[] inv, final IntComparator c ) { + IntArrays.ensureOffsetLength( refArray, offset, length ); + if ( heap.length < length ) throw new IllegalArgumentException( "The heap length (" + heap.length + ") is smaller than the number of elements (" + length + ")" ); + if ( inv.length < refArray.length ) throw new IllegalArgumentException( "The inversion array length (" + heap.length + ") is smaller than the length of the reference array (" + refArray.length + ")" ); + Arrays.fill( inv, 0, refArray.length, -1 ); + int i = length; + while( i-- != 0 ) inv[ heap[ i ] = offset + i ] = i; + i = length >>> 1; + while( i-- != 0 ) downHeap( refArray, heap, inv, length, i, c ); + } + /** Creates an indirect heap from a given index array. + * + * @param refArray the reference array. + * @param heap an array containing indices into refArray. + * @param inv the inversion array. + * @param size the number of elements in the heap. + * @param c a type-specific comparator, or null for the natural order. + */ + public static void makeHeap( final int[] refArray, final int[] heap, final int[] inv, final int size, final IntComparator c ) { + int i = size >>> 1; + while( i-- != 0 ) downHeap( refArray, heap, inv, size, i, c ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntIndirectPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntIndirectPriorityQueue.java new file mode 100644 index 0000000..a950eff --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntIndirectPriorityQueue.java @@ -0,0 +1,85 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.IndirectPriorityQueue; +/** A type-specific {@link IndirectPriorityQueue}. + * + *

Additionally, this interface strengthens {@link #comparator()}. + */ +public interface IntIndirectPriorityQueue extends IndirectPriorityQueue { + /** Returns the comparator associated with this queue. + * + * Note that this specification strengthens the one given in {@link IndirectPriorityQueue}. + * + * @return the comparator associated with this queue. + * @see IndirectPriorityQueue#comparator() + */ + IntComparator comparator(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntIterable.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntIterable.java new file mode 100644 index 0000000..a0c323f --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntIterable.java @@ -0,0 +1,88 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.lang.Iterable; +/** A type-specific {@link Iterable} that strengthens that specification of {@link Iterable#iterator()}. + * + *

Warning: Java will let you write “colon” for statements with primitive-type + * loop variables; however, what is (unfortunately) really happening is that at each iteration an + * unboxing (and, in the case of fastutil type-specific data structures, a boxing) will be performed. Watch out. + * + * @see Iterable + */ +public interface IntIterable extends Iterable { + /** Returns a type-specific iterator. + * + * Note that this specification strengthens the one given in {@link Iterable#iterator()}. + * + * @return a type-specific iterator. + */ + IntIterator iterator(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntIterator.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntIterator.java new file mode 100644 index 0000000..c6e9fc9 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntIterator.java @@ -0,0 +1,96 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.Iterator; +/** A type-specific {@link Iterator}; provides an additional method to avoid (un)boxing, and + * the possibility to skip elements. + * + * @see Iterator + */ +public interface IntIterator extends Iterator { + /** + * Returns the next element as a primitive type. + * + * @return the next element in the iteration. + * @see Iterator#next() + */ + int nextInt(); + /** Skips the given number of elements. + * + *

The effect of this call is exactly the same as that of + * calling {@link #next()} for n times (possibly stopping + * if {@link #hasNext()} becomes false). + * + * @param n the number of elements to skip. + * @return the number of elements actually skipped. + * @see Iterator#next() + */ + int skip( int n ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntIterators.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntIterators.java new file mode 100644 index 0000000..324c12c --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntIterators.java @@ -0,0 +1,637 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.NoSuchElementException; +/** A class providing static methods and objects that do useful things with type-specific iterators. + * + * @see Iterator + */ +public class IntIterators { + private IntIterators() {} + /** A class returning no elements and a type-specific iterator interface. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific iterator. + */ + public static class EmptyIterator extends AbstractIntListIterator implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptyIterator() {} + public boolean hasNext() { return false; } + public boolean hasPrevious() { return false; } + public int nextInt() { throw new NoSuchElementException(); } + public int previousInt() { throw new NoSuchElementException(); } + public int nextIndex() { return 0; } + public int previousIndex() { return -1; } + public int skip( int n ) { return 0; }; + public int back( int n ) { return 0; }; + public Object clone() { return EMPTY_ITERATOR; } + private Object readResolve() { return EMPTY_ITERATOR; } + } + /** An empty iterator (immutable). It is serializable and cloneable. + * + *

The class of this objects represent an abstract empty iterator + * that can iterate as a type-specific (list) iterator. + */ + + public final static EmptyIterator EMPTY_ITERATOR = new EmptyIterator(); + /** An iterator returning a single element. */ + private static class SingletonIterator extends AbstractIntListIterator { + private final int element; + private int curr; + public SingletonIterator( final int element ) { + this.element = element; + } + public boolean hasNext() { return curr == 0; } + public boolean hasPrevious() { return curr == 1; } + public int nextInt() { + if ( ! hasNext() ) throw new NoSuchElementException(); + curr = 1; + return element; + } + public int previousInt() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + curr = 0; + return element; + } + public int nextIndex() { + return curr; + } + public int previousIndex() { + return curr - 1; + } + } + /** Returns an iterator that iterates just over the given element. + * + * @param element the only element to be returned by a type-specific list iterator. + * @return an iterator that iterates just over element. + */ + public static IntListIterator singleton( final int element ) { + return new SingletonIterator ( element ); + } + /** A class to wrap arrays in iterators. */ + private static class ArrayIterator extends AbstractIntListIterator { + private final int[] array; + private final int offset, length; + private int curr; + public ArrayIterator( final int[] array, final int offset, final int length ) { + this.array = array; + this.offset = offset; + this.length = length; + } + public boolean hasNext() { return curr < length; } + public boolean hasPrevious() { return curr > 0; } + public int nextInt() { + if ( ! hasNext() ) throw new NoSuchElementException(); + return array[ offset + curr++ ]; + } + public int previousInt() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + return array[ offset + --curr ]; + } + public int skip( int n ) { + if ( n <= length - curr ) { + curr += n; + return n; + } + n = length - curr; + curr = length; + return n; + } + public int back( int n ) { + if ( n <= curr ) { + curr -= n; + return n; + } + n = curr; + curr = 0; + return n; + } + public int nextIndex() { + return curr; + } + public int previousIndex() { + return curr - 1; + } + } + /** Wraps the given part of an array into a type-specific list iterator. + * + *

The type-specific list iterator returned by this method will iterate + * length times, returning consecutive elements of the given + * array starting from the one with index offset. + * + * @param array an array to wrap into a type-specific list iterator. + * @param offset the first element of the array to be returned. + * @param length the number of elements to return. + * @return an iterator that will return length elements of array starting at position offset. + */ + public static IntListIterator wrap( final int[] array, final int offset, final int length ) { + IntArrays.ensureOffsetLength( array, offset, length ); + return new ArrayIterator ( array, offset, length ); + } + /** Wraps the given array into a type-specific list iterator. + * + *

The type-specific list iterator returned by this method will return + * all elements of the given array. + * + * @param array an array to wrap into a type-specific list iterator. + * @return an iterator that will the elements of array. + */ + public static IntListIterator wrap( final int[] array ) { + return new ArrayIterator ( array, 0, array.length ); + } + /** Unwraps an iterator into an array starting at a given offset for a given number of elements. + * + *

This method iterates over the given type-specific iterator and stores the elements + * returned, up to a maximum of length, in the given array starting at offset. + * The number of actually unwrapped elements is returned (it may be less than max if + * the iterator emits less than max elements). + * + * @param i a type-specific iterator. + * @param array an array to contain the output of the iterator. + * @param offset the first element of the array to be returned. + * @param max the maximum number of elements to unwrap. + * @return the number of elements unwrapped. + */ + public static int unwrap( final IntIterator i, final int array[], int offset, final int max ) { + if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" ); + if ( offset < 0 || offset + max > array.length ) throw new IllegalArgumentException(); + int j = max; + while( j-- != 0 && i.hasNext() ) array[ offset++ ] = i.nextInt(); + return max - j - 1; + } + /** Unwraps an iterator into an array. + * + *

This method iterates over the given type-specific iterator and stores the + * elements returned in the given array. The iteration will stop when the + * iterator has no more elements or when the end of the array has been reached. + * + * @param i a type-specific iterator. + * @param array an array to contain the output of the iterator. + * @return the number of elements unwrapped. + */ + public static int unwrap( final IntIterator i, final int array[] ) { + return unwrap( i, array, 0, array.length ); + } + /** Unwraps an iterator, returning an array, with a limit on the number of elements. + * + *

This method iterates over the given type-specific iterator and returns an array + * containing the elements returned by the iterator. At most max elements + * will be returned. + * + * @param i a type-specific iterator. + * @param max the maximum number of elements to be unwrapped. + * @return an array containing the elements returned by the iterator (at most max). + */ + + public static int[] unwrap( final IntIterator i, int max ) { + if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" ); + int array[] = new int[ 16 ]; + int j = 0; + while( max-- != 0 && i.hasNext() ) { + if ( j == array.length ) array = IntArrays.grow( array, j + 1 ); + array[ j++ ] = i.nextInt(); + } + return IntArrays.trim( array, j ); + } + /** Unwraps an iterator, returning an array. + * + *

This method iterates over the given type-specific iterator and returns an array + * containing the elements returned by the iterator. + * + * @param i a type-specific iterator. + * @return an array containing the elements returned by the iterator. + */ + public static int[] unwrap( final IntIterator i ) { + return unwrap( i, Integer.MAX_VALUE ); + } + /** Unwraps an iterator into a type-specific collection, with a limit on the number of elements. + * + *

This method iterates over the given type-specific iterator and stores the elements + * returned, up to a maximum of max, in the given type-specific collection. + * The number of actually unwrapped elements is returned (it may be less than max if + * the iterator emits less than max elements). + * + * @param i a type-specific iterator. + * @param c a type-specific collection array to contain the output of the iterator. + * @param max the maximum number of elements to unwrap. + * @return the number of elements unwrapped. Note that + * this is the number of elements returned by the iterator, which is not necessarily the number + * of elements that have been added to the collection (because of duplicates). + */ + public static int unwrap( final IntIterator i, final IntCollection c, final int max ) { + if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" ); + int j = max; + while( j-- != 0 && i.hasNext() ) c.add( i.nextInt() ); + return max - j - 1; + } + /** Unwraps an iterator into a type-specific collection. + * + *

This method iterates over the given type-specific iterator and stores the + * elements returned in the given type-specific collection. The returned count on the number + * unwrapped elements is a long, so that it will work also with very large collections. + * + * @param i a type-specific iterator. + * @param c a type-specific collection to contain the output of the iterator. + * @return the number of elements unwrapped. Note that + * this is the number of elements returned by the iterator, which is not necessarily the number + * of elements that have been added to the collection (because of duplicates). + */ + public static long unwrap( final IntIterator i, final IntCollection c ) { + long n = 0; + while( i.hasNext() ) { + c.add( i.nextInt() ); + n++; + } + return n; + } + /** Pours an iterator into a type-specific collection, with a limit on the number of elements. + * + *

This method iterates over the given type-specific iterator and adds + * the returned elements to the given collection (up to max). + * + * @param i a type-specific iterator. + * @param s a type-specific collection. + * @param max the maximum number of elements to be poured. + * @return the number of elements poured. Note that + * this is the number of elements returned by the iterator, which is not necessarily the number + * of elements that have been added to the collection (because of duplicates). + */ + public static int pour( final IntIterator i, final IntCollection s, final int max ) { + if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" ); + int j = max; + while( j-- != 0 && i.hasNext() ) s.add( i.nextInt() ); + return max - j - 1; + } + /** Pours an iterator into a type-specific collection. + * + *

This method iterates over the given type-specific iterator and adds + * the returned elements to the given collection. + * + * @param i a type-specific iterator. + * @param s a type-specific collection. + * @return the number of elements poured. Note that + * this is the number of elements returned by the iterator, which is not necessarily the number + * of elements that have been added to the collection (because of duplicates). + */ + public static int pour( final IntIterator i, final IntCollection s ) { + return pour( i, s, Integer.MAX_VALUE ); + } + /** Pours an iterator, returning a type-specific list, with a limit on the number of elements. + * + *

This method iterates over the given type-specific iterator and returns + * a type-specific list containing the returned elements (up to max). Iteration + * on the returned list is guaranteed to produce the elements in the same order + * in which they appeared in the iterator. + * + * + * @param i a type-specific iterator. + * @param max the maximum number of elements to be poured. + * @return a type-specific list containing the returned elements, up to max. + */ + public static IntList pour( final IntIterator i, int max ) { + final IntArrayList l = new IntArrayList (); + pour( i, l, max ); + l.trim(); + return l; + } + /** Pours an iterator, returning a type-specific list. + * + *

This method iterates over the given type-specific iterator and returns + * a list containing the returned elements. Iteration + * on the returned list is guaranteed to produce the elements in the same order + * in which they appeared in the iterator. + * + * @param i a type-specific iterator. + * @return a type-specific list containing the returned elements. + */ + public static IntList pour( final IntIterator i ) { + return pour( i, Integer.MAX_VALUE ); + } + private static class IteratorWrapper extends AbstractIntIterator { + final Iterator i; + public IteratorWrapper( final Iterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public void remove() { i.remove(); } + public int nextInt() { return ((i.next()).intValue()); } + } + /** Wraps a standard iterator into a type-specific iterator. + * + *

This method wraps a standard iterator into a type-specific one which will handle the + * type conversions for you. Of course, any attempt to wrap an iterator returning the + * instances of the wrong class will generate a {@link ClassCastException}. The + * returned iterator is backed by i: changes to one of the iterators + * will affect the other, too. + * + *

If i is already type-specific, it will returned and no new object + * will be generated. + * + * @param i an iterator. + * @return a type-specific iterator backed by i. + */ + @SuppressWarnings({"unchecked","rawtypes"}) + public static IntIterator asIntIterator( final Iterator i ) { + if ( i instanceof IntIterator ) return (IntIterator )i; + return new IteratorWrapper ( i ); + } + private static class ListIteratorWrapper extends AbstractIntListIterator { + final ListIterator i; + public ListIteratorWrapper( final ListIterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public boolean hasPrevious() { return i.hasPrevious(); } + public int nextIndex() { return i.nextIndex(); } + public int previousIndex() { return i.previousIndex(); } + public void set( int k ) { i.set( (Integer.valueOf(k)) ); } + public void add( int k ) { i.add( (Integer.valueOf(k)) ); } + public void remove() { i.remove(); } + public int nextInt() { return ((i.next()).intValue()); } + public int previousInt() { return ((i.previous()).intValue()); } + } + /** Wraps a standard list iterator into a type-specific list iterator. + * + *

This method wraps a standard list iterator into a type-specific one + * which will handle the type conversions for you. Of course, any attempt + * to wrap an iterator returning the instances of the wrong class will + * generate a {@link ClassCastException}. The + * returned iterator is backed by i: changes to one of the iterators + * will affect the other, too. + * + *

If i is already type-specific, it will returned and no new object + * will be generated. + * + * @param i a list iterator. + * @return a type-specific list iterator backed by i. + */ + @SuppressWarnings({"unchecked","rawtypes"}) + public static IntListIterator asIntIterator( final ListIterator i ) { + if ( i instanceof IntListIterator ) return (IntListIterator )i; + return new ListIteratorWrapper ( i ); + } + private static class IntervalIterator extends AbstractIntListIterator { + private final int from, to; + int curr; + public IntervalIterator( final int from, final int to ) { + this.from = this.curr = from; + this.to = to; + } + public boolean hasNext() { return curr < to; } + public boolean hasPrevious() { return curr > from; } + public int nextInt() { + if ( ! hasNext() ) throw new NoSuchElementException(); + return curr++; + } + public int previousInt() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + return --curr; + } + public int nextIndex() { return curr - from; } + public int previousIndex() { return curr - from - 1; } + public int skip( int n ) { + if ( curr + n <= to ) { + curr += n; + return n; + } + n = to - curr; + curr = to; + return n; + } + public int back( int n ) { + if ( curr - n >= from ) { + curr -= n; + return n; + } + n = curr - from ; + curr = from; + return n; + } + } + /** Creates a type-specific list iterator over an interval. + * + *

The type-specific list iterator returned by this method will return the + * elements from, from+1,…, to-1. + * + * @param from the starting element (inclusive). + * @param to the ending element (exclusive). + * @return a type-specific list iterator enumerating the elements from from to to. + */ + public static IntListIterator fromTo( final int from, final int to ) { + return new IntervalIterator( from, to ); + } + private static class IteratorConcatenator extends AbstractIntIterator { + final IntIterator a[]; + int offset, length, lastOffset = -1; + public IteratorConcatenator( final IntIterator a[], int offset, int length ) { + this.a = a; + this.offset = offset; + this.length = length; + advance(); + } + private void advance() { + while( length != 0 ) { + if ( a[ offset ].hasNext() ) break; + length--; + offset++; + } + return; + } + public boolean hasNext() { + return length > 0; + } + public int nextInt() { + if ( ! hasNext() ) throw new NoSuchElementException(); + int next = a[ lastOffset = offset ].nextInt(); + advance(); + return next; + } + public void remove() { + if ( lastOffset == -1 ) throw new IllegalStateException(); + a[ lastOffset ].remove(); + } + public int skip( int n ) { + lastOffset = -1; + int skipped = 0; + while( skipped < n && length != 0 ) { + skipped += a[ offset ].skip( n - skipped ); + if ( a[ offset ].hasNext() ) break; + length--; + offset++; + } + return skipped; + } + } + /** Concatenates all iterators contained in an array. + * + *

This method returns an iterator that will enumerate in order the elements returned + * by all iterators contained in the given array. + * + * @param a an array of iterators. + * @return an iterator obtained by concatenation. + */ + public static IntIterator concat( final IntIterator a[] ) { + return concat( a, 0, a.length ); + } + /** Concatenates a sequence of iterators contained in an array. + * + *

This method returns an iterator that will enumerate in order the elements returned + * by a[ offset ], then those returned + * by a[ offset + 1 ], and so on up to + * a[ offset + length - 1 ]. + * + * @param a an array of iterators. + * @param offset the index of the first iterator to concatenate. + * @param length the number of iterators to concatenate. + * @return an iterator obtained by concatenation of length elements of a starting at offset. + */ + public static IntIterator concat( final IntIterator a[], final int offset, final int length ) { + return new IteratorConcatenator ( a, offset, length ); + } + /** An unmodifiable wrapper class for iterators. */ + public static class UnmodifiableIterator extends AbstractIntIterator { + final protected IntIterator i; + public UnmodifiableIterator( final IntIterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public int nextInt() { return i.nextInt(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Integer next() { return i.next(); } + } + /** Returns an unmodifiable iterator backed by the specified iterator. + * + * @param i the iterator to be wrapped in an unmodifiable iterator. + * @return an unmodifiable view of the specified iterator. + */ + public static IntIterator unmodifiable( final IntIterator i ) { return new UnmodifiableIterator ( i ); } + /** An unmodifiable wrapper class for bidirectional iterators. */ + public static class UnmodifiableBidirectionalIterator extends AbstractIntBidirectionalIterator { + final protected IntBidirectionalIterator i; + public UnmodifiableBidirectionalIterator( final IntBidirectionalIterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public boolean hasPrevious() { return i.hasPrevious(); } + public int nextInt() { return i.nextInt(); } + public int previousInt() { return i.previousInt(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Integer next() { return i.next(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Integer previous() { return i.previous(); } + } + /** Returns an unmodifiable bidirectional iterator backed by the specified bidirectional iterator. + * + * @param i the bidirectional iterator to be wrapped in an unmodifiable bidirectional iterator. + * @return an unmodifiable view of the specified bidirectional iterator. + */ + public static IntBidirectionalIterator unmodifiable( final IntBidirectionalIterator i ) { return new UnmodifiableBidirectionalIterator ( i ); } + /** An unmodifiable wrapper class for list iterators. */ + public static class UnmodifiableListIterator extends AbstractIntListIterator { + final protected IntListIterator i; + public UnmodifiableListIterator( final IntListIterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public boolean hasPrevious() { return i.hasPrevious(); } + public int nextInt() { return i.nextInt(); } + public int previousInt() { return i.previousInt(); } + public int nextIndex() { return i.nextIndex(); } + public int previousIndex() { return i.previousIndex(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Integer next() { return i.next(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Integer previous() { return i.previous(); } + } + /** Returns an unmodifiable list iterator backed by the specified list iterator. + * + * @param i the list iterator to be wrapped in an unmodifiable list iterator. + * @return an unmodifiable view of the specified list iterator. + */ + public static IntListIterator unmodifiable( final IntListIterator i ) { return new UnmodifiableListIterator ( i ); } + +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntLinkedOpenCustomHashSet.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntLinkedOpenCustomHashSet.java new file mode 100644 index 0000000..ac197b8 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntLinkedOpenCustomHashSet.java @@ -0,0 +1,1071 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.HashCommon; +import static it.unimi.dsi.fastutil.HashCommon.arraySize; +import static it.unimi.dsi.fastutil.HashCommon.maxFill; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +/** A type-specific linked hash set with with a fast, small-footprint implementation. + * + *

Instances of this class use a hash table to represent a set. The table is + * filled up to a specified load factor, and then doubled in size to + * accommodate new entries. If the table is emptied below one fourth + * of the load factor, it is halved in size. However, halving is + * not performed when deleting entries from an iterator, as it would interfere + * with the iteration process. + * + *

Note that {@link #clear()} does not modify the hash table size. + * Rather, a family of {@linkplain #trim() trimming + * methods} lets you control the size of the table; this is particularly useful + * if you reuse instances of this class. + * + *

Iterators generated by this set will enumerate elements in the same order in which they + * have been added to the set (addition of elements already present + * in the set does not change the iteration order). Note that this order has nothing in common with the natural + * order of the keys. The order is kept by means of a doubly linked list, represented + * via an array of longs parallel to the table. + * + *

This class implements the interface of a sorted set, so to allow easy + * access of the iteration order: for instance, you can get the first element + * in iteration order with {@code first()} without having to create an + * iterator; however, this class partially violates the {@link java.util.SortedSet} + * contract because all subset methods throw an exception and {@link + * #comparator()} returns always null. + * + *

Additional methods, such as addAndMoveToFirst(), make it easy + * to use instances of this class as a cache (e.g., with LRU policy). + * + *

The iterators provided by this class are type-specific {@linkplain + * java.util.ListIterator list iterators}, and can be started at any + * element which is in the set (if the provided element + * is not in the set, a {@link NoSuchElementException} exception will be thrown). + * If, however, the provided element is not the first or last element in the + * set, the first access to the list index will require linear time, as in the worst case + * the entire set must be scanned in iteration order to retrieve the positional + * index of the starting element. If you use just the methods of a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator}, + * however, all operations will be performed in constant time. + * + * @see Hash + * @see HashCommon + */ +public class IntLinkedOpenCustomHashSet extends AbstractIntSortedSet implements java.io.Serializable, Cloneable, Hash { + private static final long serialVersionUID = 0L; + private static final boolean ASSERTS = false; + /** The array of keys. */ + protected transient int[] key; + /** The mask for wrapping a position counter. */ + protected transient int mask; + /** Whether this set contains the null key. */ + protected transient boolean containsNull; + /** The hash strategy of this custom set. */ + protected it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy; + /** The index of the first entry in iteration order. It is valid iff {@link #size} is nonzero; otherwise, it contains -1. */ + protected transient int first = -1; + /** The index of the last entry in iteration order. It is valid iff {@link #size} is nonzero; otherwise, it contains -1. */ + protected transient int last = -1; + /** For each entry, the next and the previous entry in iteration order, + * stored as ((prev & 0xFFFFFFFFL) << 32) | (next & 0xFFFFFFFFL). + * The first entry contains predecessor -1, and the last entry + * contains successor -1. */ + protected transient long[] link; + /** The current table size. Note that an additional element is allocated for storing the null key. */ + protected transient int n; + /** Threshold after which we rehash. It must be the table size times {@link #f}. */ + protected transient int maxFill; + /** Number of entries in the set (including the null key, if present). */ + protected int size; + /** The acceptable load factor. */ + protected final float f; + /** Creates a new hash set. + * + *

The actual table size will be the least power of two greater than expected/f. + * + * @param expected the expected number of elements in the hash set. + * @param f the load factor. + * @param strategy the strategy. + */ + + public IntLinkedOpenCustomHashSet( final int expected, final float f, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this.strategy = strategy; + if ( f <= 0 || f > 1 ) throw new IllegalArgumentException( "Load factor must be greater than 0 and smaller than or equal to 1" ); + if ( expected < 0 ) throw new IllegalArgumentException( "The expected number of elements must be nonnegative" ); + this.f = f; + n = arraySize( expected, f ); + mask = n - 1; + maxFill = maxFill( n, f ); + key = new int[ n + 1 ]; + link = new long[ n + 1 ]; + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * + * @param expected the expected number of elements in the hash set. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final int expected, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( expected, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash set with initial expected {@link Hash#DEFAULT_INITIAL_SIZE} elements + * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash set copying a given collection. + * + * @param c a {@link Collection} to be copied into the new hash set. + * @param f the load factor. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final Collection c, final float f, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( c.size(), f, strategy ); + addAll( c ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor + * copying a given collection. + * + * @param c a {@link Collection} to be copied into the new hash set. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final Collection c, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( c, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash set copying a given type-specific collection. + * + * @param c a type-specific collection to be copied into the new hash set. + * @param f the load factor. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final IntCollection c, final float f, it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( c.size(), f, strategy ); + addAll( c ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor + * copying a given type-specific collection. + * + * @param c a type-specific collection to be copied into the new hash set. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final IntCollection c, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( c, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash set using elements provided by a type-specific iterator. + * + * @param i a type-specific iterator whose elements will fill the set. + * @param f the load factor. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final IntIterator i, final float f, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( DEFAULT_INITIAL_SIZE, f, strategy ); + while( i.hasNext() ) add( i.nextInt() ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by a type-specific iterator. + * + * @param i a type-specific iterator whose elements will fill the set. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final IntIterator i, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( i, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash set using elements provided by an iterator. + * + * @param i an iterator whose elements will fill the set. + * @param f the load factor. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final Iterator i, final float f, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( IntIterators.asIntIterator( i ), f, strategy ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by an iterator. + * + * @param i an iterator whose elements will fill the set. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final Iterator i, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( IntIterators.asIntIterator( i ), strategy ); + } + /** Creates a new hash set and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the set. + * @param offset the first element to use. + * @param length the number of elements to use. + * @param f the load factor. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final int[] a, final int offset, final int length, final float f, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( length < 0 ? 0 : length, f, strategy ); + IntArrays.ensureOffsetLength( a, offset, length ); + for( int i = 0; i < length; i++ ) add( a[ offset + i ] ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the set. + * @param offset the first element to use. + * @param length the number of elements to use. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final int[] a, final int offset, final int length, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( a, offset, length, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash set copying the elements of an array. + * + * @param a an array to be copied into the new hash set. + * @param f the load factor. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final int[] a, final float f, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( a, 0, a.length, f, strategy ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor + * copying the elements of an array. + * + * @param a an array to be copied into the new hash set. + * @param strategy the strategy. + */ + public IntLinkedOpenCustomHashSet( final int[] a, final it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy ) { + this( a, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Returns the hashing strategy. + * + * @return the hashing strategy of this custom hash set. + */ + public it.unimi.dsi.fastutil.ints.IntHash.Strategy strategy() { + return strategy; + } + private int realSize() { + return containsNull ? size - 1 : size; + } + private void ensureCapacity( final int capacity ) { + final int needed = arraySize( capacity, f ); + if ( needed > n ) rehash( needed ); + } + private void tryCapacity( final long capacity ) { + final int needed = (int)Math.min( 1 << 30, Math.max( 2, HashCommon.nextPowerOfTwo( (long)Math.ceil( capacity / f ) ) ) ); + if ( needed > n ) rehash( needed ); + } + /** {@inheritDoc} */ + public boolean addAll( IntCollection c ) { + if ( f <= .5 ) ensureCapacity( c.size() ); // The resulting collection will be sized for c.size() elements + else tryCapacity( size() + c.size() ); // The resulting collection will be tentatively sized for size() + c.size() elements + return super.addAll( c ); + } + /** {@inheritDoc} */ + public boolean addAll( Collection c ) { + // The resulting collection will be at least c.size() big + if ( f <= .5 ) ensureCapacity( c.size() ); // The resulting collection will be sized for c.size() elements + else tryCapacity( size() + c.size() ); // The resulting collection will be tentatively sized for size() + c.size() elements + return super.addAll( c ); + } + public boolean add( final int k ) { + int pos; + if ( ( strategy.equals( (k), (0) ) ) ) { + if ( containsNull ) return false; + pos = n; + containsNull = true; + key[ n ] = k; + } + else { + int curr; + final int[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) { + if ( ( strategy.equals( (curr), (k) ) ) ) return false; + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( strategy.equals( (curr), (k) ) ) ) return false; + } + key[ pos ] = k; + } + if ( size == 0 ) { + first = last = pos; + // Special case of SET_UPPER_LOWER(link[ pos ], -1, -1); + link[ pos ] = -1L; + } + else { + link[ last ] ^= ( ( link[ last ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ pos ] = ( ( last & 0xFFFFFFFFL ) << 32 ) | ( -1 & 0xFFFFFFFFL ); + last = pos; + } + if ( size++ >= maxFill ) rehash( arraySize( size + 1, f ) ); + if ( ASSERTS ) checkTable(); + return true; + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + protected final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + int curr; + final int[] key = this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + fixPointers( pos, last ); + } + } + private boolean removeEntry( final int pos ) { + size--; + fixPointers( pos ); + shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return true; + } + private boolean removeNullEntry() { + containsNull = false; + key[ n ] = (0); + size--; + fixPointers( n ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return true; + } + + public boolean remove( final int k ) { + if ( ( strategy.equals( ( k), (0) ) ) ) { + if ( containsNull ) return removeNullEntry(); + return false; + } + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return removeEntry( pos ); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return removeEntry( pos ); + } + } + + public boolean contains( final int k ) { + if ( ( strategy.equals( ( k), (0) ) ) ) return containsNull; + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return true; + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return true; + } + } + /** Removes the first key in iteration order. + * @return the first key. + * @throws NoSuchElementException is this set is empty. + */ + public int removeFirstInt() { + if ( size == 0 ) throw new NoSuchElementException(); + final int pos = first; + // Abbreviated version of fixPointers(pos) + first = (int) link[ pos ]; + if ( 0 <= first ) { + // Special case of SET_PREV( link[ first ], -1 ) + link[ first ] |= (-1 & 0xFFFFFFFFL) << 32; + } + final int k = key[ pos ]; + size--; + if ( ( strategy.equals( (k), (0) ) ) ) { + containsNull = false; + key[ n ] = (0); + } + else shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return k; + } + /** Removes the the last key in iteration order. + * @return the last key. + * @throws NoSuchElementException is this set is empty. + */ + public int removeLastInt() { + if ( size == 0 ) throw new NoSuchElementException(); + final int pos = last; + // Abbreviated version of fixPointers(pos) + last = (int) ( link[ pos ] >>> 32 ); + if ( 0 <= last ) { + // Special case of SET_NEXT( link[ last ], -1 ) + link[ last ] |= -1 & 0xFFFFFFFFL; + } + final int k = key[ pos ]; + size--; + if ( ( strategy.equals( (k), (0) ) ) ) { + containsNull = false; + key[ n ] = (0); + } + else shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return k; + } + private void moveIndexToFirst( final int i ) { + if ( size == 1 || first == i ) return; + if ( last == i ) { + last = (int) ( link[ i ] >>> 32 ); + // Special case of SET_NEXT( link[ last ], -1 ); + link[ last ] |= -1 & 0xFFFFFFFFL; + } + else { + final long linki = link[ i ]; + final int prev = (int) ( linki >>> 32 ); + final int next = (int) linki; + link[ prev ] ^= ( ( link[ prev ] ^ ( linki & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( linki & 0xFFFFFFFF00000000L ) ) & 0xFFFFFFFF00000000L ); + } + link[ first ] ^= ( ( link[ first ] ^ ( ( i & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ i ] = ( ( -1 & 0xFFFFFFFFL ) << 32 ) | ( first & 0xFFFFFFFFL ); + first = i; + } + private void moveIndexToLast( final int i ) { + if ( size == 1 || last == i ) return; + if ( first == i ) { + first = (int) link[ i ]; + // Special case of SET_PREV( link[ first ], -1 ); + link[ first ] |= (-1 & 0xFFFFFFFFL) << 32; + } + else { + final long linki = link[ i ]; + final int prev = (int) ( linki >>> 32 ); + final int next = (int) linki; + link[ prev ] ^= ( ( link[ prev ] ^ ( linki & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( linki & 0xFFFFFFFF00000000L ) ) & 0xFFFFFFFF00000000L ); + } + link[ last ] ^= ( ( link[ last ] ^ ( i & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ i ] = ( ( last & 0xFFFFFFFFL ) << 32 ) | ( -1 & 0xFFFFFFFFL ); + last = i; + } + /** Adds a key to the set; if the key is already present, it is moved to the first position of the iteration order. + * + * @param k the key. + * @return true if the key was not present. + */ + public boolean addAndMoveToFirst( final int k ) { + int pos; + if ( ( strategy.equals( (k), (0) ) ) ) { + if ( containsNull ) { + moveIndexToFirst( n ); + return false; + } + containsNull = true; + pos = n; + } + else { + // The starting point. + final int key[] = this.key; + pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask; + // There's always an unused entry. TODO + while( ! ( (key[ pos ]) == (0) ) ) { + if ( ( strategy.equals( (k), (key[ pos ]) ) ) ) { + moveIndexToFirst( pos ); + return false; + } + pos = ( pos + 1 ) & mask; + } + } + key[ pos ] = k; + if ( size == 0 ) { + first = last = pos; + // Special case of SET_UPPER_LOWER( link[ pos ], -1, -1 ); + link[ pos ] = -1L; + } + else { + link[ first ] ^= ( ( link[ first ] ^ ( ( pos & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ pos ] = ( ( -1 & 0xFFFFFFFFL ) << 32 ) | ( first & 0xFFFFFFFFL ); + first = pos; + } + if ( size++ >= maxFill ) rehash( arraySize( size, f ) ); + if ( ASSERTS ) checkTable(); + return true; + } + /** Adds a key to the set; if the key is already present, it is moved to the last position of the iteration order. + * + * @param k the key. + * @return true if the key was not present. + */ + public boolean addAndMoveToLast( final int k ) { + int pos; + if ( ( strategy.equals( (k), (0) ) ) ) { + if ( containsNull ) { + moveIndexToLast( n ); + return false; + } + containsNull = true; + pos = n; + } + else { + // The starting point. + final int key[] = this.key; + pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask; + // There's always an unused entry. + while( ! ( (key[ pos ]) == (0) ) ) { + if ( ( strategy.equals( (k), (key[ pos ]) ) ) ) { + moveIndexToLast( pos ); + return false; + } + pos = ( pos + 1 ) & mask; + } + } + key[ pos ] = k; + if ( size == 0 ) { + first = last = pos; + // Special case of SET_UPPER_LOWER( link[ pos ], -1, -1 ); + link[ pos ] = -1L; + } + else { + link[ last ] ^= ( ( link[ last ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ pos ] = ( ( last & 0xFFFFFFFFL ) << 32 ) | ( -1 & 0xFFFFFFFFL ); + last = pos; + } + if ( size++ >= maxFill ) rehash( arraySize( size, f ) ); + if ( ASSERTS ) checkTable(); + return true; + } + /* Removes all elements from this set. + * + *

To increase object reuse, this method does not change the table size. + * If you want to reduce the table size, you must use {@link #trim()}. + * + */ + public void clear() { + if ( size == 0 ) return; + size = 0; + containsNull = false; + Arrays.fill( key, (0) ); + first = last = -1; + } + public int size() { + return size; + } + public boolean isEmpty() { + return size == 0; + } + /** A no-op for backward compatibility. + * + * @param growthFactor unused. + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public void growthFactor( int growthFactor ) {} + /** Gets the growth factor (2). + * + * @return the growth factor of this set, which is fixed (2). + * @see #growthFactor(int) + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public int growthFactor() { + return 16; + } + /** Modifies the {@link #link} vector so that the given entry is removed. + * This method will complete in constant time. + * + * @param i the index of an entry. + */ + protected void fixPointers( final int i ) { + if ( size == 0 ) { + first = last = -1; + return; + } + if ( first == i ) { + first = (int) link[ i ]; + if (0 <= first) { + // Special case of SET_PREV( link[ first ], -1 ) + link[ first ] |= (-1 & 0xFFFFFFFFL) << 32; + } + return; + } + if ( last == i ) { + last = (int) ( link[ i ] >>> 32 ); + if (0 <= last) { + // Special case of SET_NEXT( link[ last ], -1 ) + link[ last ] |= -1 & 0xFFFFFFFFL; + } + return; + } + final long linki = link[ i ]; + final int prev = (int) ( linki >>> 32 ); + final int next = (int) linki; + link[ prev ] ^= ( ( link[ prev ] ^ ( linki & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( linki & 0xFFFFFFFF00000000L ) ) & 0xFFFFFFFF00000000L ); + } + /** Modifies the {@link #link} vector for a shift from s to d. + * This method will complete in constant time. + * + * @param s the source position. + * @param d the destination position. + */ + protected void fixPointers( int s, int d ) { + if ( size == 1 ) { + first = last = d; + // Special case of SET(link[ d ], -1, -1) + link[ d ] = -1L; + return; + } + if ( first == s ) { + first = d; + link[ (int) link[ s ] ] ^= ( ( link[ (int) link[ s ] ] ^ ( ( d & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ d ] = link[ s ]; + return; + } + if ( last == s ) { + last = d; + link[ (int) ( link[ s ] >>> 32 )] ^= ( ( link[ (int) ( link[ s ] >>> 32 )] ^ ( d & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ d ] = link[ s ]; + return; + } + final long links = link[ s ]; + final int prev = (int) ( links >>> 32 ); + final int next = (int) links; + link[ prev ] ^= ( ( link[ prev ] ^ ( d & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( ( d & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ d ] = links; + } + /** Returns the first element of this set in iteration order. + * + * @return the first element in iteration order. + */ + public int firstInt() { + if ( size == 0 ) throw new NoSuchElementException(); + return key[ first ]; + } + /** Returns the last element of this set in iteration order. + * + * @return the last element in iteration order. + */ + public int lastInt() { + if ( size == 0 ) throw new NoSuchElementException(); + return key[ last ]; + } + public IntSortedSet tailSet( int from ) { throw new UnsupportedOperationException(); } + public IntSortedSet headSet( int to ) { throw new UnsupportedOperationException(); } + public IntSortedSet subSet( int from, int to ) { throw new UnsupportedOperationException(); } + public IntComparator comparator() { return null; } + /** A list iterator over a linked set. + * + *

This class provides a list iterator over a linked hash set. The constructor runs in constant time. + */ + private class SetIterator extends AbstractIntListIterator { + /** The entry that will be returned by the next call to {@link java.util.ListIterator#previous()} (or null if no previous entry exists). */ + int prev = -1; + /** The entry that will be returned by the next call to {@link java.util.ListIterator#next()} (or null if no next entry exists). */ + int next = -1; + /** The last entry that was returned (or -1 if we did not iterate or used {@link #remove()}). */ + int curr = -1; + /** The current index (in the sense of a {@link java.util.ListIterator}). When -1, we do not know the current index.*/ + int index = -1; + SetIterator() { + next = first; + index = 0; + } + SetIterator( int from ) { + if ( ( strategy.equals( (from), (0) ) ) ) { + if ( IntLinkedOpenCustomHashSet.this.containsNull ) { + next = (int) link[ n ]; + prev = n; + return; + } + else throw new NoSuchElementException( "The key " + from + " does not belong to this set." ); + } + if ( ( strategy.equals( (key[ last ]), (from) ) ) ) { + prev = last; + index = size; + return; + } + // The starting point. + final int key[] = IntLinkedOpenCustomHashSet.this.key; + int pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(from) ) ) & mask; + // There's always an unused entry. + while( ! ( (key[ pos ]) == (0) ) ) { + if ( ( strategy.equals( (key[ pos ]), (from) ) ) ) { + // Note: no valid index known. + next = (int) link[ pos ]; + prev = pos; + return; + } + pos = ( pos + 1 ) & mask; + } + throw new NoSuchElementException( "The key " + from + " does not belong to this set." ); + } + public boolean hasNext() { return next != -1; } + public boolean hasPrevious() { return prev != -1; } + public int nextInt() { + if ( ! hasNext() ) throw new NoSuchElementException(); + curr = next; + next = (int) link[ curr ]; + prev = curr; + if ( index >= 0 ) index++; + if ( ASSERTS ) assert curr == n || ! ( (key[ curr ]) == (0) ) : "Position " + curr + " is not used"; + return key[ curr ]; + } + public int previousInt() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + curr = prev; + prev = (int) ( link[ curr ] >>> 32 ); + next = curr; + if ( index >= 0 ) index--; + return key[ curr ]; + } + private final void ensureIndexKnown() { + if ( index >= 0 ) return; + if ( prev == -1 ) { + index = 0; + return; + } + if ( next == -1 ) { + index = size; + return; + } + int pos = first; + index = 1; + while( pos != prev ) { + pos = (int) link[ pos ]; + index++; + } + } + public int nextIndex() { + ensureIndexKnown(); + return index; + } + public int previousIndex() { + ensureIndexKnown(); + return index - 1; + } + public void remove() { + ensureIndexKnown(); + if ( curr == -1 ) throw new IllegalStateException(); + if ( curr == prev ) { + /* If the last operation was a next(), we are removing an entry that preceeds + the current index, and thus we must decrement it. */ + index--; + prev = (int) ( link[ curr ] >>> 32 ); + } + else + next = (int) link[ curr ]; + size--; + /* Now we manually fix the pointers. Because of our knowledge of next + and prev, this is going to be faster than calling fixPointers(). */ + if ( prev == -1 ) first = next; + else + link[ prev ] ^= ( ( link[ prev ] ^ ( next & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + if ( next == -1 ) last = prev; + else + link[ next ] ^= ( ( link[ next ] ^ ( ( prev & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + int last, slot, pos = curr; + curr = -1; + if ( pos == n ) { + IntLinkedOpenCustomHashSet.this.containsNull = false; + IntLinkedOpenCustomHashSet.this.key[ n ] = (0); + } + else { + int curr; + final int[] key = IntLinkedOpenCustomHashSet.this.key; + // We have to horribly duplicate the shiftKeys() code because we need to update next/prev. + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + if ( next == pos ) next = last; + if ( prev == pos ) prev = last; + fixPointers( pos, last ); + } + } + } + } + /** Returns a type-specific list iterator on the elements in this set, starting from a given element of the set. + * Please see the class documentation for implementation details. + * + * @param from an element to start from. + * @return a type-specific list iterator starting at the given element. + * @throws IllegalArgumentException if from does not belong to the set. + */ + public IntListIterator iterator( int from ) { + return new SetIterator( from ); + } + public IntListIterator iterator() { + return new SetIterator(); + } + /** A no-op for backward compatibility. The kind of tables implemented by + * this class never need rehashing. + * + *

If you need to reduce the table size to fit exactly + * this set, use {@link #trim()}. + * + * @return true. + * @see #trim() + * @deprecated A no-op. + */ + @Deprecated + public boolean rehash() { + return true; + } + /** Rehashes this set, making the table as small as possible. + * + *

This method rehashes the table to the smallest size satisfying the + * load factor. It can be used when the set will not be changed anymore, so + * to optimize access speed and size. + * + *

If the table size is already the minimum possible, this method + * does nothing. + * + * @return true if there was enough memory to trim the set. + * @see #trim(int) + */ + public boolean trim() { + final int l = arraySize( size, f ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch(OutOfMemoryError cantDoIt) { return false; } + return true; + } + /** Rehashes this set if the table is too large. + * + *

Let N be the smallest table size that can hold + * max(n,{@link #size()}) entries, still satisfying the load factor. If the current + * table size is smaller than or equal to N, this method does + * nothing. Otherwise, it rehashes this set in a table of size + * N. + * + *

This method is useful when reusing sets. {@linkplain #clear() Clearing a + * set} leaves the table size untouched. If you are reusing a set + * many times, you can call this method with a typical + * size to avoid keeping around a very large table just + * because of a few large transient sets. + * + * @param n the threshold for the trimming. + * @return true if there was enough memory to trim the set. + * @see #trim() + */ + public boolean trim( final int n ) { + final int l = HashCommon.nextPowerOfTwo( (int)Math.ceil( n / f ) ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch( OutOfMemoryError cantDoIt ) { return false; } + return true; + } + /** Rehashes the set. + * + *

This method implements the basic rehashing strategy, and may be + * overriden by subclasses implementing different rehashing strategies (e.g., + * disk-based rehashing). However, you should not override this method + * unless you understand the internal workings of this class. + * + * @param newN the new size + */ + + protected void rehash( final int newN ) { + final int key[] = this.key; + final int mask = newN - 1; // Note that this is used by the hashing macro + final int newKey[] = new int[ newN + 1 ]; + int i = first, prev = -1, newPrev = -1, t, pos; + final long link[] = this.link; + final long newLink[] = new long[ newN + 1 ]; + first = -1; + for( int j = size; j-- != 0; ) { + if ( ( strategy.equals( (key[ i ]), (0) ) ) ) pos = newN; + else { + pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(key[ i ]) ) ) & mask; + while ( ! ( (newKey[ pos ]) == (0) ) ) pos = ( pos + 1 ) & mask; + } + newKey[ pos ] = key[ i ]; + if ( prev != -1 ) { + newLink[ newPrev ] ^= ( ( newLink[ newPrev ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + newLink[ pos ] ^= ( ( newLink[ pos ] ^ ( ( newPrev & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + newPrev = pos; + } + else { + newPrev = first = pos; + // Special case of SET(newLink[ pos ], -1, -1); + newLink[ pos ] = -1L; + } + t = i; + i = (int) link[ i ]; + prev = t; + } + this.link = newLink; + this.last = newPrev; + if ( newPrev != -1 ) + // Special case of SET_NEXT( newLink[ newPrev ], -1 ); + newLink[ newPrev ] |= -1 & 0xFFFFFFFFL; + n = newN; + this.mask = mask; + maxFill = maxFill( n, f ); + this.key = newKey; + } + /** Returns a deep copy of this set. + * + *

This method performs a deep copy of this hash set; the data stored in the + * set, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this set. + */ + + public IntLinkedOpenCustomHashSet clone() { + IntLinkedOpenCustomHashSet c; + try { + c = (IntLinkedOpenCustomHashSet )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.key = key.clone(); + c.containsNull = containsNull; + c.link = link.clone(); + c.strategy = strategy; + return c; + } + /** Returns a hash code for this set. + * + * This method overrides the generic method provided by the superclass. + * Since equals() is not overriden, it is important + * that the value returned by this method is the same value as + * the one returned by the overriden method. + * + * @return a hash code for this set. + */ + public int hashCode() { + int h = 0; + for( int j = realSize(), i = 0; j-- != 0; ) { + while( ( (key[ i ]) == (0) ) ) i++; + h += ( strategy.hashCode(key[ i ]) ); + i++; + } + // Zero / null have hash zero. + return h; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + final IntIterator i = iterator(); + s.defaultWriteObject(); + for( int j = size; j-- != 0; ) s.writeInt( i.nextInt() ); + } + + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + n = arraySize( size, f ); + maxFill = maxFill( n, f ); + mask = n - 1; + final int key[] = this.key = new int[ n + 1 ]; + final long link[] = this.link = new long[ n + 1 ]; + int prev = -1; + first = last = -1; + int k; + for( int i = size, pos; i-- != 0; ) { + k = s.readInt(); + if ( ( strategy.equals( (k), (0) ) ) ) { + pos = n; + containsNull = true; + } + else { + if ( ! ( (key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) + while ( ! ( (key[ pos = ( pos + 1 ) & mask ]) == (0) ) ); + } + key[ pos ] = k; + if ( first != -1 ) { + link[ prev ] ^= ( ( link[ prev ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ pos ] ^= ( ( link[ pos ] ^ ( ( prev & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + prev = pos; + } + else { + prev = first = pos; + // Special case of SET_PREV( newLink[ pos ], -1 ); + link[ pos ] |= (-1L & 0xFFFFFFFFL) << 32; + } + } + last = prev; + if ( prev != -1 ) + // Special case of SET_NEXT( link[ prev ], -1 ); + link[ prev ] |= -1 & 0xFFFFFFFFL; + if ( ASSERTS ) checkTable(); + } + private void checkTable() {} +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntLinkedOpenHashSet.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntLinkedOpenHashSet.java new file mode 100644 index 0000000..8d7e9ad --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntLinkedOpenHashSet.java @@ -0,0 +1,1044 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.HashCommon; +import static it.unimi.dsi.fastutil.HashCommon.arraySize; +import static it.unimi.dsi.fastutil.HashCommon.maxFill; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +/** A type-specific linked hash set with with a fast, small-footprint implementation. + * + *

Instances of this class use a hash table to represent a set. The table is + * filled up to a specified load factor, and then doubled in size to + * accommodate new entries. If the table is emptied below one fourth + * of the load factor, it is halved in size. However, halving is + * not performed when deleting entries from an iterator, as it would interfere + * with the iteration process. + * + *

Note that {@link #clear()} does not modify the hash table size. + * Rather, a family of {@linkplain #trim() trimming + * methods} lets you control the size of the table; this is particularly useful + * if you reuse instances of this class. + * + *

Iterators generated by this set will enumerate elements in the same order in which they + * have been added to the set (addition of elements already present + * in the set does not change the iteration order). Note that this order has nothing in common with the natural + * order of the keys. The order is kept by means of a doubly linked list, represented + * via an array of longs parallel to the table. + * + *

This class implements the interface of a sorted set, so to allow easy + * access of the iteration order: for instance, you can get the first element + * in iteration order with {@code first()} without having to create an + * iterator; however, this class partially violates the {@link java.util.SortedSet} + * contract because all subset methods throw an exception and {@link + * #comparator()} returns always null. + * + *

Additional methods, such as addAndMoveToFirst(), make it easy + * to use instances of this class as a cache (e.g., with LRU policy). + * + *

The iterators provided by this class are type-specific {@linkplain + * java.util.ListIterator list iterators}, and can be started at any + * element which is in the set (if the provided element + * is not in the set, a {@link NoSuchElementException} exception will be thrown). + * If, however, the provided element is not the first or last element in the + * set, the first access to the list index will require linear time, as in the worst case + * the entire set must be scanned in iteration order to retrieve the positional + * index of the starting element. If you use just the methods of a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator}, + * however, all operations will be performed in constant time. + * + * @see Hash + * @see HashCommon + */ +public class IntLinkedOpenHashSet extends AbstractIntSortedSet implements java.io.Serializable, Cloneable, Hash { + private static final long serialVersionUID = 0L; + private static final boolean ASSERTS = false; + /** The array of keys. */ + protected transient int[] key; + /** The mask for wrapping a position counter. */ + protected transient int mask; + /** Whether this set contains the null key. */ + protected transient boolean containsNull; + /** The index of the first entry in iteration order. It is valid iff {@link #size} is nonzero; otherwise, it contains -1. */ + protected transient int first = -1; + /** The index of the last entry in iteration order. It is valid iff {@link #size} is nonzero; otherwise, it contains -1. */ + protected transient int last = -1; + /** For each entry, the next and the previous entry in iteration order, + * stored as ((prev & 0xFFFFFFFFL) << 32) | (next & 0xFFFFFFFFL). + * The first entry contains predecessor -1, and the last entry + * contains successor -1. */ + protected transient long[] link; + /** The current table size. Note that an additional element is allocated for storing the null key. */ + protected transient int n; + /** Threshold after which we rehash. It must be the table size times {@link #f}. */ + protected transient int maxFill; + /** Number of entries in the set (including the null key, if present). */ + protected int size; + /** The acceptable load factor. */ + protected final float f; + /** Creates a new hash set. + * + *

The actual table size will be the least power of two greater than expected/f. + * + * @param expected the expected number of elements in the hash set. + * @param f the load factor. + */ + + public IntLinkedOpenHashSet( final int expected, final float f ) { + if ( f <= 0 || f > 1 ) throw new IllegalArgumentException( "Load factor must be greater than 0 and smaller than or equal to 1" ); + if ( expected < 0 ) throw new IllegalArgumentException( "The expected number of elements must be nonnegative" ); + this.f = f; + n = arraySize( expected, f ); + mask = n - 1; + maxFill = maxFill( n, f ); + key = new int[ n + 1 ]; + link = new long[ n + 1 ]; + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * + * @param expected the expected number of elements in the hash set. + */ + public IntLinkedOpenHashSet( final int expected ) { + this( expected, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash set with initial expected {@link Hash#DEFAULT_INITIAL_SIZE} elements + * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + */ + public IntLinkedOpenHashSet() { + this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash set copying a given collection. + * + * @param c a {@link Collection} to be copied into the new hash set. + * @param f the load factor. + */ + public IntLinkedOpenHashSet( final Collection c, final float f ) { + this( c.size(), f ); + addAll( c ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor + * copying a given collection. + * + * @param c a {@link Collection} to be copied into the new hash set. + */ + public IntLinkedOpenHashSet( final Collection c ) { + this( c, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash set copying a given type-specific collection. + * + * @param c a type-specific collection to be copied into the new hash set. + * @param f the load factor. + */ + public IntLinkedOpenHashSet( final IntCollection c, final float f ) { + this( c.size(), f ); + addAll( c ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor + * copying a given type-specific collection. + * + * @param c a type-specific collection to be copied into the new hash set. + */ + public IntLinkedOpenHashSet( final IntCollection c ) { + this( c, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash set using elements provided by a type-specific iterator. + * + * @param i a type-specific iterator whose elements will fill the set. + * @param f the load factor. + */ + public IntLinkedOpenHashSet( final IntIterator i, final float f ) { + this( DEFAULT_INITIAL_SIZE, f ); + while( i.hasNext() ) add( i.nextInt() ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by a type-specific iterator. + * + * @param i a type-specific iterator whose elements will fill the set. + */ + public IntLinkedOpenHashSet( final IntIterator i ) { + this( i, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash set using elements provided by an iterator. + * + * @param i an iterator whose elements will fill the set. + * @param f the load factor. + */ + public IntLinkedOpenHashSet( final Iterator i, final float f ) { + this( IntIterators.asIntIterator( i ), f ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by an iterator. + * + * @param i an iterator whose elements will fill the set. + */ + public IntLinkedOpenHashSet( final Iterator i ) { + this( IntIterators.asIntIterator( i ) ); + } + /** Creates a new hash set and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the set. + * @param offset the first element to use. + * @param length the number of elements to use. + * @param f the load factor. + */ + public IntLinkedOpenHashSet( final int[] a, final int offset, final int length, final float f ) { + this( length < 0 ? 0 : length, f ); + IntArrays.ensureOffsetLength( a, offset, length ); + for( int i = 0; i < length; i++ ) add( a[ offset + i ] ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the set. + * @param offset the first element to use. + * @param length the number of elements to use. + */ + public IntLinkedOpenHashSet( final int[] a, final int offset, final int length ) { + this( a, offset, length, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash set copying the elements of an array. + * + * @param a an array to be copied into the new hash set. + * @param f the load factor. + */ + public IntLinkedOpenHashSet( final int[] a, final float f ) { + this( a, 0, a.length, f ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor + * copying the elements of an array. + * + * @param a an array to be copied into the new hash set. + */ + public IntLinkedOpenHashSet( final int[] a ) { + this( a, DEFAULT_LOAD_FACTOR ); + } + private int realSize() { + return containsNull ? size - 1 : size; + } + private void ensureCapacity( final int capacity ) { + final int needed = arraySize( capacity, f ); + if ( needed > n ) rehash( needed ); + } + private void tryCapacity( final long capacity ) { + final int needed = (int)Math.min( 1 << 30, Math.max( 2, HashCommon.nextPowerOfTwo( (long)Math.ceil( capacity / f ) ) ) ); + if ( needed > n ) rehash( needed ); + } + /** {@inheritDoc} */ + public boolean addAll( IntCollection c ) { + if ( f <= .5 ) ensureCapacity( c.size() ); // The resulting collection will be sized for c.size() elements + else tryCapacity( size() + c.size() ); // The resulting collection will be tentatively sized for size() + c.size() elements + return super.addAll( c ); + } + /** {@inheritDoc} */ + public boolean addAll( Collection c ) { + // The resulting collection will be at least c.size() big + if ( f <= .5 ) ensureCapacity( c.size() ); // The resulting collection will be sized for c.size() elements + else tryCapacity( size() + c.size() ); // The resulting collection will be tentatively sized for size() + c.size() elements + return super.addAll( c ); + } + public boolean add( final int k ) { + int pos; + if ( ( (k) == (0) ) ) { + if ( containsNull ) return false; + pos = n; + containsNull = true; + } + else { + int curr; + final int[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) { + if ( ( (curr) == (k) ) ) return false; + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( (curr) == (k) ) ) return false; + } + key[ pos ] = k; + } + if ( size == 0 ) { + first = last = pos; + // Special case of SET_UPPER_LOWER(link[ pos ], -1, -1); + link[ pos ] = -1L; + } + else { + link[ last ] ^= ( ( link[ last ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ pos ] = ( ( last & 0xFFFFFFFFL ) << 32 ) | ( -1 & 0xFFFFFFFFL ); + last = pos; + } + if ( size++ >= maxFill ) rehash( arraySize( size + 1, f ) ); + if ( ASSERTS ) checkTable(); + return true; + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + protected final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + int curr; + final int[] key = this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( (curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + fixPointers( pos, last ); + } + } + private boolean removeEntry( final int pos ) { + size--; + fixPointers( pos ); + shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return true; + } + private boolean removeNullEntry() { + containsNull = false; + key[ n ] = (0); + size--; + fixPointers( n ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return true; + } + + public boolean remove( final int k ) { + if ( ( (k) == (0) ) ) { + if ( containsNull ) return removeNullEntry(); + return false; + } + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return removeEntry( pos ); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return removeEntry( pos ); + } + } + + public boolean contains( final int k ) { + if ( ( (k) == (0) ) ) return containsNull; + int curr; + final int[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return true; + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return true; + } + } + /** Removes the first key in iteration order. + * @return the first key. + * @throws NoSuchElementException is this set is empty. + */ + public int removeFirstInt() { + if ( size == 0 ) throw new NoSuchElementException(); + final int pos = first; + // Abbreviated version of fixPointers(pos) + first = (int) link[ pos ]; + if ( 0 <= first ) { + // Special case of SET_PREV( link[ first ], -1 ) + link[ first ] |= (-1 & 0xFFFFFFFFL) << 32; + } + final int k = key[ pos ]; + size--; + if ( ( (k) == (0) ) ) { + containsNull = false; + key[ n ] = (0); + } + else shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return k; + } + /** Removes the the last key in iteration order. + * @return the last key. + * @throws NoSuchElementException is this set is empty. + */ + public int removeLastInt() { + if ( size == 0 ) throw new NoSuchElementException(); + final int pos = last; + // Abbreviated version of fixPointers(pos) + last = (int) ( link[ pos ] >>> 32 ); + if ( 0 <= last ) { + // Special case of SET_NEXT( link[ last ], -1 ) + link[ last ] |= -1 & 0xFFFFFFFFL; + } + final int k = key[ pos ]; + size--; + if ( ( (k) == (0) ) ) { + containsNull = false; + key[ n ] = (0); + } + else shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return k; + } + private void moveIndexToFirst( final int i ) { + if ( size == 1 || first == i ) return; + if ( last == i ) { + last = (int) ( link[ i ] >>> 32 ); + // Special case of SET_NEXT( link[ last ], -1 ); + link[ last ] |= -1 & 0xFFFFFFFFL; + } + else { + final long linki = link[ i ]; + final int prev = (int) ( linki >>> 32 ); + final int next = (int) linki; + link[ prev ] ^= ( ( link[ prev ] ^ ( linki & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( linki & 0xFFFFFFFF00000000L ) ) & 0xFFFFFFFF00000000L ); + } + link[ first ] ^= ( ( link[ first ] ^ ( ( i & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ i ] = ( ( -1 & 0xFFFFFFFFL ) << 32 ) | ( first & 0xFFFFFFFFL ); + first = i; + } + private void moveIndexToLast( final int i ) { + if ( size == 1 || last == i ) return; + if ( first == i ) { + first = (int) link[ i ]; + // Special case of SET_PREV( link[ first ], -1 ); + link[ first ] |= (-1 & 0xFFFFFFFFL) << 32; + } + else { + final long linki = link[ i ]; + final int prev = (int) ( linki >>> 32 ); + final int next = (int) linki; + link[ prev ] ^= ( ( link[ prev ] ^ ( linki & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( linki & 0xFFFFFFFF00000000L ) ) & 0xFFFFFFFF00000000L ); + } + link[ last ] ^= ( ( link[ last ] ^ ( i & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ i ] = ( ( last & 0xFFFFFFFFL ) << 32 ) | ( -1 & 0xFFFFFFFFL ); + last = i; + } + /** Adds a key to the set; if the key is already present, it is moved to the first position of the iteration order. + * + * @param k the key. + * @return true if the key was not present. + */ + public boolean addAndMoveToFirst( final int k ) { + int pos; + if ( ( (k) == (0) ) ) { + if ( containsNull ) { + moveIndexToFirst( n ); + return false; + } + containsNull = true; + pos = n; + } + else { + // The starting point. + final int key[] = this.key; + pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask; + // There's always an unused entry. TODO + while( ! ( (key[ pos ]) == (0) ) ) { + if ( ( (k) == (key[ pos ]) ) ) { + moveIndexToFirst( pos ); + return false; + } + pos = ( pos + 1 ) & mask; + } + } + key[ pos ] = k; + if ( size == 0 ) { + first = last = pos; + // Special case of SET_UPPER_LOWER( link[ pos ], -1, -1 ); + link[ pos ] = -1L; + } + else { + link[ first ] ^= ( ( link[ first ] ^ ( ( pos & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ pos ] = ( ( -1 & 0xFFFFFFFFL ) << 32 ) | ( first & 0xFFFFFFFFL ); + first = pos; + } + if ( size++ >= maxFill ) rehash( arraySize( size, f ) ); + if ( ASSERTS ) checkTable(); + return true; + } + /** Adds a key to the set; if the key is already present, it is moved to the last position of the iteration order. + * + * @param k the key. + * @return true if the key was not present. + */ + public boolean addAndMoveToLast( final int k ) { + int pos; + if ( ( (k) == (0) ) ) { + if ( containsNull ) { + moveIndexToLast( n ); + return false; + } + containsNull = true; + pos = n; + } + else { + // The starting point. + final int key[] = this.key; + pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask; + // There's always an unused entry. + while( ! ( (key[ pos ]) == (0) ) ) { + if ( ( (k) == (key[ pos ]) ) ) { + moveIndexToLast( pos ); + return false; + } + pos = ( pos + 1 ) & mask; + } + } + key[ pos ] = k; + if ( size == 0 ) { + first = last = pos; + // Special case of SET_UPPER_LOWER( link[ pos ], -1, -1 ); + link[ pos ] = -1L; + } + else { + link[ last ] ^= ( ( link[ last ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ pos ] = ( ( last & 0xFFFFFFFFL ) << 32 ) | ( -1 & 0xFFFFFFFFL ); + last = pos; + } + if ( size++ >= maxFill ) rehash( arraySize( size, f ) ); + if ( ASSERTS ) checkTable(); + return true; + } + /* Removes all elements from this set. + * + *

To increase object reuse, this method does not change the table size. + * If you want to reduce the table size, you must use {@link #trim()}. + * + */ + public void clear() { + if ( size == 0 ) return; + size = 0; + containsNull = false; + Arrays.fill( key, (0) ); + first = last = -1; + } + public int size() { + return size; + } + public boolean isEmpty() { + return size == 0; + } + /** A no-op for backward compatibility. + * + * @param growthFactor unused. + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public void growthFactor( int growthFactor ) {} + /** Gets the growth factor (2). + * + * @return the growth factor of this set, which is fixed (2). + * @see #growthFactor(int) + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public int growthFactor() { + return 16; + } + /** Modifies the {@link #link} vector so that the given entry is removed. + * This method will complete in constant time. + * + * @param i the index of an entry. + */ + protected void fixPointers( final int i ) { + if ( size == 0 ) { + first = last = -1; + return; + } + if ( first == i ) { + first = (int) link[ i ]; + if (0 <= first) { + // Special case of SET_PREV( link[ first ], -1 ) + link[ first ] |= (-1 & 0xFFFFFFFFL) << 32; + } + return; + } + if ( last == i ) { + last = (int) ( link[ i ] >>> 32 ); + if (0 <= last) { + // Special case of SET_NEXT( link[ last ], -1 ) + link[ last ] |= -1 & 0xFFFFFFFFL; + } + return; + } + final long linki = link[ i ]; + final int prev = (int) ( linki >>> 32 ); + final int next = (int) linki; + link[ prev ] ^= ( ( link[ prev ] ^ ( linki & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( linki & 0xFFFFFFFF00000000L ) ) & 0xFFFFFFFF00000000L ); + } + /** Modifies the {@link #link} vector for a shift from s to d. + * This method will complete in constant time. + * + * @param s the source position. + * @param d the destination position. + */ + protected void fixPointers( int s, int d ) { + if ( size == 1 ) { + first = last = d; + // Special case of SET(link[ d ], -1, -1) + link[ d ] = -1L; + return; + } + if ( first == s ) { + first = d; + link[ (int) link[ s ] ] ^= ( ( link[ (int) link[ s ] ] ^ ( ( d & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ d ] = link[ s ]; + return; + } + if ( last == s ) { + last = d; + link[ (int) ( link[ s ] >>> 32 )] ^= ( ( link[ (int) ( link[ s ] >>> 32 )] ^ ( d & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ d ] = link[ s ]; + return; + } + final long links = link[ s ]; + final int prev = (int) ( links >>> 32 ); + final int next = (int) links; + link[ prev ] ^= ( ( link[ prev ] ^ ( d & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( ( d & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ d ] = links; + } + /** Returns the first element of this set in iteration order. + * + * @return the first element in iteration order. + */ + public int firstInt() { + if ( size == 0 ) throw new NoSuchElementException(); + return key[ first ]; + } + /** Returns the last element of this set in iteration order. + * + * @return the last element in iteration order. + */ + public int lastInt() { + if ( size == 0 ) throw new NoSuchElementException(); + return key[ last ]; + } + public IntSortedSet tailSet( int from ) { throw new UnsupportedOperationException(); } + public IntSortedSet headSet( int to ) { throw new UnsupportedOperationException(); } + public IntSortedSet subSet( int from, int to ) { throw new UnsupportedOperationException(); } + public IntComparator comparator() { return null; } + /** A list iterator over a linked set. + * + *

This class provides a list iterator over a linked hash set. The constructor runs in constant time. + */ + private class SetIterator extends AbstractIntListIterator { + /** The entry that will be returned by the next call to {@link java.util.ListIterator#previous()} (or null if no previous entry exists). */ + int prev = -1; + /** The entry that will be returned by the next call to {@link java.util.ListIterator#next()} (or null if no next entry exists). */ + int next = -1; + /** The last entry that was returned (or -1 if we did not iterate or used {@link #remove()}). */ + int curr = -1; + /** The current index (in the sense of a {@link java.util.ListIterator}). When -1, we do not know the current index.*/ + int index = -1; + SetIterator() { + next = first; + index = 0; + } + SetIterator( int from ) { + if ( ( (from) == (0) ) ) { + if ( IntLinkedOpenHashSet.this.containsNull ) { + next = (int) link[ n ]; + prev = n; + return; + } + else throw new NoSuchElementException( "The key " + from + " does not belong to this set." ); + } + if ( ( (key[ last ]) == (from) ) ) { + prev = last; + index = size; + return; + } + // The starting point. + final int key[] = IntLinkedOpenHashSet.this.key; + int pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (from) ) ) & mask; + // There's always an unused entry. + while( ! ( (key[ pos ]) == (0) ) ) { + if ( ( (key[ pos ]) == (from) ) ) { + // Note: no valid index known. + next = (int) link[ pos ]; + prev = pos; + return; + } + pos = ( pos + 1 ) & mask; + } + throw new NoSuchElementException( "The key " + from + " does not belong to this set." ); + } + public boolean hasNext() { return next != -1; } + public boolean hasPrevious() { return prev != -1; } + public int nextInt() { + if ( ! hasNext() ) throw new NoSuchElementException(); + curr = next; + next = (int) link[ curr ]; + prev = curr; + if ( index >= 0 ) index++; + if ( ASSERTS ) assert curr == n || ! ( (key[ curr ]) == (0) ) : "Position " + curr + " is not used"; + return key[ curr ]; + } + public int previousInt() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + curr = prev; + prev = (int) ( link[ curr ] >>> 32 ); + next = curr; + if ( index >= 0 ) index--; + return key[ curr ]; + } + private final void ensureIndexKnown() { + if ( index >= 0 ) return; + if ( prev == -1 ) { + index = 0; + return; + } + if ( next == -1 ) { + index = size; + return; + } + int pos = first; + index = 1; + while( pos != prev ) { + pos = (int) link[ pos ]; + index++; + } + } + public int nextIndex() { + ensureIndexKnown(); + return index; + } + public int previousIndex() { + ensureIndexKnown(); + return index - 1; + } + public void remove() { + ensureIndexKnown(); + if ( curr == -1 ) throw new IllegalStateException(); + if ( curr == prev ) { + /* If the last operation was a next(), we are removing an entry that preceeds + the current index, and thus we must decrement it. */ + index--; + prev = (int) ( link[ curr ] >>> 32 ); + } + else + next = (int) link[ curr ]; + size--; + /* Now we manually fix the pointers. Because of our knowledge of next + and prev, this is going to be faster than calling fixPointers(). */ + if ( prev == -1 ) first = next; + else + link[ prev ] ^= ( ( link[ prev ] ^ ( next & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + if ( next == -1 ) last = prev; + else + link[ next ] ^= ( ( link[ next ] ^ ( ( prev & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + int last, slot, pos = curr; + curr = -1; + if ( pos == n ) { + IntLinkedOpenHashSet.this.containsNull = false; + IntLinkedOpenHashSet.this.key[ n ] = (0); + } + else { + int curr; + final int[] key = IntLinkedOpenHashSet.this.key; + // We have to horribly duplicate the shiftKeys() code because we need to update next/prev. + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( (curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + if ( next == pos ) next = last; + if ( prev == pos ) prev = last; + fixPointers( pos, last ); + } + } + } + } + /** Returns a type-specific list iterator on the elements in this set, starting from a given element of the set. + * Please see the class documentation for implementation details. + * + * @param from an element to start from. + * @return a type-specific list iterator starting at the given element. + * @throws IllegalArgumentException if from does not belong to the set. + */ + public IntListIterator iterator( int from ) { + return new SetIterator( from ); + } + public IntListIterator iterator() { + return new SetIterator(); + } + /** A no-op for backward compatibility. The kind of tables implemented by + * this class never need rehashing. + * + *

If you need to reduce the table size to fit exactly + * this set, use {@link #trim()}. + * + * @return true. + * @see #trim() + * @deprecated A no-op. + */ + @Deprecated + public boolean rehash() { + return true; + } + /** Rehashes this set, making the table as small as possible. + * + *

This method rehashes the table to the smallest size satisfying the + * load factor. It can be used when the set will not be changed anymore, so + * to optimize access speed and size. + * + *

If the table size is already the minimum possible, this method + * does nothing. + * + * @return true if there was enough memory to trim the set. + * @see #trim(int) + */ + public boolean trim() { + final int l = arraySize( size, f ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch(OutOfMemoryError cantDoIt) { return false; } + return true; + } + /** Rehashes this set if the table is too large. + * + *

Let N be the smallest table size that can hold + * max(n,{@link #size()}) entries, still satisfying the load factor. If the current + * table size is smaller than or equal to N, this method does + * nothing. Otherwise, it rehashes this set in a table of size + * N. + * + *

This method is useful when reusing sets. {@linkplain #clear() Clearing a + * set} leaves the table size untouched. If you are reusing a set + * many times, you can call this method with a typical + * size to avoid keeping around a very large table just + * because of a few large transient sets. + * + * @param n the threshold for the trimming. + * @return true if there was enough memory to trim the set. + * @see #trim() + */ + public boolean trim( final int n ) { + final int l = HashCommon.nextPowerOfTwo( (int)Math.ceil( n / f ) ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch( OutOfMemoryError cantDoIt ) { return false; } + return true; + } + /** Rehashes the set. + * + *

This method implements the basic rehashing strategy, and may be + * overriden by subclasses implementing different rehashing strategies (e.g., + * disk-based rehashing). However, you should not override this method + * unless you understand the internal workings of this class. + * + * @param newN the new size + */ + + protected void rehash( final int newN ) { + final int key[] = this.key; + final int mask = newN - 1; // Note that this is used by the hashing macro + final int newKey[] = new int[ newN + 1 ]; + int i = first, prev = -1, newPrev = -1, t, pos; + final long link[] = this.link; + final long newLink[] = new long[ newN + 1 ]; + first = -1; + for( int j = size; j-- != 0; ) { + if ( ( (key[ i ]) == (0) ) ) pos = newN; + else { + pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (key[ i ]) ) ) & mask; + while ( ! ( (newKey[ pos ]) == (0) ) ) pos = ( pos + 1 ) & mask; + } + newKey[ pos ] = key[ i ]; + if ( prev != -1 ) { + newLink[ newPrev ] ^= ( ( newLink[ newPrev ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + newLink[ pos ] ^= ( ( newLink[ pos ] ^ ( ( newPrev & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + newPrev = pos; + } + else { + newPrev = first = pos; + // Special case of SET(newLink[ pos ], -1, -1); + newLink[ pos ] = -1L; + } + t = i; + i = (int) link[ i ]; + prev = t; + } + this.link = newLink; + this.last = newPrev; + if ( newPrev != -1 ) + // Special case of SET_NEXT( newLink[ newPrev ], -1 ); + newLink[ newPrev ] |= -1 & 0xFFFFFFFFL; + n = newN; + this.mask = mask; + maxFill = maxFill( n, f ); + this.key = newKey; + } + /** Returns a deep copy of this set. + * + *

This method performs a deep copy of this hash set; the data stored in the + * set, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this set. + */ + + public IntLinkedOpenHashSet clone() { + IntLinkedOpenHashSet c; + try { + c = (IntLinkedOpenHashSet )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.key = key.clone(); + c.containsNull = containsNull; + c.link = link.clone(); + return c; + } + /** Returns a hash code for this set. + * + * This method overrides the generic method provided by the superclass. + * Since equals() is not overriden, it is important + * that the value returned by this method is the same value as + * the one returned by the overriden method. + * + * @return a hash code for this set. + */ + public int hashCode() { + int h = 0; + for( int j = realSize(), i = 0; j-- != 0; ) { + while( ( (key[ i ]) == (0) ) ) i++; + h += (key[ i ]); + i++; + } + // Zero / null have hash zero. + return h; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + final IntIterator i = iterator(); + s.defaultWriteObject(); + for( int j = size; j-- != 0; ) s.writeInt( i.nextInt() ); + } + + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + n = arraySize( size, f ); + maxFill = maxFill( n, f ); + mask = n - 1; + final int key[] = this.key = new int[ n + 1 ]; + final long link[] = this.link = new long[ n + 1 ]; + int prev = -1; + first = last = -1; + int k; + for( int i = size, pos; i-- != 0; ) { + k = s.readInt(); + if ( ( (k) == (0) ) ) { + pos = n; + containsNull = true; + } + else { + if ( ! ( (key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( (k) ) ) & mask ]) == (0) ) ) + while ( ! ( (key[ pos = ( pos + 1 ) & mask ]) == (0) ) ); + } + key[ pos ] = k; + if ( first != -1 ) { + link[ prev ] ^= ( ( link[ prev ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ pos ] ^= ( ( link[ pos ] ^ ( ( prev & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + prev = pos; + } + else { + prev = first = pos; + // Special case of SET_PREV( newLink[ pos ], -1 ); + link[ pos ] |= (-1L & 0xFFFFFFFFL) << 32; + } + } + last = prev; + if ( prev != -1 ) + // Special case of SET_NEXT( link[ prev ], -1 ); + link[ prev ] |= -1 & 0xFFFFFFFFL; + if ( ASSERTS ) checkTable(); + } + private void checkTable() {} +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntList.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntList.java new file mode 100644 index 0000000..b8aeebd --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntList.java @@ -0,0 +1,210 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.List; +/** A type-specific {@link List}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Note that this type-specific interface extends {@link Comparable}: it is expected that implementing + * classes perform a lexicographical comparison using the standard operator "less then" for primitive types, + * and the usual {@link Comparable#compareTo(Object) compareTo()} method for objects. + * + *

Additionally, this interface strengthens {@link #listIterator()}, + * {@link #listIterator(int)} and {@link #subList(int,int)}. + * + *

Besides polymorphic methods, this interfaces specifies methods to copy into an array or remove contiguous + * sublists. Although the abstract implementation of this interface provides simple, one-by-one implementations + * of these methods, it is expected that concrete implementation override them with optimized versions. + * + * @see List + */ +public interface IntList extends List, Comparable>, IntCollection { + /** Returns a type-specific iterator on the elements of this list (in proper sequence). + * + * Note that this specification strengthens the one given in {@link List#iterator()}. + * It would not be normally necessary, but {@link java.lang.Iterable#iterator()} is bizarrily re-specified + * in {@link List}. + * + * @return an iterator on the elements of this list (in proper sequence). + */ + IntListIterator iterator(); + /** Returns a type-specific list iterator on the list. + * + * @see #listIterator() + * @deprecated As of fastutil 5, replaced by {@link #listIterator()}. + */ + @Deprecated + IntListIterator intListIterator(); + /** Returns a type-specific list iterator on the list starting at a given index. + * + * @see #listIterator(int) + * @deprecated As of fastutil 5, replaced by {@link #listIterator(int)}. + */ + @Deprecated + IntListIterator intListIterator( int index ); + /** Returns a type-specific list iterator on the list. + * + * @see List#listIterator() + */ + IntListIterator listIterator(); + /** Returns a type-specific list iterator on the list starting at a given index. + * + * @see List#listIterator(int) + */ + IntListIterator listIterator( int index ); + /** Returns a type-specific view of the portion of this list from the index from, inclusive, to the index to, exclusive. + * @see List#subList(int,int) + * @deprecated As of fastutil 5, replaced by {@link #subList(int,int)}. + */ + @Deprecated + IntList intSubList( int from, int to ); + /** Returns a type-specific view of the portion of this list from the index from, inclusive, to the index to, exclusive. + * + *

Note that this specification strengthens the one given in {@link List#subList(int,int)}. + * + * @see List#subList(int,int) + */ + IntList subList(int from, int to); + /** Sets the size of this list. + * + *

If the specified size is smaller than the current size, the last elements are + * discarded. Otherwise, they are filled with 0/null/false. + * + * @param size the new size. + */ + void size( int size ); + /** Copies (hopefully quickly) elements of this type-specific list into the given array. + * + * @param from the start index (inclusive). + * @param a the destination array. + * @param offset the offset into the destination array where to store the first element copied. + * @param length the number of elements to be copied. + */ + void getElements( int from, int a[], int offset, int length ); + /** Removes (hopefully quickly) elements of this type-specific list. + * + * @param from the start index (inclusive). + * @param to the end index (exclusive). + */ + void removeElements( int from, int to ); + /** Add (hopefully quickly) elements to this type-specific list. + * + * @param index the index at which to add elements. + * @param a the array containing the elements. + */ + void addElements( int index, int a[] ); + /** Add (hopefully quickly) elements to this type-specific list. + * + * @param index the index at which to add elements. + * @param a the array containing the elements. + * @param offset the offset of the first element to add. + * @param length the number of elements to add. + */ + void addElements( int index, int a[], int offset, int length ); + /** + * @see List#add(Object) + */ + boolean add( int key ); + /** + * @see List#add(int,Object) + */ + void add( int index, int key ); + /** + * @see List#add(int,Object) + */ + boolean addAll( int index, IntCollection c ); + /** + * @see List#add(int,Object) + */ + boolean addAll( int index, IntList c ); + /** + * @see List#add(int,Object) + */ + boolean addAll( IntList c ); + /** + * @see List#get(int) + */ + int getInt( int index ); + /** + * @see List#indexOf(Object) + */ + int indexOf( int k ); + /** + * @see List#lastIndexOf(Object) + */ + int lastIndexOf( int k ); + /** + * @see List#remove(int) + */ + int removeInt( int index ); + /** + * @see List#set(int,Object) + */ + int set( int index, int k ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntListIterator.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntListIterator.java new file mode 100644 index 0000000..758146f --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntListIterator.java @@ -0,0 +1,85 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.ListIterator; +/** A type-specific bidirectional iterator that is also a {@link ListIterator}. + * + *

This interface merges the methods provided by a {@link ListIterator} and + * a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator}. Moreover, it provides + * type-specific versions of {@link java.util.ListIterator#add(Object) add()} + * and {@link java.util.ListIterator#set(Object) set()}. + * + * @see java.util.ListIterator + * @see it.unimi.dsi.fastutil.BidirectionalIterator + */ +public interface IntListIterator extends ListIterator, IntBidirectionalIterator { + void set( int k ); + void add( int k ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntLists.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntLists.java new file mode 100644 index 0000000..ea909a8 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntLists.java @@ -0,0 +1,334 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.List; +import java.util.Collection; +import java.util.Random; +/** A class providing static methods and objects that do useful things with type-specific lists. + * + * @see java.util.Collections + */ +public class IntLists { + private IntLists() {} + /** Shuffles the specified list using the specified pseudorandom number generator. + * + * @param l the list to be shuffled. + * @param random a pseudorandom number generator (please use a XorShift* generator). + * @return l. + */ + public static IntList shuffle( final IntList l, final Random random ) { + for( int i = l.size(); i-- != 0; ) { + final int p = random.nextInt( i + 1 ); + final int t = l.getInt( i ); + l.set( i, l.getInt( p ) ); + l.set( p, t ); + } + return l; + } + /** An immutable class representing an empty type-specific list. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific list. + */ + public static class EmptyList extends IntCollections.EmptyCollection implements IntList , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptyList() {} + public void add( final int index, final int k ) { throw new UnsupportedOperationException(); } + public boolean add( final int k ) { throw new UnsupportedOperationException(); } + public int removeInt( int i ) { throw new UnsupportedOperationException(); } + public int set( final int index, final int k ) { throw new UnsupportedOperationException(); } + public int indexOf( int k ) { return -1; } + public int lastIndexOf( int k ) { return -1; } + public boolean addAll( Collection c ) { throw new UnsupportedOperationException(); } + public boolean addAll( int i, Collection c ) { throw new UnsupportedOperationException(); } + public boolean removeAll( Collection c ) { throw new UnsupportedOperationException(); } + public Integer get( int i ) { throw new IndexOutOfBoundsException(); } + public boolean addAll( IntCollection c ) { throw new UnsupportedOperationException(); } + public boolean addAll( IntList c ) { throw new UnsupportedOperationException(); } + public boolean addAll( int i, IntCollection c ) { throw new UnsupportedOperationException(); } + public boolean addAll( int i, IntList c ) { throw new UnsupportedOperationException(); } + public void add( final int index, final Integer k ) { throw new UnsupportedOperationException(); } + public boolean add( final Integer k ) { throw new UnsupportedOperationException(); } + public Integer set( final int index, final Integer k ) { throw new UnsupportedOperationException(); } + public int getInt( int i ) { throw new IndexOutOfBoundsException(); } + public Integer remove( int k ) { throw new UnsupportedOperationException(); } + public int indexOf( Object k ) { return -1; } + public int lastIndexOf( Object k ) { return -1; } + //SUPPRESS_WARNINGS_KEY_UNCHECKED + //public KEY_ITERATOR KEY_GENERIC iterator( int i ) { if ( i == 0 ) return ITERATORS.EMPTY_ITERATOR; throw new IndexOutOfBoundsException( String.valueOf( i ) ); } + @Deprecated + + public IntIterator intIterator() { return IntIterators.EMPTY_ITERATOR; } + + public IntListIterator listIterator() { return IntIterators.EMPTY_ITERATOR; } + + public IntListIterator iterator() { return IntIterators.EMPTY_ITERATOR; } + + public IntListIterator listIterator( int i ) { if ( i == 0 ) return IntIterators.EMPTY_ITERATOR; throw new IndexOutOfBoundsException( String.valueOf( i ) ); } + @Deprecated + public IntListIterator intListIterator() { return listIterator(); } + @Deprecated + public IntListIterator intListIterator( int i ) { return listIterator( i ); } + public IntList subList( int from, int to ) { if ( from == 0 && to == 0 ) return this; throw new IndexOutOfBoundsException(); } + @Deprecated + public IntList intSubList( int from, int to ) { return subList( from, to ); } + public void getElements( int from, int[] a, int offset, int length ) { if ( from == 0 && length == 0 && offset >= 0 && offset <= a.length ) return; throw new IndexOutOfBoundsException(); } + public void removeElements( int from, int to ) { throw new UnsupportedOperationException(); } + public void addElements( int index, final int a[], int offset, int length ) { throw new UnsupportedOperationException(); } + public void addElements( int index, final int a[] ) { throw new UnsupportedOperationException(); } + public void size( int s ) { throw new UnsupportedOperationException(); } + public int compareTo( final List o ) { + if ( o == this ) return 0; + return ((List)o).isEmpty() ? 0 : -1; + } + private Object readResolve() { return EMPTY_LIST; } + public Object clone() { return EMPTY_LIST; } + public int hashCode() { return 1; } + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { return o instanceof List && ((List)o).isEmpty(); } + public String toString() { return "[]"; } + } + /** An empty list (immutable). It is serializable and cloneable. + */ + + public static final EmptyList EMPTY_LIST = new EmptyList(); + /** An immutable class representing a type-specific singleton list. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific list. + */ + public static class Singleton extends AbstractIntList implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + private final int element; + private Singleton( final int element ) { + this.element = element; + } + public int getInt( final int i ) { if ( i == 0 ) return element; throw new IndexOutOfBoundsException(); } + public int removeInt( final int i ) { throw new UnsupportedOperationException(); } + public boolean contains( final int k ) { return ( (k) == (element) ); } + public boolean addAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean addAll( final int i, final Collection c ) { throw new UnsupportedOperationException(); } + public boolean removeAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( final Collection c ) { throw new UnsupportedOperationException(); } + /* Slightly optimized w.r.t. the one in ABSTRACT_SET. */ + public int[] toIntArray() { + int a[] = new int[ 1 ]; + a[ 0 ] = element; + return a; + } + public IntListIterator listIterator() { return IntIterators.singleton( element ); } + public IntListIterator iterator() { return listIterator(); } + public IntListIterator listIterator( int i ) { + if ( i > 1 || i < 0 ) throw new IndexOutOfBoundsException(); + IntListIterator l = listIterator(); + if ( i == 1 ) l.next(); + return l; + } + + public IntList subList( final int from, final int to ) { + ensureIndex( from ); + ensureIndex( to ); + if ( from > to ) throw new IndexOutOfBoundsException( "Start index (" + from + ") is greater than end index (" + to + ")" ); + if ( from != 0 || to != 1 ) return EMPTY_LIST; + return this; + } + public int size() { return 1; } + public void size( final int size ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + public Object clone() { return this; } + public boolean rem( final int k ) { throw new UnsupportedOperationException(); } + public boolean addAll( final IntCollection c ) { throw new UnsupportedOperationException(); } + public boolean addAll( final int i, final IntCollection c ) { throw new UnsupportedOperationException(); } + } + /** Returns a type-specific immutable list containing only the specified element. The returned list is serializable and cloneable. + * + * @param element the only element of the returned list. + * @return a type-specific immutable list containing just element. + */ + public static IntList singleton( final int element ) { return new Singleton ( element ); } + /** Returns a type-specific immutable list containing only the specified element. The returned list is serializable and cloneable. + * + * @param element the only element of the returned list. + * @return a type-specific immutable list containing just element. + */ + public static IntList singleton( final Object element ) { return new Singleton ( ((((Integer)(element)).intValue())) ); } + /** A synchronized wrapper class for lists. */ + public static class SynchronizedList extends IntCollections.SynchronizedCollection implements IntList , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final IntList list; // Due to the large number of methods that are not in COLLECTION, this is worth caching. + protected SynchronizedList( final IntList l, final Object sync ) { + super( l, sync ); + this.list = l; + } + protected SynchronizedList( final IntList l ) { + super( l ); + this.list = l; + } + public int getInt( final int i ) { synchronized( sync ) { return list.getInt( i ); } } + public int set( final int i, final int k ) { synchronized( sync ) { return list.set( i, k ); } } + public void add( final int i, final int k ) { synchronized( sync ) { list.add( i, k ); } } + public int removeInt( final int i ) { synchronized( sync ) { return list.removeInt( i ); } } + public int indexOf( final int k ) { synchronized( sync ) { return list.indexOf( k ); } } + public int lastIndexOf( final int k ) { synchronized( sync ) { return list.lastIndexOf( k ); } } + public boolean addAll( final int index, final Collection c ) { synchronized( sync ) { return list.addAll( index, c ); } } + public void getElements( final int from, final int a[], final int offset, final int length ) { synchronized( sync ) { list.getElements( from, a, offset, length ); } } + public void removeElements( final int from, final int to ) { synchronized( sync ) { list.removeElements( from, to ); } } + public void addElements( int index, final int a[], int offset, int length ) { synchronized( sync ) { list.addElements( index, a, offset, length ); } } + public void addElements( int index, final int a[] ) { synchronized( sync ) { list.addElements( index, a ); } } + public void size( final int size ) { synchronized( sync ) { list.size( size ); } } + public IntListIterator iterator() { return list.listIterator(); } + public IntListIterator listIterator() { return list.listIterator(); } + public IntListIterator listIterator( final int i ) { return list.listIterator( i ); } + @Deprecated + public IntListIterator intListIterator() { return listIterator(); } + @Deprecated + public IntListIterator intListIterator( final int i ) { return listIterator( i ); } + public IntList subList( final int from, final int to ) { synchronized( sync ) { return synchronize( list.subList( from, to ), sync ); } } + @Deprecated + public IntList intSubList( final int from, final int to ) { return subList( from, to ); } + public boolean equals( final Object o ) { synchronized( sync ) { return collection.equals( o ); } } + public int hashCode() { synchronized( sync ) { return collection.hashCode(); } } + public int compareTo( final List o ) { synchronized( sync ) { return list.compareTo( o ); } } + public boolean addAll( final int index, final IntCollection c ) { synchronized( sync ) { return list.addAll( index, c ); } } + public boolean addAll( final int index, IntList l ) { synchronized( sync ) { return list.addAll( index, l ); } } + public boolean addAll( IntList l ) { synchronized( sync ) { return list.addAll( l ); } } + public Integer get( final int i ) { synchronized( sync ) { return list.get( i ); } } + public void add( final int i, Integer k ) { synchronized( sync ) { list.add( i, k ); } } + public Integer set( final int index, Integer k ) { synchronized( sync ) { return list.set( index, k ); } } + public Integer remove( final int i ) { synchronized( sync ) { return list.remove( i ); } } + public int indexOf( final Object o ) { synchronized( sync ) { return list.indexOf( o ); } } + public int lastIndexOf( final Object o ) { synchronized( sync ) { return list.lastIndexOf( o ); } } + } + /** Returns a synchronized type-specific list backed by the given type-specific list. + * + * @param l the list to be wrapped in a synchronized list. + * @return a synchronized view of the specified list. + * @see java.util.Collections#synchronizedList(List) + */ + public static IntList synchronize( final IntList l ) { return new SynchronizedList ( l ); } + /** Returns a synchronized type-specific list backed by the given type-specific list, using an assigned object to synchronize. + * + * @param l the list to be wrapped in a synchronized list. + * @param sync an object that will be used to synchronize the access to the list. + * @return a synchronized view of the specified list. + * @see java.util.Collections#synchronizedList(List) + */ + public static IntList synchronize( final IntList l, final Object sync ) { return new SynchronizedList ( l, sync ); } + /** An unmodifiable wrapper class for lists. */ + public static class UnmodifiableList extends IntCollections.UnmodifiableCollection implements IntList , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final IntList list; // Due to the large number of methods that are not in COLLECTION, this is worth caching. + protected UnmodifiableList( final IntList l ) { + super( l ); + this.list = l; + } + public int getInt( final int i ) { return list.getInt( i ); } + public int set( final int i, final int k ) { throw new UnsupportedOperationException(); } + public void add( final int i, final int k ) { throw new UnsupportedOperationException(); } + public int removeInt( final int i ) { throw new UnsupportedOperationException(); } + public int indexOf( final int k ) { return list.indexOf( k ); } + public int lastIndexOf( final int k ) { return list.lastIndexOf( k ); } + public boolean addAll( final int index, final Collection c ) { throw new UnsupportedOperationException(); } + public void getElements( final int from, final int a[], final int offset, final int length ) { list.getElements( from, a, offset, length ); } + public void removeElements( final int from, final int to ) { throw new UnsupportedOperationException(); } + public void addElements( int index, final int a[], int offset, int length ) { throw new UnsupportedOperationException(); } + public void addElements( int index, final int a[] ) { throw new UnsupportedOperationException(); } + public void size( final int size ) { list.size( size ); } + public IntListIterator iterator() { return listIterator(); } + public IntListIterator listIterator() { return IntIterators.unmodifiable( list.listIterator() ); } + public IntListIterator listIterator( final int i ) { return IntIterators.unmodifiable( list.listIterator( i ) ); } + @Deprecated + public IntListIterator intListIterator() { return listIterator(); } + @Deprecated + public IntListIterator intListIterator( final int i ) { return listIterator( i ); } + public IntList subList( final int from, final int to ) { return unmodifiable( list.subList( from, to ) ); } + @Deprecated + public IntList intSubList( final int from, final int to ) { return subList( from, to ); } + public boolean equals( final Object o ) { return collection.equals( o ); } + public int hashCode() { return collection.hashCode(); } + public int compareTo( final List o ) { return list.compareTo( o ); } + public boolean addAll( final int index, final IntCollection c ) { throw new UnsupportedOperationException(); } + public boolean addAll( final IntList l ) { throw new UnsupportedOperationException(); } + public boolean addAll( final int index, final IntList l ) { throw new UnsupportedOperationException(); } + public Integer get( final int i ) { return list.get( i ); } + public void add( final int i, Integer k ) { throw new UnsupportedOperationException(); } + public Integer set( final int index, Integer k ) { throw new UnsupportedOperationException(); } + public Integer remove( final int i ) { throw new UnsupportedOperationException(); } + public int indexOf( final Object o ) { return list.indexOf( o ); } + public int lastIndexOf( final Object o ) { return list.lastIndexOf( o ); } + } + /** Returns an unmodifiable type-specific list backed by the given type-specific list. + * + * @param l the list to be wrapped in an unmodifiable list. + * @return an unmodifiable view of the specified list. + * @see java.util.Collections#unmodifiableList(List) + */ + public static IntList unmodifiable( final IntList l ) { return new UnmodifiableList ( l ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntPriorityQueue.java new file mode 100644 index 0000000..7517420 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntPriorityQueue.java @@ -0,0 +1,108 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.NoSuchElementException; +import it.unimi.dsi.fastutil.PriorityQueue; +/** A type-specific {@link PriorityQueue}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Additionally, this interface strengthens {@link #comparator()}. + */ +public interface IntPriorityQueue extends PriorityQueue { + /** Enqueues a new element. + * + * @param x the element to enqueue. + */ + void enqueue( int x ); + /** Dequeues the {@linkplain #first() first} element from the queue. + * + * @return the dequeued element. + * @throws NoSuchElementException if the queue is empty. + */ + int dequeueInt(); + /** Returns the first element of the queue. + * + * @return the first element. + * @throws NoSuchElementException if the queue is empty. + */ + int firstInt(); + /** Returns the last element of the queue, that is, the element the would be dequeued last (optional operation). + * + * @return the last element. + * @throws NoSuchElementException if the queue is empty. + */ + int lastInt(); + /** Returns the comparator associated with this sorted set, or null if it uses its elements' natural ordering. + * + *

Note that this specification strengthens the one given in {@link PriorityQueue#comparator()}. + * + * @see PriorityQueue#comparator() + */ + IntComparator comparator(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntPriorityQueues.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntPriorityQueues.java new file mode 100644 index 0000000..4d54aa0 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntPriorityQueues.java @@ -0,0 +1,116 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +/** A class providing static methods and objects that do useful things with type-specific priority queues. + * + * @see it.unimi.dsi.fastutil.PriorityQueue + */ +public class IntPriorityQueues { + private IntPriorityQueues() {} + /** A synchronized wrapper class for priority queues. */ + public static class SynchronizedPriorityQueue implements IntPriorityQueue { + final protected IntPriorityQueue q; + final protected Object sync; + protected SynchronizedPriorityQueue( final IntPriorityQueue q, final Object sync ) { + this.q = q; + this.sync = sync; + } + protected SynchronizedPriorityQueue( final IntPriorityQueue q ) { + this.q = q; + this.sync = this; + } + public void enqueue( int x ) { synchronized( sync ) { q.enqueue( x ); } } + public int dequeueInt() { synchronized( sync ) { return q.dequeueInt(); } } + public int firstInt() { synchronized( sync ) { return q.firstInt(); } } + public int lastInt() { synchronized( sync ) { return q.lastInt(); } } + public boolean isEmpty() { synchronized( sync ) { return q.isEmpty(); } } + public int size() { synchronized( sync ) { return q.size(); } } + public void clear() { synchronized( sync ) { q.clear(); } } + public void changed() { synchronized( sync ) { q.changed(); } } + public IntComparator comparator() { synchronized( sync ) { return q.comparator(); } } + public void enqueue( Integer x ) { synchronized( sync ) { q.enqueue( x ); } } + public Integer dequeue() { synchronized( sync ) { return q.dequeue(); } } + public Integer first() { synchronized( sync ) { return q.first(); } } + public Integer last() { synchronized( sync ) { return q.last(); } } + } + /** Returns a synchronized type-specific priority queue backed by the specified type-specific priority queue. + * + * @param q the priority queue to be wrapped in a synchronized priority queue. + * @return a synchronized view of the specified priority queue. + */ + public static IntPriorityQueue synchronize( final IntPriorityQueue q ) { return new SynchronizedPriorityQueue( q ); } + /** Returns a synchronized type-specific priority queue backed by the specified type-specific priority queue, using an assigned object to synchronize. + * + * @param q the priority queue to be wrapped in a synchronized priority queue. + * @param sync an object that will be used to synchronize the access to the priority queue. + * @return a synchronized view of the specified priority queue. + */ + public static IntPriorityQueue synchronize( final IntPriorityQueue q, final Object sync ) { return new SynchronizedPriorityQueue( q, sync ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntSemiIndirectHeaps.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntSemiIndirectHeaps.java new file mode 100644 index 0000000..9e517f5 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntSemiIndirectHeaps.java @@ -0,0 +1,268 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.ints.IntArrays; +/** A class providing static methods and objects that do useful things with semi-indirect heaps. + * + *

A semi-indirect heap is based on a reference array. Elements of + * a semi-indirect heap are integers that index the reference array (note that + * in an indirect heap you can also map elements of the reference + * array to heap positions). + */ +public class IntSemiIndirectHeaps { + private IntSemiIndirectHeaps() {} + /** Moves the given element down into the semi-indirect heap until it reaches the lowest possible position. + * + * @param refArray the reference array. + * @param heap the semi-indirect heap (starting at 0). + * @param size the number of elements in the heap. + * @param i the index in the heap of the element to be moved down. + * @param c a type-specific comparator, or null for the natural order. + * @return the new position in the heap of the element of heap index i. + */ + + public static int downHeap( final int[] refArray, final int[] heap, final int size, int i, final IntComparator c ) { + assert i < size; + final int e = heap[ i ]; + final int E = refArray[ e ]; + int child; + if ( c == null ) + while ( ( child = ( i << 1 ) + 1 ) < size ) { + int t = heap[ child ]; + final int right = child + 1; + if ( right < size && ( (refArray[ heap[ right ] ]) < (refArray[ t ]) ) ) t = heap[ child = right ]; + if ( ( (E) <= (refArray[ t ]) ) ) break; + heap[ i ] = t; + i = child; + } + else + while ( ( child = ( i << 1 ) + 1 ) < size ) { + int t = heap[ child ]; + final int right = child + 1; + if ( right < size && c.compare( refArray[ heap[ right ] ], refArray[ t ] ) < 0 ) t = heap[ child = right ]; + if ( c.compare( E, refArray[ t ] ) <= 0 ) break; + heap[ i ] = t; + i = child; + } + heap[ i ] = e; + return i; + } + /** Moves the given element up in the semi-indirect heap until it reaches the highest possible position. + * + * @param refArray the reference array. + * @param heap the semi-indirect heap (starting at 0). + * @param size the number of elements in the heap. + * @param i the index in the heap of the element to be moved up. + * @param c a type-specific comparator, or null for the natural order. + * @return the new position in the heap of the element of heap index i. + */ + + public static int upHeap( final int[] refArray, final int[] heap, final int size, int i, final IntComparator c ) { + assert i < size; + final int e = heap[ i ]; + final int E = refArray[ e ]; + if ( c == null ) + while ( i != 0 ) { + final int parent = ( i - 1 ) >>> 1; + final int t = heap[ parent ]; + if ( ( (refArray[ t ]) <= (E) ) ) break; + heap[ i ] = t; + i = parent; + } + else + while ( i != 0 ) { + final int parent = ( i - 1 ) >>> 1; + final int t = heap[ parent ]; + if ( c.compare( refArray[ t ], E ) <= 0 ) break; + heap[ i ] = t; + i = parent; + } + heap[ i ] = e; + return i; + } + /** Creates a semi-indirect heap in the given array. + * + * @param refArray the reference array. + * @param offset the first element of the reference array to be put in the heap. + * @param length the number of elements to be put in the heap. + * @param heap the array where the heap is to be created. + * @param c a type-specific comparator, or null for the natural order. + */ + public static void makeHeap( final int[] refArray, final int offset, final int length, final int[] heap, final IntComparator c ) { + IntArrays.ensureOffsetLength( refArray, offset, length ); + if ( heap.length < length ) throw new IllegalArgumentException( "The heap length (" + heap.length + ") is smaller than the number of elements (" + length + ")" ); + int i = length; + while( i-- != 0 ) heap[ i ] = offset + i; + i = length >>> 1; + while( i-- != 0 ) downHeap( refArray, heap, length, i, c ); + } + /** Creates a semi-indirect heap, allocating its heap array. + * + * @param refArray the reference array. + * @param offset the first element of the reference array to be put in the heap. + * @param length the number of elements to be put in the heap. + * @param c a type-specific comparator, or null for the natural order. + * @return the heap array. + */ + public static int[] makeHeap( final int[] refArray, final int offset, final int length, final IntComparator c ) { + final int[] heap = length <= 0 ? IntArrays.EMPTY_ARRAY : new int[ length ]; + makeHeap( refArray, offset, length, heap, c ); + return heap; + } + /** Creates a semi-indirect heap from a given index array. + * + * @param refArray the reference array. + * @param heap an array containing indices into refArray. + * @param size the number of elements in the heap. + * @param c a type-specific comparator, or null for the natural order. + */ + public static void makeHeap( final int[] refArray, final int[] heap, final int size, final IntComparator c ) { + int i = size >>> 1; + while( i-- != 0 ) downHeap( refArray, heap, size, i, c ); + } + /** Retrieves the front of a heap in a given array. + * + *

The front of a semi-indirect heap is the set of indices whose associated elements in the reference array + * are equal to the element associated to the first index. + * + *

In several circumstances you need to know the front, and scanning linearly the entire heap is not + * the best strategy. This method simulates (using a partial linear scan) a breadth-first visit that + * terminates when all visited nodes are larger than the element associated + * to the top index, which implies that no elements of the front can be found later. + * In most cases this trick yields a significant improvement. + * + * @param refArray the reference array. + * @param heap an array containing indices into refArray. + * @param size the number of elements in the heap. + * @param a an array large enough to hold the front (e.g., at least long as refArray). + * @return the number of elements actually written (starting from the first position of a). + */ + + public static int front( final int[] refArray, final int[] heap, final int size, final int[] a ) { + final int top = refArray[ heap[ 0 ] ]; + int j = 0, // The current position in a + l = 0, // The first position to visit in the next level (inclusive) + r = 1, // The last position to visit in the next level (exclusive) + f = 0; // The first position (in the heap array) of the next level + for( int i = 0; i < r; i++ ) { + if ( i == f ) { // New level + if ( l >= r ) break; // If we are crossing the two bounds, we're over + f = (f << 1) + 1; // Update the first position of the next level... + i = l; // ...and jump directly to position l + l = -1; // Invalidate l + } + if ( ( (top) == (refArray[ heap[ i ] ]) ) ) { + a[ j++ ] = heap[ i ]; + if ( l == -1 ) l = i * 2 + 1; // If this is the first time in this level, set l + r = Math.min( size, i * 2 + 3 ); // Update r, but do not go beyond size + } + } + return j; + } + /** Retrieves the front of a heap in a given array using a given comparator. + * + *

The front of a semi-indirect heap is the set of indices whose associated elements in the reference array + * are equal to the element associated to the first index. + * + *

In several circumstances you need to know the front, and scanning linearly the entire heap is not + * the best strategy. This method simulates (using a partial linear scan) a breadth-first visit that + * terminates when all visited nodes are larger than the element associated + * to the top index, which implies that no elements of the front can be found later. + * In most cases this trick yields a significant improvement. + * + * @param refArray the reference array. + * @param heap an array containing indices into refArray. + * @param size the number of elements in the heap. + * @param a an array large enough to hold the front (e.g., at least long as refArray). + * @param c a type-specific comparator. + * @return the number of elements actually written (starting from the first position of a). + */ + public static int front( final int[] refArray, final int[] heap, final int size, final int[] a, final IntComparator c ) { + final int top = refArray[ heap[ 0 ] ]; + int j = 0, // The current position in a + l = 0, // The first position to visit in the next level (inclusive) + r = 1, // The last position to visit in the next level (exclusive) + f = 0; // The first position (in the heap array) of the next level + for( int i = 0; i < r; i++ ) { + if ( i == f ) { // New level + if ( l >= r ) break; // If we are crossing the two bounds, we're over + f = (f << 1) + 1; // Update the first position of the next level... + i = l; // ...and jump directly to position l + l = -1; // Invalidate l + } + if ( c.compare( top, refArray[ heap[ i ] ] ) == 0 ) { + a[ j++ ] = heap[ i ]; + if ( l == -1 ) l = i * 2 + 1; // If this is the first time in this level, set l + r = Math.min( size, i * 2 + 3 ); // Update r, but do not go beyond size + } + } + return j; + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntSet.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntSet.java new file mode 100644 index 0000000..9d8a21f --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntSet.java @@ -0,0 +1,97 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.Set; +/** A type-specific {@link Set}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Additionally, this interface strengthens (again) {@link #iterator()}. + * + * @see Set + */ +public interface IntSet extends IntCollection , Set { + /** Returns a type-specific iterator on the elements of this set. + * + *

Note that this specification strengthens the one given in {@link java.lang.Iterable#iterator()}, + * which was already strengthened in the corresponding type-specific class, + * but was weakened by the fact that this interface extends {@link Set}. + * + * @return a type-specific iterator on the elements of this set. + */ + IntIterator iterator(); + /** Removes an element from this set. + * + *

Note that the corresponding method of the type-specific collection is rem(). + * This unfortunate situation is caused by the clash + * with the similarly named index-based method in the {@link java.util.List} interface. + * + * @see java.util.Collection#remove(Object) + */ + public boolean remove( int k ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntSets.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntSets.java new file mode 100644 index 0000000..69c8c44 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntSets.java @@ -0,0 +1,186 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.Collection; +import java.util.Set; +/** A class providing static methods and objects that do useful things with type-specific sets. + * + * @see java.util.Collections + */ +public class IntSets { + private IntSets() {} + /** An immutable class representing the empty set and implementing a type-specific set interface. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific set. + */ + public static class EmptySet extends IntCollections.EmptyCollection implements IntSet , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptySet() {} + public boolean remove( int ok ) { throw new UnsupportedOperationException(); } + public Object clone() { return EMPTY_SET; } + @SuppressWarnings("rawtypes") + public boolean equals( final Object o ) { return o instanceof Set && ((Set)o).isEmpty(); } + private Object readResolve() { return EMPTY_SET; } + } + /** An empty set (immutable). It is serializable and cloneable. + */ + + public static final EmptySet EMPTY_SET = new EmptySet(); + /** An immutable class representing a type-specific singleton set. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific set. */ + public static class Singleton extends AbstractIntSet implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected final int element; + protected Singleton( final int element ) { + this.element = element; + } + public boolean add( final int k ) { throw new UnsupportedOperationException(); } + public boolean contains( final int k ) { return ( (k) == (element) ); } + public boolean addAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean removeAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( final Collection c ) { throw new UnsupportedOperationException(); } + /* Slightly optimized w.r.t. the one in ABSTRACT_SET. */ + public int[] toIntArray() { + int a[] = new int[ 1 ]; + a[ 0 ] = element; + return a; + } + public boolean addAll( final IntCollection c ) { throw new UnsupportedOperationException(); } + public boolean removeAll( final IntCollection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( final IntCollection c ) { throw new UnsupportedOperationException(); } + public IntListIterator iterator() { return IntIterators.singleton( element ); } + public int size() { return 1; } + public Object clone() { return this; } + } + /** Returns a type-specific immutable set containing only the specified element. The returned set is serializable and cloneable. + * + * @param element the only element of the returned set. + * @return a type-specific immutable set containing just element. + */ + public static IntSet singleton( final int element ) { + return new Singleton ( element ); + } + /** Returns a type-specific immutable set containing only the specified element. The returned set is serializable and cloneable. + * + * @param element the only element of the returned set. + * @return a type-specific immutable set containing just element. + */ + public static IntSet singleton( final Integer element ) { + return new Singleton ( ((element).intValue()) ); + } + /** A synchronized wrapper class for sets. */ + public static class SynchronizedSet extends IntCollections.SynchronizedCollection implements IntSet , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected SynchronizedSet( final IntSet s, final Object sync ) { + super( s, sync ); + } + protected SynchronizedSet( final IntSet s ) { + super( s ); + } + public boolean remove( final int k ) { synchronized( sync ) { return collection.remove( (Integer.valueOf(k)) ); } } + public boolean equals( final Object o ) { synchronized( sync ) { return collection.equals( o ); } } + public int hashCode() { synchronized( sync ) { return collection.hashCode(); } } + } + /** Returns a synchronized type-specific set backed by the given type-specific set. + * + * @param s the set to be wrapped in a synchronized set. + * @return a synchronized view of the specified set. + * @see java.util.Collections#synchronizedSet(Set) + */ + public static IntSet synchronize( final IntSet s ) { return new SynchronizedSet ( s ); } + /** Returns a synchronized type-specific set backed by the given type-specific set, using an assigned object to synchronize. + * + * @param s the set to be wrapped in a synchronized set. + * @param sync an object that will be used to synchronize the access to the set. + * @return a synchronized view of the specified set. + * @see java.util.Collections#synchronizedSet(Set) + */ + public static IntSet synchronize( final IntSet s, final Object sync ) { return new SynchronizedSet ( s, sync ); } + /** An unmodifiable wrapper class for sets. */ + public static class UnmodifiableSet extends IntCollections.UnmodifiableCollection implements IntSet , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected UnmodifiableSet( final IntSet s ) { + super( s ); + } + public boolean remove( final int k ) { throw new UnsupportedOperationException(); } + public boolean equals( final Object o ) { return collection.equals( o ); } + public int hashCode() { return collection.hashCode(); } + } + /** Returns an unmodifiable type-specific set backed by the given type-specific set. + * + * @param s the set to be wrapped in an unmodifiable set. + * @return an unmodifiable view of the specified set. + * @see java.util.Collections#unmodifiableSet(Set) + */ + public static IntSet unmodifiable( final IntSet s ) { return new UnmodifiableSet ( s ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntSortedSet.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntSortedSet.java new file mode 100644 index 0000000..ba95523 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntSortedSet.java @@ -0,0 +1,179 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.SortedSet; +import java.util.Collection; +/** A type-specific {@link SortedSet}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Additionally, this interface strengthens {@link #iterator()}, + * {@link #comparator()} (for primitive types), {@link SortedSet#subSet(Object,Object)}, + * {@link SortedSet#headSet(Object)} and {@link SortedSet#tailSet(Object)}. + * + * @see SortedSet + */ +public interface IntSortedSet extends IntSet , SortedSet { + /** Returns a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator} on the elements in + * this set, starting from a given element of the domain (optional operation). + * + *

This method returns a type-specific bidirectional iterator with given + * starting point. The starting point is any element comparable to the + * elements of this set (even if it does not actually belong to the + * set). The next element of the returned iterator is the least element of + * the set that is greater than the starting point (if there are no + * elements greater than the starting point, {@link + * it.unimi.dsi.fastutil.BidirectionalIterator#hasNext() hasNext()} will return + * false). The previous element of the returned iterator is + * the greatest element of the set that is smaller than or equal to the + * starting point (if there are no elements smaller than or equal to the + * starting point, {@link it.unimi.dsi.fastutil.BidirectionalIterator#hasPrevious() + * hasPrevious()} will return false). + * + *

Note that passing the last element of the set as starting point and + * calling {@link it.unimi.dsi.fastutil.BidirectionalIterator#previous() previous()} you can traverse the + * entire set in reverse order. + * + * @param fromElement an element to start from. + * @return a bidirectional iterator on the element in this set, starting at the given element. + * @throws UnsupportedOperationException if this set does not support iterators with a starting point. + */ + IntBidirectionalIterator iterator( int fromElement ); + /** Returns a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator} iterator on the collection. + * + *

The iterator returned by the {@link #iterator()} method and by this + * method are identical; however, using this method you can save a type casting. + * + * Note that this specification strengthens the one given in the corresponding type-specific + * {@link Collection}. + * + * @deprecated As of fastutil 5, replaced by {@link #iterator()}. + */ + @Deprecated + IntBidirectionalIterator intIterator(); + /** Returns a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator} on the elements in + * this set. + * + *

This method returns a parameterised bidirectional iterator. The iterator + * can be moreover safely cast to a type-specific iterator. + * + * Note that this specification strengthens the one given in the corresponding type-specific + * {@link Collection}. + * + * @return a bidirectional iterator on the element in this set. + */ + IntBidirectionalIterator iterator(); + /** Returns a view of the portion of this sorted set whose elements range from fromElement, inclusive, to toElement, exclusive. + * + *

Note that this specification strengthens the one given in {@link SortedSet#subSet(Object,Object)}. + * + * @see SortedSet#subSet(Object,Object) + */ + IntSortedSet subSet( Integer fromElement, Integer toElement) ; + /** Returns a view of the portion of this sorted set whose elements are strictly less than toElement. + * + *

Note that this specification strengthens the one given in {@link SortedSet#headSet(Object)}. + * + * @see SortedSet#headSet(Object) + */ + IntSortedSet headSet( Integer toElement ); + /** Returns a view of the portion of this sorted set whose elements are greater than or equal to fromElement. + * + *

Note that this specification strengthens the one given in {@link SortedSet#tailSet(Object)}. + * + * @see SortedSet#tailSet(Object) + */ + IntSortedSet tailSet( Integer fromElement ); + /** Returns the comparator associated with this sorted set, or null if it uses its elements' natural ordering. + * + *

Note that this specification strengthens the one given in {@link SortedSet#comparator()}. + * + * @see SortedSet#comparator() + */ + IntComparator comparator(); + /** + * @see SortedSet#subSet(Object,Object) + */ + IntSortedSet subSet( int fromElement, int toElement) ; + /** + * @see SortedSet#headSet(Object) + */ + IntSortedSet headSet( int toElement ); + /** + * @see SortedSet#tailSet(Object) + */ + IntSortedSet tailSet( int fromElement ); + /** + * @see SortedSet#first() + */ + int firstInt(); + /** + * @see SortedSet#last() + */ + int lastInt(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntSortedSets.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntSortedSets.java new file mode 100644 index 0000000..56623dc --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntSortedSets.java @@ -0,0 +1,280 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import java.util.SortedSet; +import java.util.NoSuchElementException; +/** A class providing static methods and objects that do useful things with type-specific sorted sets. + * + * @see java.util.Collections + */ +public class IntSortedSets { + private IntSortedSets() {} + /** An immutable class representing the empty sorted set and implementing a type-specific set interface. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific sorted set. + */ + public static class EmptySet extends IntSets.EmptySet implements IntSortedSet , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptySet() {} + public boolean remove( int ok ) { throw new UnsupportedOperationException(); } + @Deprecated + public IntBidirectionalIterator intIterator() { return iterator(); } + + public IntBidirectionalIterator iterator( int from ) { return IntIterators.EMPTY_ITERATOR; } + + public IntSortedSet subSet( int from, int to ) { return EMPTY_SET; } + + public IntSortedSet headSet( int from ) { return EMPTY_SET; } + + public IntSortedSet tailSet( int to ) { return EMPTY_SET; } + public int firstInt() { throw new NoSuchElementException(); } + public int lastInt() { throw new NoSuchElementException(); } + public IntComparator comparator() { return null; } + public IntSortedSet subSet( Integer from, Integer to ) { return EMPTY_SET; } + public IntSortedSet headSet( Integer from ) { return EMPTY_SET; } + public IntSortedSet tailSet( Integer to ) { return EMPTY_SET; } + public Integer first() { throw new NoSuchElementException(); } + public Integer last() { throw new NoSuchElementException(); } + public Object clone() { return EMPTY_SET; } + private Object readResolve() { return EMPTY_SET; } + } + /** An empty sorted set (immutable). It is serializable and cloneable. + * + */ + + public static final EmptySet EMPTY_SET = new EmptySet(); + /** A class representing a singleton sorted set. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific sorted set. + */ + public static class Singleton extends IntSets.Singleton implements IntSortedSet , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + final IntComparator comparator; + private Singleton( final int element, final IntComparator comparator ) { + super( element ); + this.comparator = comparator; + } + private Singleton( final int element ) { + this( element, null ); + } + + final int compare( final int k1, final int k2 ) { + return comparator == null ? ( Integer.compare((k1),(k2)) ) : comparator.compare( k1, k2 ); + } + @Deprecated + public IntBidirectionalIterator intIterator() { + return iterator(); + } + public IntBidirectionalIterator iterator( int from ) { + IntBidirectionalIterator i = iterator(); + if ( compare( element, from ) <= 0 ) i.next(); + return i; + } + public IntComparator comparator() { return comparator; } + + public IntSortedSet subSet( final int from, final int to ) { if ( compare( from, element ) <= 0 && compare( element, to ) < 0 ) return this; return EMPTY_SET; } + + public IntSortedSet headSet( final int to ) { if ( compare( element, to ) < 0 ) return this; return EMPTY_SET; } + + public IntSortedSet tailSet( final int from ) { if ( compare( from, element ) <= 0 ) return this; return EMPTY_SET; } + public int firstInt() { return element; } + public int lastInt() { return element; } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer first() { return (Integer.valueOf(element)); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Integer last() { return (Integer.valueOf(element)); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public IntSortedSet subSet( final Integer from, final Integer to ) { return subSet( ((from).intValue()), ((to).intValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public IntSortedSet headSet( final Integer to ) { return headSet( ((to).intValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public IntSortedSet tailSet( final Integer from ) { return tailSet( ((from).intValue()) ); } + } + /** Returns a type-specific immutable sorted set containing only the specified element. The returned sorted set is serializable and cloneable. + * + * @param element the only element of the returned sorted set. + * @return a type-specific immutable sorted set containing just element. + */ + public static IntSortedSet singleton( final int element ) { + return new Singleton ( element ); + } + /** Returns a type-specific immutable sorted set containing only the specified element, and using a specified comparator. The returned sorted set is serializable and cloneable. + * + * @param element the only element of the returned sorted set. + * @param comparator the comparator to use in the returned sorted set. + * @return a type-specific immutable sorted set containing just element. + */ + public static IntSortedSet singleton( final int element, final IntComparator comparator ) { + return new Singleton ( element, comparator ); + } + /** Returns a type-specific immutable sorted set containing only the specified element. The returned sorted set is serializable and cloneable. + * + * @param element the only element of the returned sorted set. + * @return a type-specific immutable sorted set containing just element. + */ + public static IntSortedSet singleton( final Object element ) { + return new Singleton( ((((Integer)(element)).intValue())) ); + } + /** Returns a type-specific immutable sorted set containing only the specified element, and using a specified comparator. The returned sorted set is serializable and cloneable. + * + * @param element the only element of the returned sorted set. + * @param comparator the comparator to use in the returned sorted set. + * @return a type-specific immutable sorted set containing just element. + */ + public static IntSortedSet singleton( final Object element, final IntComparator comparator ) { + return new Singleton( ((((Integer)(element)).intValue())), comparator ); + } + /** A synchronized wrapper class for sorted sets. */ + public static class SynchronizedSortedSet extends IntSets.SynchronizedSet implements IntSortedSet , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final IntSortedSet sortedSet; + protected SynchronizedSortedSet( final IntSortedSet s, final Object sync ) { + super( s, sync ); + sortedSet = s; + } + protected SynchronizedSortedSet( final IntSortedSet s ) { + super( s ); + sortedSet = s; + } + public IntComparator comparator() { synchronized( sync ) { return sortedSet.comparator(); } } + public IntSortedSet subSet( final int from, final int to ) { return new SynchronizedSortedSet ( sortedSet.subSet( from, to ), sync ); } + public IntSortedSet headSet( final int to ) { return new SynchronizedSortedSet ( sortedSet.headSet( to ), sync ); } + public IntSortedSet tailSet( final int from ) { return new SynchronizedSortedSet ( sortedSet.tailSet( from ), sync ); } + public IntBidirectionalIterator iterator() { return sortedSet.iterator(); } + public IntBidirectionalIterator iterator( final int from ) { return sortedSet.iterator( from ); } + @Deprecated + public IntBidirectionalIterator intIterator() { return sortedSet.iterator(); } + public int firstInt() { synchronized( sync ) { return sortedSet.firstInt(); } } + public int lastInt() { synchronized( sync ) { return sortedSet.lastInt(); } } + public Integer first() { synchronized( sync ) { return sortedSet.first(); } } + public Integer last() { synchronized( sync ) { return sortedSet.last(); } } + public IntSortedSet subSet( final Integer from, final Integer to ) { return new SynchronizedSortedSet( sortedSet.subSet( from, to ), sync ); } + public IntSortedSet headSet( final Integer to ) { return new SynchronizedSortedSet( sortedSet.headSet( to ), sync ); } + public IntSortedSet tailSet( final Integer from ) { return new SynchronizedSortedSet( sortedSet.tailSet( from ), sync ); } + } + /** Returns a synchronized type-specific sorted set backed by the given type-specific sorted set. + * + * @param s the sorted set to be wrapped in a synchronized sorted set. + * @return a synchronized view of the specified sorted set. + * @see java.util.Collections#synchronizedSortedSet(SortedSet) + */ + public static IntSortedSet synchronize( final IntSortedSet s ) { return new SynchronizedSortedSet ( s ); } + /** Returns a synchronized type-specific sorted set backed by the given type-specific sorted set, using an assigned object to synchronize. + * + * @param s the sorted set to be wrapped in a synchronized sorted set. + * @param sync an object that will be used to synchronize the access to the sorted set. + * @return a synchronized view of the specified sorted set. + * @see java.util.Collections#synchronizedSortedSet(SortedSet) + */ + public static IntSortedSet synchronize( final IntSortedSet s, final Object sync ) { return new SynchronizedSortedSet ( s, sync ); } + /** An unmodifiable wrapper class for sorted sets. */ + public static class UnmodifiableSortedSet extends IntSets.UnmodifiableSet implements IntSortedSet , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final IntSortedSet sortedSet; + protected UnmodifiableSortedSet( final IntSortedSet s ) { + super( s ); + sortedSet = s; + } + public IntComparator comparator() { return sortedSet.comparator(); } + public IntSortedSet subSet( final int from, final int to ) { return new UnmodifiableSortedSet ( sortedSet.subSet( from, to ) ); } + public IntSortedSet headSet( final int to ) { return new UnmodifiableSortedSet ( sortedSet.headSet( to ) ); } + public IntSortedSet tailSet( final int from ) { return new UnmodifiableSortedSet ( sortedSet.tailSet( from ) ); } + public IntBidirectionalIterator iterator() { return IntIterators.unmodifiable( sortedSet.iterator() ); } + public IntBidirectionalIterator iterator( final int from ) { return IntIterators.unmodifiable( sortedSet.iterator( from ) ); } + @Deprecated + public IntBidirectionalIterator intIterator() { return iterator(); } + public int firstInt() { return sortedSet.firstInt(); } + public int lastInt() { return sortedSet.lastInt(); } + public Integer first() { return sortedSet.first(); } + public Integer last() { return sortedSet.last(); } + public IntSortedSet subSet( final Integer from, final Integer to ) { return new UnmodifiableSortedSet( sortedSet.subSet( from, to ) ); } + public IntSortedSet headSet( final Integer to ) { return new UnmodifiableSortedSet( sortedSet.headSet( to ) ); } + public IntSortedSet tailSet( final Integer from ) { return new UnmodifiableSortedSet( sortedSet.tailSet( from ) ); } + } + /** Returns an unmodifiable type-specific sorted set backed by the given type-specific sorted set. + * + * @param s the sorted set to be wrapped in an unmodifiable sorted set. + * @return an unmodifiable view of the specified sorted set. + * @see java.util.Collections#unmodifiableSortedSet(SortedSet) + */ + public static IntSortedSet unmodifiable( final IntSortedSet s ) { return new UnmodifiableSortedSet ( s ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/IntStack.java b/src/main/java/it/unimi/dsi/fastutil/ints/IntStack.java new file mode 100644 index 0000000..71ac087 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/IntStack.java @@ -0,0 +1,91 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.ints; +import it.unimi.dsi.fastutil.Stack; +/** A type-specific {@link Stack}; provides some additional methods that use polymorphism to avoid (un)boxing. + */ +public interface IntStack extends Stack { + /** + * @see Stack#push(Object) + */ + void push( int k ); + /** + * @see Stack#pop() + */ + int popInt(); + /** + * @see Stack#top() + */ + int topInt(); + /** + * @see Stack#peek(int) + */ + int peekInt( int i ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/ints/package.html b/src/main/java/it/unimi/dsi/fastutil/ints/package.html new file mode 100644 index 0000000..7fe95f1 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/ints/package.html @@ -0,0 +1,12 @@ + + + + fastutil + + + + +

Provides type-specific classes for integer elements or keys. + + + diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLong2ObjectFunction.java b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLong2ObjectFunction.java new file mode 100644 index 0000000..3ef4991 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLong2ObjectFunction.java @@ -0,0 +1,150 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +/** An abstract class providing basic methods for functions implementing a type-specific interface. + * + *

Optional operations just throw an {@link + * UnsupportedOperationException}. Generic versions of accessors delegate to + * the corresponding type-specific counterparts following the interface rules + * (they take care of returning null on a missing key). + * + *

This class handles directly a default return + * value (including {@linkplain #defaultReturnValue() methods to access + * it}). Instances of classes inheriting from this class have just to return + * defRetValue to denote lack of a key in type-specific methods. The value + * is serialized. + * + *

Implementing subclasses have just to provide type-specific get(), + * type-specific containsKey(), and size() methods. + * + */ +public abstract class AbstractLong2ObjectFunction implements Long2ObjectFunction , java.io.Serializable { + private static final long serialVersionUID = -4940583368468432370L; + protected AbstractLong2ObjectFunction() {} + /** + * The default return value for get(), put() and + * remove(). + */ + protected V defRetValue; + public void defaultReturnValue( final V rv ) { + defRetValue = rv; + } + public V defaultReturnValue() { + return defRetValue; + } + public V put( long key, V value ) { + throw new UnsupportedOperationException(); + } + public V remove( long key ) { + throw new UnsupportedOperationException(); + } + public void clear() { + throw new UnsupportedOperationException(); + } + public boolean containsKey( final Object ok ) { + if ( ok == null ) return false; + return containsKey( ((((Long)(ok)).longValue())) ); + } + /** Delegates to the corresponding type-specific method, taking care of returning null on a missing key. + * + *

This method must check whether the provided key is in the map using containsKey(). Thus, + * it probes the map twice. Implementors of subclasses should override it with a more efficient method. + */ + public V get( final Object ok ) { + if ( ok == null ) return null; + final long k = ((((Long)(ok)).longValue())); + return containsKey( k ) ? (get( k )) : null; + } + /** Delegates to the corresponding type-specific method, taking care of returning null on a missing key. + * + *

This method must check whether the provided key is in the map using containsKey(). Thus, + * it probes the map twice. Implementors of subclasses should override it with a more efficient method. + * + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public V put( final Long ok, final V ov ) { + final long k = ((ok).longValue()); + final boolean containsKey = containsKey( k ); + final V v = put( k, (ov) ); + return containsKey ? (v) : null; + } + /** Delegates to the corresponding type-specific method, taking care of returning null on a missing key. + * + *

This method must check whether the provided key is in the map using containsKey(). Thus, + * it probes the map twice. Implementors of subclasses should override it with a more efficient method. + */ + public V remove( final Object ok ) { + if ( ok == null ) return null; + final long k = ((((Long)(ok)).longValue())); + final boolean containsKey = containsKey( k ); + final V v = remove( k ); + return containsKey ? (v) : null; + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLong2ObjectMap.java b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLong2ObjectMap.java new file mode 100644 index 0000000..1b2c09f --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLong2ObjectMap.java @@ -0,0 +1,271 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.AbstractObjectIterator; +import it.unimi.dsi.fastutil.objects.ObjectSet; +import java.util.Iterator; +import java.util.Map; +/** An abstract class providing basic methods for maps implementing a type-specific interface. + * + *

Optional operations just throw an {@link + * UnsupportedOperationException}. Generic versions of accessors delegate to + * the corresponding type-specific counterparts following the interface rules + * (they take care of returning null on a missing key). + * + *

As a further help, this class provides a {@link BasicEntry BasicEntry} inner class + * that implements a type-specific version of {@link java.util.Map.Entry}; it + * is particularly useful for those classes that do not implement their own + * entries (e.g., most immutable maps). + */ +public abstract class AbstractLong2ObjectMap extends AbstractLong2ObjectFunction implements Long2ObjectMap , java.io.Serializable { + private static final long serialVersionUID = -4940583368468432370L; + protected AbstractLong2ObjectMap() {} + /** Checks whether the given value is contained in {@link #values()}. */ + public boolean containsValue( Object v ) { + return values().contains( v ); + } + /** Checks whether the given value is contained in {@link #keySet()}. */ + public boolean containsKey( long k ) { + return keySet().contains( k ); + } + /** Puts all pairs in the given map. + * If the map implements the interface of this map, + * it uses the faster iterators. + * + * @param m a map. + */ + @SuppressWarnings({"unchecked","deprecation"}) + public void putAll(Map m) { + int n = m.size(); + final Iterator> i = m.entrySet().iterator(); + if (m instanceof Long2ObjectMap) { + Long2ObjectMap.Entry e; + while(n-- != 0) { + e = (Long2ObjectMap.Entry )i.next(); + put(e.getLongKey(), e.getValue()); + } + } + else { + Map.Entry e; + while(n-- != 0) { + e = i.next(); + put(e.getKey(), e.getValue()); + } + } + } + public boolean isEmpty() { + return size() == 0; + } + /** This class provides a basic but complete type-specific entry class for all those maps implementations + * that do not have entries on their own (e.g., most immutable maps). + * + *

This class does not implement {@link java.util.Map.Entry#setValue(Object) setValue()}, as the modification + * would not be reflected in the base map. + */ + public static class BasicEntry implements Long2ObjectMap.Entry { + protected long key; + protected V value; + public BasicEntry( final Long key, final V value ) { + this.key = ((key).longValue()); + this.value = (value); + } + public BasicEntry( final long key, final V value ) { + this.key = key; + this.value = value; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long getKey() { + return (Long.valueOf(key)); + } + public long getLongKey() { + return key; + } + public V getValue() { + return (value); + } + public V setValue( final V value ) { + throw new UnsupportedOperationException(); + } + public boolean equals( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + Map.Entry e = (Map.Entry)o; + return ( (key) == (((((Long)(e.getKey())).longValue()))) ) && ( (value) == null ? ((e.getValue())) == null : (value).equals((e.getValue())) ); + } + public int hashCode() { + return it.unimi.dsi.fastutil.HashCommon.long2int(key) ^ ( (value) == null ? 0 : (value).hashCode() ); + } + public String toString() { + return key + "->" + value; + } + } + /** Returns a type-specific-set view of the keys of this map. + * + *

The view is backed by the set returned by {@link #entrySet()}. Note that + * no attempt is made at caching the result of this method, as this would + * require adding some attributes that lightweight implementations would + * not need. Subclasses may easily override this policy by calling + * this method and caching the result, but implementors are encouraged to + * write more efficient ad-hoc implementations. + * + * @return a set view of the keys of this map; it may be safely cast to a type-specific interface. + */ + public LongSet keySet() { + return new AbstractLongSet () { + public boolean contains( final long k ) { return containsKey( k ); } + public int size() { return AbstractLong2ObjectMap.this.size(); } + public void clear() { AbstractLong2ObjectMap.this.clear(); } + public LongIterator iterator() { + return new AbstractLongIterator () { + final ObjectIterator> i = entrySet().iterator(); + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public long nextLong() { return ((Long2ObjectMap.Entry )i.next()).getLongKey(); }; + public boolean hasNext() { return i.hasNext(); } + }; + } + }; + } + /** Returns a type-specific-set view of the values of this map. + * + *

The view is backed by the set returned by {@link #entrySet()}. Note that + * no attempt is made at caching the result of this method, as this would + * require adding some attributes that lightweight implementations would + * not need. Subclasses may easily override this policy by calling + * this method and caching the result, but implementors are encouraged to + * write more efficient ad-hoc implementations. + * + * @return a set view of the values of this map; it may be safely cast to a type-specific interface. + */ + public ObjectCollection values() { + return new AbstractObjectCollection () { + public boolean contains( final Object k ) { return containsValue( k ); } + public int size() { return AbstractLong2ObjectMap.this.size(); } + public void clear() { AbstractLong2ObjectMap.this.clear(); } + public ObjectIterator iterator() { + return new AbstractObjectIterator () { + final ObjectIterator> i = entrySet().iterator(); + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public V next() { return ((Long2ObjectMap.Entry )i.next()).getValue(); }; + public boolean hasNext() { return i.hasNext(); } + }; + } + }; + } + @SuppressWarnings({ "unchecked", "rawtypes" }) + public ObjectSet> entrySet() { + return (ObjectSet)long2ObjectEntrySet(); + } + /** Returns a hash code for this map. + * + * The hash code of a map is computed by summing the hash codes of its entries. + * + * @return a hash code for this map. + */ + public int hashCode() { + int h = 0, n = size(); + final ObjectIterator> i = entrySet().iterator(); + while( n-- != 0 ) h += i.next().hashCode(); + return h; + } + public boolean equals(Object o) { + if ( o == this ) return true; + if ( ! ( o instanceof Map ) ) return false; + Map m = (Map)o; + if ( m.size() != size() ) return false; + return entrySet().containsAll( m.entrySet() ); + } + public String toString() { + final StringBuilder s = new StringBuilder(); + final ObjectIterator> i = entrySet().iterator(); + int n = size(); + Long2ObjectMap.Entry e; + boolean first = true; + s.append("{"); + while(n-- != 0) { + if (first) first = false; + else s.append(", "); + e = (Long2ObjectMap.Entry )i.next(); + s.append(String.valueOf(e.getLongKey())); + s.append("=>"); + if (this == e.getValue()) s.append("(this map)"); else + s.append(String.valueOf(e.getValue())); + } + s.append("}"); + return s.toString(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLong2ObjectSortedMap.java b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLong2ObjectSortedMap.java new file mode 100644 index 0000000..3b5ca83 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLong2ObjectSortedMap.java @@ -0,0 +1,193 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectIterator; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; +import it.unimi.dsi.fastutil.objects.ObjectSortedSet; +import java.util.Map; +/** An abstract class providing basic methods for sorted maps implementing a type-specific interface. */ +public abstract class AbstractLong2ObjectSortedMap extends AbstractLong2ObjectMap implements Long2ObjectSortedMap { + private static final long serialVersionUID = -1773560792952436569L; + protected AbstractLong2ObjectSortedMap() {} + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long2ObjectSortedMap headMap( final Long to ) { + return headMap( ((to).longValue()) ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long2ObjectSortedMap tailMap( final Long from ) { + return tailMap( ((from).longValue()) ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long2ObjectSortedMap subMap( final Long from, final Long to ) { + return subMap( ((from).longValue()), ((to).longValue()) ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long firstKey() { + return (Long.valueOf(firstLongKey())); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long lastKey() { + return (Long.valueOf(lastLongKey())); + } + /** Returns a type-specific-sorted-set view of the keys of this map. + * + *

The view is backed by the sorted set returned by {@link #entrySet()}. Note that + * no attempt is made at caching the result of this method, as this would + * require adding some attributes that lightweight implementations would + * not need. Subclasses may easily override this policy by calling + * this method and caching the result, but implementors are encouraged to + * write more efficient ad-hoc implementations. + * + * @return a sorted set view of the keys of this map; it may be safely cast to a type-specific interface. + */ + public LongSortedSet keySet() { + return new KeySet(); + } + /** A wrapper exhibiting the keys of a map. */ + protected class KeySet extends AbstractLongSortedSet { + public boolean contains( final long k ) { return containsKey( k ); } + public int size() { return AbstractLong2ObjectSortedMap.this.size(); } + public void clear() { AbstractLong2ObjectSortedMap.this.clear(); } + public LongComparator comparator() { return AbstractLong2ObjectSortedMap.this.comparator(); } + public long firstLong() { return firstLongKey(); } + public long lastLong() { return lastLongKey(); } + public LongSortedSet headSet( final long to ) { return headMap( to ).keySet(); } + public LongSortedSet tailSet( final long from ) { return tailMap( from ).keySet(); } + public LongSortedSet subSet( final long from, final long to ) { return subMap( from, to ).keySet(); } + public LongBidirectionalIterator iterator( final long from ) { return new KeySetIterator ( entrySet().iterator( new BasicEntry ( from, (null) ) ) ); } + public LongBidirectionalIterator iterator() { return new KeySetIterator ( entrySet().iterator() ); } + } + /** A wrapper exhibiting a map iterator as an iterator on keys. + * + *

To provide an iterator on keys, just create an instance of this + * class using the corresponding iterator on entries. + */ + protected static class KeySetIterator extends AbstractLongBidirectionalIterator { + protected final ObjectBidirectionalIterator> i; + public KeySetIterator( ObjectBidirectionalIterator> i ) { + this.i = i; + } + public long nextLong() { return ((i.next().getKey()).longValue()); }; + public long previousLong() { return ((i.previous().getKey()).longValue()); }; + public boolean hasNext() { return i.hasNext(); } + public boolean hasPrevious() { return i.hasPrevious(); } + } + /** Returns a type-specific collection view of the values contained in this map. + * + *

The view is backed by the sorted set returned by {@link #entrySet()}. Note that + * no attempt is made at caching the result of this method, as this would + * require adding some attributes that lightweight implementations would + * not need. Subclasses may easily override this policy by calling + * this method and caching the result, but implementors are encouraged to + * write more efficient ad-hoc implementations. + * + * @return a type-specific collection view of the values contained in this map. + */ + public ObjectCollection values() { + return new ValuesCollection(); + } + /** A wrapper exhibiting the values of a map. */ + protected class ValuesCollection extends AbstractObjectCollection { + public ObjectIterator iterator() { return new ValuesIterator ( entrySet().iterator() ); } + public boolean contains( final Object k ) { return containsValue( k ); } + public int size() { return AbstractLong2ObjectSortedMap.this.size(); } + public void clear() { AbstractLong2ObjectSortedMap.this.clear(); } + } + /** A wrapper exhibiting a map iterator as an iterator on values. + * + *

To provide an iterator on values, just create an instance of this + * class using the corresponding iterator on entries. + */ + protected static class ValuesIterator extends AbstractObjectIterator { + protected final ObjectBidirectionalIterator> i; + public ValuesIterator( ObjectBidirectionalIterator> i ) { + this.i = i; + } + public V next() { return (i.next().getValue()); }; + public boolean hasNext() { return i.hasNext(); } + } + @SuppressWarnings({ "unchecked", "rawtypes" }) + public ObjectSortedSet> entrySet() { + return (ObjectSortedSet)long2ObjectEntrySet(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongBidirectionalIterator.java b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongBidirectionalIterator.java new file mode 100644 index 0000000..63ee559 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongBidirectionalIterator.java @@ -0,0 +1,95 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +/** An abstract class facilitating the creation of type-specific {@linkplain it.unimi.dsi.fastutil.BidirectionalIterator bidirectional iterators}. + * + *

To create a type-specific bidirectional iterator, besides what is needed + * for an iterator you need both a method returning the previous element as + * primitive type and a method returning the previous element as an + * object. However, if you inherit from this class you need just one (anyone). + * + *

This class implements also a trivial version of {@link #back(int)} that + * uses type-specific methods. + */ +public abstract class AbstractLongBidirectionalIterator extends AbstractLongIterator implements LongBidirectionalIterator { + protected AbstractLongBidirectionalIterator() {} + /** Delegates to the corresponding generic method. */ + public long previousLong() { return previous().longValue(); } + /** Delegates to the corresponding type-specific method. */ + public Long previous() { return Long.valueOf( previousLong() ); } + /** This method just iterates the type-specific version of {@link #previous()} for + * at most n times, stopping if {@link + * #hasPrevious()} becomes false. */ + public int back( final int n ) { + int i = n; + while( i-- != 0 && hasPrevious() ) previousLong(); + return n - i - 1; + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongCollection.java b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongCollection.java new file mode 100644 index 0000000..fdd3120 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongCollection.java @@ -0,0 +1,271 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Iterator; +/** An abstract class providing basic methods for collections implementing a type-specific interface. + * + *

In particular, this class provide {@link #iterator()}, add(), {@link #remove(Object)} and + * {@link #contains(Object)} methods that just call the type-specific counterpart. + */ +public abstract class AbstractLongCollection extends AbstractCollection implements LongCollection { + protected AbstractLongCollection() {} + public long[] toArray( long a[] ) { + return toLongArray( a ); + } + public long[] toLongArray() { + return toLongArray( null ); + } + public long[] toLongArray( long a[] ) { + if ( a == null || a.length < size() ) a = new long[ size() ]; + LongIterators.unwrap( iterator(), a ); + return a; + } + /** Adds all elements of the given type-specific collection to this collection. + * + * @param c a type-specific collection. + * @return true if this collection changed as a result of the call. + */ + public boolean addAll( LongCollection c ) { + boolean retVal = false; + final LongIterator i = c.iterator(); + int n = c.size(); + while( n-- != 0 ) if ( add( i.nextLong() ) ) retVal = true; + return retVal; + } + /** Checks whether this collection contains all elements from the given type-specific collection. + * + * @param c a type-specific collection. + * @return true if this collection contains all elements of the argument. + */ + public boolean containsAll( LongCollection c ) { + final LongIterator i = c.iterator(); + int n = c.size(); + while( n-- != 0 ) if ( ! contains( i.nextLong() ) ) return false; + return true; + } + /** Retains in this collection only elements from the given type-specific collection. + * + * @param c a type-specific collection. + * @return true if this collection changed as a result of the call. + */ + public boolean retainAll( LongCollection c ) { + boolean retVal = false; + int n = size(); + final LongIterator i = iterator(); + while( n-- != 0 ) { + if ( ! c.contains( i.nextLong() ) ) { + i.remove(); + retVal = true; + } + } + return retVal; + } + /** Remove from this collection all elements in the given type-specific collection. + * + * @param c a type-specific collection. + * @return true if this collection changed as a result of the call. + */ + public boolean removeAll( LongCollection c ) { + boolean retVal = false; + int n = c.size(); + final LongIterator i = c.iterator(); + while( n-- != 0 ) if ( rem( i.nextLong() ) ) retVal = true; + return retVal; + } + public Object[] toArray() { + final Object[] a = new Object[ size() ]; + it.unimi.dsi.fastutil.objects.ObjectIterators.unwrap( iterator(), a ); + return a; + } + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + final int size = size(); + if ( a.length < size ) a = (T[])java.lang.reflect.Array.newInstance( a.getClass().getComponentType(), size ); + it.unimi.dsi.fastutil.objects.ObjectIterators.unwrap( iterator(), a ); + if ( size < a.length ) a[ size ] = null; + return a; + } + /** Adds all elements of the given collection to this collection. + * + * @param c a collection. + * @return true if this collection changed as a result of the call. + */ + public boolean addAll( Collection c ) { + boolean retVal = false; + final Iterator i = c.iterator(); + int n = c.size(); + while( n-- != 0 ) if ( add( i.next() ) ) retVal = true; + return retVal; + } + public boolean add( long k ) { + throw new UnsupportedOperationException(); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public LongIterator longIterator() { + return iterator(); + } + public abstract LongIterator iterator(); + /** Delegates to the type-specific rem() method. */ + public boolean remove( Object ok ) { + if ( ok == null ) return false; + return rem( ((((Long)(ok)).longValue())) ); + } + /** Delegates to the corresponding type-specific method. */ + public boolean add( final Long o ) { + return add( o.longValue() ); + } + /** Delegates to the corresponding type-specific method. */ + public boolean rem( final Object o ) { + if ( o == null ) return false; + return rem( ((((Long)(o)).longValue())) ); + } + /** Delegates to the corresponding type-specific method. */ + public boolean contains( final Object o ) { + if ( o == null ) return false; + return contains( ((((Long)(o)).longValue())) ); + } + public boolean contains( final long k ) { + final LongIterator iterator = iterator(); + while ( iterator.hasNext() ) if ( k == iterator.nextLong() ) return true; + return false; + } + public boolean rem( final long k ) { + final LongIterator iterator = iterator(); + while ( iterator.hasNext() ) + if ( k == iterator.nextLong() ) { + iterator.remove(); + return true; + } + return false; + } + /** Checks whether this collection contains all elements from the given collection. + * + * @param c a collection. + * @return true if this collection contains all elements of the argument. + */ + public boolean containsAll( Collection c ) { + int n = c.size(); + final Iterator i = c.iterator(); + while( n-- != 0 ) if ( ! contains( i.next() ) ) return false; + return true; + } + /** Retains in this collection only elements from the given collection. + * + * @param c a collection. + * @return true if this collection changed as a result of the call. + */ + public boolean retainAll( Collection c ) { + boolean retVal = false; + int n = size(); + final Iterator i = iterator(); + while( n-- != 0 ) { + if ( ! c.contains( i.next() ) ) { + i.remove(); + retVal = true; + } + } + return retVal; + } + /** Remove from this collection all elements in the given collection. + * If the collection is an instance of this class, it uses faster iterators. + * + * @param c a collection. + * @return true if this collection changed as a result of the call. + */ + public boolean removeAll( Collection c ) { + boolean retVal = false; + int n = c.size(); + final Iterator i = c.iterator(); + while( n-- != 0 ) if ( remove( i.next() ) ) retVal = true; + return retVal; + } + public boolean isEmpty() { + return size() == 0; + } + public String toString() { + final StringBuilder s = new StringBuilder(); + final LongIterator i = iterator(); + int n = size(); + long k; + boolean first = true; + s.append("{"); + while(n-- != 0) { + if (first) first = false; + else s.append(", "); + k = i.nextLong(); + s.append(String.valueOf(k)); + } + s.append("}"); + return s.toString(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongComparator.java b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongComparator.java new file mode 100644 index 0000000..f437517 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongComparator.java @@ -0,0 +1,87 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +/** An abstract class facilitating the creation of type-specific {@linkplain java.util.Comparator comparators}. + * + *

To create a type-specific comparator you need both a method comparing + * primitive types and a method comparing objects. However, if you have the + * first one you can just inherit from this class and get for free the second + * one. + * + * @see java.util.Comparator + */ +public abstract class AbstractLongComparator implements LongComparator , java.io.Serializable { + private static final long serialVersionUID = 0L; + protected AbstractLongComparator() {} + public int compare( Long ok1, Long ok2 ) { + return compare( ok1.longValue(), ok2.longValue() ); + } + public abstract int compare( long k1, long k2 ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongIterator.java b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongIterator.java new file mode 100644 index 0000000..610c855 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongIterator.java @@ -0,0 +1,100 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +/** An abstract class facilitating the creation of type-specific iterators. + * + *

To create a type-specific iterator you need both a method returning the + * next element as primitive type and a method returning the next element as an + * object. However, if you inherit from this class you need just one (anyone). + * + *

This class implements also a trivial version of {@link #skip(int)} that uses + * type-specific methods; moreover, {@link #remove()} will throw an {@link + * UnsupportedOperationException}. + * + * @see java.util.Iterator + */ +public abstract class AbstractLongIterator implements LongIterator { + protected AbstractLongIterator() {} + /** Delegates to the corresponding generic method. */ + public long nextLong() { return next().longValue(); } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long next() { return Long.valueOf( nextLong() ); } + /** This method just throws an {@link UnsupportedOperationException}. */ + public void remove() { throw new UnsupportedOperationException(); } + /** This method just iterates the type-specific version of {@link #next()} for at most + * n times, stopping if {@link #hasNext()} becomes false.*/ + public int skip( final int n ) { + int i = n; + while( i-- != 0 && hasNext() ) nextLong(); + return n - i - 1; + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongList.java b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongList.java new file mode 100644 index 0000000..d4f51d2 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongList.java @@ -0,0 +1,577 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.List; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.Collection; +import java.util.NoSuchElementException; +/** An abstract class providing basic methods for lists implementing a type-specific list interface. + * + *

As an additional bonus, this class implements on top of the list operations a type-specific stack. + */ +public abstract class AbstractLongList extends AbstractLongCollection implements LongList , LongStack { + protected AbstractLongList() {} + /** Ensures that the given index is nonnegative and not greater than the list size. + * + * @param index an index. + * @throws IndexOutOfBoundsException if the given index is negative or greater than the list size. + */ + protected void ensureIndex( final int index ) { + if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" ); + if ( index > size() ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than list size (" + ( size() ) + ")" ); + } + /** Ensures that the given index is nonnegative and smaller than the list size. + * + * @param index an index. + * @throws IndexOutOfBoundsException if the given index is negative or not smaller than the list size. + */ + protected void ensureRestrictedIndex( final int index ) { + if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" ); + if ( index >= size() ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + ( size() ) + ")" ); + } + public void add( final int index, final long k ) { + throw new UnsupportedOperationException(); + } + public boolean add( final long k ) { + add( size(), k ); + return true; + } + public long removeLong( int i ) { + throw new UnsupportedOperationException(); + } + public long set( final int index, final long k ) { + throw new UnsupportedOperationException(); + } + public boolean addAll( int index, final Collection c ) { + ensureIndex( index ); + int n = c.size(); + if ( n == 0 ) return false; + Iterator i = c.iterator(); + while( n-- != 0 ) add( index++, i.next() ); + return true; + } + /** Delegates to a more generic method. */ + public boolean addAll( final Collection c ) { + return addAll( size(), c ); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public LongListIterator longListIterator() { + return listIterator(); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public LongListIterator longListIterator( final int index ) { + return listIterator( index ); + } + public LongListIterator iterator() { + return listIterator(); + } + public LongListIterator listIterator() { + return listIterator( 0 ); + } + public LongListIterator listIterator( final int index ) { + ensureIndex( index ); + return new AbstractLongListIterator () { + int pos = index, last = -1; + public boolean hasNext() { return pos < AbstractLongList.this.size(); } + public boolean hasPrevious() { return pos > 0; } + public long nextLong() { if ( ! hasNext() ) throw new NoSuchElementException(); return AbstractLongList.this.getLong( last = pos++ ); } + public long previousLong() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return AbstractLongList.this.getLong( last = --pos ); } + public int nextIndex() { return pos; } + public int previousIndex() { return pos - 1; } + public void add( long k ) { + AbstractLongList.this.add( pos++, k ); + last = -1; + } + public void set( long k ) { + if ( last == -1 ) throw new IllegalStateException(); + AbstractLongList.this.set( last, k ); + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + AbstractLongList.this.removeLong( last ); + /* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */ + if ( last < pos ) pos--; + last = -1; + } + }; + } + public boolean contains( final long k ) { + return indexOf( k ) >= 0; + } + public int indexOf( final long k ) { + final LongListIterator i = listIterator(); + long e; + while( i.hasNext() ) { + e = i.nextLong(); + if ( ( (k) == (e) ) ) return i.previousIndex(); + } + return -1; + } + public int lastIndexOf( final long k ) { + LongListIterator i = listIterator( size() ); + long e; + while( i.hasPrevious() ) { + e = i.previousLong(); + if ( ( (k) == (e) ) ) return i.nextIndex(); + } + return -1; + } + public void size( final int size ) { + int i = size(); + if ( size > i ) while( i++ < size ) add( (0) ); + else while( i-- != size ) remove( i ); + } + public LongList subList( final int from, final int to ) { + ensureIndex( from ); + ensureIndex( to ); + if ( from > to ) throw new IndexOutOfBoundsException( "Start index (" + from + ") is greater than end index (" + to + ")" ); + return new LongSubList ( this, from, to ); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public LongList longSubList( final int from, final int to ) { + return subList( from, to ); + } + /** Removes elements of this type-specific list one-by-one. + * + *

This is a trivial iterator-based implementation. It is expected that + * implementations will override this method with a more optimized version. + * + * + * @param from the start index (inclusive). + * @param to the end index (exclusive). + */ + public void removeElements( final int from, final int to ) { + ensureIndex( to ); + LongListIterator i = listIterator( from ); + int n = to - from; + if ( n < 0 ) throw new IllegalArgumentException( "Start index (" + from + ") is greater than end index (" + to + ")" ); + while( n-- != 0 ) { + i.nextLong(); + i.remove(); + } + } + /** Adds elements to this type-specific list one-by-one. + * + *

This is a trivial iterator-based implementation. It is expected that + * implementations will override this method with a more optimized version. + * + * @param index the index at which to add elements. + * @param a the array containing the elements. + * @param offset the offset of the first element to add. + * @param length the number of elements to add. + */ + public void addElements( int index, final long a[], int offset, int length ) { + ensureIndex( index ); + if ( offset < 0 ) throw new ArrayIndexOutOfBoundsException( "Offset (" + offset + ") is negative" ); + if ( offset + length > a.length ) throw new ArrayIndexOutOfBoundsException( "End index (" + ( offset + length ) + ") is greater than array length (" + a.length + ")" ); + while( length-- != 0 ) add( index++, a[ offset++ ] ); + } + public void addElements( final int index, final long a[] ) { + addElements( index, a, 0, a.length ); + } + /** Copies element of this type-specific list into the given array one-by-one. + * + *

This is a trivial iterator-based implementation. It is expected that + * implementations will override this method with a more optimized version. + * + * @param from the start index (inclusive). + * @param a the destination array. + * @param offset the offset into the destination array where to store the first element copied. + * @param length the number of elements to be copied. + */ + public void getElements( final int from, final long a[], int offset, int length ) { + LongListIterator i = listIterator( from ); + if ( offset < 0 ) throw new ArrayIndexOutOfBoundsException( "Offset (" + offset + ") is negative" ); + if ( offset + length > a.length ) throw new ArrayIndexOutOfBoundsException( "End index (" + ( offset + length ) + ") is greater than array length (" + a.length + ")" ); + if ( from + length > size() ) throw new IndexOutOfBoundsException( "End index (" + ( from + length ) + ") is greater than list size (" + size() + ")" ); + while( length-- != 0 ) a[ offset++ ] = i.nextLong(); + } + private boolean valEquals( final Object a, final Object b ) { + return a == null ? b == null : a.equals( b ); + } + public boolean equals( final Object o ) { + if ( o == this ) return true; + if ( ! ( o instanceof List ) ) return false; + final List l = (List)o; + int s = size(); + if ( s != l.size() ) return false; + if ( l instanceof LongList ) { + final LongListIterator i1 = listIterator(), i2 = ((LongList )l).listIterator(); + while( s-- != 0 ) if ( i1.nextLong() != i2.nextLong() ) return false; + return true; + } + final ListIterator i1 = listIterator(), i2 = l.listIterator(); + while( s-- != 0 ) if ( ! valEquals( i1.next(), i2.next() ) ) return false; + return true; + } + /** Compares this list to another object. If the + * argument is a {@link java.util.List}, this method performs a lexicographical comparison; otherwise, + * it throws a ClassCastException. + * + * @param l a list. + * @return if the argument is a {@link java.util.List}, a negative integer, + * zero, or a positive integer as this list is lexicographically less than, equal + * to, or greater than the argument. + * @throws ClassCastException if the argument is not a list. + */ + + public int compareTo( final List l ) { + if ( l == this ) return 0; + if ( l instanceof LongList ) { + final LongListIterator i1 = listIterator(), i2 = ((LongList )l).listIterator(); + int r; + long e1, e2; + while( i1.hasNext() && i2.hasNext() ) { + e1 = i1.nextLong(); + e2 = i2.nextLong(); + if ( ( r = ( Long.compare((e1),(e2)) ) ) != 0 ) return r; + } + return i2.hasNext() ? -1 : ( i1.hasNext() ? 1 : 0 ); + } + ListIterator i1 = listIterator(), i2 = l.listIterator(); + int r; + while( i1.hasNext() && i2.hasNext() ) { + if ( ( r = ((Comparable)i1.next()).compareTo( i2.next() ) ) != 0 ) return r; + } + return i2.hasNext() ? -1 : ( i1.hasNext() ? 1 : 0 ); + } + /** Returns the hash code for this list, which is identical to {@link java.util.List#hashCode()}. + * + * @return the hash code for this list. + */ + public int hashCode() { + LongIterator i = iterator(); + int h = 1, s = size(); + while ( s-- != 0 ) { + long k = i.nextLong(); + h = 31 * h + it.unimi.dsi.fastutil.HashCommon.long2int(k); + } + return h; + } + public void push( long o ) { + add( o ); + } + public long popLong() { + if ( isEmpty() ) throw new NoSuchElementException(); + return removeLong( size() - 1 ); + } + public long topLong() { + if ( isEmpty() ) throw new NoSuchElementException(); + return getLong( size() - 1 ); + } + public long peekLong( int i ) { + return getLong( size() - 1 - i ); + } + public boolean rem( long k ) { + int index = indexOf( k ); + if ( index == -1 ) return false; + removeLong( index ); + return true; + } + /** Delegates to rem(). */ + public boolean remove( final Object o ) { + return rem( ((((Long)(o)).longValue())) ); + } + /** Delegates to a more generic method. */ + public boolean addAll( final int index, final LongCollection c ) { + return addAll( index, (Collection)c ); + } + /** Delegates to a more generic method. */ + public boolean addAll( final int index, final LongList l ) { + return addAll( index, (LongCollection)l ); + } + public boolean addAll( final LongCollection c ) { + return addAll( size(), c ); + } + public boolean addAll( final LongList l ) { + return addAll( size(), l ); + } + /** Delegates to the corresponding type-specific method. */ + public void add( final int index, final Long ok ) { + add( index, ok.longValue() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long set( final int index, final Long ok ) { + return (Long.valueOf(set( index, ok.longValue() ))); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long get( final int index ) { + return (Long.valueOf(getLong( index ))); + } + /** Delegates to the corresponding type-specific method. */ + public int indexOf( final Object ok) { + return indexOf( ((((Long)(ok)).longValue())) ); + } + /** Delegates to the corresponding type-specific method. */ + public int lastIndexOf( final Object ok ) { + return lastIndexOf( ((((Long)(ok)).longValue())) ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long remove( final int index ) { + return (Long.valueOf(removeLong( index ))); + } + /** Delegates to the corresponding type-specific method. */ + public void push( Long o ) { + push( o.longValue() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long pop() { + return Long.valueOf( popLong() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long top() { + return Long.valueOf( topLong() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long peek( int i ) { + return Long.valueOf( peekLong( i ) ); + } + public String toString() { + final StringBuilder s = new StringBuilder(); + final LongIterator i = iterator(); + int n = size(); + long k; + boolean first = true; + s.append("["); + while( n-- != 0 ) { + if (first) first = false; + else s.append(", "); + k = i.nextLong(); + s.append( String.valueOf( k ) ); + } + s.append("]"); + return s.toString(); + } + public static class LongSubList extends AbstractLongList implements java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + /** The list this sublist restricts. */ + protected final LongList l; + /** Initial (inclusive) index of this sublist. */ + protected final int from; + /** Final (exclusive) index of this sublist. */ + protected int to; + private static final boolean ASSERTS = false; + public LongSubList( final LongList l, final int from, final int to ) { + this.l = l; + this.from = from; + this.to = to; + } + private void assertRange() { + if ( ASSERTS ) { + assert from <= l.size(); + assert to <= l.size(); + assert to >= from; + } + } + public boolean add( final long k ) { + l.add( to, k ); + to++; + if ( ASSERTS ) assertRange(); + return true; + } + public void add( final int index, final long k ) { + ensureIndex( index ); + l.add( from + index, k ); + to++; + if ( ASSERTS ) assertRange(); + } + public boolean addAll( final int index, final Collection c ) { + ensureIndex( index ); + to += c.size(); + if ( ASSERTS ) { + boolean retVal = l.addAll( from + index, c ); + assertRange(); + return retVal; + } + return l.addAll( from + index, c ); + } + public long getLong( int index ) { + ensureRestrictedIndex( index ); + return l.getLong( from + index ); + } + public long removeLong( int index ) { + ensureRestrictedIndex( index ); + to--; + return l.removeLong( from + index ); + } + public long set( int index, long k ) { + ensureRestrictedIndex( index ); + return l.set( from + index, k ); + } + public void clear() { + removeElements( 0, size() ); + if ( ASSERTS ) assertRange(); + } + public int size() { + return to - from; + } + public void getElements( final int from, final long[] a, final int offset, final int length ) { + ensureIndex( from ); + if ( from + length > size() ) throw new IndexOutOfBoundsException( "End index (" + from + length + ") is greater than list size (" + size() + ")" ); + l.getElements( this.from + from, a, offset, length ); + } + public void removeElements( final int from, final int to ) { + ensureIndex( from ); + ensureIndex( to ); + l.removeElements( this.from + from, this.from + to ); + this.to -= ( to - from ); + if ( ASSERTS ) assertRange(); + } + public void addElements( int index, final long a[], int offset, int length ) { + ensureIndex( index ); + l.addElements( this.from + index, a, offset, length ); + this.to += length; + if ( ASSERTS ) assertRange(); + } + public LongListIterator listIterator( final int index ) { + ensureIndex( index ); + return new AbstractLongListIterator () { + int pos = index, last = -1; + public boolean hasNext() { return pos < size(); } + public boolean hasPrevious() { return pos > 0; } + public long nextLong() { if ( ! hasNext() ) throw new NoSuchElementException(); return l.getLong( from + ( last = pos++ ) ); } + public long previousLong() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return l.getLong( from + ( last = --pos ) ); } + public int nextIndex() { return pos; } + public int previousIndex() { return pos - 1; } + public void add( long k ) { + if ( last == -1 ) throw new IllegalStateException(); + LongSubList.this.add( pos++, k ); + last = -1; + if ( ASSERTS ) assertRange(); + } + public void set( long k ) { + if ( last == -1 ) throw new IllegalStateException(); + LongSubList.this.set( last, k ); + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + LongSubList.this.removeLong( last ); + /* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */ + if ( last < pos ) pos--; + last = -1; + if ( ASSERTS ) assertRange(); + } + }; + } + public LongList subList( final int from, final int to ) { + ensureIndex( from ); + ensureIndex( to ); + if ( from > to ) throw new IllegalArgumentException( "Start index (" + from + ") is greater than end index (" + to + ")" ); + return new LongSubList ( this, from, to ); + } + public boolean rem( long k ) { + int index = indexOf( k ); + if ( index == -1 ) return false; + to--; + l.removeLong( from + index ); + if ( ASSERTS ) assertRange(); + return true; + } + public boolean remove( final Object o ) { + return rem( ((((Long)(o)).longValue())) ); + } + public boolean addAll( final int index, final LongCollection c ) { + ensureIndex( index ); + to += c.size(); + if ( ASSERTS ) { + boolean retVal = l.addAll( from + index, c ); + assertRange(); + return retVal; + } + return l.addAll( from + index, c ); + } + public boolean addAll( final int index, final LongList l ) { + ensureIndex( index ); + to += l.size(); + if ( ASSERTS ) { + boolean retVal = this.l.addAll( from + index, l ); + assertRange(); + return retVal; + } + return this.l.addAll( from + index, l ); + } + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongListIterator.java b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongListIterator.java new file mode 100644 index 0000000..963a9cd --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongListIterator.java @@ -0,0 +1,92 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +/** An abstract class facilitating the creation of type-specific {@linkplain java.util.ListIterator list iterators}. + * + *

This class provides trivial type-specific implementations of {@link + * java.util.ListIterator#set(Object) set()} and {@link java.util.ListIterator#add(Object) add()} which + * throw an {@link UnsupportedOperationException}. For primitive types, it also + * provides a trivial implementation of {@link java.util.ListIterator#set(Object) set()} and {@link + * java.util.ListIterator#add(Object) add()} that just invokes the type-specific one. + * + * + * @see java.util.ListIterator + */ +public abstract class AbstractLongListIterator extends AbstractLongBidirectionalIterator implements LongListIterator { + protected AbstractLongListIterator() {} + /** Delegates to the corresponding type-specific method. */ + public void set( Long ok ) { set( ok.longValue() ); } + /** Delegates to the corresponding type-specific method. */ + public void add( Long ok ) { add( ok.longValue() ); } + /** This method just throws an {@link UnsupportedOperationException}. */ + public void set( long k ) { throw new UnsupportedOperationException(); } + /** This method just throws an {@link UnsupportedOperationException}. */ + public void add( long k ) { throw new UnsupportedOperationException(); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongPriorityQueue.java new file mode 100644 index 0000000..f7606fb --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongPriorityQueue.java @@ -0,0 +1,95 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.AbstractPriorityQueue; +/** An abstract class providing basic methods for priority queues implementing a type-specific interface. + * + */ +public abstract class AbstractLongPriorityQueue extends AbstractPriorityQueue implements java.io.Serializable, LongPriorityQueue { + private static final long serialVersionUID = 1L; + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public void enqueue( final Long x ) { enqueue( x.longValue() ); } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long dequeue() { return (Long.valueOf(dequeueLong())); } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long first() { return (Long.valueOf(firstLong())); } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long last() { return (Long.valueOf(lastLong())); } + /** Throws an {@link UnsupportedOperationException}. */ + public long lastLong() { throw new UnsupportedOperationException(); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongSet.java b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongSet.java new file mode 100644 index 0000000..91c6eef --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongSet.java @@ -0,0 +1,115 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.Set; +/** An abstract class providing basic methods for sets implementing a type-specific interface. */ +public abstract class AbstractLongSet extends AbstractLongCollection implements Cloneable, LongSet { + protected AbstractLongSet() {} + public abstract LongIterator iterator(); + public boolean equals( final Object o ) { + if ( o == this ) return true; + if ( !( o instanceof Set ) ) return false; + Set s = (Set) o; + if ( s.size() != size() ) return false; + return containsAll(s); + } + /** Returns a hash code for this set. + * + * The hash code of a set is computed by summing the hash codes of + * its elements. + * + * @return a hash code for this set. + */ + public int hashCode() { + int h = 0, n = size(); + LongIterator i = iterator(); + long k; + while( n-- != 0 ) { + k = i.nextLong(); // We need k because KEY2JAVAHASH() is a macro with repeated evaluation. + h += it.unimi.dsi.fastutil.HashCommon.long2int(k); + } + return h; + } + public boolean remove( long k ) { + throw new UnsupportedOperationException(); + } + /** Delegates to remove(). + * + * @param k the element to be removed. + * @return true if the set was modified. + */ + public boolean rem( long k ) { + return remove( k ); + } + /** Delegates to the corresponding type-specific method. */ + public boolean remove( final Object o ) { + return remove( ((((Long)(o)).longValue())) ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongSortedSet.java b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongSortedSet.java new file mode 100644 index 0000000..84bd619 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/AbstractLongSortedSet.java @@ -0,0 +1,110 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +/** An abstract class providing basic methods for sorted sets implementing a type-specific interface. */ +public abstract class AbstractLongSortedSet extends AbstractLongSet implements LongSortedSet { + protected AbstractLongSortedSet() {} + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public LongSortedSet headSet( final Long to ) { + return headSet( to.longValue() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public LongSortedSet tailSet( final Long from ) { + return tailSet( from.longValue() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public LongSortedSet subSet( final Long from, final Long to ) { + return subSet( from.longValue(), to.longValue() ); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long first() { + return (Long.valueOf(firstLong())); + } + /** Delegates to the corresponding type-specific method. + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long last() { + return (Long.valueOf(lastLong())); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public LongBidirectionalIterator longIterator() { + return iterator(); + } + public abstract LongBidirectionalIterator iterator(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectArrayMap.java b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectArrayMap.java new file mode 100644 index 0000000..23ece85 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectArrayMap.java @@ -0,0 +1,346 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2007-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.Map; +import java.util.NoSuchElementException; +import it.unimi.dsi.fastutil.objects.AbstractObjectIterator; +import it.unimi.dsi.fastutil.objects.AbstractObjectSet; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectCollections; +import it.unimi.dsi.fastutil.objects.ObjectArraySet; +import it.unimi.dsi.fastutil.objects.ObjectArrays; +/** A simple, brute-force implementation of a map based on two parallel backing arrays. + * + *

The main purpose of this + * implementation is that of wrapping cleanly the brute-force approach to the storage of a very + * small number of pairs: just put them into two parallel arrays and scan linearly to find an item. + */ +public class Long2ObjectArrayMap extends AbstractLong2ObjectMap implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = 1L; + /** The keys (valid up to {@link #size}, excluded). */ + private transient long[] key; + /** The values (parallel to {@link #key}). */ + private transient Object[] value; + /** The number of valid entries in {@link #key} and {@link #value}. */ + private int size; + /** Creates a new empty array map with given key and value backing arrays. The resulting map will have as many entries as the given arrays. + * + *

It is responsibility of the caller that the elements of key are distinct. + * + * @param key the key array. + * @param value the value array (it must have the same length as key). + */ + public Long2ObjectArrayMap( final long[] key, final Object[] value ) { + this.key = key; + this.value = value; + size = key.length; + if( key.length != value.length ) throw new IllegalArgumentException( "Keys and values have different lengths (" + key.length + ", " + value.length + ")" ); + } + /** Creates a new empty array map. + */ + public Long2ObjectArrayMap() { + this.key = LongArrays.EMPTY_ARRAY; + this.value = ObjectArrays.EMPTY_ARRAY; + } + /** Creates a new empty array map of given capacity. + * + * @param capacity the initial capacity. + */ + public Long2ObjectArrayMap( final int capacity ) { + this.key = new long[ capacity ]; + this.value = new Object[ capacity ]; + } + /** Creates a new empty array map copying the entries of a given map. + * + * @param m a map. + */ + public Long2ObjectArrayMap( final Long2ObjectMap m ) { + this( m.size() ); + putAll( m ); + } + /** Creates a new empty array map copying the entries of a given map. + * + * @param m a map. + */ + public Long2ObjectArrayMap( final Map m ) { + this( m.size() ); + putAll( m ); + } + /** Creates a new array map with given key and value backing arrays, using the given number of elements. + * + *

It is responsibility of the caller that the first size elements of key are distinct. + * + * @param key the key array. + * @param value the value array (it must have the same length as key). + * @param size the number of valid elements in key and value. + */ + public Long2ObjectArrayMap( final long[] key, final Object[] value, final int size ) { + this.key = key; + this.value = value; + this.size = size; + if( key.length != value.length ) throw new IllegalArgumentException( "Keys and values have different lengths (" + key.length + ", " + value.length + ")" ); + if ( size > key.length ) throw new IllegalArgumentException( "The provided size (" + size + ") is larger than or equal to the backing-arrays size (" + key.length + ")" ); + } + private final class EntrySet extends AbstractObjectSet > implements FastEntrySet { + @Override + public ObjectIterator > iterator() { + return new AbstractObjectIterator >() { + int curr = -1, next = 0; + public boolean hasNext() { + return next < size; + } + @SuppressWarnings("unchecked") + public Entry next() { + if ( ! hasNext() ) throw new NoSuchElementException(); + return new AbstractLong2ObjectMap.BasicEntry ( key[ curr = next ], (V) value[ next++ ] ); + } + public void remove() { + if ( curr == -1 ) throw new IllegalStateException(); + curr = -1; + final int tail = size-- - next--; + System.arraycopy( key, next + 1, key, next, tail ); + System.arraycopy( value, next + 1, value, next, tail ); + value[ size ] = null; + } + }; + } + public ObjectIterator > fastIterator() { + return new AbstractObjectIterator >() { + int next = 0, curr = -1; + final BasicEntry entry = new BasicEntry ( (0), (null) ); + public boolean hasNext() { + return next < size; + } + @SuppressWarnings("unchecked") + public Entry next() { + if ( ! hasNext() ) throw new NoSuchElementException(); + entry.key = key[ curr = next ]; + entry.value = (V) value[ next++ ]; + return entry; + } + public void remove() { + if ( curr == -1 ) throw new IllegalStateException(); + curr = -1; + final int tail = size-- - next--; + System.arraycopy( key, next + 1, key, next, tail ); + System.arraycopy( value, next + 1, value, next, tail ); + value[ size ] = null; + } + }; + } + public int size() { + return size; + } + @SuppressWarnings("unchecked") + public boolean contains( Object o ) { + if ( ! ( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final long k = ((e.getKey()).longValue()); + return Long2ObjectArrayMap.this.containsKey( k ) && ( (Long2ObjectArrayMap.this.get( k )) == null ? ((e.getValue())) == null : (Long2ObjectArrayMap.this.get( k )).equals((e.getValue())) ); + } + @SuppressWarnings("unchecked") + @Override + public boolean remove( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final long k = ((e.getKey()).longValue()); + final V v = (e.getValue()); + final int oldPos = Long2ObjectArrayMap.this.findKey( k ); + if ( oldPos == -1 || ! ( (v) == null ? (Long2ObjectArrayMap.this.value[ oldPos ]) == null : (v).equals(Long2ObjectArrayMap.this.value[ oldPos ]) ) ) return false; + final int tail = size - oldPos - 1; + System.arraycopy( Long2ObjectArrayMap.this.key, oldPos + 1, Long2ObjectArrayMap.this.key, oldPos, tail ); + System.arraycopy( Long2ObjectArrayMap.this.value, oldPos + 1, Long2ObjectArrayMap.this.value, oldPos, tail ); + Long2ObjectArrayMap.this.size--; + Long2ObjectArrayMap.this.value[ size ] = null; + return true; + } + } + public FastEntrySet long2ObjectEntrySet() { + return new EntrySet(); + } + private int findKey( final long k ) { + final long[] key = this.key; + for( int i = size; i-- != 0; ) if ( ( (key[ i ]) == (k) ) ) return i; + return -1; + } + @SuppressWarnings("unchecked") + public V get( final long k ) { + final long[] key = this.key; + for( int i = size; i-- != 0; ) if ( ( (key[ i ]) == (k) ) ) return (V) value[ i ]; + return defRetValue; + } + public int size() { + return size; + } + @Override + public void clear() { + for( int i = size; i-- != 0; ) { + value[ i ] = null; + } + size = 0; + } + @Override + public boolean containsKey( final long k ) { + return findKey( k ) != -1; + } + @Override + public boolean containsValue( Object v ) { + for( int i = size; i-- != 0; ) if ( ( (value[ i ]) == null ? (v) == null : (value[ i ]).equals(v) ) ) return true; + return false; + } + @Override + public boolean isEmpty() { + return size == 0; + } + @Override + @SuppressWarnings("unchecked") + public V put( long k, V v ) { + final int oldKey = findKey( k ); + if ( oldKey != -1 ) { + final V oldValue = (V) value[ oldKey ]; + value[ oldKey ] = v; + return oldValue; + } + if ( size == key.length ) { + final long[] newKey = new long[ size == 0 ? 2 : size * 2 ]; + final Object[] newValue = new Object[ size == 0 ? 2 : size * 2 ]; + for( int i = size; i-- != 0; ) { + newKey[ i ] = key[ i ]; + newValue[ i ] = value[ i ]; + } + key = newKey; + value = newValue; + } + key[ size ] = k; + value[ size ] = v; + size++; + return defRetValue; + } + @Override + @SuppressWarnings("unchecked") + public V remove( final long k ) { + final int oldPos = findKey( k ); + if ( oldPos == -1 ) return defRetValue; + final V oldValue = (V) value[ oldPos ]; + final int tail = size - oldPos - 1; + System.arraycopy( key, oldPos + 1, key, oldPos, tail ); + System.arraycopy( value, oldPos + 1, value, oldPos, tail ); + size--; + value[ size ] = null; + return oldValue; + } + @Override + public LongSet keySet() { + return new LongArraySet ( key, size ); + } + @Override + public ObjectCollection values() { + return ObjectCollections.unmodifiable( new ObjectArraySet ( value, size ) ); + } + /** Returns a deep copy of this map. + * + *

This method performs a deep copy of this hash map; the data stored in the + * map, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this map. + */ + @SuppressWarnings("unchecked") + public Long2ObjectArrayMap clone() { + Long2ObjectArrayMap c; + try { + c = (Long2ObjectArrayMap )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.key = key.clone(); + c.value = value.clone(); + return c; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + s.defaultWriteObject(); + for( int i = 0; i < size; i++ ) { + s.writeLong( key[ i ] ); + s.writeObject( value[ i ] ); + } + } + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + key = new long[ size ]; + value = new Object[ size ]; + for( int i = 0; i < size; i++ ) { + key[ i ] = s.readLong(); + value[ i ] = s.readObject(); + } + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectFunction.java b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectFunction.java new file mode 100644 index 0000000..be0234e --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectFunction.java @@ -0,0 +1,137 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.Function; +/** A type-specific {@link Function}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Type-specific versions of get(), put() and + * remove() cannot rely on null to denote absence of + * a key. Rather, they return a {@linkplain #defaultReturnValue() default + * return value}, which is set to 0 cast to the return type (false + * for booleans) at creation, but can be changed using the + * defaultReturnValue() method. + * + *

For uniformity reasons, even maps returning objects implement the default + * return value (of course, in this case the default return value is + * initialized to null). + * + *

Warning: to fall in line as much as possible with the + * {@linkplain java.util.Map standard map interface}, it is strongly suggested + * that standard versions of get(), put() and + * remove() for maps with primitive-type values return + * null to denote missing keys rather than wrap the default + * return value in an object (of course, for maps with object keys and values + * this is not possible, as there is no type-specific version). + * + * @see Function + */ +public interface Long2ObjectFunction extends Function { + /** Adds a pair to the map. + * + * @param key the key. + * @param value the value. + * @return the old value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + * @see Function#put(Object,Object) + */ + V put( long key, V value ); + /** Returns the value to which the given key is mapped. + * + * @param key the key. + * @return the corresponding value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + * @see Function#get(Object) + */ + V get( long key ); + /** Removes the mapping with the given key. + * @param key the key. + * @return the old value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + * @see Function#remove(Object) + */ + V remove( long key ); + /** + * @see Function#containsKey(Object) + */ + boolean containsKey( long key ); + /** Sets the default return value. + * + * This value must be returned by type-specific versions of + * get(), put() and remove() to + * denote that the map does not contain the specified key. It must be + * 0/false/null by default. + * + * @param rv the new default return value. + * @see #defaultReturnValue() + */ + void defaultReturnValue( V rv ); + /** Gets the default return value. + * + * @return the current default return value. + */ + V defaultReturnValue(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectFunctions.java b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectFunctions.java new file mode 100644 index 0000000..5afe8fb --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectFunctions.java @@ -0,0 +1,224 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +/** A class providing static methods and objects that do useful things with type-specific functions. + * + * @see it.unimi.dsi.fastutil.Function + * @see java.util.Collections + */ +public class Long2ObjectFunctions { + private Long2ObjectFunctions() {} + /** An immutable class representing an empty type-specific function. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific function. + */ + public static class EmptyFunction extends AbstractLong2ObjectFunction implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptyFunction() {} + public V get( final long k ) { return (null); } + public boolean containsKey( final long k ) { return false; } + public V defaultReturnValue() { return (null); } + public void defaultReturnValue( final V defRetValue ) { throw new UnsupportedOperationException(); } + @Override + public V get( final Object k ) { return null; } + public int size() { return 0; } + public void clear() {} + private Object readResolve() { return EMPTY_FUNCTION; } + public Object clone() { return EMPTY_FUNCTION; } + } + /** An empty type-specific function (immutable). It is serializable and cloneable. */ + @SuppressWarnings("rawtypes") + public static final EmptyFunction EMPTY_FUNCTION = new EmptyFunction(); + /** An immutable class representing a type-specific singleton function. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific function. + */ + public static class Singleton extends AbstractLong2ObjectFunction implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected final long key; + protected final V value; + protected Singleton( final long key, final V value ) { + this.key = key; + this.value = value; + } + public boolean containsKey( final long k ) { return ( (key) == (k) ); } + public V get( final long k ) { if ( ( (key) == (k) ) ) return value; return defRetValue; } + public int size() { return 1; } + public Object clone() { return this; } + } + /** Returns a type-specific immutable function containing only the specified pair. The returned function is serializable and cloneable. + * + *

Note that albeit the returned function is immutable, its default return value may be changed. + * + * @param key the only key of the returned function. + * @param value the only value of the returned function. + * @return a type-specific immutable function containing just the pair <key,value>. + */ + public static Long2ObjectFunction singleton( final long key, V value ) { + return new Singleton ( key, value ); + } + /** Returns a type-specific immutable function containing only the specified pair. The returned function is serializable and cloneable. + * + *

Note that albeit the returned function is immutable, its default return value may be changed. + * + * @param key the only key of the returned function. + * @param value the only value of the returned function. + * @return a type-specific immutable function containing just the pair <key,value>. + */ + public static Long2ObjectFunction singleton( final Long key, final V value ) { + return new Singleton ( ((key).longValue()), (value) ); + } + /** A synchronized wrapper class for functions. */ + public static class SynchronizedFunction extends AbstractLong2ObjectFunction implements java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final Long2ObjectFunction function; + protected final Object sync; + protected SynchronizedFunction( final Long2ObjectFunction f, final Object sync ) { + if ( f == null ) throw new NullPointerException(); + this.function = f; + this.sync = sync; + } + protected SynchronizedFunction( final Long2ObjectFunction f ) { + if ( f == null ) throw new NullPointerException(); + this.function = f; + this.sync = this; + } + public int size() { synchronized( sync ) { return function.size(); } } + public boolean containsKey( final long k ) { synchronized( sync ) { return function.containsKey( k ); } } + public V defaultReturnValue() { synchronized( sync ) { return function.defaultReturnValue(); } } + public void defaultReturnValue( final V defRetValue ) { synchronized( sync ) { function.defaultReturnValue( defRetValue ); } } + public V put( final long k, final V v ) { synchronized( sync ) { return function.put( k, v ); } } + public void clear() { synchronized( sync ) { function.clear(); } } + public String toString() { synchronized( sync ) { return function.toString(); } } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Long k, final V v ) { synchronized( sync ) { return function.put( k, v ); } } + @Override + public V get( final Object k ) { synchronized( sync ) { return function.get( k ); } } + @Override + public V remove( final Object k ) { synchronized( sync ) { return function.remove( k ); } } + @Override + public V remove( final long k ) { synchronized( sync ) { return function.remove( k ); } } + @Override + public V get( final long k ) { synchronized( sync ) { return function.get( k ); } } + public boolean containsKey( final Object ok ) { synchronized( sync ) { return function.containsKey( ok ); } } + } + /** Returns a synchronized type-specific function backed by the given type-specific function. + * + * @param f the function to be wrapped in a synchronized function. + * @return a synchronized view of the specified function. + * @see java.util.Collections#synchronizedMap(java.util.Map) + */ + public static Long2ObjectFunction synchronize( final Long2ObjectFunction f ) { return new SynchronizedFunction ( f ); } + /** Returns a synchronized type-specific function backed by the given type-specific function, using an assigned object to synchronize. + * + * @param f the function to be wrapped in a synchronized function. + * @param sync an object that will be used to synchronize the access to the function. + * @return a synchronized view of the specified function. + * @see java.util.Collections#synchronizedMap(java.util.Map) + */ + public static Long2ObjectFunction synchronize( final Long2ObjectFunction f, final Object sync ) { return new SynchronizedFunction ( f, sync ); } + /** An unmodifiable wrapper class for functions. */ + public static class UnmodifiableFunction extends AbstractLong2ObjectFunction implements java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final Long2ObjectFunction function; + protected UnmodifiableFunction( final Long2ObjectFunction f ) { + if ( f == null ) throw new NullPointerException(); + this.function = f; + } + public int size() { return function.size(); } + public boolean containsKey( final long k ) { return function.containsKey( k ); } + public V defaultReturnValue() { return function.defaultReturnValue(); } + public void defaultReturnValue( final V defRetValue ) { throw new UnsupportedOperationException(); } + public V put( final long k, final V v ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + public String toString() { return function.toString(); } + @Override + public V remove( final long k ) { throw new UnsupportedOperationException(); } + @Override + public V get( final long k ) { return function.get( k ); } + public boolean containsKey( final Object ok ) { return function.containsKey( ok ); } + @Override + public V remove( final Object k ) { throw new UnsupportedOperationException(); } + @Override + public V get( final Object k ) { return function.get( k ); } + } + /** Returns an unmodifiable type-specific function backed by the given type-specific function. + * + * @param f the function to be wrapped in an unmodifiable function. + * @return an unmodifiable view of the specified function. + * @see java.util.Collections#unmodifiableMap(java.util.Map) + */ + public static Long2ObjectFunction unmodifiable( final Long2ObjectFunction f ) { return new UnmodifiableFunction ( f ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap.java b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap.java new file mode 100644 index 0000000..d221ba0 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap.java @@ -0,0 +1,1444 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.HashCommon; +import static it.unimi.dsi.fastutil.HashCommon.arraySize; +import static it.unimi.dsi.fastutil.HashCommon.maxFill; +import java.util.Map; +import java.util.Arrays; +import java.util.NoSuchElementException; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import java.util.Comparator; +import it.unimi.dsi.fastutil.objects.AbstractObjectSortedSet; +import it.unimi.dsi.fastutil.objects.ObjectListIterator; +import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; +import it.unimi.dsi.fastutil.objects.ObjectSortedSet; +/** A type-specific linked hash map with with a fast, small-footprint implementation. + * + *

Instances of this class use a hash table to represent a map. The table is + * filled up to a specified load factor, and then doubled in size to + * accommodate new entries. If the table is emptied below one fourth + * of the load factor, it is halved in size. However, halving is + * not performed when deleting entries from an iterator, as it would interfere + * with the iteration process. + * + *

Note that {@link #clear()} does not modify the hash table size. + * Rather, a family of {@linkplain #trim() trimming + * methods} lets you control the size of the table; this is particularly useful + * if you reuse instances of this class. + * + *

Iterators generated by this map will enumerate pairs in the same order in which they + * have been added to the map (addition of pairs whose key is already present + * in the set does not change the iteration order). Note that this order has nothing in common with the natural + * order of the keys. The order is kept by means of a doubly linked list, represented + * via an array of longs parallel to the table. + * + *

This class implements the interface of a sorted map, so to allow easy + * access of the iteration order: for instance, you can get the first key + * in iteration order with {@code firstKey()} without having to create an + * iterator; however, this class partially violates the {@link java.util.SortedMap} + * contract because all submap methods throw an exception and {@link + * #comparator()} returns always null. + * + *

Additional methods, such as getAndMoveToFirst(), make it easy + * to use instances of this class as a cache (e.g., with LRU policy). + * + *

The iterators provided by the views of this class using are type-specific + * {@linkplain java.util.ListIterator list iterators}, and can be started at any + * element which is a key of the map, or + * a {@link NoSuchElementException} exception will be thrown. + * If, however, the provided element is not the first or last key in the + * set, the first access to the list index will require linear time, as in the worst case + * the entire key set must be scanned in iteration order to retrieve the positional + * index of the starting key. If you use just the methods of a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator}, + * however, all operations will be performed in constant time. + * + * @see Hash + * @see HashCommon + */ +public class Long2ObjectLinkedOpenHashMap extends AbstractLong2ObjectSortedMap implements java.io.Serializable, Cloneable, Hash { + private static final long serialVersionUID = 0L; + private static final boolean ASSERTS = false; + /** The array of keys. */ + protected transient long[] key; + /** The array of values. */ + protected transient V[] value; + /** The mask for wrapping a position counter. */ + protected transient int mask; + /** Whether this set contains the key zero. */ + protected transient boolean containsNullKey; + /** The index of the first entry in iteration order. It is valid iff {@link #size} is nonzero; otherwise, it contains -1. */ + protected transient int first = -1; + /** The index of the last entry in iteration order. It is valid iff {@link #size} is nonzero; otherwise, it contains -1. */ + protected transient int last = -1; + /** For each entry, the next and the previous entry in iteration order, + * stored as ((prev & 0xFFFFFFFFL) << 32) | (next & 0xFFFFFFFFL). + * The first entry contains predecessor -1, and the last entry + * contains successor -1. */ + protected transient long[] link; + /** The current table size. */ + protected transient int n; + /** Threshold after which we rehash. It must be the table size times {@link #f}. */ + protected transient int maxFill; + /** Number of entries in the set (including the key zero, if present). */ + protected int size; + /** The acceptable load factor. */ + protected final float f; + /** Cached set of entries. */ + protected transient FastSortedEntrySet entries; + /** Cached set of keys. */ + protected transient LongSortedSet keys; + /** Cached collection of values. */ + protected transient ObjectCollection values; + /** Creates a new hash map. + * + *

The actual table size will be the least power of two greater than expected/f. + * + * @param expected the expected number of elements in the hash set. + * @param f the load factor. + */ + @SuppressWarnings("unchecked") + public Long2ObjectLinkedOpenHashMap( final int expected, final float f ) { + if ( f <= 0 || f > 1 ) throw new IllegalArgumentException( "Load factor must be greater than 0 and smaller than or equal to 1" ); + if ( expected < 0 ) throw new IllegalArgumentException( "The expected number of elements must be nonnegative" ); + this.f = f; + n = arraySize( expected, f ); + mask = n - 1; + maxFill = maxFill( n, f ); + key = new long[ n + 1 ]; + value = (V[]) new Object[ n + 1 ]; + link = new long[ n + 1 ]; + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * + * @param expected the expected number of elements in the hash map. + */ + public Long2ObjectLinkedOpenHashMap( final int expected ) { + this( expected, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map with initial expected {@link Hash#DEFAULT_INITIAL_SIZE} entries + * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + */ + public Long2ObjectLinkedOpenHashMap() { + this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map copying a given one. + * + * @param m a {@link Map} to be copied into the new hash map. + * @param f the load factor. + */ + public Long2ObjectLinkedOpenHashMap( final Map m, final float f ) { + this( m.size(), f ); + putAll( m ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given one. + * + * @param m a {@link Map} to be copied into the new hash map. + */ + public Long2ObjectLinkedOpenHashMap( final Map m ) { + this( m, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map copying a given type-specific one. + * + * @param m a type-specific map to be copied into the new hash map. + * @param f the load factor. + */ + public Long2ObjectLinkedOpenHashMap( final Long2ObjectMap m, final float f ) { + this( m.size(), f ); + putAll( m ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given type-specific one. + * + * @param m a type-specific map to be copied into the new hash map. + */ + public Long2ObjectLinkedOpenHashMap( final Long2ObjectMap m ) { + this( m, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map using the elements of two parallel arrays. + * + * @param k the array of keys of the new hash map. + * @param v the array of corresponding values in the new hash map. + * @param f the load factor. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Long2ObjectLinkedOpenHashMap( final long[] k, final V[] v, final float f ) { + this( k.length, f ); + if ( k.length != v.length ) throw new IllegalArgumentException( "The key array and the value array have different lengths (" + k.length + " and " + v.length + ")" ); + for( int i = 0; i < k.length; i++ ) this.put( k[ i ], v[ i ] ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using the elements of two parallel arrays. + * + * @param k the array of keys of the new hash map. + * @param v the array of corresponding values in the new hash map. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Long2ObjectLinkedOpenHashMap( final long[] k, final V[] v ) { + this( k, v, DEFAULT_LOAD_FACTOR ); + } + private int realSize() { + return containsNullKey ? size - 1 : size; + } + private void ensureCapacity( final int capacity ) { + final int needed = arraySize( capacity, f ); + if ( needed > n ) rehash( needed ); + } + private void tryCapacity( final long capacity ) { + final int needed = (int)Math.min( 1 << 30, Math.max( 2, HashCommon.nextPowerOfTwo( (long)Math.ceil( capacity / f ) ) ) ); + if ( needed > n ) rehash( needed ); + } + private V removeEntry( final int pos ) { + final V oldValue = value[ pos ]; + value[ pos ] = null; + size--; + fixPointers( pos ); + shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return oldValue; + } + private V removeNullEntry() { + containsNullKey = false; + final V oldValue = value[ n ]; + value[ n ] = null; + size--; + fixPointers( n ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return oldValue; + } + /** {@inheritDoc} */ + public void putAll(Map m) { + if ( f <= .5 ) ensureCapacity( m.size() ); // The resulting map will be sized for m.size() elements + else tryCapacity( size() + m.size() ); // The resulting map will be tentatively sized for size() + m.size() elements + super.putAll( m ); + } + private int insert(final long k, final V v) { + int pos; + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) return n; + containsNullKey = true; + pos = n; + } + else { + long curr; + final long[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) { + if ( ( (curr) == (k) ) ) return pos; + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( (curr) == (k) ) ) return pos; + } + } + key[ pos ] = k; + value[ pos ] = v; + if ( size == 0 ) { + first = last = pos; + // Special case of SET_UPPER_LOWER( link[ pos ], -1, -1 ); + link[ pos ] = -1L; + } + else { + link[ last ] ^= ( ( link[ last ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ pos ] = ( ( last & 0xFFFFFFFFL ) << 32 ) | ( -1 & 0xFFFFFFFFL ); + last = pos; + } + if ( size++ >= maxFill ) rehash( arraySize( size + 1, f ) ); + if ( ASSERTS ) checkTable(); + return -1; + } + public V put(final long k, final V v) { + final int pos = insert( k, v ); + if ( pos < 0 ) return defRetValue; + final V oldValue = value[ pos ]; + value[ pos ] = v; + return oldValue; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Long ok, final V ov ) { + final V v = (ov); + final int pos = insert( ((ok).longValue()), v ); + if ( pos < 0 ) return (this.defRetValue); + final V oldValue = value[ pos ]; + value[ pos ] = v; + return (oldValue); + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + protected final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + long curr; + final long[] key = this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + value[ last ] = null; + return; + } + slot = (int)it.unimi.dsi.fastutil.HashCommon.mix( (curr) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + value[ last ] = value[ pos ]; + fixPointers( pos, last ); + } + } + + public V remove( final long k ) { + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) return removeNullEntry(); + return defRetValue; + } + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return removeEntry( pos ); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return removeEntry( pos ); + } + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + + public V remove( final Object ok ) { + final long k = ((((Long)(ok)).longValue())); + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) return (removeNullEntry()); + return (this.defRetValue); + } + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (curr) == (k) ) ) return (removeEntry( pos )); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (curr) == (k) ) ) return (removeEntry( pos )); + } + } + private V setValue( final int pos, final V v ) { + final V oldValue = value[ pos ]; + value[ pos ] = v; + return oldValue; + } + /** Removes the mapping associated with the first key in iteration order. + * @return the value previously associated with the first key in iteration order. + * @throws NoSuchElementException is this map is empty. + */ + public V removeFirst() { + if ( size == 0 ) throw new NoSuchElementException(); + final int pos = first; + // Abbreviated version of fixPointers(pos) + first = (int) link[ pos ]; + if ( 0 <= first ) { + // Special case of SET_PREV( link[ first ], -1 ) + link[ first ] |= (-1 & 0xFFFFFFFFL) << 32; + } + size--; + final V v = value[ pos ]; + if ( pos == n ) { + containsNullKey = false; + value[ n ] = null; + } + else shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return v; + } + /** Removes the mapping associated with the last key in iteration order. + * @return the value previously associated with the last key in iteration order. + * @throws NoSuchElementException is this map is empty. + */ + public V removeLast() { + if ( size == 0 ) throw new NoSuchElementException(); + final int pos = last; + // Abbreviated version of fixPointers(pos) + last = (int) ( link[ pos ] >>> 32 ); + if ( 0 <= last ) { + // Special case of SET_NEXT( link[ last ], -1 ) + link[ last ] |= -1 & 0xFFFFFFFFL; + } + size--; + final V v = value[ pos ]; + if ( pos == n ) { + containsNullKey = false; + value[ n ] = null; + } + else shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return v; + } + private void moveIndexToFirst( final int i ) { + if ( size == 1 || first == i ) return; + if ( last == i ) { + last = (int) ( link[ i ] >>> 32 ); + // Special case of SET_NEXT( link[ last ], -1 ); + link[ last ] |= -1 & 0xFFFFFFFFL; + } + else { + final long linki = link[ i ]; + final int prev = (int) ( linki >>> 32 ); + final int next = (int) linki; + link[ prev ] ^= ( ( link[ prev ] ^ ( linki & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( linki & 0xFFFFFFFF00000000L ) ) & 0xFFFFFFFF00000000L ); + } + link[ first ] ^= ( ( link[ first ] ^ ( ( i & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ i ] = ( ( -1 & 0xFFFFFFFFL ) << 32 ) | ( first & 0xFFFFFFFFL ); + first = i; + } + private void moveIndexToLast( final int i ) { + if ( size == 1 || last == i ) return; + if ( first == i ) { + first = (int) link[ i ]; + // Special case of SET_PREV( link[ first ], -1 ); + link[ first ] |= (-1 & 0xFFFFFFFFL) << 32; + } + else { + final long linki = link[ i ]; + final int prev = (int) ( linki >>> 32 ); + final int next = (int) linki; + link[ prev ] ^= ( ( link[ prev ] ^ ( linki & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( linki & 0xFFFFFFFF00000000L ) ) & 0xFFFFFFFF00000000L ); + } + link[ last ] ^= ( ( link[ last ] ^ ( i & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ i ] = ( ( last & 0xFFFFFFFFL ) << 32 ) | ( -1 & 0xFFFFFFFFL ); + last = i; + } + /** Returns the value to which the given key is mapped; if the key is present, it is moved to the first position of the iteration order. + * + * @param k the key. + * @return the corresponding value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + */ + public V getAndMoveToFirst( final long k ) { + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) { + moveIndexToFirst( n ); + return value[ n ]; + } + return defRetValue; + } + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) { + moveIndexToFirst( pos ); + return value[ pos ]; + } + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) { + moveIndexToFirst( pos ); + return value[ pos ]; + } + } + } + /** Returns the value to which the given key is mapped; if the key is present, it is moved to the last position of the iteration order. + * + * @param k the key. + * @return the corresponding value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + */ + public V getAndMoveToLast( final long k ) { + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) { + moveIndexToLast( n ); + return value[ n ]; + } + return defRetValue; + } + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) { + moveIndexToLast( pos ); + return value[ pos ]; + } + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) { + moveIndexToLast( pos ); + return value[ pos ]; + } + } + } + /** Adds a pair to the map; if the key is already present, it is moved to the first position of the iteration order. + * + * @param k the key. + * @param v the value. + * @return the old value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + */ + public V putAndMoveToFirst( final long k, final V v ) { + int pos; + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) { + moveIndexToFirst( n ); + return setValue( n, v ); + } + containsNullKey = true; + pos = n; + } + else { + long curr; + final long[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) { + if ( ( (curr) == (k) ) ) { + moveIndexToFirst( pos ); + return setValue( pos, v ); + } + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( (curr) == (k) ) ) { + moveIndexToFirst( pos ); + return setValue( pos, v ); + } + } + } + key[ pos ] = k; + value[ pos ] = v; + if ( size == 0 ) { + first = last = pos; + // Special case of SET_UPPER_LOWER( link[ pos ], -1, -1 ); + link[ pos ] = -1L; + } + else { + link[ first ] ^= ( ( link[ first ] ^ ( ( pos & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ pos ] = ( ( -1 & 0xFFFFFFFFL ) << 32 ) | ( first & 0xFFFFFFFFL ); + first = pos; + } + if ( size++ >= maxFill ) rehash( arraySize( size, f ) ); + if ( ASSERTS ) checkTable(); + return defRetValue; + } + /** Adds a pair to the map; if the key is already present, it is moved to the last position of the iteration order. + * + * @param k the key. + * @param v the value. + * @return the old value, or the {@linkplain #defaultReturnValue() default return value} if no value was present for the given key. + */ + public V putAndMoveToLast( final long k, final V v ) { + int pos; + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) { + moveIndexToLast( n ); + return setValue( n, v ); + } + containsNullKey = true; + pos = n; + } + else { + long curr; + final long[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) { + if ( ( (curr) == (k) ) ) { + moveIndexToLast( pos ); + return setValue( pos, v ); + } + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( (curr) == (k) ) ) { + moveIndexToLast( pos ); + return setValue( pos, v ); + } + } + } + key[ pos ] = k; + value[ pos ] = v; + if ( size == 0 ) { + first = last = pos; + // Special case of SET_UPPER_LOWER( link[ pos ], -1, -1 ); + link[ pos ] = -1L; + } + else { + link[ last ] ^= ( ( link[ last ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ pos ] = ( ( last & 0xFFFFFFFFL ) << 32 ) | ( -1 & 0xFFFFFFFFL ); + last = pos; + } + if ( size++ >= maxFill ) rehash( arraySize( size, f ) ); + if ( ASSERTS ) checkTable(); + return defRetValue; + } + /** @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public V get( final Long ok ) { + if ( ok == null ) return null; + final long k = ((ok).longValue()); + if ( ( (k) == (0) ) ) return containsNullKey ? (value[ n ]) : (this.defRetValue); + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (k) == (curr) ) ) return (value[ pos ]); + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (k) == (curr) ) ) return (value[ pos ]); + } + } + + public V get( final long k ) { + if ( ( (k) == (0) ) ) return containsNullKey ? value[ n ] : defRetValue; + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return value[ pos ]; + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return value[ pos ]; + } + } + + public boolean containsKey( final long k ) { + if ( ( (k) == (0) ) ) return containsNullKey; + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return true; + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return true; + } + } + public boolean containsValue( final Object v ) { + final V value[] = this.value; + final long key[] = this.key; + if ( containsNullKey && ( (value[ n ]) == null ? (v) == null : (value[ n ]).equals(v) ) ) return true; + for( int i = n; i-- != 0; ) if ( ! ( (key[ i ]) == (0) ) && ( (value[ i ]) == null ? (v) == null : (value[ i ]).equals(v) ) ) return true; + return false; + } + /* Removes all elements from this map. + * + *

To increase object reuse, this method does not change the table size. + * If you want to reduce the table size, you must use {@link #trim()}. + * + */ + public void clear() { + if ( size == 0 ) return; + size = 0; + containsNullKey = false; + Arrays.fill( key, (0) ); + Arrays.fill( value, null ); + first = last = -1; + } + public int size() { + return size; + } + public boolean isEmpty() { + return size == 0; + } + /** A no-op for backward compatibility. + * + * @param growthFactor unused. + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public void growthFactor( int growthFactor ) {} + /** Gets the growth factor (2). + * + * @return the growth factor of this set, which is fixed (2). + * @see #growthFactor(int) + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public int growthFactor() { + return 16; + } + /** The entry class for a hash map does not record key and value, but + * rather the position in the hash table of the corresponding entry. This + * is necessary so that calls to {@link java.util.Map.Entry#setValue(Object)} are reflected in + * the map */ + final class MapEntry implements Long2ObjectMap.Entry , Map.Entry { + // The table index this entry refers to, or -1 if this entry has been deleted. + int index; + MapEntry( final int index ) { + this.index = index; + } + MapEntry() {} + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long getKey() { + return (Long.valueOf(key[ index ])); + } + public long getLongKey() { + return key[ index ]; + } + public V getValue() { + return (value[ index ]); + } + public V setValue( final V v ) { + final V oldValue = value[ index ]; + value[ index ] = v; + return oldValue; + } + @SuppressWarnings("unchecked") + public boolean equals( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + Map.Entry e = (Map.Entry)o; + return ( (key[ index ]) == (((e.getKey()).longValue())) ) && ( (value[ index ]) == null ? ((e.getValue())) == null : (value[ index ]).equals((e.getValue())) ); + } + public int hashCode() { + return it.unimi.dsi.fastutil.HashCommon.long2int(key[ index ]) ^ ( (value[ index ]) == null ? 0 : (value[ index ]).hashCode() ); + } + public String toString() { + return key[ index ] + "=>" + value[ index ]; + } + } + /** Modifies the {@link #link} vector so that the given entry is removed. + * This method will complete in constant time. + * + * @param i the index of an entry. + */ + protected void fixPointers( final int i ) { + if ( size == 0 ) { + first = last = -1; + return; + } + if ( first == i ) { + first = (int) link[ i ]; + if (0 <= first) { + // Special case of SET_PREV( link[ first ], -1 ) + link[ first ] |= (-1 & 0xFFFFFFFFL) << 32; + } + return; + } + if ( last == i ) { + last = (int) ( link[ i ] >>> 32 ); + if (0 <= last) { + // Special case of SET_NEXT( link[ last ], -1 ) + link[ last ] |= -1 & 0xFFFFFFFFL; + } + return; + } + final long linki = link[ i ]; + final int prev = (int) ( linki >>> 32 ); + final int next = (int) linki; + link[ prev ] ^= ( ( link[ prev ] ^ ( linki & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( linki & 0xFFFFFFFF00000000L ) ) & 0xFFFFFFFF00000000L ); + } + /** Modifies the {@link #link} vector for a shift from s to d. + *

This method will complete in constant time. + * + * @param s the source position. + * @param d the destination position. + */ + protected void fixPointers( int s, int d ) { + if ( size == 1 ) { + first = last = d; + // Special case of SET_UPPER_LOWER( link[ d ], -1, -1 ) + link[ d ] = -1L; + return; + } + if ( first == s ) { + first = d; + link[ (int) link[ s ] ] ^= ( ( link[ (int) link[ s ] ] ^ ( ( d & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ d ] = link[ s ]; + return; + } + if ( last == s ) { + last = d; + link[ (int) ( link[ s ] >>> 32 )] ^= ( ( link[ (int) ( link[ s ] >>> 32 )] ^ ( d & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ d ] = link[ s ]; + return; + } + final long links = link[ s ]; + final int prev = (int) ( links >>> 32 ); + final int next = (int) links; + link[ prev ] ^= ( ( link[ prev ] ^ ( d & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ next ] ^= ( ( link[ next ] ^ ( ( d & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + link[ d ] = links; + } + /** Returns the first key of this map in iteration order. + * + * @return the first key in iteration order. + */ + public long firstLongKey() { + if ( size == 0 ) throw new NoSuchElementException(); + return key[ first ]; + } + /** Returns the last key of this map in iteration order. + * + * @return the last key in iteration order. + */ + public long lastLongKey() { + if ( size == 0 ) throw new NoSuchElementException(); + return key[ last ]; + } + public LongComparator comparator() { return null; } + public Long2ObjectSortedMap tailMap( long from ) { throw new UnsupportedOperationException(); } + public Long2ObjectSortedMap headMap( long to ) { throw new UnsupportedOperationException(); } + public Long2ObjectSortedMap subMap( long from, long to ) { throw new UnsupportedOperationException(); } + /** A list iterator over a linked map. + * + *

This class provides a list iterator over a linked hash map. The constructor runs in constant time. + */ + private class MapIterator { + /** The entry that will be returned by the next call to {@link java.util.ListIterator#previous()} (or null if no previous entry exists). */ + int prev = -1; + /** The entry that will be returned by the next call to {@link java.util.ListIterator#next()} (or null if no next entry exists). */ + int next = -1; + /** The last entry that was returned (or -1 if we did not iterate or used {@link java.util.Iterator#remove()}). */ + int curr = -1; + /** The current index (in the sense of a {@link java.util.ListIterator}). Note that this value is not meaningful when this iterator has been created using the nonempty constructor.*/ + int index = -1; + private MapIterator() { + next = first; + index = 0; + } + private MapIterator( final long from ) { + if ( ( (from) == (0) ) ) { + if ( Long2ObjectLinkedOpenHashMap.this.containsNullKey ) { + next = (int) link[ n ]; + prev = n; + return; + } + else throw new NoSuchElementException( "The key " + from + " does not belong to this map." ); + } + if ( ( (key[ last ]) == (from) ) ) { + prev = last; + index = size; + return; + } + // The starting point. + int pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (from) ) & mask; + // There's always an unused entry. + while( ! ( (key[ pos ]) == (0) ) ) { + if ( ( (key[ pos ]) == (from) ) ) { + // Note: no valid index known. + next = (int) link[ pos ]; + prev = pos; + return; + } + pos = ( pos + 1 ) & mask; + } + throw new NoSuchElementException( "The key " + from + " does not belong to this map." ); + } + public boolean hasNext() { return next != -1; } + public boolean hasPrevious() { return prev != -1; } + private final void ensureIndexKnown() { + if ( index >= 0 ) return; + if ( prev == -1 ) { + index = 0; + return; + } + if ( next == -1 ) { + index = size; + return; + } + int pos = first; + index = 1; + while( pos != prev ) { + pos = (int) link[ pos ]; + index++; + } + } + public int nextIndex() { + ensureIndexKnown(); + return index; + } + public int previousIndex() { + ensureIndexKnown(); + return index - 1; + } + public int nextEntry() { + if ( ! hasNext() ) throw new NoSuchElementException(); + curr = next; + next = (int) link[ curr ]; + prev = curr; + if ( index >= 0 ) index++; + return curr; + } + public int previousEntry() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + curr = prev; + prev = (int) ( link[ curr ] >>> 32 ); + next = curr; + if ( index >= 0 ) index--; + return curr; + } + public void remove() { + ensureIndexKnown(); + if ( curr == -1 ) throw new IllegalStateException(); + if ( curr == prev ) { + /* If the last operation was a next(), we are removing an entry that preceeds + the current index, and thus we must decrement it. */ + index--; + prev = (int) ( link[ curr ] >>> 32 ); + } + else + next = (int) link[ curr ]; + size--; + /* Now we manually fix the pointers. Because of our knowledge of next + and prev, this is going to be faster than calling fixPointers(). */ + if ( prev == -1 ) first = next; + else + link[ prev ] ^= ( ( link[ prev ] ^ ( next & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + if ( next == -1 ) last = prev; + else + link[ next ] ^= ( ( link[ next ] ^ ( ( prev & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + int last, slot, pos = curr; + curr = -1; + if ( pos == n ) { + Long2ObjectLinkedOpenHashMap.this.containsNullKey = false; + value[ n ] = null; + } + else { + long curr; + final long[] key = Long2ObjectLinkedOpenHashMap.this.key; + // We have to horribly duplicate the shiftKeys() code because we need to update next/prev. + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + value[ last ] = null; + return; + } + slot = (int)it.unimi.dsi.fastutil.HashCommon.mix( (curr) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + value[ last ] = value[ pos ]; + if ( next == pos ) next = last; + if ( prev == pos ) prev = last; + fixPointers( pos, last ); + } + } + } + public int skip( final int n ) { + int i = n; + while( i-- != 0 && hasNext() ) nextEntry(); + return n - i - 1; + } + public int back( final int n ) { + int i = n; + while( i-- != 0 && hasPrevious() ) previousEntry(); + return n - i - 1; + } + } + private class EntryIterator extends MapIterator implements ObjectListIterator > { + private MapEntry entry; + public EntryIterator() {} + public EntryIterator( long from ) { + super( from ); + } + public MapEntry next() { + return entry = new MapEntry( nextEntry() ); + } + public MapEntry previous() { + return entry = new MapEntry( previousEntry() ); + } + @Override + public void remove() { + super.remove(); + entry.index = -1; // You cannot use a deleted entry. + } + public void set( Long2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + public void add( Long2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + } + private class FastEntryIterator extends MapIterator implements ObjectListIterator > { + final MapEntry entry = new MapEntry(); + public FastEntryIterator() {} + public FastEntryIterator( long from ) { + super( from ); + } + public MapEntry next() { + entry.index = nextEntry(); + return entry; + } + public MapEntry previous() { + entry.index = previousEntry(); + return entry; + } + public void set( Long2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + public void add( Long2ObjectMap.Entry ok ) { throw new UnsupportedOperationException(); } + } + private final class MapEntrySet extends AbstractObjectSortedSet > implements FastSortedEntrySet { + public ObjectBidirectionalIterator > iterator() { + return new EntryIterator(); + } + public Comparator > comparator() { return null; } + public ObjectSortedSet > subSet( Long2ObjectMap.Entry fromElement, Long2ObjectMap.Entry toElement) { throw new UnsupportedOperationException(); } + public ObjectSortedSet > headSet( Long2ObjectMap.Entry toElement ) { throw new UnsupportedOperationException(); } + public ObjectSortedSet > tailSet( Long2ObjectMap.Entry fromElement ) { throw new UnsupportedOperationException(); } + public Long2ObjectMap.Entry first() { + if ( size == 0 ) throw new NoSuchElementException(); + return new MapEntry( Long2ObjectLinkedOpenHashMap.this.first ); + } + public Long2ObjectMap.Entry last() { + if ( size == 0 ) throw new NoSuchElementException(); + return new MapEntry( Long2ObjectLinkedOpenHashMap.this.last ); + } + @SuppressWarnings("unchecked") + public boolean contains( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final long k = ((e.getKey()).longValue()); + if ( ( (k) == (0) ) ) return ( Long2ObjectLinkedOpenHashMap.this.containsNullKey && ( (value[ n ]) == null ? ((e.getValue())) == null : (value[ n ]).equals((e.getValue())) ) ); + long curr; + final long[] key = Long2ObjectLinkedOpenHashMap.this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return ( (value[ pos ]) == null ? ((e.getValue())) == null : (value[ pos ]).equals((e.getValue())) ); + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return ( (value[ pos ]) == null ? ((e.getValue())) == null : (value[ pos ]).equals((e.getValue())) ); + } + } + @SuppressWarnings("unchecked") + public boolean remove( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final long k = ((e.getKey()).longValue()); + final V v = (e.getValue()); + if ( ( (k) == (0) ) ) { + if ( containsNullKey && ( (value[ n ]) == null ? (v) == null : (value[ n ]).equals(v) ) ) { + removeNullEntry(); + return true; + } + return false; + } + long curr; + final long[] key = Long2ObjectLinkedOpenHashMap.this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return false; + if ( ( (curr) == (k) ) ) { + if ( ( (value[ pos ]) == null ? (v) == null : (value[ pos ]).equals(v) ) ) { + removeEntry( pos ); + return true; + } + return false; + } + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (curr) == (k) ) ) { + if ( ( (value[ pos ]) == null ? (v) == null : (value[ pos ]).equals(v) ) ) { + removeEntry( pos ); + return true; + } + } + } + } + public int size() { + return size; + } + public void clear() { + Long2ObjectLinkedOpenHashMap.this.clear(); + } + public ObjectBidirectionalIterator > iterator( final Long2ObjectMap.Entry from ) { + return new EntryIterator( from.getLongKey() ); + } + public ObjectBidirectionalIterator > fastIterator() { + return new FastEntryIterator(); + } + public ObjectBidirectionalIterator > fastIterator( final Long2ObjectMap.Entry from ) { + return new FastEntryIterator( from.getLongKey() ); + } + } + public FastSortedEntrySet long2ObjectEntrySet() { + if ( entries == null ) entries = new MapEntrySet(); + return entries; + } + /** An iterator on keys. + * + *

We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods + * (and possibly their type-specific counterparts) so that they return keys + * instead of entries. + */ + private final class KeyIterator extends MapIterator implements LongListIterator { + public KeyIterator( final long k ) { super( k ); } + public long previousLong() { return key[ previousEntry() ]; } + public void set( long k ) { throw new UnsupportedOperationException(); } + public void add( long k ) { throw new UnsupportedOperationException(); } + public Long previous() { return (Long.valueOf(key[ previousEntry() ])); } + public void set( Long ok ) { throw new UnsupportedOperationException(); } + public void add( Long ok ) { throw new UnsupportedOperationException(); } + public KeyIterator() { super(); } + public long nextLong() { return key[ nextEntry() ]; } + public Long next() { return (Long.valueOf(key[ nextEntry() ])); } + } + private final class KeySet extends AbstractLongSortedSet { + public LongListIterator iterator( final long from ) { + return new KeyIterator( from ); + } + public LongListIterator iterator() { + return new KeyIterator(); + } + public int size() { + return size; + } + public boolean contains( long k ) { + return containsKey( k ); + } + public boolean remove( long k ) { + final int oldSize = size; + Long2ObjectLinkedOpenHashMap.this.remove( k ); + return size != oldSize; + } + public void clear() { + Long2ObjectLinkedOpenHashMap.this.clear(); + } + public long firstLong() { + if ( size == 0 ) throw new NoSuchElementException(); + return key[ first ]; + } + public long lastLong() { + if ( size == 0 ) throw new NoSuchElementException(); + return key[ last ]; + } + public LongComparator comparator() { return null; } + final public LongSortedSet tailSet( long from ) { throw new UnsupportedOperationException(); } + final public LongSortedSet headSet( long to ) { throw new UnsupportedOperationException(); } + final public LongSortedSet subSet( long from, long to ) { throw new UnsupportedOperationException(); } + } + public LongSortedSet keySet() { + if ( keys == null ) keys = new KeySet(); + return keys; + } + /** An iterator on values. + * + *

We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods + * (and possibly their type-specific counterparts) so that they return values + * instead of entries. + */ + private final class ValueIterator extends MapIterator implements ObjectListIterator { + public V previous() { return value[ previousEntry() ]; } + public void set( V v ) { throw new UnsupportedOperationException(); } + public void add( V v ) { throw new UnsupportedOperationException(); } + public ValueIterator() { super(); } + public V next() { return value[ nextEntry() ]; } + } + public ObjectCollection values() { + if ( values == null ) values = new AbstractObjectCollection () { + public ObjectIterator iterator() { + return new ValueIterator(); + } + public int size() { + return size; + } + public boolean contains( Object v ) { + return containsValue( v ); + } + public void clear() { + Long2ObjectLinkedOpenHashMap.this.clear(); + } + }; + return values; + } + /** A no-op for backward compatibility. The kind of tables implemented by + * this class never need rehashing. + * + *

If you need to reduce the table size to fit exactly + * this set, use {@link #trim()}. + * + * @return true. + * @see #trim() + * @deprecated A no-op. + */ + @Deprecated + public boolean rehash() { + return true; + } + /** Rehashes the map, making the table as small as possible. + * + *

This method rehashes the table to the smallest size satisfying the + * load factor. It can be used when the set will not be changed anymore, so + * to optimize access speed and size. + * + *

If the table size is already the minimum possible, this method + * does nothing. + * + * @return true if there was enough memory to trim the map. + * @see #trim(int) + */ + public boolean trim() { + final int l = arraySize( size, f ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch(OutOfMemoryError cantDoIt) { return false; } + return true; + } + /** Rehashes this map if the table is too large. + * + *

Let N be the smallest table size that can hold + * max(n,{@link #size()}) entries, still satisfying the load factor. If the current + * table size is smaller than or equal to N, this method does + * nothing. Otherwise, it rehashes this map in a table of size + * N. + * + *

This method is useful when reusing maps. {@linkplain #clear() Clearing a + * map} leaves the table size untouched. If you are reusing a map + * many times, you can call this method with a typical + * size to avoid keeping around a very large table just + * because of a few large transient maps. + * + * @param n the threshold for the trimming. + * @return true if there was enough memory to trim the map. + * @see #trim() + */ + public boolean trim( final int n ) { + final int l = HashCommon.nextPowerOfTwo( (int)Math.ceil( n / f ) ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch( OutOfMemoryError cantDoIt ) { return false; } + return true; + } + /** Rehashes the map. + * + *

This method implements the basic rehashing strategy, and may be + * overriden by subclasses implementing different rehashing strategies (e.g., + * disk-based rehashing). However, you should not override this method + * unless you understand the internal workings of this class. + * + * @param newN the new size + */ + @SuppressWarnings("unchecked") + protected void rehash( final int newN ) { + final long key[] = this.key; + final V value[] = this.value; + final int mask = newN - 1; // Note that this is used by the hashing macro + final long newKey[] = new long[ newN + 1 ]; + final V newValue[] = (V[]) new Object[ newN + 1 ]; + int i = first, prev = -1, newPrev = -1, t, pos; + final long link[] = this.link; + final long newLink[] = new long[ newN + 1 ]; + first = -1; + for( int j = size; j-- != 0; ) { + if ( ( (key[ i ]) == (0) ) ) pos = newN; + else { + pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (key[ i ]) ) & mask; + while ( ! ( (newKey[ pos ]) == (0) ) ) pos = ( pos + 1 ) & mask; + } + newKey[ pos ] = key[ i ]; + newValue[ pos ] = value[ i ]; + if ( prev != -1 ) { + newLink[ newPrev ] ^= ( ( newLink[ newPrev ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + newLink[ pos ] ^= ( ( newLink[ pos ] ^ ( ( newPrev & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + newPrev = pos; + } + else { + newPrev = first = pos; + // Special case of SET(newLink[ pos ], -1, -1); + newLink[ pos ] = -1L; + } + t = i; + i = (int) link[ i ]; + prev = t; + } + this.link = newLink; + this.last = newPrev; + if ( newPrev != -1 ) + // Special case of SET_NEXT( newLink[ newPrev ], -1 ); + newLink[ newPrev ] |= -1 & 0xFFFFFFFFL; + n = newN; + this.mask = mask; + maxFill = maxFill( n, f ); + this.key = newKey; + this.value = newValue; + } + /** Returns a deep copy of this map. + * + *

This method performs a deep copy of this hash map; the data stored in the + * map, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this map. + */ + @SuppressWarnings("unchecked") + public Long2ObjectLinkedOpenHashMap clone() { + Long2ObjectLinkedOpenHashMap c; + try { + c = (Long2ObjectLinkedOpenHashMap )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.keys = null; + c.values = null; + c.entries = null; + c.containsNullKey = containsNullKey; + c.key = key.clone(); + c.value = value.clone(); + c.link = link.clone(); + return c; + } + /** Returns a hash code for this map. + * + * This method overrides the generic method provided by the superclass. + * Since equals() is not overriden, it is important + * that the value returned by this method is the same value as + * the one returned by the overriden method. + * + * @return a hash code for this map. + */ + public int hashCode() { + int h = 0; + for( int j = realSize(), i = 0, t = 0; j-- != 0; ) { + while( ( (key[ i ]) == (0) ) ) i++; + t = it.unimi.dsi.fastutil.HashCommon.long2int(key[ i ]); + if ( this != value[ i ] ) + t ^= ( (value[ i ]) == null ? 0 : (value[ i ]).hashCode() ); + h += t; + i++; + } + // Zero / null keys have hash zero. + if ( containsNullKey ) h += ( (value[ n ]) == null ? 0 : (value[ n ]).hashCode() ); + return h; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + final long key[] = this.key; + final V value[] = this.value; + final MapIterator i = new MapIterator(); + s.defaultWriteObject(); + for( int j = size, e; j-- != 0; ) { + e = i.nextEntry(); + s.writeLong( key[ e ] ); + s.writeObject( value[ e ] ); + } + } + @SuppressWarnings("unchecked") + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + n = arraySize( size, f ); + maxFill = maxFill( n, f ); + mask = n - 1; + final long key[] = this.key = new long[ n + 1 ]; + final V value[] = this.value = (V[]) new Object[ n + 1 ]; + final long link[] = this.link = new long[ n + 1 ]; + int prev = -1; + first = last = -1; + long k; + V v; + for( int i = size, pos; i-- != 0; ) { + k = s.readLong(); + v = (V) s.readObject(); + if ( ( (k) == (0) ) ) { + pos = n; + containsNullKey = true; + } + else { + pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask; + while ( ! ( (key[ pos ]) == (0) ) ) pos = ( pos + 1 ) & mask; + } + key[ pos ] = k; + value[ pos ] = v; + if ( first != -1 ) { + link[ prev ] ^= ( ( link[ prev ] ^ ( pos & 0xFFFFFFFFL ) ) & 0xFFFFFFFFL ); + link[ pos ] ^= ( ( link[ pos ] ^ ( ( prev & 0xFFFFFFFFL ) << 32 ) ) & 0xFFFFFFFF00000000L ); + prev = pos; + } + else { + prev = first = pos; + // Special case of SET_PREV( newLink[ pos ], -1 ); + link[ pos ] |= (-1L & 0xFFFFFFFFL) << 32; + } + } + last = prev; + if ( prev != -1 ) + // Special case of SET_NEXT( link[ prev ], -1 ); + link[ prev ] |= -1 & 0xFFFFFFFFL; + if ( ASSERTS ) checkTable(); + } + private void checkTable() {} +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectMap.java b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectMap.java new file mode 100644 index 0000000..afbb18d --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectMap.java @@ -0,0 +1,151 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectSet; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import java.util.Map; +/** A type-specific {@link Map}; provides some additional methods that use polymorphism to avoid (un)boxing, and handling of a default return value. + * + *

Besides extending the corresponding type-specific {@linkplain it.unimi.dsi.fastutil.Function function}, this interface strengthens {@link #entrySet()}, + * {@link #keySet()} and {@link #values()}. Maps returning entry sets of type {@link FastEntrySet} support also fast iteration. + * + *

A submap or subset may or may not have an + * independent default return value (which however must be initialized to the + * default return value of the originator). + * + * @see Map + */ +public interface Long2ObjectMap extends Long2ObjectFunction , Map { + /** An entry set providing fast iteration. + * + *

In some cases (e.g., hash-based classes) iteration over an entry set requires the creation + * of a large number of {@link java.util.Map.Entry} objects. Some fastutil + * maps might return {@linkplain #entrySet() entry set} objects of type FastEntrySet: in this case, {@link #fastIterator() fastIterator()} + * will return an iterator that is guaranteed not to create a large number of objects, possibly + * by returning always the same entry (of course, mutated). + */ + public interface FastEntrySet extends ObjectSet > { + /** Returns a fast iterator over this entry set; the iterator might return always the same entry object, suitably mutated. + * + * @return a fast iterator over this entry set; the iterator might return always the same {@link java.util.Map.Entry} object, suitably mutated. + */ + public ObjectIterator > fastIterator(); + } + /** Returns a set view of the mappings contained in this map. + *

Note that this specification strengthens the one given in {@link Map#entrySet()}. + * + * @return a set view of the mappings contained in this map. + * @see Map#entrySet() + */ + ObjectSet> entrySet(); + /** Returns a type-specific set view of the mappings contained in this map. + * + *

This method is necessary because there is no inheritance along + * type parameters: it is thus impossible to strengthen {@link #entrySet()} + * so that it returns an {@link it.unimi.dsi.fastutil.objects.ObjectSet} + * of type-specific entries (the latter makes it possible to + * access keys and values with type-specific methods). + * + * @return a type-specific set view of the mappings contained in this map. + * @see #entrySet() + */ + ObjectSet > long2ObjectEntrySet(); + /** Returns a set view of the keys contained in this map. + *

Note that this specification strengthens the one given in {@link Map#keySet()}. + * + * @return a set view of the keys contained in this map. + * @see Map#keySet() + */ + LongSet keySet(); + /** Returns a set view of the values contained in this map. + *

Note that this specification strengthens the one given in {@link Map#values()}. + * + * @return a set view of the values contained in this map. + * @see Map#values() + */ + ObjectCollection values(); + /** A type-specific {@link java.util.Map.Entry}; provides some additional methods + * that use polymorphism to avoid (un)boxing. + * + * @see java.util.Map.Entry + */ + interface Entry extends Map.Entry { + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + Long getKey(); + /** + * @see java.util.Map.Entry#getKey() + */ + long getLongKey(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectMaps.java b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectMaps.java new file mode 100644 index 0000000..9047158 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectMaps.java @@ -0,0 +1,312 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.objects.ObjectSet; +import it.unimi.dsi.fastutil.objects.ObjectSets; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectCollections; +import java.util.Map; +/** A class providing static methods and objects that do useful things with type-specific maps. + * + * @see it.unimi.dsi.fastutil.Maps + * @see java.util.Collections + */ +public class Long2ObjectMaps { + private Long2ObjectMaps() {} + /** An immutable class representing an empty type-specific map. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific map. + */ + public static class EmptyMap extends Long2ObjectFunctions.EmptyFunction implements Long2ObjectMap , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptyMap() {} + public boolean containsValue( final Object v ) { return false; } + public void putAll( final Map m ) { throw new UnsupportedOperationException(); } + @SuppressWarnings("unchecked") + public ObjectSet > long2ObjectEntrySet() { return ObjectSets.EMPTY_SET; } + + public LongSet keySet() { return LongSets.EMPTY_SET; } + @SuppressWarnings("unchecked") + public ObjectCollection values() { return ObjectSets.EMPTY_SET; } + private Object readResolve() { return EMPTY_MAP; } + public Object clone() { return EMPTY_MAP; } + public boolean isEmpty() { return true; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + public ObjectSet> entrySet() { return (ObjectSet)long2ObjectEntrySet(); } + public int hashCode() { return 0; } + public boolean equals( final Object o ) { + if ( ! ( o instanceof Map ) ) return false; + return ((Map)o).isEmpty(); + } + public String toString() { return "{}"; } + } + /** An empty type-specific map (immutable). It is serializable and cloneable. + */ + @SuppressWarnings("rawtypes") + public static final EmptyMap EMPTY_MAP = new EmptyMap(); + /** Return an empty map (immutable). It is serializable and cloneable. + * + *

This method provides a typesafe access to {@link #EMPTY_MAP}. + * @return an empty map (immutable). + */ + @SuppressWarnings("unchecked") + public static Long2ObjectMap emptyMap() { + return EMPTY_MAP; + } + /** An immutable class representing a type-specific singleton map. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific map. + */ + public static class Singleton extends Long2ObjectFunctions.Singleton implements Long2ObjectMap , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected transient ObjectSet > entries; + protected transient LongSet keys; + protected transient ObjectCollection values; + protected Singleton( final long key, final V value ) { + super( key, value ); + } + public boolean containsValue( final Object v ) { return ( (value) == null ? (v) == null : (value).equals(v) ); } + public void putAll( final Map m ) { throw new UnsupportedOperationException(); } + public ObjectSet > long2ObjectEntrySet() { if ( entries == null ) entries = ObjectSets.singleton( (Long2ObjectMap.Entry )new SingletonEntry() ); return entries; } + public LongSet keySet() { if ( keys == null ) keys = LongSets.singleton( key ); return keys; } + public ObjectCollection values() { if ( values == null ) values = ObjectSets.singleton( value ); return values; } + protected class SingletonEntry implements Long2ObjectMap.Entry , Map.Entry { + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long getKey() { return (Long.valueOf(Singleton.this.key)); } + public V getValue() { return (Singleton.this.value); } + public long getLongKey() { return Singleton.this.key; } + public V setValue( final V value ) { throw new UnsupportedOperationException(); } + public boolean equals( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + Map.Entry e = (Map.Entry)o; + return ( (Singleton.this.key) == (((((Long)(e.getKey())).longValue()))) ) && ( (Singleton.this.value) == null ? ((e.getValue())) == null : (Singleton.this.value).equals((e.getValue())) ); + } + public int hashCode() { return it.unimi.dsi.fastutil.HashCommon.long2int(Singleton.this.key) ^ ( (Singleton.this.value) == null ? 0 : (Singleton.this.value).hashCode() ); } + public String toString() { return Singleton.this.key + "->" + Singleton.this.value; } + } + public boolean isEmpty() { return false; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + public ObjectSet> entrySet() { return (ObjectSet)long2ObjectEntrySet(); } + public int hashCode() { return it.unimi.dsi.fastutil.HashCommon.long2int(key) ^ ( (value) == null ? 0 : (value).hashCode() ); } + public boolean equals( final Object o ) { + if ( o == this ) return true; + if ( ! ( o instanceof Map ) ) return false; + Map m = (Map)o; + if ( m.size() != 1 ) return false; + return entrySet().iterator().next().equals( m.entrySet().iterator().next() ); + } + public String toString() { return "{" + key + "=>" + value + "}"; } + } + /** Returns a type-specific immutable map containing only the specified pair. The returned map is serializable and cloneable. + * + *

Note that albeit the returned map is immutable, its default return value may be changed. + * + * @param key the only key of the returned map. + * @param value the only value of the returned map. + * @return a type-specific immutable map containing just the pair <key,value>. + */ + public static Long2ObjectMap singleton( final long key, V value ) { + return new Singleton ( key, value ); + } + /** Returns a type-specific immutable map containing only the specified pair. The returned map is serializable and cloneable. + * + *

Note that albeit the returned map is immutable, its default return value may be changed. + * + * @param key the only key of the returned map. + * @param value the only value of the returned map. + * @return a type-specific immutable map containing just the pair <key,value>. + */ + public static Long2ObjectMap singleton( final Long key, final V value ) { + return new Singleton ( ((key).longValue()), (value) ); + } + /** A synchronized wrapper class for maps. */ + public static class SynchronizedMap extends Long2ObjectFunctions.SynchronizedFunction implements Long2ObjectMap , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final Long2ObjectMap map; + protected transient ObjectSet > entries; + protected transient LongSet keys; + protected transient ObjectCollection values; + protected SynchronizedMap( final Long2ObjectMap m, final Object sync ) { + super( m, sync ); + this.map = m; + } + protected SynchronizedMap( final Long2ObjectMap m ) { + super( m ); + this.map = m; + } + public int size() { synchronized( sync ) { return map.size(); } } + public boolean containsKey( final long k ) { synchronized( sync ) { return map.containsKey( k ); } } + public boolean containsValue( final Object v ) { synchronized( sync ) { return map.containsValue( v ); } } + public V defaultReturnValue() { synchronized( sync ) { return map.defaultReturnValue(); } } + public void defaultReturnValue( final V defRetValue ) { synchronized( sync ) { map.defaultReturnValue( defRetValue ); } } + public V put( final long k, final V v ) { synchronized( sync ) { return map.put( k, v ); } } + //public void putAll( final MAP KEY_VALUE_EXTENDS_GENERIC c ) { synchronized( sync ) { map.putAll( c ); } } + public void putAll( final Map m ) { synchronized( sync ) { map.putAll( m ); } } + public ObjectSet > long2ObjectEntrySet() { if ( entries == null ) entries = ObjectSets.synchronize( map.long2ObjectEntrySet(), sync ); return entries; } + public LongSet keySet() { if ( keys == null ) keys = LongSets.synchronize( map.keySet(), sync ); return keys; } + public ObjectCollection values() { if ( values == null ) return ObjectCollections.synchronize( map.values(), sync ); return values; } + public void clear() { synchronized( sync ) { map.clear(); } } + public String toString() { synchronized( sync ) { return map.toString(); } } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Long k, final V v ) { synchronized( sync ) { return map.put( k, v ); } } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V remove( final long k ) { synchronized( sync ) { return map.remove( k ); } } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V get( final long k ) { synchronized( sync ) { return map.get( k ); } } + public boolean containsKey( final Object ok ) { synchronized( sync ) { return map.containsKey( ok ); } } + public boolean isEmpty() { synchronized( sync ) { return map.isEmpty(); } } + public ObjectSet> entrySet() { synchronized( sync ) { return map.entrySet(); } } + public int hashCode() { synchronized( sync ) { return map.hashCode(); } } + public boolean equals( final Object o ) { synchronized( sync ) { return map.equals( o ); } } + } + /** Returns a synchronized type-specific map backed by the given type-specific map. + * + * @param m the map to be wrapped in a synchronized map. + * @return a synchronized view of the specified map. + * @see java.util.Collections#synchronizedMap(Map) + */ + public static Long2ObjectMap synchronize( final Long2ObjectMap m ) { return new SynchronizedMap ( m ); } + /** Returns a synchronized type-specific map backed by the given type-specific map, using an assigned object to synchronize. + * + * @param m the map to be wrapped in a synchronized map. + * @param sync an object that will be used to synchronize the access to the map. + * @return a synchronized view of the specified map. + * @see java.util.Collections#synchronizedMap(Map) + */ + public static Long2ObjectMap synchronize( final Long2ObjectMap m, final Object sync ) { return new SynchronizedMap ( m, sync ); } + /** An unmodifiable wrapper class for maps. */ + public static class UnmodifiableMap extends Long2ObjectFunctions.UnmodifiableFunction implements Long2ObjectMap , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final Long2ObjectMap map; + protected transient ObjectSet > entries; + protected transient LongSet keys; + protected transient ObjectCollection values; + protected UnmodifiableMap( final Long2ObjectMap m ) { + super( m ); + this.map = m; + } + public int size() { return map.size(); } + public boolean containsKey( final long k ) { return map.containsKey( k ); } + public boolean containsValue( final Object v ) { return map.containsValue( v ); } + public V defaultReturnValue() { throw new UnsupportedOperationException(); } + public void defaultReturnValue( final V defRetValue ) { throw new UnsupportedOperationException(); } + public V put( final long k, final V v ) { throw new UnsupportedOperationException(); } + //public void putAll( final MAP KEY_VALUE_EXTENDS_GENERIC c ) { throw new UnsupportedOperationException(); } + public void putAll( final Map m ) { throw new UnsupportedOperationException(); } + public ObjectSet > long2ObjectEntrySet() { if ( entries == null ) entries = ObjectSets.unmodifiable( map.long2ObjectEntrySet() ); return entries; } + public LongSet keySet() { if ( keys == null ) keys = LongSets.unmodifiable( map.keySet() ); return keys; } + public ObjectCollection values() { if ( values == null ) return ObjectCollections.unmodifiable( map.values() ); return values; } + public void clear() { throw new UnsupportedOperationException(); } + public String toString() { return map.toString(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V remove( final long k ) { throw new UnsupportedOperationException(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V get( final long k ) { return map.get( k ); } + public boolean containsKey( final Object ok ) { return map.containsKey( ok ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V remove( final Object k ) { throw new UnsupportedOperationException(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V get( final Object k ) { return map.get( k ); } + public boolean isEmpty() { return map.isEmpty(); } + public ObjectSet> entrySet() { return ObjectSets.unmodifiable( map.entrySet() ); } + } + /** Returns an unmodifiable type-specific map backed by the given type-specific map. + * + * @param m the map to be wrapped in an unmodifiable map. + * @return an unmodifiable view of the specified map. + * @see java.util.Collections#unmodifiableMap(Map) + */ + public static Long2ObjectMap unmodifiable( final Long2ObjectMap m ) { return new UnmodifiableMap ( m ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectOpenCustomHashMap.java b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectOpenCustomHashMap.java new file mode 100644 index 0000000..547fcbf --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectOpenCustomHashMap.java @@ -0,0 +1,922 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.HashCommon; +import static it.unimi.dsi.fastutil.HashCommon.arraySize; +import static it.unimi.dsi.fastutil.HashCommon.maxFill; +import java.util.Map; +import java.util.Arrays; +import java.util.NoSuchElementException; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.AbstractObjectSet; +/** A type-specific hash map with a fast, small-footprint implementation whose {@linkplain it.unimi.dsi.fastutil.Hash.Strategy hashing strategy} + * is specified at creation time. + * + *

Instances of this class use a hash table to represent a map. The table is + * filled up to a specified load factor, and then doubled in size to + * accommodate new entries. If the table is emptied below one fourth + * of the load factor, it is halved in size. However, halving is + * not performed when deleting entries from an iterator, as it would interfere + * with the iteration process. + * + *

Note that {@link #clear()} does not modify the hash table size. + * Rather, a family of {@linkplain #trim() trimming + * methods} lets you control the size of the table; this is particularly useful + * if you reuse instances of this class. + * + * @see Hash + * @see HashCommon + */ +public class Long2ObjectOpenCustomHashMap extends AbstractLong2ObjectMap implements java.io.Serializable, Cloneable, Hash { + private static final long serialVersionUID = 0L; + private static final boolean ASSERTS = false; + /** The array of keys. */ + protected transient long[] key; + /** The array of values. */ + protected transient V[] value; + /** The mask for wrapping a position counter. */ + protected transient int mask; + /** Whether this set contains the key zero. */ + protected transient boolean containsNullKey; + /** The hash strategy of this custom map. */ + protected it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy; + /** The current table size. */ + protected transient int n; + /** Threshold after which we rehash. It must be the table size times {@link #f}. */ + protected transient int maxFill; + /** Number of entries in the set (including the key zero, if present). */ + protected int size; + /** The acceptable load factor. */ + protected final float f; + /** Cached set of entries. */ + protected transient FastEntrySet entries; + /** Cached set of keys. */ + protected transient LongSet keys; + /** Cached collection of values. */ + protected transient ObjectCollection values; + /** Creates a new hash map. + * + *

The actual table size will be the least power of two greater than expected/f. + * + * @param expected the expected number of elements in the hash set. + * @param f the load factor. + * @param strategy the strategy. + */ + @SuppressWarnings("unchecked") + public Long2ObjectOpenCustomHashMap( final int expected, final float f, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this.strategy = strategy; + if ( f <= 0 || f > 1 ) throw new IllegalArgumentException( "Load factor must be greater than 0 and smaller than or equal to 1" ); + if ( expected < 0 ) throw new IllegalArgumentException( "The expected number of elements must be nonnegative" ); + this.f = f; + n = arraySize( expected, f ); + mask = n - 1; + maxFill = maxFill( n, f ); + key = new long[ n + 1 ]; + value = (V[]) new Object[ n + 1 ]; + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * + * @param expected the expected number of elements in the hash map. + * @param strategy the strategy. + */ + public Long2ObjectOpenCustomHashMap( final int expected, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( expected, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash map with initial expected {@link Hash#DEFAULT_INITIAL_SIZE} entries + * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * @param strategy the strategy. + */ + public Long2ObjectOpenCustomHashMap( final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash map copying a given one. + * + * @param m a {@link Map} to be copied into the new hash map. + * @param f the load factor. + * @param strategy the strategy. + */ + public Long2ObjectOpenCustomHashMap( final Map m, final float f, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( m.size(), f, strategy ); + putAll( m ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given one. + * + * @param m a {@link Map} to be copied into the new hash map. + * @param strategy the strategy. + */ + public Long2ObjectOpenCustomHashMap( final Map m, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( m, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash map copying a given type-specific one. + * + * @param m a type-specific map to be copied into the new hash map. + * @param f the load factor. + * @param strategy the strategy. + */ + public Long2ObjectOpenCustomHashMap( final Long2ObjectMap m, final float f, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( m.size(), f, strategy ); + putAll( m ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given type-specific one. + * + * @param m a type-specific map to be copied into the new hash map. + * @param strategy the strategy. + */ + public Long2ObjectOpenCustomHashMap( final Long2ObjectMap m, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( m, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash map using the elements of two parallel arrays. + * + * @param k the array of keys of the new hash map. + * @param v the array of corresponding values in the new hash map. + * @param f the load factor. + * @param strategy the strategy. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Long2ObjectOpenCustomHashMap( final long[] k, final V[] v, final float f, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( k.length, f, strategy ); + if ( k.length != v.length ) throw new IllegalArgumentException( "The key array and the value array have different lengths (" + k.length + " and " + v.length + ")" ); + for( int i = 0; i < k.length; i++ ) this.put( k[ i ], v[ i ] ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using the elements of two parallel arrays. + * + * @param k the array of keys of the new hash map. + * @param v the array of corresponding values in the new hash map. + * @param strategy the strategy. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Long2ObjectOpenCustomHashMap( final long[] k, final V[] v, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( k, v, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Returns the hashing strategy. + * + * @return the hashing strategy of this custom hash map. + */ + public it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy() { + return strategy; + } + private int realSize() { + return containsNullKey ? size - 1 : size; + } + private void ensureCapacity( final int capacity ) { + final int needed = arraySize( capacity, f ); + if ( needed > n ) rehash( needed ); + } + private void tryCapacity( final long capacity ) { + final int needed = (int)Math.min( 1 << 30, Math.max( 2, HashCommon.nextPowerOfTwo( (long)Math.ceil( capacity / f ) ) ) ); + if ( needed > n ) rehash( needed ); + } + private V removeEntry( final int pos ) { + final V oldValue = value[ pos ]; + value[ pos ] = null; + size--; + shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return oldValue; + } + private V removeNullEntry() { + containsNullKey = false; + final V oldValue = value[ n ]; + value[ n ] = null; + size--; + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return oldValue; + } + /** {@inheritDoc} */ + public void putAll(Map m) { + if ( f <= .5 ) ensureCapacity( m.size() ); // The resulting map will be sized for m.size() elements + else tryCapacity( size() + m.size() ); // The resulting map will be tentatively sized for size() + m.size() elements + super.putAll( m ); + } + private int insert(final long k, final V v) { + int pos; + if ( ( strategy.equals( (k), (0) ) ) ) { + if ( containsNullKey ) return n; + containsNullKey = true; + pos = n; + } + else { + long curr; + final long[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) { + if ( ( strategy.equals( (curr), (k) ) ) ) return pos; + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( strategy.equals( (curr), (k) ) ) ) return pos; + } + } + key[ pos ] = k; + value[ pos ] = v; + if ( size++ >= maxFill ) rehash( arraySize( size + 1, f ) ); + if ( ASSERTS ) checkTable(); + return -1; + } + public V put(final long k, final V v) { + final int pos = insert( k, v ); + if ( pos < 0 ) return defRetValue; + final V oldValue = value[ pos ]; + value[ pos ] = v; + return oldValue; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Long ok, final V ov ) { + final V v = (ov); + final int pos = insert( ((ok).longValue()), v ); + if ( pos < 0 ) return (this.defRetValue); + final V oldValue = value[ pos ]; + value[ pos ] = v; + return (oldValue); + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + protected final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + long curr; + final long[] key = this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + value[ last ] = null; + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + value[ last ] = value[ pos ]; + } + } + + public V remove( final long k ) { + if ( ( strategy.equals( ( k), (0) ) ) ) { + if ( containsNullKey ) return removeNullEntry(); + return defRetValue; + } + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( strategy.equals( (k), (curr) ) ) ) return removeEntry( pos ); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( strategy.equals( (k), (curr) ) ) ) return removeEntry( pos ); + } + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + + public V remove( final Object ok ) { + final long k = ((((Long)(ok)).longValue())); + if ( ( strategy.equals( (k), (0) ) ) ) { + if ( containsNullKey ) return (removeNullEntry()); + return (this.defRetValue); + } + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( strategy.equals( (curr), (k) ) ) ) return (removeEntry( pos )); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( strategy.equals( (curr), (k) ) ) ) return (removeEntry( pos )); + } + } + /** @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public V get( final Long ok ) { + if ( ok == null ) return null; + final long k = ((ok).longValue()); + if ( ( strategy.equals( (k), (0) ) ) ) return containsNullKey ? (value[ n ]) : (this.defRetValue); + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( strategy.equals( (k), (curr) ) ) ) return (value[ pos ]); + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( strategy.equals( (k), (curr) ) ) ) return (value[ pos ]); + } + } + + public V get( final long k ) { + if ( ( strategy.equals( ( k), (0) ) ) ) return containsNullKey ? value[ n ] : defRetValue; + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( strategy.equals( (k), (curr) ) ) ) return value[ pos ]; + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( strategy.equals( (k), (curr) ) ) ) return value[ pos ]; + } + } + + public boolean containsKey( final long k ) { + if ( ( strategy.equals( ( k), (0) ) ) ) return containsNullKey; + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return true; + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return true; + } + } + public boolean containsValue( final Object v ) { + final V value[] = this.value; + final long key[] = this.key; + if ( containsNullKey && ( (value[ n ]) == null ? (v) == null : (value[ n ]).equals(v) ) ) return true; + for( int i = n; i-- != 0; ) if ( ! ( (key[ i ]) == (0) ) && ( (value[ i ]) == null ? (v) == null : (value[ i ]).equals(v) ) ) return true; + return false; + } + /* Removes all elements from this map. + * + *

To increase object reuse, this method does not change the table size. + * If you want to reduce the table size, you must use {@link #trim()}. + * + */ + public void clear() { + if ( size == 0 ) return; + size = 0; + containsNullKey = false; + Arrays.fill( key, (0) ); + Arrays.fill( value, null ); + } + public int size() { + return size; + } + public boolean isEmpty() { + return size == 0; + } + /** A no-op for backward compatibility. + * + * @param growthFactor unused. + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public void growthFactor( int growthFactor ) {} + /** Gets the growth factor (2). + * + * @return the growth factor of this set, which is fixed (2). + * @see #growthFactor(int) + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public int growthFactor() { + return 16; + } + /** The entry class for a hash map does not record key and value, but + * rather the position in the hash table of the corresponding entry. This + * is necessary so that calls to {@link java.util.Map.Entry#setValue(Object)} are reflected in + * the map */ + final class MapEntry implements Long2ObjectMap.Entry , Map.Entry { + // The table index this entry refers to, or -1 if this entry has been deleted. + int index; + MapEntry( final int index ) { + this.index = index; + } + MapEntry() {} + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long getKey() { + return (Long.valueOf(key[ index ])); + } + public long getLongKey() { + return key[ index ]; + } + public V getValue() { + return (value[ index ]); + } + public V setValue( final V v ) { + final V oldValue = value[ index ]; + value[ index ] = v; + return oldValue; + } + @SuppressWarnings("unchecked") + public boolean equals( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + Map.Entry e = (Map.Entry)o; + return ( strategy.equals( (key[ index ]), (((e.getKey()).longValue())) ) ) && ( (value[ index ]) == null ? ((e.getValue())) == null : (value[ index ]).equals((e.getValue())) ); + } + public int hashCode() { + return ( strategy.hashCode(key[ index ]) ) ^ ( (value[ index ]) == null ? 0 : (value[ index ]).hashCode() ); + } + public String toString() { + return key[ index ] + "=>" + value[ index ]; + } + } + /** An iterator over a hash map. */ + private class MapIterator { + /** The index of the last entry returned, if positive or zero; initially, {@link #n}. If negative, the last + entry returned was that of the key of index {@code - pos - 1} from the {@link #wrapped} list. */ + int pos = n; + /** The index of the last entry that has been returned (more precisely, the value of {@link #pos} if {@link #pos} is positive, + or {@link Integer#MIN_VALUE} if {@link #pos} is negative). It is -1 if either + we did not return an entry yet, or the last returned entry has been removed. */ + int last = -1; + /** A downward counter measuring how many entries must still be returned. */ + int c = size; + /** A boolean telling us whether we should return the entry with the null key. */ + boolean mustReturnNullKey = Long2ObjectOpenCustomHashMap.this.containsNullKey; + /** A lazily allocated list containing keys of entries that have wrapped around the table because of removals. */ + LongArrayList wrapped; + public boolean hasNext() { + return c != 0; + } + public int nextEntry() { + if ( ! hasNext() ) throw new NoSuchElementException(); + c--; + if ( mustReturnNullKey ) { + mustReturnNullKey = false; + return last = n; + } + final long key[] = Long2ObjectOpenCustomHashMap.this.key; + for(;;) { + if ( --pos < 0 ) { + // We are just enumerating elements from the wrapped list. + last = Integer.MIN_VALUE; + final long k = wrapped.getLong( - pos - 1 ); + int p = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask; + while ( ! ( strategy.equals( (k), (key[ p ]) ) ) ) p = ( p + 1 ) & mask; + return p; + } + if ( ! ( (key[ pos ]) == (0) ) ) return last = pos; + } + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + private final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + long curr; + final long[] key = Long2ObjectOpenCustomHashMap.this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + value[ last ] = null; + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + if ( pos < last ) { // Wrapped entry. + if ( wrapped == null ) wrapped = new LongArrayList ( 2 ); + wrapped.add( key[ pos ] ); + } + key[ last ] = curr; + value[ last ] = value[ pos ]; + } + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + if ( last == n ) { + containsNullKey = false; + value[ n ] = null; + } + else if ( pos >= 0 ) shiftKeys( last ); + else { + // We're removing wrapped entries. + Long2ObjectOpenCustomHashMap.this.remove( wrapped.getLong( - pos - 1 ) ); + last = -1; // Note that we must not decrement size + return; + } + size--; + last = -1; // You can no longer remove this entry. + if ( ASSERTS ) checkTable(); + } + public int skip( final int n ) { + int i = n; + while( i-- != 0 && hasNext() ) nextEntry(); + return n - i - 1; + } + } + private class EntryIterator extends MapIterator implements ObjectIterator > { + private MapEntry entry; + public Long2ObjectMap.Entry next() { + return entry = new MapEntry( nextEntry() ); + } + @Override + public void remove() { + super.remove(); + entry.index = -1; // You cannot use a deleted entry. + } + } + private class FastEntryIterator extends MapIterator implements ObjectIterator > { + private final MapEntry entry = new MapEntry(); + public MapEntry next() { + entry.index = nextEntry(); + return entry; + } + } + private final class MapEntrySet extends AbstractObjectSet > implements FastEntrySet { + public ObjectIterator > iterator() { + return new EntryIterator(); + } + public ObjectIterator > fastIterator() { + return new FastEntryIterator(); + } + @SuppressWarnings("unchecked") + public boolean contains( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final long k = ((e.getKey()).longValue()); + if ( ( strategy.equals( (k), (0) ) ) ) return ( Long2ObjectOpenCustomHashMap.this.containsNullKey && ( (value[ n ]) == null ? ((e.getValue())) == null : (value[ n ]).equals((e.getValue())) ) ); + long curr; + final long[] key = Long2ObjectOpenCustomHashMap.this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return ( (value[ pos ]) == null ? ((e.getValue())) == null : (value[ pos ]).equals((e.getValue())) ); + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return ( (value[ pos ]) == null ? ((e.getValue())) == null : (value[ pos ]).equals((e.getValue())) ); + } + } + @SuppressWarnings("unchecked") + public boolean remove( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final long k = ((e.getKey()).longValue()); + final V v = (e.getValue()); + if ( ( strategy.equals( (k), (0) ) ) ) { + if ( containsNullKey && ( (value[ n ]) == null ? (v) == null : (value[ n ]).equals(v) ) ) { + removeNullEntry(); + return true; + } + return false; + } + long curr; + final long[] key = Long2ObjectOpenCustomHashMap.this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (curr), (k) ) ) ) { + if ( ( (value[ pos ]) == null ? (v) == null : (value[ pos ]).equals(v) ) ) { + removeEntry( pos ); + return true; + } + return false; + } + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (curr), (k) ) ) ) { + if ( ( (value[ pos ]) == null ? (v) == null : (value[ pos ]).equals(v) ) ) { + removeEntry( pos ); + return true; + } + } + } + } + public int size() { + return size; + } + public void clear() { + Long2ObjectOpenCustomHashMap.this.clear(); + } + } + public FastEntrySet long2ObjectEntrySet() { + if ( entries == null ) entries = new MapEntrySet(); + return entries; + } + /** An iterator on keys. + * + *

We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods + * (and possibly their type-specific counterparts) so that they return keys + * instead of entries. + */ + private final class KeyIterator extends MapIterator implements LongIterator { + public KeyIterator() { super(); } + public long nextLong() { return key[ nextEntry() ]; } + public Long next() { return (Long.valueOf(key[ nextEntry() ])); } + } + private final class KeySet extends AbstractLongSet { + public LongIterator iterator() { + return new KeyIterator(); + } + public int size() { + return size; + } + public boolean contains( long k ) { + return containsKey( k ); + } + public boolean remove( long k ) { + final int oldSize = size; + Long2ObjectOpenCustomHashMap.this.remove( k ); + return size != oldSize; + } + public void clear() { + Long2ObjectOpenCustomHashMap.this.clear(); + } + } + public LongSet keySet() { + if ( keys == null ) keys = new KeySet(); + return keys; + } + /** An iterator on values. + * + *

We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods + * (and possibly their type-specific counterparts) so that they return values + * instead of entries. + */ + private final class ValueIterator extends MapIterator implements ObjectIterator { + public ValueIterator() { super(); } + public V next() { return value[ nextEntry() ]; } + } + public ObjectCollection values() { + if ( values == null ) values = new AbstractObjectCollection () { + public ObjectIterator iterator() { + return new ValueIterator(); + } + public int size() { + return size; + } + public boolean contains( Object v ) { + return containsValue( v ); + } + public void clear() { + Long2ObjectOpenCustomHashMap.this.clear(); + } + }; + return values; + } + /** A no-op for backward compatibility. The kind of tables implemented by + * this class never need rehashing. + * + *

If you need to reduce the table size to fit exactly + * this set, use {@link #trim()}. + * + * @return true. + * @see #trim() + * @deprecated A no-op. + */ + @Deprecated + public boolean rehash() { + return true; + } + /** Rehashes the map, making the table as small as possible. + * + *

This method rehashes the table to the smallest size satisfying the + * load factor. It can be used when the set will not be changed anymore, so + * to optimize access speed and size. + * + *

If the table size is already the minimum possible, this method + * does nothing. + * + * @return true if there was enough memory to trim the map. + * @see #trim(int) + */ + public boolean trim() { + final int l = arraySize( size, f ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch(OutOfMemoryError cantDoIt) { return false; } + return true; + } + /** Rehashes this map if the table is too large. + * + *

Let N be the smallest table size that can hold + * max(n,{@link #size()}) entries, still satisfying the load factor. If the current + * table size is smaller than or equal to N, this method does + * nothing. Otherwise, it rehashes this map in a table of size + * N. + * + *

This method is useful when reusing maps. {@linkplain #clear() Clearing a + * map} leaves the table size untouched. If you are reusing a map + * many times, you can call this method with a typical + * size to avoid keeping around a very large table just + * because of a few large transient maps. + * + * @param n the threshold for the trimming. + * @return true if there was enough memory to trim the map. + * @see #trim() + */ + public boolean trim( final int n ) { + final int l = HashCommon.nextPowerOfTwo( (int)Math.ceil( n / f ) ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch( OutOfMemoryError cantDoIt ) { return false; } + return true; + } + /** Rehashes the map. + * + *

This method implements the basic rehashing strategy, and may be + * overriden by subclasses implementing different rehashing strategies (e.g., + * disk-based rehashing). However, you should not override this method + * unless you understand the internal workings of this class. + * + * @param newN the new size + */ + @SuppressWarnings("unchecked") + protected void rehash( final int newN ) { + final long key[] = this.key; + final V value[] = this.value; + final int mask = newN - 1; // Note that this is used by the hashing macro + final long newKey[] = new long[ newN + 1 ]; + final V newValue[] = (V[]) new Object[ newN + 1 ]; + int i = n, pos; + for( int j = realSize(); j-- != 0; ) { + while( ( (key[ --i ]) == (0) ) ); + if ( ! ( (newKey[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(key[ i ]) ) ) & mask ]) == (0) ) ) + while ( ! ( (newKey[ pos = ( pos + 1 ) & mask ]) == (0) ) ); + newKey[ pos ] = key[ i ]; + newValue[ pos ] = value[ i ]; + } + newValue[ newN ] = value[ n ]; + n = newN; + this.mask = mask; + maxFill = maxFill( n, f ); + this.key = newKey; + this.value = newValue; + } + /** Returns a deep copy of this map. + * + *

This method performs a deep copy of this hash map; the data stored in the + * map, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this map. + */ + @SuppressWarnings("unchecked") + public Long2ObjectOpenCustomHashMap clone() { + Long2ObjectOpenCustomHashMap c; + try { + c = (Long2ObjectOpenCustomHashMap )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.keys = null; + c.values = null; + c.entries = null; + c.containsNullKey = containsNullKey; + c.key = key.clone(); + c.value = value.clone(); + c.strategy = strategy; + return c; + } + /** Returns a hash code for this map. + * + * This method overrides the generic method provided by the superclass. + * Since equals() is not overriden, it is important + * that the value returned by this method is the same value as + * the one returned by the overriden method. + * + * @return a hash code for this map. + */ + public int hashCode() { + int h = 0; + for( int j = realSize(), i = 0, t = 0; j-- != 0; ) { + while( ( (key[ i ]) == (0) ) ) i++; + t = ( strategy.hashCode(key[ i ]) ); + if ( this != value[ i ] ) + t ^= ( (value[ i ]) == null ? 0 : (value[ i ]).hashCode() ); + h += t; + i++; + } + // Zero / null keys have hash zero. + if ( containsNullKey ) h += ( (value[ n ]) == null ? 0 : (value[ n ]).hashCode() ); + return h; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + final long key[] = this.key; + final V value[] = this.value; + final MapIterator i = new MapIterator(); + s.defaultWriteObject(); + for( int j = size, e; j-- != 0; ) { + e = i.nextEntry(); + s.writeLong( key[ e ] ); + s.writeObject( value[ e ] ); + } + } + @SuppressWarnings("unchecked") + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + n = arraySize( size, f ); + maxFill = maxFill( n, f ); + mask = n - 1; + final long key[] = this.key = new long[ n + 1 ]; + final V value[] = this.value = (V[]) new Object[ n + 1 ]; + long k; + V v; + for( int i = size, pos; i-- != 0; ) { + k = s.readLong(); + v = (V) s.readObject(); + if ( ( strategy.equals( (k), (0) ) ) ) { + pos = n; + containsNullKey = true; + } + else { + pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask; + while ( ! ( (key[ pos ]) == (0) ) ) pos = ( pos + 1 ) & mask; + } + key[ pos ] = k; + value[ pos ] = v; + } + if ( ASSERTS ) checkTable(); + } + private void checkTable() {} +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap.java b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap.java new file mode 100644 index 0000000..9666263 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap.java @@ -0,0 +1,901 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.HashCommon; +import static it.unimi.dsi.fastutil.HashCommon.arraySize; +import static it.unimi.dsi.fastutil.HashCommon.maxFill; +import java.util.Map; +import java.util.Arrays; +import java.util.NoSuchElementException; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.AbstractObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectIterator; +import it.unimi.dsi.fastutil.objects.AbstractObjectSet; +/** A type-specific hash map with a fast, small-footprint implementation. + * + *

Instances of this class use a hash table to represent a map. The table is + * filled up to a specified load factor, and then doubled in size to + * accommodate new entries. If the table is emptied below one fourth + * of the load factor, it is halved in size. However, halving is + * not performed when deleting entries from an iterator, as it would interfere + * with the iteration process. + * + *

Note that {@link #clear()} does not modify the hash table size. + * Rather, a family of {@linkplain #trim() trimming + * methods} lets you control the size of the table; this is particularly useful + * if you reuse instances of this class. + * + * @see Hash + * @see HashCommon + */ +public class Long2ObjectOpenHashMap extends AbstractLong2ObjectMap implements java.io.Serializable, Cloneable, Hash { + private static final long serialVersionUID = 0L; + private static final boolean ASSERTS = false; + /** The array of keys. */ + protected transient long[] key; + /** The array of values. */ + protected transient V[] value; + /** The mask for wrapping a position counter. */ + protected transient int mask; + /** Whether this set contains the key zero. */ + protected transient boolean containsNullKey; + /** The current table size. */ + protected transient int n; + /** Threshold after which we rehash. It must be the table size times {@link #f}. */ + protected transient int maxFill; + /** Number of entries in the set (including the key zero, if present). */ + protected int size; + /** The acceptable load factor. */ + protected final float f; + /** Cached set of entries. */ + protected transient FastEntrySet entries; + /** Cached set of keys. */ + protected transient LongSet keys; + /** Cached collection of values. */ + protected transient ObjectCollection values; + /** Creates a new hash map. + * + *

The actual table size will be the least power of two greater than expected/f. + * + * @param expected the expected number of elements in the hash set. + * @param f the load factor. + */ + @SuppressWarnings("unchecked") + public Long2ObjectOpenHashMap( final int expected, final float f ) { + if ( f <= 0 || f > 1 ) throw new IllegalArgumentException( "Load factor must be greater than 0 and smaller than or equal to 1" ); + if ( expected < 0 ) throw new IllegalArgumentException( "The expected number of elements must be nonnegative" ); + this.f = f; + n = arraySize( expected, f ); + mask = n - 1; + maxFill = maxFill( n, f ); + key = new long[ n + 1 ]; + value = (V[]) new Object[ n + 1 ]; + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * + * @param expected the expected number of elements in the hash map. + */ + public Long2ObjectOpenHashMap( final int expected ) { + this( expected, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map with initial expected {@link Hash#DEFAULT_INITIAL_SIZE} entries + * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + */ + public Long2ObjectOpenHashMap() { + this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map copying a given one. + * + * @param m a {@link Map} to be copied into the new hash map. + * @param f the load factor. + */ + public Long2ObjectOpenHashMap( final Map m, final float f ) { + this( m.size(), f ); + putAll( m ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given one. + * + * @param m a {@link Map} to be copied into the new hash map. + */ + public Long2ObjectOpenHashMap( final Map m ) { + this( m, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map copying a given type-specific one. + * + * @param m a type-specific map to be copied into the new hash map. + * @param f the load factor. + */ + public Long2ObjectOpenHashMap( final Long2ObjectMap m, final float f ) { + this( m.size(), f ); + putAll( m ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor copying a given type-specific one. + * + * @param m a type-specific map to be copied into the new hash map. + */ + public Long2ObjectOpenHashMap( final Long2ObjectMap m ) { + this( m, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash map using the elements of two parallel arrays. + * + * @param k the array of keys of the new hash map. + * @param v the array of corresponding values in the new hash map. + * @param f the load factor. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Long2ObjectOpenHashMap( final long[] k, final V[] v, final float f ) { + this( k.length, f ); + if ( k.length != v.length ) throw new IllegalArgumentException( "The key array and the value array have different lengths (" + k.length + " and " + v.length + ")" ); + for( int i = 0; i < k.length; i++ ) this.put( k[ i ], v[ i ] ); + } + /** Creates a new hash map with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using the elements of two parallel arrays. + * + * @param k the array of keys of the new hash map. + * @param v the array of corresponding values in the new hash map. + * @throws IllegalArgumentException if k and v have different lengths. + */ + public Long2ObjectOpenHashMap( final long[] k, final V[] v ) { + this( k, v, DEFAULT_LOAD_FACTOR ); + } + private int realSize() { + return containsNullKey ? size - 1 : size; + } + private void ensureCapacity( final int capacity ) { + final int needed = arraySize( capacity, f ); + if ( needed > n ) rehash( needed ); + } + private void tryCapacity( final long capacity ) { + final int needed = (int)Math.min( 1 << 30, Math.max( 2, HashCommon.nextPowerOfTwo( (long)Math.ceil( capacity / f ) ) ) ); + if ( needed > n ) rehash( needed ); + } + private V removeEntry( final int pos ) { + final V oldValue = value[ pos ]; + value[ pos ] = null; + size--; + shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return oldValue; + } + private V removeNullEntry() { + containsNullKey = false; + final V oldValue = value[ n ]; + value[ n ] = null; + size--; + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return oldValue; + } + /** {@inheritDoc} */ + public void putAll(Map m) { + if ( f <= .5 ) ensureCapacity( m.size() ); // The resulting map will be sized for m.size() elements + else tryCapacity( size() + m.size() ); // The resulting map will be tentatively sized for size() + m.size() elements + super.putAll( m ); + } + private int insert(final long k, final V v) { + int pos; + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) return n; + containsNullKey = true; + pos = n; + } + else { + long curr; + final long[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) { + if ( ( (curr) == (k) ) ) return pos; + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( (curr) == (k) ) ) return pos; + } + } + key[ pos ] = k; + value[ pos ] = v; + if ( size++ >= maxFill ) rehash( arraySize( size + 1, f ) ); + if ( ASSERTS ) checkTable(); + return -1; + } + public V put(final long k, final V v) { + final int pos = insert( k, v ); + if ( pos < 0 ) return defRetValue; + final V oldValue = value[ pos ]; + value[ pos ] = v; + return oldValue; + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public V put( final Long ok, final V ov ) { + final V v = (ov); + final int pos = insert( ((ok).longValue()), v ); + if ( pos < 0 ) return (this.defRetValue); + final V oldValue = value[ pos ]; + value[ pos ] = v; + return (oldValue); + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + protected final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + long curr; + final long[] key = this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + value[ last ] = null; + return; + } + slot = (int)it.unimi.dsi.fastutil.HashCommon.mix( (curr) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + value[ last ] = value[ pos ]; + } + } + + public V remove( final long k ) { + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) return removeNullEntry(); + return defRetValue; + } + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return removeEntry( pos ); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return removeEntry( pos ); + } + } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + + public V remove( final Object ok ) { + final long k = ((((Long)(ok)).longValue())); + if ( ( (k) == (0) ) ) { + if ( containsNullKey ) return (removeNullEntry()); + return (this.defRetValue); + } + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (curr) == (k) ) ) return (removeEntry( pos )); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (curr) == (k) ) ) return (removeEntry( pos )); + } + } + /** @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public V get( final Long ok ) { + if ( ok == null ) return null; + final long k = ((ok).longValue()); + if ( ( (k) == (0) ) ) return containsNullKey ? (value[ n ]) : (this.defRetValue); + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (k) == (curr) ) ) return (value[ pos ]); + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return (this.defRetValue); + if ( ( (k) == (curr) ) ) return (value[ pos ]); + } + } + + public V get( final long k ) { + if ( ( (k) == (0) ) ) return containsNullKey ? value[ n ] : defRetValue; + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return value[ pos ]; + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return defRetValue; + if ( ( (k) == (curr) ) ) return value[ pos ]; + } + } + + public boolean containsKey( final long k ) { + if ( ( (k) == (0) ) ) return containsNullKey; + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return true; + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return true; + } + } + public boolean containsValue( final Object v ) { + final V value[] = this.value; + final long key[] = this.key; + if ( containsNullKey && ( (value[ n ]) == null ? (v) == null : (value[ n ]).equals(v) ) ) return true; + for( int i = n; i-- != 0; ) if ( ! ( (key[ i ]) == (0) ) && ( (value[ i ]) == null ? (v) == null : (value[ i ]).equals(v) ) ) return true; + return false; + } + /* Removes all elements from this map. + * + *

To increase object reuse, this method does not change the table size. + * If you want to reduce the table size, you must use {@link #trim()}. + * + */ + public void clear() { + if ( size == 0 ) return; + size = 0; + containsNullKey = false; + Arrays.fill( key, (0) ); + Arrays.fill( value, null ); + } + public int size() { + return size; + } + public boolean isEmpty() { + return size == 0; + } + /** A no-op for backward compatibility. + * + * @param growthFactor unused. + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public void growthFactor( int growthFactor ) {} + /** Gets the growth factor (2). + * + * @return the growth factor of this set, which is fixed (2). + * @see #growthFactor(int) + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public int growthFactor() { + return 16; + } + /** The entry class for a hash map does not record key and value, but + * rather the position in the hash table of the corresponding entry. This + * is necessary so that calls to {@link java.util.Map.Entry#setValue(Object)} are reflected in + * the map */ + final class MapEntry implements Long2ObjectMap.Entry , Map.Entry { + // The table index this entry refers to, or -1 if this entry has been deleted. + int index; + MapEntry( final int index ) { + this.index = index; + } + MapEntry() {} + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long getKey() { + return (Long.valueOf(key[ index ])); + } + public long getLongKey() { + return key[ index ]; + } + public V getValue() { + return (value[ index ]); + } + public V setValue( final V v ) { + final V oldValue = value[ index ]; + value[ index ] = v; + return oldValue; + } + @SuppressWarnings("unchecked") + public boolean equals( final Object o ) { + if (!(o instanceof Map.Entry)) return false; + Map.Entry e = (Map.Entry)o; + return ( (key[ index ]) == (((e.getKey()).longValue())) ) && ( (value[ index ]) == null ? ((e.getValue())) == null : (value[ index ]).equals((e.getValue())) ); + } + public int hashCode() { + return it.unimi.dsi.fastutil.HashCommon.long2int(key[ index ]) ^ ( (value[ index ]) == null ? 0 : (value[ index ]).hashCode() ); + } + public String toString() { + return key[ index ] + "=>" + value[ index ]; + } + } + /** An iterator over a hash map. */ + private class MapIterator { + /** The index of the last entry returned, if positive or zero; initially, {@link #n}. If negative, the last + entry returned was that of the key of index {@code - pos - 1} from the {@link #wrapped} list. */ + int pos = n; + /** The index of the last entry that has been returned (more precisely, the value of {@link #pos} if {@link #pos} is positive, + or {@link Integer#MIN_VALUE} if {@link #pos} is negative). It is -1 if either + we did not return an entry yet, or the last returned entry has been removed. */ + int last = -1; + /** A downward counter measuring how many entries must still be returned. */ + int c = size; + /** A boolean telling us whether we should return the entry with the null key. */ + boolean mustReturnNullKey = Long2ObjectOpenHashMap.this.containsNullKey; + /** A lazily allocated list containing keys of entries that have wrapped around the table because of removals. */ + LongArrayList wrapped; + public boolean hasNext() { + return c != 0; + } + public int nextEntry() { + if ( ! hasNext() ) throw new NoSuchElementException(); + c--; + if ( mustReturnNullKey ) { + mustReturnNullKey = false; + return last = n; + } + final long key[] = Long2ObjectOpenHashMap.this.key; + for(;;) { + if ( --pos < 0 ) { + // We are just enumerating elements from the wrapped list. + last = Integer.MIN_VALUE; + final long k = wrapped.getLong( - pos - 1 ); + int p = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask; + while ( ! ( (k) == (key[ p ]) ) ) p = ( p + 1 ) & mask; + return p; + } + if ( ! ( (key[ pos ]) == (0) ) ) return last = pos; + } + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + private final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + long curr; + final long[] key = Long2ObjectOpenHashMap.this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + value[ last ] = null; + return; + } + slot = (int)it.unimi.dsi.fastutil.HashCommon.mix( (curr) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + if ( pos < last ) { // Wrapped entry. + if ( wrapped == null ) wrapped = new LongArrayList ( 2 ); + wrapped.add( key[ pos ] ); + } + key[ last ] = curr; + value[ last ] = value[ pos ]; + } + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + if ( last == n ) { + containsNullKey = false; + value[ n ] = null; + } + else if ( pos >= 0 ) shiftKeys( last ); + else { + // We're removing wrapped entries. + Long2ObjectOpenHashMap.this.remove( wrapped.getLong( - pos - 1 ) ); + last = -1; // Note that we must not decrement size + return; + } + size--; + last = -1; // You can no longer remove this entry. + if ( ASSERTS ) checkTable(); + } + public int skip( final int n ) { + int i = n; + while( i-- != 0 && hasNext() ) nextEntry(); + return n - i - 1; + } + } + private class EntryIterator extends MapIterator implements ObjectIterator > { + private MapEntry entry; + public Long2ObjectMap.Entry next() { + return entry = new MapEntry( nextEntry() ); + } + @Override + public void remove() { + super.remove(); + entry.index = -1; // You cannot use a deleted entry. + } + } + private class FastEntryIterator extends MapIterator implements ObjectIterator > { + private final MapEntry entry = new MapEntry(); + public MapEntry next() { + entry.index = nextEntry(); + return entry; + } + } + private final class MapEntrySet extends AbstractObjectSet > implements FastEntrySet { + public ObjectIterator > iterator() { + return new EntryIterator(); + } + public ObjectIterator > fastIterator() { + return new FastEntryIterator(); + } + @SuppressWarnings("unchecked") + public boolean contains( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final long k = ((e.getKey()).longValue()); + if ( ( (k) == (0) ) ) return ( Long2ObjectOpenHashMap.this.containsNullKey && ( (value[ n ]) == null ? ((e.getValue())) == null : (value[ n ]).equals((e.getValue())) ) ); + long curr; + final long[] key = Long2ObjectOpenHashMap.this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return ( (value[ pos ]) == null ? ((e.getValue())) == null : (value[ pos ]).equals((e.getValue())) ); + // There's always an unused entry. + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return ( (value[ pos ]) == null ? ((e.getValue())) == null : (value[ pos ]).equals((e.getValue())) ); + } + } + @SuppressWarnings("unchecked") + public boolean remove( final Object o ) { + if ( !( o instanceof Map.Entry ) ) return false; + final Map.Entry e = (Map.Entry)o; + if ( e.getKey() == null ) return false; + final long k = ((e.getKey()).longValue()); + final V v = (e.getValue()); + if ( ( (k) == (0) ) ) { + if ( containsNullKey && ( (value[ n ]) == null ? (v) == null : (value[ n ]).equals(v) ) ) { + removeNullEntry(); + return true; + } + return false; + } + long curr; + final long[] key = Long2ObjectOpenHashMap.this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return false; + if ( ( (curr) == (k) ) ) { + if ( ( (value[ pos ]) == null ? (v) == null : (value[ pos ]).equals(v) ) ) { + removeEntry( pos ); + return true; + } + return false; + } + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (curr) == (k) ) ) { + if ( ( (value[ pos ]) == null ? (v) == null : (value[ pos ]).equals(v) ) ) { + removeEntry( pos ); + return true; + } + } + } + } + public int size() { + return size; + } + public void clear() { + Long2ObjectOpenHashMap.this.clear(); + } + } + public FastEntrySet long2ObjectEntrySet() { + if ( entries == null ) entries = new MapEntrySet(); + return entries; + } + /** An iterator on keys. + * + *

We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods + * (and possibly their type-specific counterparts) so that they return keys + * instead of entries. + */ + private final class KeyIterator extends MapIterator implements LongIterator { + public KeyIterator() { super(); } + public long nextLong() { return key[ nextEntry() ]; } + public Long next() { return (Long.valueOf(key[ nextEntry() ])); } + } + private final class KeySet extends AbstractLongSet { + public LongIterator iterator() { + return new KeyIterator(); + } + public int size() { + return size; + } + public boolean contains( long k ) { + return containsKey( k ); + } + public boolean remove( long k ) { + final int oldSize = size; + Long2ObjectOpenHashMap.this.remove( k ); + return size != oldSize; + } + public void clear() { + Long2ObjectOpenHashMap.this.clear(); + } + } + public LongSet keySet() { + if ( keys == null ) keys = new KeySet(); + return keys; + } + /** An iterator on values. + * + *

We simply override the {@link java.util.ListIterator#next()}/{@link java.util.ListIterator#previous()} methods + * (and possibly their type-specific counterparts) so that they return values + * instead of entries. + */ + private final class ValueIterator extends MapIterator implements ObjectIterator { + public ValueIterator() { super(); } + public V next() { return value[ nextEntry() ]; } + } + public ObjectCollection values() { + if ( values == null ) values = new AbstractObjectCollection () { + public ObjectIterator iterator() { + return new ValueIterator(); + } + public int size() { + return size; + } + public boolean contains( Object v ) { + return containsValue( v ); + } + public void clear() { + Long2ObjectOpenHashMap.this.clear(); + } + }; + return values; + } + /** A no-op for backward compatibility. The kind of tables implemented by + * this class never need rehashing. + * + *

If you need to reduce the table size to fit exactly + * this set, use {@link #trim()}. + * + * @return true. + * @see #trim() + * @deprecated A no-op. + */ + @Deprecated + public boolean rehash() { + return true; + } + /** Rehashes the map, making the table as small as possible. + * + *

This method rehashes the table to the smallest size satisfying the + * load factor. It can be used when the set will not be changed anymore, so + * to optimize access speed and size. + * + *

If the table size is already the minimum possible, this method + * does nothing. + * + * @return true if there was enough memory to trim the map. + * @see #trim(int) + */ + public boolean trim() { + final int l = arraySize( size, f ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch(OutOfMemoryError cantDoIt) { return false; } + return true; + } + /** Rehashes this map if the table is too large. + * + *

Let N be the smallest table size that can hold + * max(n,{@link #size()}) entries, still satisfying the load factor. If the current + * table size is smaller than or equal to N, this method does + * nothing. Otherwise, it rehashes this map in a table of size + * N. + * + *

This method is useful when reusing maps. {@linkplain #clear() Clearing a + * map} leaves the table size untouched. If you are reusing a map + * many times, you can call this method with a typical + * size to avoid keeping around a very large table just + * because of a few large transient maps. + * + * @param n the threshold for the trimming. + * @return true if there was enough memory to trim the map. + * @see #trim() + */ + public boolean trim( final int n ) { + final int l = HashCommon.nextPowerOfTwo( (int)Math.ceil( n / f ) ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch( OutOfMemoryError cantDoIt ) { return false; } + return true; + } + /** Rehashes the map. + * + *

This method implements the basic rehashing strategy, and may be + * overriden by subclasses implementing different rehashing strategies (e.g., + * disk-based rehashing). However, you should not override this method + * unless you understand the internal workings of this class. + * + * @param newN the new size + */ + @SuppressWarnings("unchecked") + protected void rehash( final int newN ) { + final long key[] = this.key; + final V value[] = this.value; + final int mask = newN - 1; // Note that this is used by the hashing macro + final long newKey[] = new long[ newN + 1 ]; + final V newValue[] = (V[]) new Object[ newN + 1 ]; + int i = n, pos; + for( int j = realSize(); j-- != 0; ) { + while( ( (key[ --i ]) == (0) ) ); + if ( ! ( (newKey[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (key[ i ]) ) & mask ]) == (0) ) ) + while ( ! ( (newKey[ pos = ( pos + 1 ) & mask ]) == (0) ) ); + newKey[ pos ] = key[ i ]; + newValue[ pos ] = value[ i ]; + } + newValue[ newN ] = value[ n ]; + n = newN; + this.mask = mask; + maxFill = maxFill( n, f ); + this.key = newKey; + this.value = newValue; + } + /** Returns a deep copy of this map. + * + *

This method performs a deep copy of this hash map; the data stored in the + * map, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this map. + */ + @SuppressWarnings("unchecked") + public Long2ObjectOpenHashMap clone() { + Long2ObjectOpenHashMap c; + try { + c = (Long2ObjectOpenHashMap )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.keys = null; + c.values = null; + c.entries = null; + c.containsNullKey = containsNullKey; + c.key = key.clone(); + c.value = value.clone(); + return c; + } + /** Returns a hash code for this map. + * + * This method overrides the generic method provided by the superclass. + * Since equals() is not overriden, it is important + * that the value returned by this method is the same value as + * the one returned by the overriden method. + * + * @return a hash code for this map. + */ + public int hashCode() { + int h = 0; + for( int j = realSize(), i = 0, t = 0; j-- != 0; ) { + while( ( (key[ i ]) == (0) ) ) i++; + t = it.unimi.dsi.fastutil.HashCommon.long2int(key[ i ]); + if ( this != value[ i ] ) + t ^= ( (value[ i ]) == null ? 0 : (value[ i ]).hashCode() ); + h += t; + i++; + } + // Zero / null keys have hash zero. + if ( containsNullKey ) h += ( (value[ n ]) == null ? 0 : (value[ n ]).hashCode() ); + return h; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + final long key[] = this.key; + final V value[] = this.value; + final MapIterator i = new MapIterator(); + s.defaultWriteObject(); + for( int j = size, e; j-- != 0; ) { + e = i.nextEntry(); + s.writeLong( key[ e ] ); + s.writeObject( value[ e ] ); + } + } + @SuppressWarnings("unchecked") + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + n = arraySize( size, f ); + maxFill = maxFill( n, f ); + mask = n - 1; + final long key[] = this.key = new long[ n + 1 ]; + final V value[] = this.value = (V[]) new Object[ n + 1 ]; + long k; + V v; + for( int i = size, pos; i-- != 0; ) { + k = s.readLong(); + v = (V) s.readObject(); + if ( ( (k) == (0) ) ) { + pos = n; + containsNullKey = true; + } + else { + pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask; + while ( ! ( (key[ pos ]) == (0) ) ) pos = ( pos + 1 ) & mask; + } + key[ pos ] = k; + value[ pos ] = v; + } + if ( ASSERTS ) checkTable(); + } + private void checkTable() {} +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectSortedMap.java b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectSortedMap.java new file mode 100644 index 0000000..365ebc7 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectSortedMap.java @@ -0,0 +1,181 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.objects.ObjectCollection; +import it.unimi.dsi.fastutil.objects.ObjectSortedSet; +import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; +import java.util.Map; +import java.util.SortedMap; +/** A type-specific {@link SortedMap}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Additionally, this interface strengthens {@link #entrySet()}, + * {@link #keySet()}, {@link #values()}, + * {@link #comparator()}, {@link SortedMap#subMap(Object,Object)}, {@link SortedMap#headMap(Object)} and {@link SortedMap#tailMap(Object)}. + * + * @see SortedMap + */ +public interface Long2ObjectSortedMap extends Long2ObjectMap , SortedMap { + /** A sorted entry set providing fast iteration. + * + *

In some cases (e.g., hash-based classes) iteration over an entry set requires the creation + * of a large number of entry objects. Some fastutil + * maps might return {@linkplain #entrySet() entry set} objects of type FastSortedEntrySet: in this case, {@link #fastIterator() fastIterator()} + * will return an iterator that is guaranteed not to create a large number of objects, possibly + * by returning always the same entry (of course, mutated). + */ + public interface FastSortedEntrySet extends ObjectSortedSet >, FastEntrySet { + /** Returns a fast iterator over this sorted entry set; the iterator might return always the same entry object, suitably mutated. + * + * @return a fast iterator over this sorted entry set; the iterator might return always the same entry object, suitably mutated. + */ + public ObjectBidirectionalIterator > fastIterator( Long2ObjectMap.Entry from ); + } + /** Returns a sorted-set view of the mappings contained in this map. + * Note that this specification strengthens the one given in the + * corresponding type-specific unsorted map. + * + * @return a sorted-set view of the mappings contained in this map. + * @see Map#entrySet() + */ + ObjectSortedSet> entrySet(); + /** Returns a type-specific sorted-set view of the mappings contained in this map. + * Note that this specification strengthens the one given in the + * corresponding type-specific unsorted map. + * + * @return a type-specific sorted-set view of the mappings contained in this map. + * @see #entrySet() + */ + ObjectSortedSet > long2ObjectEntrySet(); + /** Returns a sorted-set view of the keys contained in this map. + * Note that this specification strengthens the one given in the + * corresponding type-specific unsorted map. + * + * @return a sorted-set view of the keys contained in this map. + * @see Map#keySet() + */ + LongSortedSet keySet(); + /** Returns a set view of the values contained in this map. + *

Note that this specification strengthens the one given in {@link Map#values()}, + * which was already strengthened in the corresponding type-specific class, + * but was weakened by the fact that this interface extends {@link SortedMap}. + * + * @return a set view of the values contained in this map. + * @see Map#values() + */ + ObjectCollection values(); + /** Returns the comparator associated with this sorted set, or null if it uses its keys' natural ordering. + * + *

Note that this specification strengthens the one given in {@link SortedMap#comparator()}. + * + * @see SortedMap#comparator() + */ + LongComparator comparator(); + /** Returns a view of the portion of this sorted map whose keys range from fromKey, inclusive, to toKey, exclusive. + * + *

Note that this specification strengthens the one given in {@link SortedMap#subMap(Object,Object)}. + * + * @see SortedMap#subMap(Object,Object) + */ + Long2ObjectSortedMap subMap(Long fromKey, Long toKey); + /** Returns a view of the portion of this sorted map whose keys are strictly less than toKey. + * + *

Note that this specification strengthens the one given in {@link SortedMap#headMap(Object)}. + * + * @see SortedMap#headMap(Object) + */ + Long2ObjectSortedMap headMap(Long toKey); + /** Returns a view of the portion of this sorted map whose keys are greater than or equal to fromKey. + * + *

Note that this specification strengthens the one given in {@link SortedMap#tailMap(Object)}. + * + * @see SortedMap#tailMap(Object) + */ + Long2ObjectSortedMap tailMap(Long fromKey); + /** Returns a view of the portion of this sorted map whose keys range from fromKey, inclusive, to toKey, exclusive. + * @see SortedMap#subMap(Object,Object) + */ + Long2ObjectSortedMap subMap(long fromKey, long toKey); + /** Returns a view of the portion of this sorted map whose keys are strictly less than toKey. + * @see SortedMap#headMap(Object) + */ + Long2ObjectSortedMap headMap(long toKey); + /** Returns a view of the portion of this sorted map whose keys are greater than or equal to fromKey. + * @see SortedMap#tailMap(Object) + */ + Long2ObjectSortedMap tailMap(long fromKey); + /** + * @see SortedMap#firstKey() + */ + long firstLongKey(); + /** + * @see SortedMap#lastKey() + */ + long lastLongKey(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectSortedMaps.java b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectSortedMaps.java new file mode 100644 index 0000000..1a91791 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/Long2ObjectSortedMaps.java @@ -0,0 +1,326 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.objects.ObjectSortedSet; +import it.unimi.dsi.fastutil.objects.ObjectSortedSets; +import java.util.Comparator; +import java.util.Map; +import java.util.SortedMap; +import java.util.NoSuchElementException; +/** A class providing static methods and objects that do useful things with type-specific sorted maps. + * + * @see java.util.Collections + */ +public class Long2ObjectSortedMaps { + private Long2ObjectSortedMaps() {} + /** Returns a comparator for entries based on a given comparator on keys. + * + * @param comparator a comparator on keys. + * @return the associated comparator on entries. + */ + public static Comparator> entryComparator( final LongComparator comparator ) { + return new Comparator>() { + public int compare( Map.Entry x, Map.Entry y ) { + return comparator.compare( x.getKey(), y.getKey() ); + } + }; + } + /** An immutable class representing an empty type-specific sorted map. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific sorted map. + */ + public static class EmptySortedMap extends Long2ObjectMaps.EmptyMap implements Long2ObjectSortedMap , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptySortedMap() {} + public LongComparator comparator() { return null; } + @SuppressWarnings("unchecked") + public ObjectSortedSet > long2ObjectEntrySet() { return ObjectSortedSets.EMPTY_SET; } + @SuppressWarnings("unchecked") + public ObjectSortedSet> entrySet() { return ObjectSortedSets.EMPTY_SET; } + + public LongSortedSet keySet() { return LongSortedSets.EMPTY_SET; } + @SuppressWarnings("unchecked") + public Long2ObjectSortedMap subMap( final long from, final long to ) { return EMPTY_MAP; } + @SuppressWarnings("unchecked") + public Long2ObjectSortedMap headMap( final long to ) { return EMPTY_MAP; } + @SuppressWarnings("unchecked") + public Long2ObjectSortedMap tailMap( final long from ) { return EMPTY_MAP; } + public long firstLongKey() { throw new NoSuchElementException(); } + public long lastLongKey() { throw new NoSuchElementException(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long2ObjectSortedMap headMap( Long oto ) { return headMap( ((oto).longValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long2ObjectSortedMap tailMap( Long ofrom ) { return tailMap( ((ofrom).longValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long2ObjectSortedMap subMap( Long ofrom, Long oto ) { return subMap( ((ofrom).longValue()), ((oto).longValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long firstKey() { return (Long.valueOf(firstLongKey())); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long lastKey() { return (Long.valueOf(lastLongKey())); } + } + /** An empty sorted map (immutable). It is serializable and cloneable. + */ + @SuppressWarnings("rawtypes") + public static final EmptySortedMap EMPTY_MAP = new EmptySortedMap(); + /** Return an empty sorted map (immutable). It is serializable and cloneable. + * + *

This method provides a typesafe access to {@link #EMPTY_MAP}. + * @return an empty sorted map (immutable). + */ + @SuppressWarnings("unchecked") + public static Long2ObjectSortedMap emptyMap() { + return EMPTY_MAP; + } + /** An immutable class representing a type-specific singleton sorted map. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific sorted map. + */ + public static class Singleton extends Long2ObjectMaps.Singleton implements Long2ObjectSortedMap , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected final LongComparator comparator; + protected Singleton( final long key, final V value, LongComparator comparator ) { + super( key, value ); + this.comparator = comparator; + } + protected Singleton( final long key, final V value ) { + this( key, value, null ); + } + + final int compare( final long k1, final long k2 ) { + return comparator == null ? ( Long.compare((k1),(k2)) ) : comparator.compare( k1, k2 ); + } + public LongComparator comparator() { return comparator; } + + public ObjectSortedSet > long2ObjectEntrySet() { if ( entries == null ) entries = ObjectSortedSets.singleton( (Long2ObjectMap.Entry )new SingletonEntry(), (Comparator >)entryComparator( comparator ) ); return (ObjectSortedSet >)entries; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + public ObjectSortedSet> entrySet() { return (ObjectSortedSet)long2ObjectEntrySet(); } + public LongSortedSet keySet() { if ( keys == null ) keys = LongSortedSets.singleton( key, comparator ); return (LongSortedSet )keys; } + @SuppressWarnings("unchecked") + public Long2ObjectSortedMap subMap( final long from, final long to ) { if ( compare( from, key ) <= 0 && compare( key, to ) < 0 ) return this; return EMPTY_MAP; } + @SuppressWarnings("unchecked") + public Long2ObjectSortedMap headMap( final long to ) { if ( compare( key, to ) < 0 ) return this; return EMPTY_MAP; } + @SuppressWarnings("unchecked") + public Long2ObjectSortedMap tailMap( final long from ) { if ( compare( from, key ) <= 0 ) return this; return EMPTY_MAP; } + public long firstLongKey() { return key; } + public long lastLongKey() { return key; } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long2ObjectSortedMap headMap( Long oto ) { return headMap( ((oto).longValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long2ObjectSortedMap tailMap( Long ofrom ) { return tailMap( ((ofrom).longValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long2ObjectSortedMap subMap( Long ofrom, Long oto ) { return subMap( ((ofrom).longValue()), ((oto).longValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long firstKey() { return (Long.valueOf(firstLongKey())); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long lastKey() { return (Long.valueOf(lastLongKey())); } + } + /** Returns a type-specific immutable sorted map containing only the specified pair. The returned sorted map is serializable and cloneable. + * + *

Note that albeit the returned map is immutable, its default return value may be changed. + * + * @param key the only key of the returned sorted map. + * @param value the only value of the returned sorted map. + * @return a type-specific immutable sorted map containing just the pair <key,value>. + */ + public static Long2ObjectSortedMap singleton( final Long key, V value ) { + return new Singleton ( ((key).longValue()), (value) ); + } + /** RETURNS a type-specific immutable sorted map containing only the specified pair. The returned sorted map is serializable and cloneable. + * + *

Note that albeit the returned map is immutable, its default return value may be changed. + * + * @param key the only key of the returned sorted map. + * @param value the only value of the returned sorted map. + * @param comparator the comparator to use in the returned sorted map. + * @return a type-specific immutable sorted map containing just the pair <key,value>. + */ + public static Long2ObjectSortedMap singleton( final Long key, V value, LongComparator comparator ) { + return new Singleton ( ((key).longValue()), (value), comparator ); + } + /** Returns a type-specific immutable sorted map containing only the specified pair. The returned sorted map is serializable and cloneable. + * + *

Note that albeit the returned map is immutable, its default return value may be changed. + * + * @param key the only key of the returned sorted map. + * @param value the only value of the returned sorted map. + * @return a type-specific immutable sorted map containing just the pair <key,value>. + */ + public static Long2ObjectSortedMap singleton( final long key, final V value ) { + return new Singleton ( key, value ); + } + /** Returns a type-specific immutable sorted map containing only the specified pair. The returned sorted map is serializable and cloneable. + * + *

Note that albeit the returned map is immutable, its default return value may be changed. + * + * @param key the only key of the returned sorted map. + * @param value the only value of the returned sorted map. + * @param comparator the comparator to use in the returned sorted map. + * @return a type-specific immutable sorted map containing just the pair <key,value>. + */ + public static Long2ObjectSortedMap singleton( final long key, final V value, LongComparator comparator ) { + return new Singleton ( key, value, comparator ); + } + /** A synchronized wrapper class for sorted maps. */ + public static class SynchronizedSortedMap extends Long2ObjectMaps.SynchronizedMap implements Long2ObjectSortedMap , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final Long2ObjectSortedMap sortedMap; + protected SynchronizedSortedMap( final Long2ObjectSortedMap m, final Object sync ) { + super( m, sync ); + sortedMap = m; + } + protected SynchronizedSortedMap( final Long2ObjectSortedMap m ) { + super( m ); + sortedMap = m; + } + public LongComparator comparator() { synchronized( sync ) { return sortedMap.comparator(); } } + public ObjectSortedSet > long2ObjectEntrySet() { if ( entries == null ) entries = ObjectSortedSets.synchronize( sortedMap.long2ObjectEntrySet(), sync ); return (ObjectSortedSet >)entries; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + public ObjectSortedSet> entrySet() { return (ObjectSortedSet)long2ObjectEntrySet(); } + public LongSortedSet keySet() { if ( keys == null ) keys = LongSortedSets.synchronize( sortedMap.keySet(), sync ); return (LongSortedSet )keys; } + public Long2ObjectSortedMap subMap( final long from, final long to ) { return new SynchronizedSortedMap ( sortedMap.subMap( from, to ), sync ); } + public Long2ObjectSortedMap headMap( final long to ) { return new SynchronizedSortedMap ( sortedMap.headMap( to ), sync ); } + public Long2ObjectSortedMap tailMap( final long from ) { return new SynchronizedSortedMap ( sortedMap.tailMap( from ), sync ); } + public long firstLongKey() { synchronized( sync ) { return sortedMap.firstLongKey(); } } + public long lastLongKey() { synchronized( sync ) { return sortedMap.lastLongKey(); } } + public Long firstKey() { synchronized( sync ) { return sortedMap.firstKey(); } } + public Long lastKey() { synchronized( sync ) { return sortedMap.lastKey(); } } + public Long2ObjectSortedMap subMap( final Long from, final Long to ) { return new SynchronizedSortedMap ( sortedMap.subMap( from, to ), sync ); } + public Long2ObjectSortedMap headMap( final Long to ) { return new SynchronizedSortedMap ( sortedMap.headMap( to ), sync ); } + public Long2ObjectSortedMap tailMap( final Long from ) { return new SynchronizedSortedMap ( sortedMap.tailMap( from ), sync ); } + } + /** Returns a synchronized type-specific sorted map backed by the given type-specific sorted map. + * + * @param m the sorted map to be wrapped in a synchronized sorted map. + * @return a synchronized view of the specified sorted map. + * @see java.util.Collections#synchronizedSortedMap(SortedMap) + */ + public static Long2ObjectSortedMap synchronize( final Long2ObjectSortedMap m ) { return new SynchronizedSortedMap ( m ); } + /** Returns a synchronized type-specific sorted map backed by the given type-specific sorted map, using an assigned object to synchronize. + * + * @param m the sorted map to be wrapped in a synchronized sorted map. + * @param sync an object that will be used to synchronize the access to the sorted sorted map. + * @return a synchronized view of the specified sorted map. + * @see java.util.Collections#synchronizedSortedMap(SortedMap) + */ + public static Long2ObjectSortedMap synchronize( final Long2ObjectSortedMap m, final Object sync ) { return new SynchronizedSortedMap ( m, sync ); } + /** An unmodifiable wrapper class for sorted maps. */ + public static class UnmodifiableSortedMap extends Long2ObjectMaps.UnmodifiableMap implements Long2ObjectSortedMap , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final Long2ObjectSortedMap sortedMap; + protected UnmodifiableSortedMap( final Long2ObjectSortedMap m ) { + super( m ); + sortedMap = m; + } + public LongComparator comparator() { return sortedMap.comparator(); } + public ObjectSortedSet > long2ObjectEntrySet() { if ( entries == null ) entries = ObjectSortedSets.unmodifiable( sortedMap.long2ObjectEntrySet() ); return (ObjectSortedSet >)entries; } + @SuppressWarnings({ "rawtypes", "unchecked" }) + public ObjectSortedSet> entrySet() { return (ObjectSortedSet)long2ObjectEntrySet(); } + public LongSortedSet keySet() { if ( keys == null ) keys = LongSortedSets.unmodifiable( sortedMap.keySet() ); return (LongSortedSet )keys; } + public Long2ObjectSortedMap subMap( final long from, final long to ) { return new UnmodifiableSortedMap ( sortedMap.subMap( from, to ) ); } + public Long2ObjectSortedMap headMap( final long to ) { return new UnmodifiableSortedMap ( sortedMap.headMap( to ) ); } + public Long2ObjectSortedMap tailMap( final long from ) { return new UnmodifiableSortedMap ( sortedMap.tailMap( from ) ); } + public long firstLongKey() { return sortedMap.firstLongKey(); } + public long lastLongKey() { return sortedMap.lastLongKey(); } + public Long firstKey() { return sortedMap.firstKey(); } + public Long lastKey() { return sortedMap.lastKey(); } + public Long2ObjectSortedMap subMap( final Long from, final Long to ) { return new UnmodifiableSortedMap ( sortedMap.subMap( from, to ) ); } + public Long2ObjectSortedMap headMap( final Long to ) { return new UnmodifiableSortedMap ( sortedMap.headMap( to ) ); } + public Long2ObjectSortedMap tailMap( final Long from ) { return new UnmodifiableSortedMap ( sortedMap.tailMap( from ) ); } + } + /** Returns an unmodifiable type-specific sorted map backed by the given type-specific sorted map. + * + * @param m the sorted map to be wrapped in an unmodifiable sorted map. + * @return an unmodifiable view of the specified sorted map. + * @see java.util.Collections#unmodifiableSortedMap(SortedMap) + */ + public static Long2ObjectSortedMap unmodifiable( final Long2ObjectSortedMap m ) { return new UnmodifiableSortedMap ( m ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongArrayFIFOQueue.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongArrayFIFOQueue.java new file mode 100644 index 0000000..6242492 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongArrayFIFOQueue.java @@ -0,0 +1,226 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2010-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.io.Serializable; +import it.unimi.dsi.fastutil.HashCommon; +import java.util.NoSuchElementException; +/** A type-specific array-based FIFO queue, supporting also deque operations. + * + *

Instances of this class represent a FIFO queue using a backing + * array in a circular way. The array is enlarged and shrunk as needed. You can use the {@link #trim()} method + * to reduce its memory usage, if necessary. + * + *

This class provides additional methods that implement a deque (double-ended queue). + */ +public class LongArrayFIFOQueue extends AbstractLongPriorityQueue implements Serializable { + private static final long serialVersionUID = 0L; + /** The standard initial capacity of a queue. */ + public final static int INITIAL_CAPACITY = 4; + /** The backing array. */ + protected transient long array[]; + /** The current (cached) length of {@link #array}. */ + protected transient int length; + /** The start position in {@link #array}. It is always strictly smaller than {@link #length}.*/ + protected transient int start; + /** The end position in {@link #array}. It is always strictly smaller than {@link #length}. + * Might be actually smaller than {@link #start} because {@link #array} is used cyclically. */ + protected transient int end; + /** Creates a new empty queue with given capacity. + * + * @param capacity the initial capacity of this queue. + */ + + public LongArrayFIFOQueue( final int capacity ) { + if ( capacity < 0 ) throw new IllegalArgumentException( "Initial capacity (" + capacity + ") is negative" ); + array = new long[ Math.max( 1, capacity ) ]; // Never build a queue with zero-sized backing array. + length = array.length; + } + /** Creates a new empty queue with standard {@linkplain #INITIAL_CAPACITY initial capacity}. + */ + public LongArrayFIFOQueue() { + this( INITIAL_CAPACITY ); + } + /** Returns null (FIFO queues have no comparator). + * @return null. + */ + @Override + public LongComparator comparator() { + return null; + } + @Override + public long dequeueLong() { + if ( start == end ) throw new NoSuchElementException(); + final long t = array[ start ]; + if ( ++start == length ) start = 0; + reduce(); + return t; + } + /** Dequeues the last element from the queue. + * + * @return the dequeued element. + * @throws NoSuchElementException if the queue is empty. + */ + public long dequeueLastLong() { + if ( start == end ) throw new NoSuchElementException(); + if ( end == 0 ) end = length; + final long t = array[ --end ]; + reduce(); + return t; + } + + private final void resize( final int size, final int newLength ) { + final long[] newArray = new long[ newLength ]; + if ( start >= end ) { + if ( size != 0 ) { + System.arraycopy( array, start, newArray, 0, length - start ); + System.arraycopy( array, 0, newArray, length - start, end ); + } + } + else System.arraycopy( array, start, newArray, 0, end - start ); + start = 0; + end = size; + array = newArray; + length = newLength; + } + private final void expand() { + resize( length, (int)Math.min( it.unimi.dsi.fastutil.Arrays.MAX_ARRAY_SIZE, 2L * length ) ); + } + private final void reduce() { + final int size = size(); + if ( length > INITIAL_CAPACITY && size <= length / 4 ) resize( size, length / 2 ); + } + @Override + public void enqueue( long x ) { + array[ end++ ] = x; + if ( end == length ) end = 0; + if ( end == start ) expand(); + } + /** Enqueues a new element as the first element (in dequeuing order) of the queue. + */ + public void enqueueFirst( long x ) { + if ( start == 0 ) start = length; + array[ --start ] = x; + if ( end == start ) expand(); + } + /** Returns the first element of the queue. + * @return the first element of the queue. + */ + public long firstLong() { + if ( start == end ) throw new NoSuchElementException(); + return array[ start ]; + } + /** Returns the last element of the queue. + * @return the last element of the queue. + */ + public long lastLong() { + if ( start == end ) throw new NoSuchElementException(); + return array[ ( end == 0 ? length : end ) - 1 ]; + } + @Override + public void clear() { + start = end = 0; + } + /** Trims the queue to the smallest possible size. */ + + public void trim() { + final int size = size(); + final long[] newArray = + new long[ size + 1 ]; + if ( start <= end ) System.arraycopy( array, start, newArray, 0, end - start ); + else { + System.arraycopy( array, start, newArray, 0, length - start ); + System.arraycopy( array, 0, newArray, length - start, end ); + } + start = 0; + length = ( end = size ) + 1; + array = newArray; + } + @Override + public int size() { + final int apparentLength = end - start; + return apparentLength >= 0 ? apparentLength : length + apparentLength; + } + private void writeObject( java.io.ObjectOutputStream s ) throws java.io.IOException { + s.defaultWriteObject(); + int size = size(); + s.writeInt( size ); + for( int i = start; size-- != 0; ) { + s.writeLong( array[ i++ ] ); + if ( i == length ) i = 0; + } + } + + private void readObject( java.io.ObjectInputStream s ) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + end = s.readInt(); + array = new long[ length = HashCommon.nextPowerOfTwo( end + 1 ) ]; + for( int i = 0; i < end; i++ ) array[ i ] = s.readLong(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongArrayList.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongArrayList.java new file mode 100644 index 0000000..11d1194 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongArrayList.java @@ -0,0 +1,501 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.RandomAccess; +import java.util.NoSuchElementException; +/** A type-specific array-based list; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

This class implements a lightweight, fast, open, optimized, + * reuse-oriented version of array-based lists. Instances of this class + * represent a list with an array that is enlarged as needed when new entries + * are created (by doubling its current length), but is + * never made smaller (even on a {@link #clear()}). A family of + * {@linkplain #trim() trimming methods} lets you control the size of the + * backing array; this is particularly useful if you reuse instances of this class. + * Range checks are equivalent to those of {@link java.util}'s classes, but + * they are delayed as much as possible. The backing array is exposed by the + * {@link #elements()} method. + * + *

This class implements the bulk methods removeElements(), + * addElements() and getElements() using + * high-performance system calls (e.g., {@link + * System#arraycopy(Object,int,Object,int,int) System.arraycopy()} instead of + * expensive loops. + * + * @see java.util.ArrayList + */ +public class LongArrayList extends AbstractLongList implements RandomAccess, Cloneable, java.io.Serializable { + private static final long serialVersionUID = -7046029254386353130L; + /** The initial default capacity of an array list. */ + public final static int DEFAULT_INITIAL_CAPACITY = 16; + /** The backing array. */ + protected transient long a[]; + /** The current actual size of the list (never greater than the backing-array length). */ + protected int size; + private static final boolean ASSERTS = false; + /** Creates a new array list using a given array. + * + *

This constructor is only meant to be used by the wrapping methods. + * + * @param a the array that will be used to back this array list. + */ + @SuppressWarnings("unused") + protected LongArrayList( final long a[], boolean dummy ) { + this.a = a; + } + /** Creates a new array list with given capacity. + * + * @param capacity the initial capacity of the array list (may be 0). + */ + + public LongArrayList( final int capacity ) { + if ( capacity < 0 ) throw new IllegalArgumentException( "Initial capacity (" + capacity + ") is negative" ); + a = new long[ capacity ]; + } + /** Creates a new array list with {@link #DEFAULT_INITIAL_CAPACITY} capacity. + */ + public LongArrayList() { + this( DEFAULT_INITIAL_CAPACITY ); + } + /** Creates a new array list and fills it with a given collection. + * + * @param c a collection that will be used to fill the array list. + */ + public LongArrayList( final Collection c ) { + this( c.size() ); + size = LongIterators.unwrap( LongIterators.asLongIterator( c.iterator() ), a ); + } + /** Creates a new array list and fills it with a given type-specific collection. + * + * @param c a type-specific collection that will be used to fill the array list. + */ + public LongArrayList( final LongCollection c ) { + this( c.size() ); + size = LongIterators.unwrap( c.iterator(), a ); + } + /** Creates a new array list and fills it with a given type-specific list. + * + * @param l a type-specific list that will be used to fill the array list. + */ + public LongArrayList( final LongList l ) { + this( l.size() ); + l.getElements( 0, a, 0, size = l.size() ); + } + /** Creates a new array list and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the array list. + */ + public LongArrayList( final long a[] ) { + this( a, 0, a.length ); + } + /** Creates a new array list and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the array list. + * @param offset the first element to use. + * @param length the number of elements to use. + */ + public LongArrayList( final long a[], final int offset, final int length ) { + this( length ); + System.arraycopy( a, offset, this.a, 0, length ); + size = length; + } + /** Creates a new array list and fills it with the elements returned by an iterator.. + * + * @param i an iterator whose returned elements will fill the array list. + */ + public LongArrayList( final Iterator i ) { + this(); + while( i.hasNext() ) this.add( i.next() ); + } + /** Creates a new array list and fills it with the elements returned by a type-specific iterator.. + * + * @param i a type-specific iterator whose returned elements will fill the array list. + */ + public LongArrayList( final LongIterator i ) { + this(); + while( i.hasNext() ) this.add( i.nextLong() ); + } + /** Returns the backing array of this list. + * + * @return the backing array. + */ + public long[] elements() { + return a; + } + /** Wraps a given array into an array list of given size. + * + *

Note it is guaranteed + * that the type of the array returned by {@link #elements()} will be the same + * (see the comments in the class documentation). + * + * @param a an array to wrap. + * @param length the length of the resulting array list. + * @return a new array list of the given size, wrapping the given array. + */ + public static LongArrayList wrap( final long a[], final int length ) { + if ( length > a.length ) throw new IllegalArgumentException( "The specified length (" + length + ") is greater than the array size (" + a.length + ")" ); + final LongArrayList l = new LongArrayList ( a, false ); + l.size = length; + return l; + } + /** Wraps a given array into an array list. + * + *

Note it is guaranteed + * that the type of the array returned by {@link #elements()} will be the same + * (see the comments in the class documentation). + * + * @param a an array to wrap. + * @return a new array list wrapping the given array. + */ + public static LongArrayList wrap( final long a[] ) { + return wrap( a, a.length ); + } + /** Ensures that this array list can contain the given number of entries without resizing. + * + * @param capacity the new minimum capacity for this array list. + */ + + public void ensureCapacity( final int capacity ) { + a = LongArrays.ensureCapacity( a, capacity, size ); + if ( ASSERTS ) assert size <= a.length; + } + /** Grows this array list, ensuring that it can contain the given number of entries without resizing, + * and in case enlarging it at least by a factor of two. + * + * @param capacity the new minimum capacity for this array list. + */ + + private void grow( final int capacity ) { + a = LongArrays.grow( a, capacity, size ); + if ( ASSERTS ) assert size <= a.length; + } + public void add( final int index, final long k ) { + ensureIndex( index ); + grow( size + 1 ); + if ( index != size ) System.arraycopy( a, index, a, index + 1, size - index ); + a[ index ] = k; + size++; + if ( ASSERTS ) assert size <= a.length; + } + public boolean add( final long k ) { + grow( size + 1 ); + a[ size++ ] = k; + if ( ASSERTS ) assert size <= a.length; + return true; + } + public long getLong( final int index ) { + if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" ); + return a[ index ]; + } + public int indexOf( final long k ) { + for( int i = 0; i < size; i++ ) if ( ( (k) == (a[ i ]) ) ) return i; + return -1; + } + public int lastIndexOf( final long k ) { + for( int i = size; i-- != 0; ) if ( ( (k) == (a[ i ]) ) ) return i; + return -1; + } + public long removeLong( final int index ) { + if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" ); + final long old = a[ index ]; + size--; + if ( index != size ) System.arraycopy( a, index + 1, a, index, size - index ); + if ( ASSERTS ) assert size <= a.length; + return old; + } + public boolean rem( final long k ) { + int index = indexOf( k ); + if ( index == -1 ) return false; + removeLong( index ); + if ( ASSERTS ) assert size <= a.length; + return true; + } + public long set( final int index, final long k ) { + if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" ); + long old = a[ index ]; + a[ index ] = k; + return old; + } + public void clear() { + size = 0; + if ( ASSERTS ) assert size <= a.length; + } + public int size() { + return size; + } + public void size( final int size ) { + if ( size > a.length ) ensureCapacity( size ); + if ( size > this.size ) Arrays.fill( a, this.size, size, (0) ); + this.size = size; + } + public boolean isEmpty() { + return size == 0; + } + /** Trims this array list so that the capacity is equal to the size. + * + * @see java.util.ArrayList#trimToSize() + */ + public void trim() { + trim( 0 ); + } + /** Trims the backing array if it is too large. + * + * If the current array length is smaller than or equal to + * n, this method does nothing. Otherwise, it trims the + * array length to the maximum between n and {@link #size()}. + * + *

This method is useful when reusing lists. {@linkplain #clear() Clearing a + * list} leaves the array length untouched. If you are reusing a list + * many times, you can call this method with a typical + * size to avoid keeping around a very large array just + * because of a few large transient lists. + * + * @param n the threshold for the trimming. + */ + + public void trim( final int n ) { + // TODO: use Arrays.trim() and preserve type only if necessary + if ( n >= a.length || size == a.length ) return; + final long t[] = new long[ Math.max( n, size ) ]; + System.arraycopy( a, 0, t, 0, size ); + a = t; + if ( ASSERTS ) assert size <= a.length; + } + /** Copies element of this type-specific list into the given array using optimized system calls. + * + * @param from the start index (inclusive). + * @param a the destination array. + * @param offset the offset into the destination array where to store the first element copied. + * @param length the number of elements to be copied. + */ + public void getElements( final int from, final long[] a, final int offset, final int length ) { + LongArrays.ensureOffsetLength( a, offset, length ); + System.arraycopy( this.a, from, a, offset, length ); + } + /** Removes elements of this type-specific list using optimized system calls. + * + * @param from the start index (inclusive). + * @param to the end index (exclusive). + */ + public void removeElements( final int from, final int to ) { + it.unimi.dsi.fastutil.Arrays.ensureFromTo( size, from, to ); + System.arraycopy( a, to, a, from, size - to ); + size -= ( to - from ); + } + /** Adds elements to this type-specific list using optimized system calls. + * + * @param index the index at which to add elements. + * @param a the array containing the elements. + * @param offset the offset of the first element to add. + * @param length the number of elements to add. + */ + public void addElements( final int index, final long a[], final int offset, final int length ) { + ensureIndex( index ); + LongArrays.ensureOffsetLength( a, offset, length ); + grow( size + length ); + System.arraycopy( this.a, index, this.a, index + length, size - index ); + System.arraycopy( a, offset, this.a, index, length ); + size += length; + } + public long[] toLongArray( long a[] ) { + if ( a == null || a.length < size ) a = new long[ size ]; + System.arraycopy( this.a, 0, a, 0, size ); + return a; + } + public boolean addAll( int index, final LongCollection c ) { + ensureIndex( index ); + int n = c.size(); + if ( n == 0 ) return false; + grow( size + n ); + if ( index != size ) System.arraycopy( a, index, a, index + n, size - index ); + final LongIterator i = c.iterator(); + size += n; + while( n-- != 0 ) a[ index++ ] = i.nextLong(); + if ( ASSERTS ) assert size <= a.length; + return true; + } + public boolean addAll( final int index, final LongList l ) { + ensureIndex( index ); + final int n = l.size(); + if ( n == 0 ) return false; + grow( size + n ); + if ( index != size ) System.arraycopy( a, index, a, index + n, size - index ); + l.getElements( 0, a, index, n ); + size += n; + if ( ASSERTS ) assert size <= a.length; + return true; + } + @Override + public boolean removeAll( final LongCollection c ) { + final long[] a = this.a; + int j = 0; + for( int i = 0; i < size; i++ ) + if ( ! c.contains( a[ i ] ) ) a[ j++ ] = a[ i ]; + final boolean modified = size != j; + size = j; + return modified; + } + @Override + public boolean removeAll( final Collection c ) { + final long[] a = this.a; + int j = 0; + for( int i = 0; i < size; i++ ) + if ( ! c.contains( (Long.valueOf(a[ i ])) ) ) a[ j++ ] = a[ i ]; + final boolean modified = size != j; + size = j; + return modified; + } + public LongListIterator listIterator( final int index ) { + ensureIndex( index ); + return new AbstractLongListIterator () { + int pos = index, last = -1; + public boolean hasNext() { return pos < size; } + public boolean hasPrevious() { return pos > 0; } + public long nextLong() { if ( ! hasNext() ) throw new NoSuchElementException(); return a[ last = pos++ ]; } + public long previousLong() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return a[ last = --pos ]; } + public int nextIndex() { return pos; } + public int previousIndex() { return pos - 1; } + public void add( long k ) { + LongArrayList.this.add( pos++, k ); + last = -1; + } + public void set( long k ) { + if ( last == -1 ) throw new IllegalStateException(); + LongArrayList.this.set( last, k ); + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + LongArrayList.this.removeLong( last ); + /* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */ + if ( last < pos ) pos--; + last = -1; + } + }; + } + public LongArrayList clone() { + LongArrayList c = new LongArrayList ( size ); + System.arraycopy( a, 0, c.a, 0, size ); + c.size = size; + return c; + } + /** Compares this type-specific array list to another one. + * + *

This method exists only for sake of efficiency. The implementation + * inherited from the abstract implementation would already work. + * + * @param l a type-specific array list. + * @return true if the argument contains the same elements of this type-specific array list. + */ + public boolean equals( final LongArrayList l ) { + if ( l == this ) return true; + int s = size(); + if ( s != l.size() ) return false; + final long[] a1 = a; + final long[] a2 = l.a; + while( s-- != 0 ) if ( a1[ s ] != a2[ s ] ) return false; + return true; + } + /** Compares this array list to another array list. + * + *

This method exists only for sake of efficiency. The implementation + * inherited from the abstract implementation would already work. + * + * @param l an array list. + * @return a negative integer, + * zero, or a positive integer as this list is lexicographically less than, equal + * to, or greater than the argument. + */ + + public int compareTo( final LongArrayList l ) { + final int s1 = size(), s2 = l.size(); + final long a1[] = a, a2[] = l.a; + long e1, e2; + int r, i; + for( i = 0; i < s1 && i < s2; i++ ) { + e1 = a1[ i ]; + e2 = a2[ i ]; + if ( ( r = ( Long.compare((e1),(e2)) ) ) != 0 ) return r; + } + return i < s2 ? -1 : ( i < s1 ? 1 : 0 ); + } + private void writeObject( java.io.ObjectOutputStream s ) throws java.io.IOException { + s.defaultWriteObject(); + for( int i = 0; i < size; i++ ) s.writeLong( a[ i ] ); + } + + private void readObject( java.io.ObjectInputStream s ) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + a = new long[ size ]; + for( int i = 0; i < size; i++ ) a[ i ] = s.readLong(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongArrayPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongArrayPriorityQueue.java new file mode 100644 index 0000000..8b3f90d --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongArrayPriorityQueue.java @@ -0,0 +1,229 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.NoSuchElementException; +/** A type-specific array-based priority queue. + * + *

Instances of this class represent a priority queue using a backing + * array—all operations are performed directly on the array. The array is + * enlarged as needed, but it is never shrunk. Use the {@link #trim()} method + * to reduce its size, if necessary. + * + *

This implementation is extremely inefficient, but it is difficult to beat + * when the size of the queue is very small. + */ +public class LongArrayPriorityQueue extends AbstractLongPriorityQueue implements java.io.Serializable { + private static final long serialVersionUID = 1L; + /** The backing array. */ + + protected transient long array[] = LongArrays.EMPTY_ARRAY; + /** The number of elements in this queue. */ + protected int size; + /** The type-specific comparator used in this queue. */ + protected LongComparator c; + /** The first index, cached, if {@link #firstIndexValid} is true. */ + transient protected int firstIndex; + /** Whether {@link #firstIndex} contains a valid value. */ + transient protected boolean firstIndexValid; + /** Creates a new empty queue with a given capacity and comparator. + * + * @param capacity the initial capacity of this queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + + public LongArrayPriorityQueue( int capacity, LongComparator c ) { + if ( capacity > 0 ) this.array = new long[ capacity ]; + this.c = c; + } + /** Creates a new empty queue with a given capacity and using the natural order. + * + * @param capacity the initial capacity of this queue. + */ + public LongArrayPriorityQueue( int capacity ) { + this( capacity, null ); + } + /** Creates a new empty queue with a given comparator. + * + * @param c the comparator used in this queue, or null for the natural order. + */ + public LongArrayPriorityQueue( LongComparator c ) { + this( 0, c ); + } + /** Creates a new empty queue using the natural order. + */ + public LongArrayPriorityQueue() { + this( 0, null ); + } + /** Wraps a given array in a queue using a given comparator. + * + *

The queue returned by this method will be backed by the given array. + * + * @param a an array. + * @param size the number of elements to be included in the queue. + * @param c the comparator used in this queue, or null for the natural order. + */ + public LongArrayPriorityQueue( final long[] a, int size, final LongComparator c ) { + this( c ); + this.array = a; + this.size = size; + } + /** Wraps a given array in a queue using a given comparator. + * + *

The queue returned by this method will be backed by the given array. + * + * @param a an array. + * @param c the comparator used in this queue, or null for the natural order. + */ + public LongArrayPriorityQueue( final long[] a, final LongComparator c ) { + this( a, a.length, c ); + } + /** Wraps a given array in a queue using the natural order. + * + *

The queue returned by this method will be backed by the given array. + * + * @param a an array. + * @param size the number of elements to be included in the queue. + */ + public LongArrayPriorityQueue( final long[] a, int size ) { + this( a, size, null ); + } + /** Wraps a given array in a queue using the natural order. + * + *

The queue returned by this method will be backed by the given array. + * + * @param a an array. + */ + public LongArrayPriorityQueue( final long[] a ) { + this( a, a.length ); + } + /** Returns the index of the smallest element. */ + + private int findFirst() { + if ( firstIndexValid ) return this.firstIndex; + firstIndexValid = true; + int i = size; + int firstIndex = --i; + long first = array[ firstIndex ]; + if ( c == null ) { while( i-- != 0 ) if ( ( (array[ i ]) < (first) ) ) first = array[ firstIndex = i ]; } + else while( i-- != 0 ) { if ( c.compare( array[ i ], first ) < 0 ) first = array[ firstIndex = i ]; } + return this.firstIndex = firstIndex; + } + private void ensureNonEmpty() { + if ( size == 0 ) throw new NoSuchElementException(); + } + + public void enqueue( long x ) { + if ( size == array.length ) array = LongArrays.grow( array, size + 1 ); + if ( firstIndexValid ) { + if ( c == null ) { if ( ( (x) < (array[ firstIndex ]) ) ) firstIndex = size; } + else if ( c.compare( x, array[ firstIndex ] ) < 0 ) firstIndex = size; + } + else firstIndexValid = false; + array[ size++ ] = x; + } + public long dequeueLong() { + ensureNonEmpty(); + final int first = findFirst(); + final long result = array[ first ]; + System.arraycopy( array, first + 1, array, first, --size - first ); + firstIndexValid = false; + return result; + } + public long firstLong() { + ensureNonEmpty(); + return array[ findFirst() ]; + } + public void changed() { + ensureNonEmpty(); + firstIndexValid = false; + } + public int size() { return size; } + public void clear() { + size = 0; + firstIndexValid = false; + } + /** Trims the underlying array so that it has exactly {@link #size()} elements. + */ + public void trim() { + array = LongArrays.trim( array, size ); + } + public LongComparator comparator() { return c; } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + s.defaultWriteObject(); + s.writeInt( array.length ); + for( int i = 0; i < size; i++ ) s.writeLong( array[ i ] ); + } + + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + array = new long[ s.readInt() ]; + for( int i = 0; i < size; i++ ) array[ i ] = s.readLong(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongArraySet.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongArraySet.java new file mode 100644 index 0000000..d9e82a2 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongArraySet.java @@ -0,0 +1,218 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2007-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.Collection; +import java.util.NoSuchElementException; +/** A simple, brute-force implementation of a set based on a backing array. + * + *

The main purpose of this + * implementation is that of wrapping cleanly the brute-force approach to the storage of a very + * small number of items: just put them into an array and scan linearly to find an item. + */ +public class LongArraySet extends AbstractLongSet implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = 1L; + /** The backing array (valid up to {@link #size}, excluded). */ + private transient long[] a; + /** The number of valid entries in {@link #a}. */ + private int size; + /** Creates a new array set using the given backing array. The resulting set will have as many elements as the array. + * + *

It is responsibility of the caller that the elements of a are distinct. + * + * @param a the backing array. + */ + public LongArraySet( final long[] a ) { + this.a = a; + size = a.length; + } + /** Creates a new empty array set. + */ + public LongArraySet() { + this.a = LongArrays.EMPTY_ARRAY; + } + /** Creates a new empty array set of given initial capacity. + * + * @param capacity the initial capacity. + */ + public LongArraySet( final int capacity ) { + this.a = new long[ capacity ]; + } + /** Creates a new array set copying the contents of a given collection. + * @param c a collection. + */ + public LongArraySet( LongCollection c ) { + this( c.size () ); + addAll( c ); + } + /** Creates a new array set copying the contents of a given set. + * @param c a collection. + */ + public LongArraySet( final Collection c ) { + this( c.size() ); + addAll( c ); + } + /** Creates a new array set using the given backing array and the given number of elements of the array. + * + *

It is responsibility of the caller that the first size elements of a are distinct. + * + * @param a the backing array. + * @param size the number of valid elements in a. + */ + public LongArraySet( final long[] a, final int size ) { + this.a = a; + this.size = size; + if ( size > a.length ) throw new IllegalArgumentException( "The provided size (" + size + ") is larger than or equal to the array size (" + a.length + ")" ); + } + private int findKey( final long o ) { + for( int i = size; i-- != 0; ) if ( ( (a[ i ]) == (o) ) ) return i; + return -1; + } + @Override + + public LongIterator iterator() { + return new AbstractLongIterator () { + int next = 0; + public boolean hasNext() { + return next < size; + } + public long nextLong() { + if ( ! hasNext() ) throw new NoSuchElementException(); + return a[ next++ ]; + } + public void remove() { + final int tail = size-- - next--; + System.arraycopy( a, next + 1, a, next, tail ); + } + }; + } + public boolean contains( final long k ) { + return findKey( k ) != -1; + } + public int size() { + return size; + } + @Override + public boolean remove( final long k ) { + final int pos = findKey( k ); + if ( pos == -1 ) return false; + final int tail = size - pos - 1; + for( int i = 0; i < tail; i++ ) a[ pos + i ] = a[ pos + i + 1 ]; + size--; + return true; + } + @Override + public boolean add( final long k ) { + final int pos = findKey( k ); + if ( pos != -1 ) return false; + if ( size == a.length ) { + final long[] b = new long[ size == 0 ? 2 : size * 2 ]; + for( int i = size; i-- != 0; ) b[ i ] = a[ i ]; + a = b; + } + a[ size++ ] = k; + return true; + } + @Override + public void clear() { + size = 0; + } + @Override + public boolean isEmpty() { + return size == 0; + } + /** Returns a deep copy of this set. + * + *

This method performs a deep copy of this hash set; the data stored in the + * set, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this set. + */ + + public LongArraySet clone() { + LongArraySet c; + try { + c = (LongArraySet )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.a = a.clone(); + return c; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + s.defaultWriteObject(); + for( int i = 0; i < size; i++ ) s.writeLong( a[ i ] ); + } + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + a = new long[ size ]; + for( int i = 0; i < size; i++ ) a[ i ] = s.readLong(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongArrays.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongArrays.java new file mode 100644 index 0000000..0f453ac --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongArrays.java @@ -0,0 +1,2463 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * + * For the sorting and binary search code: + * + * Copyright (C) 1999 CERN - European Organization for Nuclear Research. + * + * Permission to use, copy, modify, distribute and sell this software and + * its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation. CERN makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without expressed or implied warranty. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.Arrays; +import it.unimi.dsi.fastutil.Hash; +import java.util.Random; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.RecursiveAction; +import it.unimi.dsi.fastutil.ints.IntArrays; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorCompletionService; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; +/** A class providing static methods and objects that do useful things with type-specific arrays. + * + *

In particular, the ensureCapacity(), grow(), + * trim() and setLength() methods allow to handle + * arrays much like array lists. This can be very useful when efficiency (or + * syntactic simplicity) reasons make array lists unsuitable. + * + *

Note that {@link it.unimi.dsi.fastutil.io.BinIO} and {@link it.unimi.dsi.fastutil.io.TextIO} + * contain several methods make it possible to load and save arrays of primitive types as sequences + * of elements in {@link java.io.DataInput} format (i.e., not as objects) or as sequences of lines of text. + * + *

Sorting

+ * + *

There are several sorting methods available. The main theme is that of letting you choose + * the sorting algorithm you prefer (i.e., trading stability of mergesort for no memory allocation in quicksort). + * Several algorithms provide a parallel version, that will use the {@linkplain Runtime#availableProcessors() number of cores available}. + * Some algorithms also provide an explicit indirect sorting facility, which makes it possible + * to sort an array using the values in another array as comparator. + * + *

All comparison-based algorithm have an implementation based on a type-specific comparator. + * + *

As a general rule, sequential radix sort is significantly faster than quicksort or mergesort, in particular + * on random-looking data. In + * the parallel case, up to a few cores parallel radix sort is still the fastest, but at some point quicksort + * exploits parallelism better. + * + *

If you are fine with not knowing exactly which algorithm will be run (in particular, not knowing exactly whether a support array will be allocated), + * the dual-pivot parallel sorts in {@link java.util.Arrays} + * are about 50% faster than the classical single-pivot implementation used here. + * + *

In any case, if sorting time is important I suggest that you benchmark your sorting load + * with your data distribution and on your architecture. + * + * @see java.util.Arrays + */ +public class LongArrays { + private LongArrays() {} + /** A static, final, empty array. */ + public final static long[] EMPTY_ARRAY = {}; + /** Ensures that an array can contain the given number of entries. + * + *

If you cannot foresee whether this array will need again to be + * enlarged, you should probably use grow() instead. + * + * @param array an array. + * @param length the new minimum length for this array. + * @return array, if it contains length entries or more; otherwise, + * an array with length entries whose first array.length + * entries are the same as those of array. + */ + public static long[] ensureCapacity( final long[] array, final int length ) { + if ( length > array.length ) { + final long t[] = + new long[ length ]; + System.arraycopy( array, 0, t, 0, array.length ); + return t; + } + return array; + } + /** Ensures that an array can contain the given number of entries, preserving just a part of the array. + * + * @param array an array. + * @param length the new minimum length for this array. + * @param preserve the number of elements of the array that must be preserved in case a new allocation is necessary. + * @return array, if it can contain length entries or more; otherwise, + * an array with length entries whose first preserve + * entries are the same as those of array. + */ + public static long[] ensureCapacity( final long[] array, final int length, final int preserve ) { + if ( length > array.length ) { + final long t[] = + new long[ length ]; + System.arraycopy( array, 0, t, 0, preserve ); + return t; + } + return array; + } + /** Grows the given array to the maximum between the given length and + * the current length multiplied by two, provided that the given + * length is larger than the current length. + * + *

If you want complete control on the array growth, you + * should probably use ensureCapacity() instead. + * + * @param array an array. + * @param length the new minimum length for this array. + * @return array, if it can contain length + * entries; otherwise, an array with + * max(length,array.length/φ) entries whose first + * array.length entries are the same as those of array. + * */ + public static long[] grow( final long[] array, final int length ) { + if ( length > array.length ) { + final int newLength = (int)Math.max( Math.min( 2L * array.length, Arrays.MAX_ARRAY_SIZE ), length ); + final long t[] = + new long[ newLength ]; + System.arraycopy( array, 0, t, 0, array.length ); + return t; + } + return array; + } + /** Grows the given array to the maximum between the given length and + * the current length multiplied by two, provided that the given + * length is larger than the current length, preserving just a part of the array. + * + *

If you want complete control on the array growth, you + * should probably use ensureCapacity() instead. + * + * @param array an array. + * @param length the new minimum length for this array. + * @param preserve the number of elements of the array that must be preserved in case a new allocation is necessary. + * @return array, if it can contain length + * entries; otherwise, an array with + * max(length,array.length/φ) entries whose first + * preserve entries are the same as those of array. + * */ + public static long[] grow( final long[] array, final int length, final int preserve ) { + if ( length > array.length ) { + final int newLength = (int)Math.max( Math.min( 2L * array.length, Arrays.MAX_ARRAY_SIZE ), length ); + final long t[] = + new long[ newLength ]; + System.arraycopy( array, 0, t, 0, preserve ); + return t; + } + return array; + } + /** Trims the given array to the given length. + * + * @param array an array. + * @param length the new maximum length for the array. + * @return array, if it contains length + * entries or less; otherwise, an array with + * length entries whose entries are the same as + * the first length entries of array. + * + */ + public static long[] trim( final long[] array, final int length ) { + if ( length >= array.length ) return array; + final long t[] = + length == 0 ? EMPTY_ARRAY : new long[ length ]; + System.arraycopy( array, 0, t, 0, length ); + return t; + } + /** Sets the length of the given array. + * + * @param array an array. + * @param length the new length for the array. + * @return array, if it contains exactly length + * entries; otherwise, if it contains more than + * length entries, an array with length entries + * whose entries are the same as the first length entries of + * array; otherwise, an array with length entries + * whose first array.length entries are the same as those of + * array. + * + */ + public static long[] setLength( final long[] array, final int length ) { + if ( length == array.length ) return array; + if ( length < array.length ) return trim( array, length ); + return ensureCapacity( array, length ); + } + /** Returns a copy of a portion of an array. + * + * @param array an array. + * @param offset the first element to copy. + * @param length the number of elements to copy. + * @return a new array containing length elements of array starting at offset. + */ + public static long[] copy( final long[] array, final int offset, final int length ) { + ensureOffsetLength( array, offset, length ); + final long[] a = + length == 0 ? EMPTY_ARRAY : new long[ length ]; + System.arraycopy( array, offset, a, 0, length ); + return a; + } + /** Returns a copy of an array. + * + * @param array an array. + * @return a copy of array. + */ + public static long[] copy( final long[] array ) { + return array.clone(); + } + /** Fills the given array with the given value. + * + * @param array an array. + * @param value the new value for all elements of the array. + * @deprecated Please use the corresponding {@link java.util.Arrays} method. + */ + @Deprecated + public static void fill( final long[] array, final long value ) { + int i = array.length; + while( i-- != 0 ) array[ i ] = value; + } + /** Fills a portion of the given array with the given value. + * + * @param array an array. + * @param from the starting index of the portion to fill (inclusive). + * @param to the end index of the portion to fill (exclusive). + * @param value the new value for all elements of the specified portion of the array. + * @deprecated Please use the corresponding {@link java.util.Arrays} method. + */ + @Deprecated + public static void fill( final long[] array, final int from, int to, final long value ) { + ensureFromTo( array, from, to ); + if ( from == 0 ) while( to-- != 0 ) array[ to ] = value; + else for( int i = from; i < to; i++ ) array[ i ] = value; + } + /** Returns true if the two arrays are elementwise equal. + * + * @param a1 an array. + * @param a2 another array. + * @return true if the two arrays are of the same length, and their elements are equal. + * @deprecated Please use the corresponding {@link java.util.Arrays} method, which is intrinsified in recent JVMs. + */ + @Deprecated + public static boolean equals( final long[] a1, final long a2[] ) { + int i = a1.length; + if ( i != a2.length ) return false; + while( i-- != 0 ) if (! ( (a1[ i ]) == (a2[ i ]) ) ) return false; + return true; + } + /** Ensures that a range given by its first (inclusive) and last (exclusive) elements fits an array. + * + *

This method may be used whenever an array range check is needed. + * + * @param a an array. + * @param from a start index (inclusive). + * @param to an end index (exclusive). + * @throws IllegalArgumentException if from is greater than to. + * @throws ArrayIndexOutOfBoundsException if from or to are greater than the array length or negative. + */ + public static void ensureFromTo( final long[] a, final int from, final int to ) { + Arrays.ensureFromTo( a.length, from, to ); + } + /** Ensures that a range given by an offset and a length fits an array. + * + *

This method may be used whenever an array range check is needed. + * + * @param a an array. + * @param offset a start index. + * @param length a length (the number of elements in the range). + * @throws IllegalArgumentException if length is negative. + * @throws ArrayIndexOutOfBoundsException if offset is negative or offset+length is greater than the array length. + */ + public static void ensureOffsetLength( final long[] a, final int offset, final int length ) { + Arrays.ensureOffsetLength( a.length, offset, length ); + } + /** Ensures that two arrays are of the same length. + * + * @param a an array. + * @param b another array. + * @throws IllegalArgumentException if the two argument arrays are not of the same length. + */ + public static void ensureSameLength( final long[] a, final long[] b ) { + if ( a.length != b.length ) throw new IllegalArgumentException( "Array size mismatch: " + a.length + " != " + b.length ); + } + private static final int QUICKSORT_NO_REC = 16; + private static final int PARALLEL_QUICKSORT_NO_FORK = 8192; + private static final int QUICKSORT_MEDIAN_OF_9 = 128; + private static final int MERGESORT_NO_REC = 16; + /** Swaps two elements of an anrray. + * + * @param x an array. + * @param a a position in {@code x}. + * @param b another position in {@code x}. + */ + public static void swap( final long x[], final int a, final int b ) { + final long t = x[ a ]; + x[ a ] = x[ b ]; + x[ b ] = t; + } + /** Swaps two sequences of elements of an array. + * + * @param x an array. + * @param a a position in {@code x}. + * @param b another position in {@code x}. + * @param n the number of elements to exchange starting at {@code a} and {@code b}. + */ + public static void swap( final long[] x, int a, int b, final int n ) { + for( int i = 0; i < n; i++, a++, b++ ) swap( x, a, b ); + } + private static int med3( final long x[], final int a, final int b, final int c, LongComparator comp ) { + final int ab = comp.compare( x[ a ], x[ b ] ); + final int ac = comp.compare( x[ a ], x[ c ] ); + final int bc = comp.compare( x[ b ], x[ c ] ); + return ( ab < 0 ? + ( bc < 0 ? b : ac < 0 ? c : a ) : + ( bc > 0 ? b : ac > 0 ? c : a ) ); + } + private static void selectionSort( final long[] a, final int from, final int to, final LongComparator comp ) { + for( int i = from; i < to - 1; i++ ) { + int m = i; + for( int j = i + 1; j < to; j++ ) if ( comp.compare( a[ j ], a[ m ] ) < 0 ) m = j; + if ( m != i ) { + final long u = a[ i ]; + a[ i ] = a[ m ]; + a[ m ] = u; + } + } + } + private static void insertionSort( final long[] a, final int from, final int to, final LongComparator comp ) { + for ( int i = from; ++i < to; ) { + long t = a[ i ]; + int j = i; + for ( long u = a[ j - 1 ]; comp.compare( t, u ) < 0; u = a[ --j - 1 ] ) { + a[ j ] = u; + if ( from == j - 1 ) { + --j; + break; + } + } + a[ j ] = t; + } + } + /** Sorts the specified range of elements according to the order induced by the specified + * comparator using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param comp the comparator to determine the sorting order. + * + */ + public static void quickSort( final long[] x, final int from, final int to, final LongComparator comp ) { + final int len = to - from; + // Selection sort on smallest arrays + if ( len < QUICKSORT_NO_REC ) { + selectionSort( x, from, to, comp ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9 + int s = len / 8; + l = med3( x, l, l + s, l + 2 * s, comp ); + m = med3( x, m - s, m, m + s, comp ); + n = med3( x, n - 2 * s, n - s, n, comp ); + } + m = med3( x, l, m, n, comp ); // Mid-size, med of 3 + final long v = x[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while( true ) { + int comparison; + while ( b <= c && ( comparison = comp.compare( x[ b ], v ) ) <= 0 ) { + if ( comparison == 0 ) swap( x, a++, b ); + b++; + } + while ( c >= b && ( comparison = comp.compare( x[ c ], v ) ) >=0 ) { + if ( comparison == 0 ) swap( x, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, b++, c-- ); + } + // Swap partition elements back to middle + int s; + s = Math.min( a - from, b - a ); + swap( x, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, b, to - s, s ); + // Recursively sort non-partition-elements + if ( ( s = b - a ) > 1 ) quickSort( x, from, from + s, comp ); + if ( ( s = d - c ) > 1 ) quickSort( x, to - s, to, comp ); + } + /** Sorts an array 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. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param x the array to be sorted. + * @param comp the comparator to determine the sorting order. + * + */ + public static void quickSort( final long[] x, final LongComparator comp ) { + quickSort( x, 0, x.length, comp ); + } + protected static class ForkJoinQuickSortComp extends RecursiveAction { + private static final long serialVersionUID = 1L; + private final int from; + private final int to; + private final long[] x; + private final LongComparator comp; + public ForkJoinQuickSortComp( final long[] x , final int from , final int to, final LongComparator comp ) { + this.from = from; + this.to = to; + this.x = x; + this.comp = comp; + } + @Override + protected void compute() { + final long[] x = this.x; + final int len = to - from; + if ( len < PARALLEL_QUICKSORT_NO_FORK ) { + quickSort( x, from, to, comp ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + int s = len / 8; + l = med3( x, l, l + s, l + 2 * s ); + m = med3( x, m - s, m, m + s ); + n = med3( x, n - 2 * s, n - s, n ); + m = med3( x, l, m, n ); + final long v = x[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison; + while ( b <= c && ( comparison = comp.compare( x[ b ], v ) ) <= 0 ) { + if ( comparison == 0 ) swap( x, a++, b ); + b++; + } + while ( c >= b && ( comparison = comp.compare( x[ c ], v ) ) >= 0 ) { + if ( comparison == 0 ) swap( x, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, b++, c-- ); + } + // Swap partition elements back to middle + int t; + s = Math.min( a - from, b - a ); + swap( x, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, b, to - s, s ); + // Recursively sort non-partition-elements + s = b - a; + t = d - c; + if ( s > 1 && t > 1 ) invokeAll( new ForkJoinQuickSortComp ( x, from, from + s, comp ), new ForkJoinQuickSortComp ( x, to - t, to, comp ) ); + else if ( s > 1 ) invokeAll( new ForkJoinQuickSortComp ( x, from, from + s, comp ) ); + else invokeAll( new ForkJoinQuickSortComp ( x, to - t, to, comp ) ); + } + } + /** Sorts the specified range of elements according to the order induced by the specified + * comparator using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param comp the comparator to determine the sorting order. + */ + public static void parallelQuickSort( final long[] x, final int from, final int to, final LongComparator comp ) { + if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSort( x, from, to, comp ); + else { + final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() ); + pool.invoke( new ForkJoinQuickSortComp ( x, from, to, comp ) ); + pool.shutdown(); + } + } + /** Sorts an array according to the order induced by the specified + * comparator using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the array to be sorted. + * @param comp the comparator to determine the sorting order. + */ + public static void parallelQuickSort( final long[] x, final LongComparator comp ) { + parallelQuickSort( x, 0, x.length, comp ); + } + + private static int med3( final long x[], final int a, final int b, final int c ) { + final int ab = ( Long.compare((x[ a ]),(x[ b ])) ); + final int ac = ( Long.compare((x[ a ]),(x[ c ])) ); + final int bc = ( Long.compare((x[ b ]),(x[ c ])) ); + return ( ab < 0 ? + ( bc < 0 ? b : ac < 0 ? c : a ) : + ( bc > 0 ? b : ac > 0 ? c : a ) ); + } + + private static void selectionSort( final long[] a, final int from, final int to ) { + for( int i = from; i < to - 1; i++ ) { + int m = i; + for( int j = i + 1; j < to; j++ ) if ( ( (a[ j ]) < (a[ m ]) ) ) m = j; + if ( m != i ) { + final long u = a[ i ]; + a[ i ] = a[ m ]; + a[ m ] = u; + } + } + } + + private static void insertionSort( final long[] a, final int from, final int to ) { + for ( int i = from; ++i < to; ) { + long t = a[ i ]; + int j = i; + for ( long u = a[ j - 1 ]; ( (t) < (u) ); u = a[ --j - 1 ] ) { + a[ j ] = u; + if ( from == j - 1 ) { + --j; + break; + } + } + a[ j ] = t; + } + } + /** Sorts the specified range of elements according to the natural ascending order using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + + public static void quickSort( final long[] x, final int from, final int to ) { + final int len = to - from; + // Selection sort on smallest arrays + if ( len < QUICKSORT_NO_REC ) { + selectionSort( x, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9 + int s = len / 8; + l = med3( x, l, l + s, l + 2 * s ); + m = med3( x, m - s, m, m + s ); + n = med3( x, n - 2 * s, n - s, n ); + } + m = med3( x, l, m, n ); // Mid-size, med of 3 + final long v = x[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while(true) { + int comparison; + while ( b <= c && ( comparison = ( Long.compare((x[ b ]),(v)) ) ) <= 0 ) { + if ( comparison == 0 ) swap( x, a++, b ); + b++; + } + while (c >= b && ( comparison = ( Long.compare((x[ c ]),(v)) ) ) >=0 ) { + if ( comparison == 0 ) swap( x, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, b++, c-- ); + } + // Swap partition elements back to middle + int s; + s = Math.min( a - from, b - a ); + swap( x, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, b, to - s, s ); + // Recursively sort non-partition-elements + if ( ( s = b - a ) > 1 ) quickSort( x, from, from + s ); + if ( ( s = d - c ) > 1 ) quickSort( x, to - s, to ); + } + /** Sorts an array according to the natural ascending order using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param x the array to be sorted. + * + */ + public static void quickSort( final long[] x ) { + quickSort( x, 0, x.length ); + } + protected static class ForkJoinQuickSort extends RecursiveAction { + private static final long serialVersionUID = 1L; + private final int from; + private final int to; + private final long[] x; + public ForkJoinQuickSort( final long[] x , final int from , final int to ) { + this.from = from; + this.to = to; + this.x = x; + } + @Override + + protected void compute() { + final long[] x = this.x; + final int len = to - from; + if ( len < PARALLEL_QUICKSORT_NO_FORK ) { + quickSort( x, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + int s = len / 8; + l = med3( x, l, l + s, l + 2 * s ); + m = med3( x, m - s, m, m + s ); + n = med3( x, n - 2 * s, n - s, n ); + m = med3( x, l, m, n ); + final long v = x[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison; + while ( b <= c && ( comparison = ( Long.compare((x[ b ]),(v)) ) ) <= 0 ) { + if ( comparison == 0 ) swap( x, a++, b ); + b++; + } + while ( c >= b && ( comparison = ( Long.compare((x[ c ]),(v)) ) ) >= 0 ) { + if ( comparison == 0 ) swap( x, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, b++, c-- ); + } + // Swap partition elements back to middle + int t; + s = Math.min( a - from, b - a ); + swap( x, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, b, to - s, s ); + // Recursively sort non-partition-elements + s = b - a; + t = d - c; + if ( s > 1 && t > 1 ) invokeAll( new ForkJoinQuickSort ( x, from, from + s ), new ForkJoinQuickSort ( x, to - t, to ) ); + else if ( s > 1 ) invokeAll( new ForkJoinQuickSort ( x, from, from + s ) ); + else invokeAll( new ForkJoinQuickSort ( x, to - t, to ) ); + } + } + /** Sorts the specified range of elements according to the natural ascending order using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void parallelQuickSort( final long[] x, final int from, final int to ) { + if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSort( x, from, to ); + else { + final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() ); + pool.invoke( new ForkJoinQuickSort ( x, from, to ) ); + pool.shutdown(); + } + } + /** Sorts an array according to the natural ascending order using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the array to be sorted. + * + */ + public static void parallelQuickSort( final long[] x ) { + parallelQuickSort( x, 0, x.length ); + } + + private static int med3Indirect( final int perm[], final long x[], final int a, final int b, final int c ) { + final long aa = x[ perm[ a ] ]; + final long bb = x[ perm[ b ] ]; + final long cc = x[ perm[ c ] ]; + final int ab = ( Long.compare((aa),(bb)) ); + final int ac = ( Long.compare((aa),(cc)) ); + final int bc = ( Long.compare((bb),(cc)) ); + return ( ab < 0 ? + ( bc < 0 ? b : ac < 0 ? c : a ) : + ( bc > 0 ? b : ac > 0 ? c : a ) ); + } + + private static void insertionSortIndirect( final int[] perm, final long[] a, final int from, final int to ) { + for ( int i = from; ++i < to; ) { + int t = perm[ i ]; + int j = i; + for ( int u = perm[ j - 1 ]; ( (a[ t ]) < (a[ u ]) ); u = perm[ --j - 1 ] ) { + perm[ j ] = u; + if ( from == j - 1 ) { + --j; + break; + } + } + perm[ j ] = t; + } + } + /** Sorts the specified range of elements according to the natural ascending order using indirect quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param perm a permutation array indexing {@code x}. + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + + public static void quickSortIndirect( final int[] perm, final long[] x, final int from, final int to ) { + final int len = to - from; + // Selection sort on smallest arrays + if ( len < QUICKSORT_NO_REC ) { + insertionSortIndirect( perm, x, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9 + int s = len / 8; + l = med3Indirect( perm, x, l, l + s, l + 2 * s ); + m = med3Indirect( perm, x, m - s, m, m + s ); + n = med3Indirect( perm, x, n - 2 * s, n - s, n ); + } + m = med3Indirect( perm, x, l, m, n ); // Mid-size, med of 3 + final long v = x[ perm[ m ] ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while(true) { + int comparison; + while ( b <= c && ( comparison = ( Long.compare((x[ perm[ b ] ]),(v)) ) ) <= 0 ) { + if ( comparison == 0 ) IntArrays.swap( perm, a++, b ); + b++; + } + while (c >= b && ( comparison = ( Long.compare((x[ perm[ c ] ]),(v)) ) ) >=0 ) { + if ( comparison == 0 ) IntArrays.swap( perm, c, d-- ); + c--; + } + if ( b > c ) break; + IntArrays.swap( perm, b++, c-- ); + } + // Swap partition elements back to middle + int s; + s = Math.min( a - from, b - a ); + IntArrays.swap( perm, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + IntArrays.swap( perm, b, to - s, s ); + // Recursively sort non-partition-elements + if ( ( s = b - a ) > 1 ) quickSortIndirect( perm, x, from, from + s ); + if ( ( s = d - c ) > 1 ) quickSortIndirect( perm, x, to - s, to ); + } + /** Sorts an array according to the natural ascending order using indirect quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param perm a permutation array indexing {@code x}. + * @param x the array to be sorted. + */ + public static void quickSortIndirect( final int perm[], final long[] x ) { + quickSortIndirect( perm, x, 0, x.length ); + } + protected static class ForkJoinQuickSortIndirect extends RecursiveAction { + private static final long serialVersionUID = 1L; + private final int from; + private final int to; + private final int[] perm; + private final long[] x; + public ForkJoinQuickSortIndirect( final int perm[], final long[] x , final int from , final int to ) { + this.from = from; + this.to = to; + this.x = x; + this.perm = perm; + } + @Override + + protected void compute() { + final long[] x = this.x; + final int len = to - from; + if ( len < PARALLEL_QUICKSORT_NO_FORK ) { + quickSortIndirect( perm, x, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + int s = len / 8; + l = med3Indirect( perm, x, l, l + s, l + 2 * s ); + m = med3Indirect( perm, x, m - s, m, m + s ); + n = med3Indirect( perm, x, n - 2 * s, n - s, n ); + m = med3Indirect( perm, x, l, m, n ); + final long v = x[ perm[ m ] ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison; + while ( b <= c && ( comparison = ( Long.compare((x[ perm[ b ] ]),(v)) ) ) <= 0 ) { + if ( comparison == 0 ) IntArrays.swap( perm, a++, b ); + b++; + } + while ( c >= b && ( comparison = ( Long.compare((x[ perm[ c ] ]),(v)) ) ) >= 0 ) { + if ( comparison == 0 ) IntArrays.swap( perm, c, d-- ); + c--; + } + if ( b > c ) break; + IntArrays.swap( perm, b++, c-- ); + } + // Swap partition elements back to middle + int t; + s = Math.min( a - from, b - a ); + IntArrays.swap( perm, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + IntArrays.swap( perm, b, to - s, s ); + // Recursively sort non-partition-elements + s = b - a; + t = d - c; + if ( s > 1 && t > 1 ) invokeAll( new ForkJoinQuickSortIndirect ( perm, x, from, from + s ), new ForkJoinQuickSortIndirect ( perm, x, to - t, to ) ); + else if ( s > 1 ) invokeAll( new ForkJoinQuickSortIndirect ( perm, x, from, from + s ) ); + else invokeAll( new ForkJoinQuickSortIndirect ( perm, x, to - t, to ) ); + } + } + /** Sorts the specified range of elements according to the natural ascending order using a parallel indirect quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param perm a permutation array indexing {@code x}. + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void parallelQuickSortIndirect( final int[] perm, final long[] x, final int from, final int to ) { + if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSortIndirect( perm, x, from, to ); + else { + final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() ); + pool.invoke( new ForkJoinQuickSortIndirect ( perm, x, from, to ) ); + pool.shutdown(); + } + } + /** Sorts an array according to the natural ascending order using a parallel indirect quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param perm a permutation array indexing {@code x}. + * @param x the array to be sorted. + * + */ + public static void parallelQuickSortIndirect( final int perm[], final long[] x ) { + parallelQuickSortIndirect( perm, x, 0, x.length ); + } + /** Stabilizes a permutation. + * + *

This method can be used to stabilize the permutation generated by an indirect sorting, assuming that + * initially the permutation array was in ascending order (e.g., the identity, as usually happens). This method + * scans the permutation, and for each non-singleton block of elements with the same associated values in {@code x}, + * permutes them in ascending order. The resulting permutation corresponds to a stable sort. + * + *

Usually combining an unstable indirect sort and this method is more efficient than using a stable sort, + * as most stable sort algorithms require a support array. + * + *

More precisely, assuming that x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ], after + * stabilization we will also have that x[ perm[ i ] ] = x[ perm[ i + 1 ] ] implies + * perm[ i ] ≤ perm[ i + 1 ]. + * + * @param perm a permutation array indexing {@code x} so that it is sorted. + * @param x the sorted array to be stabilized. + * @param from the index of the first element (inclusive) to be stabilized. + * @param to the index of the last element (exclusive) to be stabilized. + */ + public static void stabilize( final int perm[], final long[] x, final int from, final int to ) { + int curr = from; + for( int i = from + 1; i < to; i++ ) { + if ( x[ perm[ i ] ] != x[ perm[ curr ] ] ) { + if ( i - curr > 1 ) IntArrays.parallelQuickSort( perm, curr, i ); + curr = i; + } + } + if ( to - curr > 1 ) IntArrays.parallelQuickSort( perm, curr, to ); + } + /** Stabilizes a permutation. + * + *

This method can be used to stabilize the permutation generated by an indirect sorting, assuming that + * initially the permutation array was in ascending order (e.g., the identity, as usually happens). This method + * scans the permutation, and for each non-singleton block of elements with the same associated values in {@code x}, + * permutes them in ascending order. The resulting permutation corresponds to a stable sort. + * + *

Usually combining an unstable indirect sort and this method is more efficient than using a stable sort, + * as most stable sort algorithms require a support array. + * + *

More precisely, assuming that x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ], after + * stabilization we will also have that x[ perm[ i ] ] = x[ perm[ i + 1 ] ] implies + * perm[ i ] ≤ perm[ i + 1 ]. + * + * @param perm a permutation array indexing {@code x} so that it is sorted. + * @param x the sorted array to be stabilized. + */ + public static void stabilize( final int perm[], final long[] x ) { + stabilize( perm, x, 0, perm.length ); + } + + private static int med3( final long x[], final long[] y, final int a, final int b, final int c ) { + int t; + final int ab = ( t = ( Long.compare((x[ a ]),(x[ b ])) ) ) == 0 ? ( Long.compare((y[ a ]),(y[ b ])) ) : t; + final int ac = ( t = ( Long.compare((x[ a ]),(x[ c ])) ) ) == 0 ? ( Long.compare((y[ a ]),(y[ c ])) ) : t; + final int bc = ( t = ( Long.compare((x[ b ]),(x[ c ])) ) ) == 0 ? ( Long.compare((y[ b ]),(y[ c ])) ) : t; + return ( ab < 0 ? + ( bc < 0 ? b : ac < 0 ? c : a ) : + ( bc > 0 ? b : ac > 0 ? c : a ) ); + } + private static void swap( final long x[], final long[] y, final int a, final int b ) { + final long t = x[ a ]; + final long u = y[ a ]; + x[ a ] = x[ b ]; + y[ a ] = y[ b ]; + x[ b ] = t; + y[ b ] = u; + } + private static void swap( final long[] x, final long[] y, int a, int b, final int n ) { + for ( int i = 0; i < n; i++, a++, b++ ) swap( x, y, a, b ); + } + + private static void selectionSort( final long[] a, final long[] b, final int from, final int to ) { + for( int i = from; i < to - 1; i++ ) { + int m = i, u; + for( int j = i + 1; j < to; j++ ) + if ( ( u = ( Long.compare((a[ j ]),(a[ m ])) ) ) < 0 || u == 0 && ( (b[ j ]) < (b[ m ]) ) ) m = j; + if ( m != i ) { + long t = a[ i ]; + a[ i ] = a[ m ]; + a[ m ] = t; + t = b[ i ]; + b[ i ] = b[ m ]; + b[ m ] = t; + } + } + } + /** Sorts the specified range of elements of two arrays according to the natural lexicographical + * ascending order using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implements a lexicographical sorting of the arguments. Pairs of + * elements in the same position in the two provided arrays will be considered a single key, and + * permuted accordingly. In the end, either x[ i ] < x[ i + 1 ] or x[ i ] + * == x[ i + 1 ] and y[ i ] ≤ y[ i + 1 ]. + * + * @param x the first array to be sorted. + * @param y the second array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + + public static void quickSort( final long[] x, final long[] y, final int from, final int to ) { + final int len = to - from; + if ( len < QUICKSORT_NO_REC ) { + selectionSort( x, y, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9 + int s = len / 8; + l = med3( x, y, l, l + s, l + 2 * s ); + m = med3( x, y, m - s, m, m + s ); + n = med3( x, y, n - 2 * s, n - s, n ); + } + m = med3( x, y, l, m, n ); // Mid-size, med of 3 + final long v = x[ m ], w = y[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison, t; + while ( b <= c && ( comparison = ( t = ( Long.compare((x[ b ]),(v)) ) ) == 0 ? ( Long.compare((y[ b ]),(w)) ) : t ) <= 0 ) { + if ( comparison == 0 ) swap( x, y, a++, b ); + b++; + } + while ( c >= b && ( comparison = ( t = ( Long.compare((x[ c ]),(v)) ) ) == 0 ? ( Long.compare((y[ c ]),(w)) ) : t ) >= 0 ) { + if ( comparison == 0 ) swap( x, y, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, y, b++, c-- ); + } + // Swap partition elements back to middle + int s; + s = Math.min( a - from, b - a ); + swap( x, y, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, y, b, to - s, s ); + // Recursively sort non-partition-elements + if ( ( s = b - a ) > 1 ) quickSort( x, y, from, from + s ); + if ( ( s = d - c ) > 1 ) quickSort( x, y, to - s, to ); + } + /** Sorts two arrays according to the natural lexicographical ascending order using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implements a lexicographical sorting of the arguments. Pairs of + * elements in the same position in the two provided arrays will be considered a single key, and + * permuted accordingly. In the end, either x[ i ] < x[ i + 1 ] or x[ i ] + * == x[ i + 1 ] and y[ i ] ≤ y[ i + 1 ]. + * + * @param x the first array to be sorted. + * @param y the second array to be sorted. + */ + public static void quickSort( final long[] x, final long[] y ) { + ensureSameLength( x, y ); + quickSort( x, y, 0, x.length ); + } + protected static class ForkJoinQuickSort2 extends RecursiveAction { + private static final long serialVersionUID = 1L; + private final int from; + private final int to; + private final long[] x, y; + public ForkJoinQuickSort2( final long[] x, final long[] y, final int from , final int to ) { + this.from = from; + this.to = to; + this.x = x; + this.y = y; + } + @Override + + protected void compute() { + final long[] x = this.x; + final long[] y = this.y; + final int len = to - from; + if ( len < PARALLEL_QUICKSORT_NO_FORK ) { + quickSort( x, y, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + int s = len / 8; + l = med3( x, y, l, l + s, l + 2 * s ); + m = med3( x, y, m - s, m, m + s ); + n = med3( x, y, n - 2 * s, n - s, n ); + m = med3( x, y, l, m, n ); + final long v = x[ m ], w = y[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison, t; + while ( b <= c && ( comparison = ( t = ( Long.compare((x[ b ]),(v)) ) ) == 0 ? ( Long.compare((y[ b ]),(w)) ) : t ) <= 0 ) { + if ( comparison == 0 ) swap( x, y, a++, b ); + b++; + } + while ( c >= b && ( comparison = ( t = ( Long.compare((x[ c ]),(v)) ) ) == 0 ? ( Long.compare((y[ c ]),(w)) ) : t ) >= 0 ) { + if ( comparison == 0 ) swap( x, y, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, y, b++, c-- ); + } + // Swap partition elements back to middle + int t; + s = Math.min( a - from, b - a ); + swap( x, y, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, y, b, to - s, s ); + s = b - a; + t = d - c; + // Recursively sort non-partition-elements + if ( s > 1 && t > 1 ) invokeAll( new ForkJoinQuickSort2 ( x, y, from, from + s ), new ForkJoinQuickSort2 ( x, y, to - t, to ) ); + else if ( s > 1 ) invokeAll( new ForkJoinQuickSort2 ( x, y, from, from + s ) ); + else invokeAll( new ForkJoinQuickSort2 ( x, y, to - t, to ) ); + } + } + /** Sorts the specified range of elements of two arrays according to the natural lexicographical + * ascending order using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implements a lexicographical sorting of the arguments. Pairs of + * elements in the same position in the two provided arrays will be considered a single key, and + * permuted accordingly. In the end, either x[ i ] < x[ i + 1 ] or x[ i ] + * == x[ i + 1 ] and y[ i ] ≤ y[ i + 1 ]. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the first array to be sorted. + * @param y the second array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void parallelQuickSort( final long[] x, final long[] y, final int from, final int to ) { + if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSort( x, y, from, to ); + final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() ); + pool.invoke( new ForkJoinQuickSort2 ( x, y, from, to ) ); + pool.shutdown(); + } + /** Sorts two arrays according to the natural lexicographical + * ascending order using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implements a lexicographical sorting of the arguments. Pairs of + * elements in the same position in the two provided arrays will be considered a single key, and + * permuted accordingly. In the end, either x[ i ] < x[ i + 1 ] or x[ i ] + * == x[ i + 1 ] and y[ i ] ≤ y[ i + 1 ]. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the first array to be sorted. + * @param y the second array to be sorted. + */ + public static void parallelQuickSort( final long[] x, final long[] y ) { + ensureSameLength( x, y ); + parallelQuickSort( x, y, 0, x.length ); + } + /** Sorts the specified range of elements according to the natural ascending order using mergesort, using a given pre-filled support array. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. Moreover, no support arrays will be allocated. + + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param supp a support array containing at least to elements, and whose entries are identical to those + * of {@code a} in the specified range. + */ + + public static void mergeSort( final long a[], final int from, final int to, final long supp[] ) { + int len = to - from; + // Insertion sort on smallest arrays + if ( len < MERGESORT_NO_REC ) { + insertionSort( a, from, to ); + return; + } + // Recursively sort halves of a into supp + final int mid = ( from + to ) >>> 1; + mergeSort( supp, from, mid, a ); + mergeSort( supp, mid, to, a ); + // If list is already sorted, just copy from supp to a. This is an + // optimization that results in faster sorts for nearly ordered lists. + if ( ( (supp[ mid - 1 ]) <= (supp[ mid ]) ) ) { + System.arraycopy( supp, from, a, from, len ); + return; + } + // Merge sorted halves (now in supp) into a + for( int i = from, p = from, q = mid; i < to; i++ ) { + if ( q >= to || p < mid && ( (supp[ p ]) <= (supp[ q ]) ) ) a[ i ] = supp[ p++ ]; + else a[ i ] = supp[ q++ ]; + } + } + /** Sorts the specified range of elements according to the natural ascending order using mergesort. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. An array as large as a will be allocated by this method. + + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void mergeSort( final long a[], final int from, final int to ) { + mergeSort( a, from, to, a.clone() ); + } + /** Sorts an array according to the natural ascending order using mergesort. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. An array as large as a will be allocated by this method. + + * @param a the array to be sorted. + */ + public static void mergeSort( final long a[] ) { + mergeSort( a, 0, a.length ); + } + /** Sorts the specified range of elements according to the order induced by the specified + * comparator using mergesort, using a given pre-filled support array. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. Moreover, no support arrays will be allocated. + + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param comp the comparator to determine the sorting order. + * @param supp a support array containing at least to elements, and whose entries are identical to those + * of {@code a} in the specified range. + */ + public static void mergeSort( final long a[], final int from, final int to, LongComparator comp, final long supp[] ) { + int len = to - from; + // Insertion sort on smallest arrays + if ( len < MERGESORT_NO_REC ) { + insertionSort( a, from, to, comp ); + return; + } + // Recursively sort halves of a into supp + final int mid = ( from + to ) >>> 1; + mergeSort( supp, from, mid, comp, a ); + mergeSort( supp, mid, to, comp, a ); + // If list is already sorted, just copy from supp to a. This is an + // optimization that results in faster sorts for nearly ordered lists. + if ( comp.compare( supp[ mid - 1 ], supp[ mid ] ) <= 0 ) { + System.arraycopy( supp, from, a, from, len ); + return; + } + // Merge sorted halves (now in supp) into a + for( int i = from, p = from, q = mid; i < to; i++ ) { + if ( q >= to || p < mid && comp.compare( supp[ p ], supp[ q ] ) <= 0 ) a[ i ] = supp[ p++ ]; + else a[ i ] = supp[ q++ ]; + } + } + /** Sorts the specified range of elements according to the order induced by the specified + * comparator using mergesort. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. An array as large as a will be allocated by this method. + * + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param comp the comparator to determine the sorting order. + */ + public static void mergeSort( final long a[], final int from, final int to, LongComparator comp ) { + mergeSort( a, from, to, comp, a.clone() ); + } + /** Sorts an array 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. An array as large as a will be allocated by this method. + + * @param a the array to be sorted. + * @param comp the comparator to determine the sorting order. + */ + public static void mergeSort( final long a[], LongComparator comp ) { + mergeSort( a, 0, a.length, comp ); + } + /** + * Searches a range of the specified array for the specified value using + * the binary search algorithm. The range must be sorted prior to making this call. + * If it is not sorted, the results are undefined. If the range contains multiple elements with + * the specified value, there is no guarantee which one will be found. + * + * @param a the array to be searched. + * @param from the index of the first element (inclusive) to be searched. + * @param to the index of the last element (exclusive) to be searched. + * @param key the value to be searched for. + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The insertion + * point is defined as the the point at which the value would + * be inserted into the array: the index of the first + * element greater than the key, or the length of the array, if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be ≥ 0 if + * and only if the key is found. + * @see java.util.Arrays + */ + + public static int binarySearch( final long[] a, int from, int to, final long key ) { + long midVal; + to--; + while (from <= to) { + final int mid = (from + to) >>> 1; + midVal = a[ mid ]; + if (midVal < key) from = mid + 1; + else if (midVal > key) to = mid - 1; + else return mid; + } + return -( from + 1 ); + } + /** + * Searches an array for the specified value using + * the binary search algorithm. The range must be sorted prior to making this call. + * If it is not sorted, the results are undefined. If the range contains multiple elements with + * the specified value, there is no guarantee which one will be found. + * + * @param a the array to be searched. + * @param key the value to be searched for. + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The insertion + * point is defined as the the point at which the value would + * be inserted into the array: the index of the first + * element greater than the key, or the length of the array, if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be ≥ 0 if + * and only if the key is found. + * @see java.util.Arrays + */ + public static int binarySearch( final long[] a, final long key ) { + return binarySearch( a, 0, a.length, key ); + } + /** + * Searches a range of the specified array for the specified value using + * the binary search algorithm and a specified comparator. The range must be sorted following the comparator prior to making this call. + * If it is not sorted, the results are undefined. If the range contains multiple elements with + * the specified value, there is no guarantee which one will be found. + * + * @param a the array to be searched. + * @param from the index of the first element (inclusive) to be searched. + * @param to the index of the last element (exclusive) to be searched. + * @param key the value to be searched for. + * @param c a comparator. + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The insertion + * point is defined as the the point at which the value would + * be inserted into the array: the index of the first + * element greater than the key, or the length of the array, if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be ≥ 0 if + * and only if the key is found. + * @see java.util.Arrays + */ + public static int binarySearch( final long[] a, int from, int to, final long key, final LongComparator c ) { + long midVal; + to--; + while (from <= to) { + final int mid = (from + to) >>> 1; + midVal = a[ mid ]; + final int cmp = c.compare( midVal, key ); + if ( cmp < 0 ) from = mid + 1; + else if (cmp > 0) to = mid - 1; + else return mid; // key found + } + return -( from + 1 ); + } + /** + * Searches an array for the specified value using + * the binary search algorithm and a specified comparator. The range must be sorted following the comparator prior to making this call. + * If it is not sorted, the results are undefined. If the range contains multiple elements with + * the specified value, there is no guarantee which one will be found. + * + * @param a the array to be searched. + * @param key the value to be searched for. + * @param c a comparator. + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The insertion + * point is defined as the the point at which the value would + * be inserted into the array: the index of the first + * element greater than the key, or the length of the array, if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be ≥ 0 if + * and only if the key is found. + * @see java.util.Arrays + */ + public static int binarySearch( final long[] a, final long key, final LongComparator c ) { + return binarySearch( a, 0, a.length, key, c ); + } + /** The size of a digit used during radix sort (must be a power of 2). */ + private static final int DIGIT_BITS = 8; + /** The mask to extract a digit of {@link #DIGIT_BITS} bits. */ + private static final int DIGIT_MASK = ( 1 << DIGIT_BITS ) - 1; + /** The number of digits per element. */ + private static final int DIGITS_PER_ELEMENT = Long.SIZE / DIGIT_BITS; + private static final int RADIXSORT_NO_REC = 1024; + private static final int PARALLEL_RADIXSORT_NO_FORK = 1024; + /** This method fixes negative numbers so that the combination exponent/significand is lexicographically sorted. */ + /** Sorts the specified array using radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This implementation is significantly faster than quicksort + * already at small sizes (say, more than 10000 elements), but it can only + * sort in ascending order. + * + * @param a the array to be sorted. + */ + public static void radixSort( final long[] a ) { + radixSort( a, 0, a.length ); + } + /** Sorts the specified range of an array using radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This implementation is significantly faster than quicksort + * already at small sizes (say, more than 10000 elements), but it can only + * sort in ascending order. + * + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void radixSort( final long[] a, final int from, final int to ) { + if ( to - from < RADIXSORT_NO_REC ) { + quickSort( a, from, to ); + return; + } + final int maxLevel = DIGITS_PER_ELEMENT - 1; + final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( DIGITS_PER_ELEMENT - 1 ) + 1; + int stackPos = 0; + final int[] offsetStack = new int[ stackSize ]; + final int[] lengthStack = new int[ stackSize ]; + final int[] levelStack = new int[ stackSize ]; + offsetStack[ stackPos ] = from; + lengthStack[ stackPos ] = to - from; + levelStack[ stackPos++ ] = 0; + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + while( stackPos > 0 ) { + final int first = offsetStack[ --stackPos ]; + final int length = lengthStack[ stackPos ]; + final int level = levelStack[ stackPos ]; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ (int)((a[ i ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + long t = a[ i ]; + c = (int)((t) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while ( ( d = --pos[ c ] ) > i ) { + final long z = t; + t = a[ d ]; + a[ d ] = z; + c = (int)((t) >>> shift & DIGIT_MASK ^ signMask); + } + a[ i ] = t; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < RADIXSORT_NO_REC ) quickSort( a, i, i + count[ c ] ); + else { + offsetStack[ stackPos ] = i; + lengthStack[ stackPos ] = count[ c ]; + levelStack[ stackPos++ ] = level + 1; + } + } + } + } + } + protected final static class Segment { + protected final int offset, length, level; + protected Segment( final int offset, final int length, final int level ) { + this.offset = offset; + this.length = length; + this.level = level; + } + @Override + public String toString() { + return "Segment [offset=" + offset + ", length=" + length + ", level=" + level + "]"; + } + } + protected final static Segment POISON_PILL = new Segment( -1, -1, -1 ); + /** Sorts the specified range of an array using parallel radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This implementation uses a pool of {@link Runtime#availableProcessors()} threads. + * + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void parallelRadixSort( final long[] a, final int from, final int to ) { + if ( to - from < PARALLEL_RADIXSORT_NO_FORK ) { + quickSort( a, from, to ); + return; + } + final int maxLevel = DIGITS_PER_ELEMENT - 1; + final LinkedBlockingQueue queue = new LinkedBlockingQueue(); + queue.add( new Segment( from, to - from, 0 ) ); + final AtomicInteger queueSize = new AtomicInteger( 1 ); + final int numberOfThreads = Runtime.getRuntime().availableProcessors(); + final ExecutorService executorService = Executors.newFixedThreadPool( numberOfThreads, Executors.defaultThreadFactory() ); + final ExecutorCompletionService executorCompletionService = new ExecutorCompletionService( executorService ); + for( int i = numberOfThreads; i-- != 0; ) executorCompletionService.submit( new Callable() { + public Void call() throws Exception { + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + for(;;) { + if ( queueSize.get() == 0 ) for( int i = numberOfThreads; i-- != 0; ) queue.add( POISON_PILL ); + final Segment segment = queue.take(); + if ( segment == POISON_PILL ) return null; + final int first = segment.offset; + final int length = segment.length; + final int level = segment.level; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ (int)((a[ i ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + long t = a[ i ]; + c = (int)((t) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { + while( ( d = --pos[ c ] ) > i ) { + final long z = t; + t = a[ d ]; + a[ d ] = z; + c = (int)((t) >>> shift & DIGIT_MASK ^ signMask); + } + a[ i ] = t; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < PARALLEL_RADIXSORT_NO_FORK ) quickSort( a, i, i + count[ c ] ); + else { + queueSize.incrementAndGet(); + queue.add( new Segment( i, count[ c ], level + 1 ) ); + } + } + } + queueSize.decrementAndGet(); + } + } + } ); + Throwable problem = null; + for( int i = numberOfThreads; i-- != 0; ) + try { + executorCompletionService.take().get(); + } + catch( Exception e ) { + problem = e.getCause(); // We keep only the last one. They will be logged anyway. + } + executorService.shutdown(); + if ( problem != null ) throw ( problem instanceof RuntimeException ) ? (RuntimeException)problem : new RuntimeException( problem ); + } + /** Sorts the specified array using parallel radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This implementation uses a pool of {@link Runtime#availableProcessors()} threads. + * + * @param a the array to be sorted. + */ + public static void parallelRadixSort( final long[] a ) { + parallelRadixSort( a, 0, a.length ); + } + /** Sorts the specified array using indirect radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]. + * + *

This implementation will allocate, in the stable case, a support array as large as perm (note that the stable + * version is slightly faster). + * + * @param perm a permutation array indexing a. + * @param a the array to be sorted. + * @param stable whether the sorting algorithm should be stable. + */ + public static void radixSortIndirect( final int[] perm, final long[] a, final boolean stable ) { + radixSortIndirect( perm, a, 0, perm.length, stable ); + } + /** Sorts the specified array using indirect radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]. + * + *

This implementation will allocate, in the stable case, a support array as large as perm (note that the stable + * version is slightly faster). + * + * @param perm a permutation array indexing a. + * @param a the array to be sorted. + * @param from the index of the first element of perm (inclusive) to be permuted. + * @param to the index of the last element of perm (exclusive) to be permuted. + * @param stable whether the sorting algorithm should be stable. + */ + public static void radixSortIndirect( final int[] perm, final long[] a, final int from, final int to, final boolean stable ) { + if ( to - from < RADIXSORT_NO_REC ) { + insertionSortIndirect( perm, a, from, to ); + return; + } + final int maxLevel = DIGITS_PER_ELEMENT - 1; + final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( DIGITS_PER_ELEMENT - 1 ) + 1; + int stackPos = 0; + final int[] offsetStack = new int[ stackSize ]; + final int[] lengthStack = new int[ stackSize ]; + final int[] levelStack = new int[ stackSize ]; + offsetStack[ stackPos ] = from; + lengthStack[ stackPos ] = to - from; + levelStack[ stackPos++ ] = 0; + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + final int[] support = stable ? new int[ perm.length ] : null; + while( stackPos > 0 ) { + final int first = offsetStack[ --stackPos ]; + final int length = lengthStack[ stackPos ]; + final int level = levelStack[ stackPos ]; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ (int)((a[ perm[ i ] ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = stable ? 0 : first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + if ( stable ) { + for( int i = first + length; i-- != first; ) support[ --pos[ (int)((a[ perm[ i ] ]) >>> shift & DIGIT_MASK ^ signMask) ] ] = perm[ i ]; + System.arraycopy( support, 0, perm, first, length ); + for( int i = 0, p = first; i <= lastUsed; i++ ) { + if ( level < maxLevel && count[ i ] > 1 ) { + if ( count[ i ] < RADIXSORT_NO_REC ) insertionSortIndirect( perm, a, p, p + count[ i ] ); + else { + offsetStack[ stackPos ] = p; + lengthStack[ stackPos ] = count[ i ]; + levelStack[ stackPos++ ] = level + 1; + } + } + p += count[ i ]; + } + java.util.Arrays.fill( count, 0 ); + } + else { + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + int t = perm[ i ]; + c = (int)((a[ t ]) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while( ( d = --pos[ c ] ) > i ) { + final int z = t; + t = perm[ d ]; + perm[ d ] = z; + c = (int)((a[ t ]) >>> shift & DIGIT_MASK ^ signMask); + } + perm[ i ] = t; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < RADIXSORT_NO_REC ) insertionSortIndirect( perm, a, i, i + count[ c ] ); + else { + offsetStack[ stackPos ] = i; + lengthStack[ stackPos ] = count[ c ]; + levelStack[ stackPos++ ] = level + 1; + } + } + } + } + } + } + /** Sorts the specified range of an array using parallel indirect radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]. + * + *

This implementation uses a pool of {@link Runtime#availableProcessors()} threads. + * + * @param perm a permutation array indexing a. + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param stable whether the sorting algorithm should be stable. + */ + public static void parallelRadixSortIndirect( final int perm[], final long[] a, final int from, final int to, final boolean stable ) { + if ( to - from < PARALLEL_RADIXSORT_NO_FORK ) { + radixSortIndirect( perm, a, from, to, stable ); + return; + } + final int maxLevel = DIGITS_PER_ELEMENT - 1; + final LinkedBlockingQueue queue = new LinkedBlockingQueue(); + queue.add( new Segment( from, to - from, 0 ) ); + final AtomicInteger queueSize = new AtomicInteger( 1 ); + final int numberOfThreads = Runtime.getRuntime().availableProcessors(); + final ExecutorService executorService = Executors.newFixedThreadPool( numberOfThreads, Executors.defaultThreadFactory() ); + final ExecutorCompletionService executorCompletionService = new ExecutorCompletionService( executorService ); + final int[] support = stable ? new int[ perm.length ] : null; + for( int i = numberOfThreads; i-- != 0; ) executorCompletionService.submit( new Callable() { + public Void call() throws Exception { + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + for(;;) { + if ( queueSize.get() == 0 ) for( int i = numberOfThreads; i-- != 0; ) queue.add( POISON_PILL ); + final Segment segment = queue.take(); + if ( segment == POISON_PILL ) return null; + final int first = segment.offset; + final int length = segment.length; + final int level = segment.level; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ (int)((a[ perm[ i ] ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + if ( stable ) { + for( int i = first + length; i-- != first; ) support[ --pos[ (int)((a[ perm[ i ] ]) >>> shift & DIGIT_MASK ^ signMask) ] ] = perm[ i ]; + System.arraycopy( support, first, perm, first, length ); + for( int i = 0, p = first; i <= lastUsed; i++ ) { + if ( level < maxLevel && count[ i ] > 1 ) { + if ( count[ i ] < PARALLEL_RADIXSORT_NO_FORK ) radixSortIndirect( perm, a, p, p + count[ i ], stable ); + else { + queueSize.incrementAndGet(); + queue.add( new Segment( p, count[ i ], level + 1 ) ); + } + } + p += count[ i ]; + } + java.util.Arrays.fill( count, 0 ); + } + else { + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + int t = perm[ i ]; + c = (int)((a[ t ]) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while( ( d = --pos[ c ] ) > i ) { + final int z = t; + t = perm[ d ]; + perm[ d ] = z; + c = (int)((a[ t ]) >>> shift & DIGIT_MASK ^ signMask); + } + perm[ i ] = t; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < PARALLEL_RADIXSORT_NO_FORK ) radixSortIndirect( perm, a, i, i + count[ c ], stable ); + else { + queueSize.incrementAndGet(); + queue.add( new Segment( i, count[ c ], level + 1 ) ); + } + } + } + } + queueSize.decrementAndGet(); + } + } + } ); + Throwable problem = null; + for( int i = numberOfThreads; i-- != 0; ) + try { + executorCompletionService.take().get(); + } + catch( Exception e ) { + problem = e.getCause(); // We keep only the last one. They will be logged anyway. + } + executorService.shutdown(); + if ( problem != null ) throw ( problem instanceof RuntimeException ) ? (RuntimeException)problem : new RuntimeException( problem ); + } + /** Sorts the specified array using parallel indirect radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]. + * + *

This implementation uses a pool of {@link Runtime#availableProcessors()} threads. + * + * @param perm a permutation array indexing a. + * @param a the array to be sorted. + * @param stable whether the sorting algorithm should be stable. + */ + public static void parallelRadixSortIndirect( final int perm[], final long[] a, final boolean stable ) { + parallelRadixSortIndirect( perm, a, 0, a.length, stable ); + } + /** Sorts the specified pair of arrays lexicographically using radix sort. + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implements a lexicographical sorting of the arguments. Pairs of elements + * in the same position in the two provided arrays will be considered a single key, and permuted + * accordingly. In the end, either a[ i ] < a[ i + 1 ] or a[ i ] == a[ i + 1 ] and b[ i ] ≤ b[ i + 1 ]. + * + * @param a the first array to be sorted. + * @param b the second array to be sorted. + */ + public static void radixSort( final long[] a, final long[] b ) { + ensureSameLength( a, b ); + radixSort( a, b, 0, a.length ); + } + /** Sorts the specified range of elements of two arrays using radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implements a lexicographical sorting of the arguments. Pairs of elements + * in the same position in the two provided arrays will be considered a single key, and permuted + * accordingly. In the end, either a[ i ] < a[ i + 1 ] or a[ i ] == a[ i + 1 ] and b[ i ] ≤ b[ i + 1 ]. + * + * @param a the first array to be sorted. + * @param b the second array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void radixSort( final long[] a, final long[] b, final int from, final int to ) { + if ( to - from < RADIXSORT_NO_REC ) { + selectionSort( a, b, from, to ); + return; + } + final int layers = 2; + final int maxLevel = DIGITS_PER_ELEMENT * layers - 1; + final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( layers * DIGITS_PER_ELEMENT - 1 ) + 1; + int stackPos = 0; + final int[] offsetStack = new int[ stackSize ]; + final int[] lengthStack = new int[ stackSize ]; + final int[] levelStack = new int[ stackSize ]; + offsetStack[ stackPos ] = from; + lengthStack[ stackPos ] = to - from; + levelStack[ stackPos++ ] = 0; + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + while( stackPos > 0 ) { + final int first = offsetStack[ --stackPos ]; + final int length = lengthStack[ stackPos ]; + final int level = levelStack[ stackPos ]; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final long[] k = level < DIGITS_PER_ELEMENT ? a : b; // This is the key array + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ (int)((k[ i ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + long t = a[ i ]; + long u = b[ i ]; + c = (int)((k[ i ]) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while( ( d = --pos[ c ] ) > i ) { + c = (int)((k[ d ]) >>> shift & DIGIT_MASK ^ signMask); + long z = t; + t = a[ d ]; + a[ d ] = z; + z = u; + u = b[ d ]; + b[ d ] = z; + } + a[ i ] = t; + b[ i ] = u; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < RADIXSORT_NO_REC ) selectionSort( a, b, i, i + count[ c ] ); + else { + offsetStack[ stackPos ] = i; + lengthStack[ stackPos ] = count[ c ]; + levelStack[ stackPos++ ] = level + 1; + } + } + } + } + } + /** Sorts the specified range of elements of two arrays using a parallel radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implements a lexicographical sorting of the arguments. Pairs of elements + * in the same position in the two provided arrays will be considered a single key, and permuted + * accordingly. In the end, either a[ i ] < a[ i + 1 ] or a[ i ] == a[ i + 1 ] and b[ i ] ≤ b[ i + 1 ]. + * + *

This implementation uses a pool of {@link Runtime#availableProcessors()} threads. + * + * @param a the first array to be sorted. + * @param b the second array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void parallelRadixSort( final long[] a, final long[] b, final int from, final int to ) { + if ( to - from < PARALLEL_RADIXSORT_NO_FORK ) { + quickSort( a, b, from, to ); + return; + } + final int layers = 2; + if ( a.length != b.length ) throw new IllegalArgumentException( "Array size mismatch." ); + final int maxLevel = DIGITS_PER_ELEMENT * layers - 1; + final LinkedBlockingQueue queue = new LinkedBlockingQueue(); + queue.add( new Segment( from, to - from, 0 ) ); + final AtomicInteger queueSize = new AtomicInteger( 1 ); + final int numberOfThreads = Runtime.getRuntime().availableProcessors(); + final ExecutorService executorService = Executors.newFixedThreadPool( numberOfThreads, Executors.defaultThreadFactory() ); + final ExecutorCompletionService executorCompletionService = new ExecutorCompletionService( executorService ); + for ( int i = numberOfThreads; i-- != 0; ) + executorCompletionService.submit( new Callable() { + public Void call() throws Exception { + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + for ( ;; ) { + if ( queueSize.get() == 0 ) for ( int i = numberOfThreads; i-- != 0; ) + queue.add( POISON_PILL ); + final Segment segment = queue.take(); + if ( segment == POISON_PILL ) return null; + final int first = segment.offset; + final int length = segment.length; + final int level = segment.level; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final long[] k = level < DIGITS_PER_ELEMENT ? a : b; // This is the key array + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; + // Count keys. + for ( int i = first + length; i-- != first; ) + count[ (int)((k[ i ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + final int end = first + length - count[ lastUsed ]; + for ( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + long t = a[ i ]; + long u = b[ i ]; + c = (int)((k[ i ]) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while ( ( d = --pos[ c ] ) > i ) { + c = (int)((k[ d ]) >>> shift & DIGIT_MASK ^ signMask); + final long z = t; + final long w = u; + t = a[ d ]; + u = b[ d ]; + a[ d ] = z; + b[ d ] = w; + } + a[ i ] = t; + b[ i ] = u; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < PARALLEL_RADIXSORT_NO_FORK ) quickSort( a, b, i, i + count[ c ] ); + else { + queueSize.incrementAndGet(); + queue.add( new Segment( i, count[ c ], level + 1 ) ); + } + } + } + queueSize.decrementAndGet(); + } + } + } ); + Throwable problem = null; + for ( int i = numberOfThreads; i-- != 0; ) + try { + executorCompletionService.take().get(); + } + catch ( Exception e ) { + problem = e.getCause(); // We keep only the last one. They will be logged anyway. + } + executorService.shutdown(); + if ( problem != null ) throw ( problem instanceof RuntimeException ) ? (RuntimeException)problem : new RuntimeException( problem ); + } + /** Sorts two arrays using a parallel radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implements a lexicographical sorting of the arguments. Pairs of elements + * in the same position in the two provided arrays will be considered a single key, and permuted + * accordingly. In the end, either a[ i ] < a[ i + 1 ] or a[ i ] == a[ i + 1 ] and b[ i ] ≤ b[ i + 1 ]. + * + *

This implementation uses a pool of {@link Runtime#availableProcessors()} threads. + * + * @param a the first array to be sorted. + * @param b the second array to be sorted. + */ + public static void parallelRadixSort( final long[] a, final long[] b ) { + ensureSameLength( a, b ); + parallelRadixSort( a, b, 0, a.length ); + } + private static void insertionSortIndirect( final int[] perm, final long[] a, final long[] b, final int from, final int to ) { + for ( int i = from; ++i < to; ) { + int t = perm[ i ]; + int j = i; + for ( int u = perm[ j - 1 ]; ( (a[ t ]) < (a[ u ]) ) || ( (a[ t ]) == (a[ u ]) ) && ( (b[ t ]) < (b[ u ]) ); u = perm[ --j - 1 ] ) { + perm[ j ] = u; + if ( from == j - 1 ) { + --j; + break; + } + } + perm[ j ] = t; + } + } + /** Sorts the specified pair of arrays lexicographically using indirect radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]. + * + *

This implementation will allocate, in the stable case, a further support array as large as perm (note that the stable + * version is slightly faster). + * + * @param perm a permutation array indexing a. + * @param a the array to be sorted. + * @param b the second array to be sorted. + * @param stable whether the sorting algorithm should be stable. + */ + public static void radixSortIndirect( final int[] perm, final long[] a, final long[] b, final boolean stable ) { + ensureSameLength( a, b ); + radixSortIndirect( perm, a, b, 0, a.length, stable ); + } + /** Sorts the specified pair of arrays lexicographically using indirect radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * a[ perm[ i ] ] ≤ a[ perm[ i + 1 ] ]. + * + *

This implementation will allocate, in the stable case, a further support array as large as perm (note that the stable + * version is slightly faster). + * + * @param perm a permutation array indexing a. + * @param a the array to be sorted. + * @param b the second array to be sorted. + * @param from the index of the first element of perm (inclusive) to be permuted. + * @param to the index of the last element of perm (exclusive) to be permuted. + * @param stable whether the sorting algorithm should be stable. + */ + public static void radixSortIndirect( final int[] perm, final long[] a, final long[] b, final int from, final int to, final boolean stable ) { + if ( to - from < RADIXSORT_NO_REC ) { + insertionSortIndirect( perm, a, b, from, to ); + return; + } + final int layers = 2; + final int maxLevel = DIGITS_PER_ELEMENT * layers - 1; + final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( layers * DIGITS_PER_ELEMENT - 1 ) + 1; + int stackPos = 0; + final int[] offsetStack = new int[ stackSize ]; + final int[] lengthStack = new int[ stackSize ]; + final int[] levelStack = new int[ stackSize ]; + offsetStack[ stackPos ] = from; + lengthStack[ stackPos ] = to - from; + levelStack[ stackPos++ ] = 0; + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + final int[] support = stable ? new int[ perm.length ] : null; + while( stackPos > 0 ) { + final int first = offsetStack[ --stackPos ]; + final int length = lengthStack[ stackPos ]; + final int level = levelStack[ stackPos ]; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final long[] k = level < DIGITS_PER_ELEMENT ? a : b; // This is the key array + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ (int)((k[ perm[ i ] ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = stable ? 0 : first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + if ( stable ) { + for( int i = first + length; i-- != first; ) support[ --pos[ (int)((k[ perm[ i ] ]) >>> shift & DIGIT_MASK ^ signMask) ] ] = perm[ i ]; + System.arraycopy( support, 0, perm, first, length ); + for( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( level < maxLevel && count[ i ] > 1 ) { + if ( count[ i ] < RADIXSORT_NO_REC ) insertionSortIndirect( perm, a, b, p, p + count[ i ] ); + else { + offsetStack[ stackPos ] = p; + lengthStack[ stackPos ] = count[ i ]; + levelStack[ stackPos++ ] = level + 1; + } + } + p += count[ i ]; + } + java.util.Arrays.fill( count, 0 ); + } + else { + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + int t = perm[ i ]; + c = (int)((k[ t ]) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while( ( d = --pos[ c ] ) > i ) { + final int z = t; + t = perm[ d ]; + perm[ d ] = z; + c = (int)((k[ t ]) >>> shift & DIGIT_MASK ^ signMask); + } + perm[ i ] = t; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < RADIXSORT_NO_REC ) insertionSortIndirect( perm, a, b, i, i + count[ c ] ); + else { + offsetStack[ stackPos ] = i; + lengthStack[ stackPos ] = count[ c ]; + levelStack[ stackPos++ ] = level + 1; + } + } + } + } + } + } + private static void selectionSort( final long[][] a, final int from, final int to, final int level ) { + final int layers = a.length; + final int firstLayer = level / DIGITS_PER_ELEMENT; + for( int i = from; i < to - 1; i++ ) { + int m = i; + for( int j = i + 1; j < to; j++ ) { + for( int p = firstLayer; p < layers; p++ ) { + if ( a[ p ][ j ] < a[ p ][ m ] ) { + m = j; + break; + } + else if ( a[ p ][ j ] > a[ p ][ m ] ) break; + } + } + if ( m != i ) { + for( int p = layers; p-- != 0; ) { + final long u = a[ p ][ i ]; + a[ p ][ i ] = a[ p ][ m ]; + a[ p ][ m ] = u; + } + } + } + } + /** Sorts the specified array of arrays lexicographically using radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implements a lexicographical sorting of the provided arrays. Tuples of elements + * in the same position will be considered a single key, and permuted + * accordingly. + * + * @param a an array containing arrays of equal length to be sorted lexicographically in parallel. + */ + public static void radixSort( final long[][] a ) { + radixSort( a, 0, a[ 0 ].length ); + } + /** Sorts the specified array of arrays lexicographically using radix sort. + * + *

The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas + * McIlroy, “Engineering radix sort”, Computing Systems, 6(1), pages 5−27 (1993). + * + *

This method implements a lexicographical sorting of the provided arrays. Tuples of elements + * in the same position will be considered a single key, and permuted + * accordingly. + * + * @param a an array containing arrays of equal length to be sorted lexicographically in parallel. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void radixSort( final long[][] a, final int from, final int to ) { + if ( to - from < RADIXSORT_NO_REC ) { + selectionSort( a, from, to, 0 ); + return; + } + final int layers = a.length; + final int maxLevel = DIGITS_PER_ELEMENT * layers - 1; + for( int p = layers, l = a[ 0 ].length; p-- != 0; ) if ( a[ p ].length != l ) throw new IllegalArgumentException( "The array of index " + p + " has not the same length of the array of index 0." ); + final int stackSize = ( ( 1 << DIGIT_BITS ) - 1 ) * ( layers * DIGITS_PER_ELEMENT - 1 ) + 1; + int stackPos = 0; + final int[] offsetStack = new int[ stackSize ]; + final int[] lengthStack = new int[ stackSize ]; + final int[] levelStack = new int[ stackSize ]; + offsetStack[ stackPos ] = from; + lengthStack[ stackPos ] = to - from; + levelStack[ stackPos++ ] = 0; + final int[] count = new int[ 1 << DIGIT_BITS ]; + final int[] pos = new int[ 1 << DIGIT_BITS ]; + final long[] t = new long[ layers ]; + while( stackPos > 0 ) { + final int first = offsetStack[ --stackPos ]; + final int length = lengthStack[ stackPos ]; + final int level = levelStack[ stackPos ]; + final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0; + final long[] k = a[ level / DIGITS_PER_ELEMENT ]; // This is the key array + final int shift = ( DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT ) * DIGIT_BITS; // This is the shift that extract the right byte from a key + // Count keys. + for( int i = first + length; i-- != first; ) count[ (int)((k[ i ]) >>> shift & DIGIT_MASK ^ signMask) ]++; + // Compute cumulative distribution + int lastUsed = -1; + for ( int i = 0, p = first; i < 1 << DIGIT_BITS; i++ ) { + if ( count[ i ] != 0 ) lastUsed = i; + pos[ i ] = ( p += count[ i ] ); + } + final int end = first + length - count[ lastUsed ]; + // i moves through the start of each block + for( int i = first, c = -1, d; i <= end; i += count[ c ], count[ c ] = 0 ) { + for( int p = layers; p-- != 0; ) t[ p ] = a[ p ][ i ]; + c = (int)((k[ i ]) >>> shift & DIGIT_MASK ^ signMask); + if ( i < end ) { // When all slots are OK, the last slot is necessarily OK. + while( ( d = --pos[ c ] ) > i ) { + c = (int)((k[ d ]) >>> shift & DIGIT_MASK ^ signMask); + for( int p = layers; p-- != 0; ) { + final long u = t[ p ]; + t[ p ] = a[ p ][ d ]; + a[ p ][ d ] = u; + } + } + for( int p = layers; p-- != 0; ) a[ p ][ i ] = t[ p ]; + } + if ( level < maxLevel && count[ c ] > 1 ) { + if ( count[ c ] < RADIXSORT_NO_REC ) selectionSort( a, i, i + count[ c ], level + 1 ); + else { + offsetStack[ stackPos ] = i; + lengthStack[ stackPos ] = count[ c ]; + levelStack[ stackPos++ ] = level + 1; + } + } + } + } + } + /** Shuffles the specified array fragment using the specified pseudorandom number generator. + * + * @param a the array to be shuffled. + * @param from the index of the first element (inclusive) to be shuffled. + * @param to the index of the last element (exclusive) to be shuffled. + * @param random a pseudorandom number generator (please use a XorShift* generator). + * @return a. + */ + public static long[] shuffle( final long[] a, final int from, final int to, final Random random ) { + for( int i = to - from; i-- != 0; ) { + final int p = random.nextInt( i + 1 ); + final long t = a[ from + i ]; + a[ from + i ] = a[ from + p ]; + a[ from + p ] = t; + } + return a; + } + /** Shuffles the specified array using the specified pseudorandom number generator. + * + * @param a the array to be shuffled. + * @param random a pseudorandom number generator (please use a XorShift* generator). + * @return a. + */ + public static long[] shuffle( final long[] a, final Random random ) { + for( int i = a.length; i-- != 0; ) { + final int p = random.nextInt( i + 1 ); + final long t = a[ i ]; + a[ i ] = a[ p ]; + a[ p ] = t; + } + return a; + } + /** Reverses the order of the elements in the specified array. + * + * @param a the array to be reversed. + * @return a. + */ + public static long[] reverse( final long[] a ) { + final int length = a.length; + for( int i = length / 2; i-- != 0; ) { + final long t = a[ length - i - 1 ]; + a[ length - i - 1 ] = a[ i ]; + a[ i ] = t; + } + return a; + } + /** Reverses the order of the elements in the specified array fragment. + * + * @param a the array to be reversed. + * @param from the index of the first element (inclusive) to be reversed. + * @param to the index of the last element (exclusive) to be reversed. + * @return a. + */ + public static long[] reverse( final long[] a, final int from, final int to ) { + final int length = to - from; + for( int i = length / 2; i-- != 0; ) { + final long t = a[ from + length - i - 1 ]; + a[ from + length - i - 1 ] = a[ from + i ]; + a[ from + i ] = t; + } + return a; + } + /** A type-specific content-based hash strategy for arrays. */ + private static final class ArrayHashStrategy implements Hash.Strategy, java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + public int hashCode( final long[] o ) { + return java.util.Arrays.hashCode( o ); + } + public boolean equals( final long[] a, final long[] b ) { + return java.util.Arrays.equals( a, b ); + } + } + /** A type-specific content-based hash strategy for arrays. + * + *

This hash strategy may be used in custom hash collections whenever keys are + * arrays, and they must be considered equal by content. This strategy + * will handle null correctly, and it is serializable. + */ + public final static Hash.Strategy HASH_STRATEGY = new ArrayHashStrategy(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongBidirectionalIterator.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongBidirectionalIterator.java new file mode 100644 index 0000000..ae2906f --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongBidirectionalIterator.java @@ -0,0 +1,97 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.BidirectionalIterator; +import it.unimi.dsi.fastutil.objects.ObjectBidirectionalIterator; +/** A type-specific bidirectional iterator; provides an additional method to avoid (un)boxing, + * and the possibility to skip elements backwards. + * + * @see BidirectionalIterator + */ +public interface LongBidirectionalIterator extends LongIterator , ObjectBidirectionalIterator { + /** + * Returns the previous element as a primitive type. + * + * @return the previous element in the iteration. + * @see java.util.ListIterator#previous() + */ + long previousLong(); + /** Moves back for the given number of elements. + * + *

The effect of this call is exactly the same as that of + * calling {@link #previous()} for n times (possibly stopping + * if {@link #hasPrevious()} becomes false). + * + * @param n the number of elements to skip back. + * @return the number of elements actually skipped. + * @see java.util.Iterator#next() + */ + int back( int n ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongCollection.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongCollection.java new file mode 100644 index 0000000..0708d1f --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongCollection.java @@ -0,0 +1,169 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.Collection; +/** A type-specific {@link Collection}; provides some additional methods + * that use polymorphism to avoid (un)boxing. + * + *

Additionally, this class defines strengthens (again) {@link #iterator()} and defines + * a slightly different semantics for {@link #toArray(Object[])}. + * + * @see Collection + */ +public interface LongCollection extends Collection, LongIterable { + /** Returns a type-specific iterator on the elements of this collection. + * + *

Note that this specification strengthens the one given in + * {@link java.lang.Iterable#iterator()}, which was already + * strengthened in the corresponding type-specific class, + * but was weakened by the fact that this interface extends {@link Collection}. + * + * @return a type-specific iterator on the elements of this collection. + */ + LongIterator iterator(); + /** Returns a type-specific iterator on this elements of this collection. + * + * @see #iterator() + * @deprecated As of fastutil 5, replaced by {@link #iterator()}. + */ + @Deprecated + LongIterator longIterator(); + /** Returns an containing the items of this collection; + * the runtime type of the returned array is that of the specified array. + * + *

Warning: Note that, contrarily to {@link Collection#toArray(Object[])}, this + * methods just writes all elements of this collection: no special + * value will be added after the last one. + * + * @param a if this array is big enough, it will be used to store this collection. + * @return a primitive type array containing the items of this collection. + * @see Collection#toArray(Object[]) + */ + T[] toArray(T[] a); + /** + * @see Collection#contains(Object) + */ + boolean contains( long key ); + /** Returns a primitive type array containing the items of this collection. + * @return a primitive type array containing the items of this collection. + * @see Collection#toArray() + */ + long[] toLongArray(); + /** Returns a primitive type array containing the items of this collection. + * + *

Note that, contrarily to {@link Collection#toArray(Object[])}, this + * methods just writes all elements of this collection: no special + * value will be added after the last one. + * + * @param a if this array is big enough, it will be used to store this collection. + * @return a primitive type array containing the items of this collection. + * @see Collection#toArray(Object[]) + */ + long[] toLongArray( long a[] ); + /** Returns a primitive type array containing the items of this collection. + * + *

Note that, contrarily to {@link Collection#toArray(Object[])}, this + * methods just writes all elements of this collection: no special + * value will be added after the last one. + * + * @param a if this array is big enough, it will be used to store this collection. + * @return a primitive type array containing the items of this collection. + * @see Collection#toArray(Object[]) + */ + long[] toArray( long a[] ); + /** + * @see Collection#add(Object) + */ + boolean add( long key ); + /** Note that this method should be called {@link java.util.Collection#remove(Object) remove()}, but the clash + * with the similarly named index-based method in the {@link java.util.List} interface + * forces us to use a distinguished name. For simplicity, the set interfaces reinstates + * remove(). + * + * @see Collection#remove(Object) + */ + boolean rem( long key ); + /** + * @see Collection#addAll(Collection) + */ + boolean addAll( LongCollection c ); + /** + * @see Collection#containsAll(Collection) + */ + boolean containsAll( LongCollection c ); + /** + * @see Collection#removeAll(Collection) + */ + boolean removeAll( LongCollection c ); + /** + * @see Collection#retainAll(Collection) + */ + boolean retainAll( LongCollection c ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongCollections.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongCollections.java new file mode 100644 index 0000000..1574de8 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongCollections.java @@ -0,0 +1,237 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.Collection; +import it.unimi.dsi.fastutil.objects.ObjectArrays; +/** A class providing static methods and objects that do useful things with type-specific collections. + * + * @see java.util.Collections + */ +public class LongCollections { + private LongCollections() {} + /** An immutable class representing an empty type-specific collection. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific collection. + */ + public abstract static class EmptyCollection extends AbstractLongCollection { + protected EmptyCollection() {} + public boolean add( long k ) { throw new UnsupportedOperationException(); } + public boolean contains( long k ) { return false; } + public Object[] toArray() { return ObjectArrays.EMPTY_ARRAY; } + public long[] toLongArray( long[] a ) { return a; } + public long[] toLongArray() { return LongArrays.EMPTY_ARRAY; } + public boolean rem( long k ) { throw new UnsupportedOperationException(); } + public boolean addAll( LongCollection c ) { throw new UnsupportedOperationException(); } + public boolean removeAll( LongCollection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( LongCollection c ) { throw new UnsupportedOperationException(); } + public boolean containsAll( LongCollection c ) { return c.isEmpty(); } + + public LongBidirectionalIterator iterator() { return LongIterators.EMPTY_ITERATOR; } + public int size() { return 0; } + public void clear() {} + public int hashCode() { return 0; } + public boolean equals( Object o ) { + if ( o == this ) return true; + if ( ! ( o instanceof Collection ) ) return false; + return ((Collection)o).isEmpty(); + } + } + /** A synchronized wrapper class for collections. */ + public static class SynchronizedCollection implements LongCollection , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final LongCollection collection; + protected final Object sync; + protected SynchronizedCollection( final LongCollection c, final Object sync ) { + if ( c == null ) throw new NullPointerException(); + this.collection = c; + this.sync = sync; + } + protected SynchronizedCollection( final LongCollection c ) { + if ( c == null ) throw new NullPointerException(); + this.collection = c; + this.sync = this; + } + public int size() { synchronized( sync ) { return collection.size(); } } + public boolean isEmpty() { synchronized( sync ) { return collection.isEmpty(); } } + public boolean contains( final long o ) { synchronized( sync ) { return collection.contains( o ); } } + public long[] toLongArray() { synchronized( sync ) { return collection.toLongArray(); } } + public Object[] toArray() { synchronized( sync ) { return collection.toArray(); } } + public long[] toLongArray( final long[] a ) { synchronized( sync ) { return collection.toLongArray( a ); } } + public long[] toArray( final long[] a ) { synchronized( sync ) { return collection.toLongArray( a ); } } + public boolean addAll( final LongCollection c ) { synchronized( sync ) { return collection.addAll( c ); } } + public boolean containsAll( final LongCollection c ) { synchronized( sync ) { return collection.containsAll( c ); } } + public boolean removeAll( final LongCollection c ) { synchronized( sync ) { return collection.removeAll( c ); } } + public boolean retainAll( final LongCollection c ) { synchronized( sync ) { return collection.retainAll( c ); } } + public boolean add( final Long k ) { synchronized( sync ) { return collection.add( k ); } } + public boolean contains( final Object k ) { synchronized( sync ) { return collection.contains( k ); } } + public T[] toArray( final T[] a ) { synchronized( sync ) { return collection.toArray( a ); } } + public LongIterator iterator() { return collection.iterator(); } + @Deprecated + public LongIterator longIterator() { return iterator(); } + public boolean add( final long k ) { synchronized( sync ) { return collection.add( k ); } } + public boolean rem( final long k ) { synchronized( sync ) { return collection.rem( k ); } } + public boolean remove( final Object ok ) { synchronized( sync ) { return collection.remove( ok ); } } + public boolean addAll( final Collection c ) { synchronized( sync ) { return collection.addAll( c ); } } + public boolean containsAll( final Collection c ) { synchronized( sync ) { return collection.containsAll( c ); } } + public boolean removeAll( final Collection c ) { synchronized( sync ) { return collection.removeAll( c ); } } + public boolean retainAll( final Collection c ) { synchronized( sync ) { return collection.retainAll( c ); } } + public void clear() { synchronized( sync ) { collection.clear(); } } + public String toString() { synchronized( sync ) { return collection.toString(); } } + } + /** Returns a synchronized collection backed by the specified collection. + * + * @param c the collection to be wrapped in a synchronized collection. + * @return a synchronized view of the specified collection. + * @see java.util.Collections#synchronizedCollection(Collection) + */ + public static LongCollection synchronize( final LongCollection c ) { return new SynchronizedCollection ( c ); } + /** Returns a synchronized collection backed by the specified collection, using an assigned object to synchronize. + * + * @param c the collection to be wrapped in a synchronized collection. + * @param sync an object that will be used to synchronize the list access. + * @return a synchronized view of the specified collection. + * @see java.util.Collections#synchronizedCollection(Collection) + */ + public static LongCollection synchronize( final LongCollection c, final Object sync ) { return new SynchronizedCollection ( c, sync ); } + /** An unmodifiable wrapper class for collections. */ + public static class UnmodifiableCollection implements LongCollection , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final LongCollection collection; + protected UnmodifiableCollection( final LongCollection c ) { + if ( c == null ) throw new NullPointerException(); + this.collection = c; + } + public int size() { return collection.size(); } + public boolean isEmpty() { return collection.isEmpty(); } + public boolean contains( final long o ) { return collection.contains( o ); } + public LongIterator iterator() { return LongIterators.unmodifiable( collection.iterator() ); } + @Deprecated + public LongIterator longIterator() { return iterator(); } + public boolean add( final long k ) { throw new UnsupportedOperationException(); } + public boolean remove( final Object ok ) { throw new UnsupportedOperationException(); } + public boolean addAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean containsAll( final Collection c ) { return collection.containsAll( c ); } + public boolean removeAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( final Collection c ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + public String toString() { return collection.toString(); } + public T[] toArray( final T[] a ) { return collection.toArray( a ); } + public Object[] toArray() { return collection.toArray(); } + public long[] toLongArray() { return collection.toLongArray(); } + public long[] toLongArray( final long[] a ) { return collection.toLongArray( a ); } + public long[] toArray( final long[] a ) { return collection.toArray( a ); } + public boolean rem( final long k ) { throw new UnsupportedOperationException(); } + public boolean addAll( final LongCollection c ) { throw new UnsupportedOperationException(); } + public boolean containsAll( final LongCollection c ) { return collection.containsAll( c ); } + public boolean removeAll( final LongCollection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( final LongCollection c ) { throw new UnsupportedOperationException(); } + public boolean add( final Long k ) { throw new UnsupportedOperationException(); } + public boolean contains( final Object k ) { return collection.contains( k ); } + } + /** Returns an unmodifiable collection backed by the specified collection. + * + * @param c the collection to be wrapped in an unmodifiable collection. + * @return an unmodifiable view of the specified collection. + * @see java.util.Collections#unmodifiableCollection(Collection) + */ + public static LongCollection unmodifiable( final LongCollection c ) { return new UnmodifiableCollection ( c ); } + /** A collection wrapper class for iterables. */ + public static class IterableCollection extends AbstractLongCollection implements java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final LongIterable iterable; + protected IterableCollection( final LongIterable iterable ) { + if ( iterable == null ) throw new NullPointerException(); + this.iterable = iterable; + } + public int size() { + int c = 0; + final LongIterator iterator = iterator(); + while( iterator.hasNext() ) { + iterator.next(); + c++; + } + return c; + } + public boolean isEmpty() { return iterable.iterator().hasNext(); } + public LongIterator iterator() { return iterable.iterator(); } + @Deprecated + public LongIterator longIterator() { return iterator(); } + } + /** Returns an unmodifiable collection backed by the specified iterable. + * + * @param iterable the iterable object to be wrapped in an unmodifiable collection. + * @return an unmodifiable collection view of the specified iterable. + */ + public static LongCollection asCollection( final LongIterable iterable ) { + if ( iterable instanceof LongCollection ) return (LongCollection )iterable; + return new IterableCollection ( iterable ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongComparator.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongComparator.java new file mode 100644 index 0000000..31e394a --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongComparator.java @@ -0,0 +1,90 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.Comparator; +/** A type-specific {@link Comparator}; provides methods to compare two primitive types both as objects + * and as primitive types. + * + *

Note that fastutil provides a corresponding abstract class that + * can be used to implement this interface just by specifying the type-specific + * comparator. + * + * @see Comparator + */ +public interface LongComparator extends Comparator { + /** Compares the given primitive types. + * + * @see java.util.Comparator + * @return A positive integer, zero, or a negative integer if the first + * argument is greater than, equal to, or smaller than, respectively, the + * second one. + */ + public int compare( long k1, long k2 ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongComparators.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongComparators.java new file mode 100644 index 0000000..7098bbc --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongComparators.java @@ -0,0 +1,113 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +/** A class providing static methods and objects that do useful things with comparators. + */ +public class LongComparators { + private LongComparators() {} + /** A type-specific comparator mimicking the natural order. */ + protected static class NaturalImplicitComparator extends AbstractLongComparator implements java.io.Serializable { + private static final long serialVersionUID = 1L; + public final int compare( final long a, final long b ) { + return ( Long.compare((a),(b)) ); + } + private Object readResolve() { return NATURAL_COMPARATOR; } + }; + + public static final LongComparator NATURAL_COMPARATOR = new NaturalImplicitComparator(); + /** A type-specific comparator mimicking the opposite of the natural order. */ + protected static class OppositeImplicitComparator extends AbstractLongComparator implements java.io.Serializable { + private static final long serialVersionUID = 1L; + public final int compare( final long a, final long b ) { + return - ( Long.compare((a),(b)) ); + } + private Object readResolve() { return OPPOSITE_COMPARATOR; } + }; + + public static final LongComparator OPPOSITE_COMPARATOR = new OppositeImplicitComparator(); + protected static class OppositeComparator extends AbstractLongComparator implements java.io.Serializable { + private static final long serialVersionUID = 1L; + private final LongComparator comparator; + protected OppositeComparator( final LongComparator c ) { + comparator = c; + } + public final int compare( final long a, final long b ) { + return comparator.compare( b, a ); + } + }; + /** Returns a comparator representing the opposite order of the given comparator. + * + * @param c a comparator. + * @return a comparator representing the opposite order of c. + */ + public static LongComparator oppositeComparator( final LongComparator c ) { + return new OppositeComparator ( c ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongHash.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongHash.java new file mode 100644 index 0000000..5b394ab --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongHash.java @@ -0,0 +1,96 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.Hash; +/** A type-specific {@link Hash} interface. + * + * @see Hash + */ +public interface LongHash { + /** A type-specific hash strategy. + * + * @see it.unimi.dsi.fastutil.Hash.Strategy + */ + public interface Strategy { + /** Returns the hash code of the specified element with respect to this hash strategy. + * + * @param e an element. + * @return the hash code of the given element with respect to this hash strategy. + */ + public int hashCode( long e ); + /** Returns true if the given elements are equal with respect to this hash strategy. + * + * @param a an element. + * @param b another element. + * @return true if the two specified elements are equal with respect to this hash strategy. + */ + public boolean equals( long a, long b ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongHeaps.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongHeaps.java new file mode 100644 index 0000000..b63b1a2 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongHeaps.java @@ -0,0 +1,155 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +/** A class providing static methods and objects that do useful things with heaps. + * + *

The static methods of this class allow to treat arrays as 0-based heaps. They + * are used in the implementation of heap-based queues, but they may be also used + * directly. + * + */ +public class LongHeaps { + private LongHeaps() {} + /** Moves the given element down into the heap until it reaches the lowest possible position. + * + * @param heap the heap (starting at 0). + * @param size the number of elements in the heap. + * @param i the index of the element that must be moved down. + * @param c a type-specific comparator, or null for the natural order. + * @return the new position of the element of index i. + */ + + public static int downHeap( final long[] heap, final int size, int i, final LongComparator c ) { + assert i < size; + final long e = heap[ i ]; + int child; + if ( c == null ) + while ( ( child = ( i << 1 ) + 1 ) < size ) { + long t = heap[ child ]; + final int right = child + 1; + if ( right < size && ( (heap[ right ]) < (t) ) ) t = heap[ child = right ]; + if ( ( (e) <= (t) ) ) break; + heap[ i ] = t; + i = child; + } + else + while ( ( child = ( i << 1 ) + 1 ) < size ) { + long t = heap[ child ]; + final int right = child + 1; + if ( right < size && c.compare( heap[ right ], t ) < 0 ) t = heap[ child = right ]; + if ( c.compare( e, t ) <= 0 ) break; + heap[ i ] = t; + i = child; + } + heap[ i ] = e; + return i; + } + /** Moves the given element up in the heap until it reaches the highest possible position. + * + * @param heap the heap (starting at 0). + * @param size the number of elements in the heap. + * @param i the index of the element that must be moved up. + * @param c a type-specific comparator, or null for the natural order. + * @return the new position of the element of index i. + */ + + public static int upHeap( final long[] heap, final int size, int i, final LongComparator c ) { + assert i < size; + final long e = heap[ i ]; + if ( c == null ) + while ( i != 0 ) { + final int parent = ( i - 1 ) >>> 1; + final long t = heap[ parent ]; + if ( ( (t) <= (e) ) ) break; + heap[ i ] = t; + i = parent; + } + else + while ( i != 0 ) { + final int parent = ( i - 1 ) >>> 1; + final long t = heap[ parent ]; + if ( c.compare( t, e ) <= 0 ) break; + heap[ i ] = t; + i = parent; + } + heap[ i ] = e; + return i; + } + /** Makes an array into a heap. + * + * @param heap the heap (starting at 0). + * @param size the number of elements in the heap. + * @param c a type-specific comparator, or null for the natural order. + */ + public static void makeHeap( final long[] heap, final int size, final LongComparator c ) { + int i = size >>> 1; + while( i-- != 0 ) downHeap( heap, size, i, c ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongIterable.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongIterable.java new file mode 100644 index 0000000..b9bdf8b --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongIterable.java @@ -0,0 +1,88 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.lang.Iterable; +/** A type-specific {@link Iterable} that strengthens that specification of {@link Iterable#iterator()}. + * + *

Warning: Java will let you write “colon” for statements with primitive-type + * loop variables; however, what is (unfortunately) really happening is that at each iteration an + * unboxing (and, in the case of fastutil type-specific data structures, a boxing) will be performed. Watch out. + * + * @see Iterable + */ +public interface LongIterable extends Iterable { + /** Returns a type-specific iterator. + * + * Note that this specification strengthens the one given in {@link Iterable#iterator()}. + * + * @return a type-specific iterator. + */ + LongIterator iterator(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongIterator.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongIterator.java new file mode 100644 index 0000000..9838448 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongIterator.java @@ -0,0 +1,96 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.Iterator; +/** A type-specific {@link Iterator}; provides an additional method to avoid (un)boxing, and + * the possibility to skip elements. + * + * @see Iterator + */ +public interface LongIterator extends Iterator { + /** + * Returns the next element as a primitive type. + * + * @return the next element in the iteration. + * @see Iterator#next() + */ + long nextLong(); + /** Skips the given number of elements. + * + *

The effect of this call is exactly the same as that of + * calling {@link #next()} for n times (possibly stopping + * if {@link #hasNext()} becomes false). + * + * @param n the number of elements to skip. + * @return the number of elements actually skipped. + * @see Iterator#next() + */ + int skip( int n ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongIterators.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongIterators.java new file mode 100644 index 0000000..1d71ab0 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongIterators.java @@ -0,0 +1,658 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.NoSuchElementException; +/** A class providing static methods and objects that do useful things with type-specific iterators. + * + * @see Iterator + */ +public class LongIterators { + private LongIterators() {} + /** A class returning no elements and a type-specific iterator interface. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific iterator. + */ + public static class EmptyIterator extends AbstractLongListIterator implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptyIterator() {} + public boolean hasNext() { return false; } + public boolean hasPrevious() { return false; } + public long nextLong() { throw new NoSuchElementException(); } + public long previousLong() { throw new NoSuchElementException(); } + public int nextIndex() { return 0; } + public int previousIndex() { return -1; } + public int skip( int n ) { return 0; }; + public int back( int n ) { return 0; }; + public Object clone() { return EMPTY_ITERATOR; } + private Object readResolve() { return EMPTY_ITERATOR; } + } + /** An empty iterator (immutable). It is serializable and cloneable. + * + *

The class of this objects represent an abstract empty iterator + * that can iterate as a type-specific (list) iterator. + */ + + public final static EmptyIterator EMPTY_ITERATOR = new EmptyIterator(); + /** An iterator returning a single element. */ + private static class SingletonIterator extends AbstractLongListIterator { + private final long element; + private int curr; + public SingletonIterator( final long element ) { + this.element = element; + } + public boolean hasNext() { return curr == 0; } + public boolean hasPrevious() { return curr == 1; } + public long nextLong() { + if ( ! hasNext() ) throw new NoSuchElementException(); + curr = 1; + return element; + } + public long previousLong() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + curr = 0; + return element; + } + public int nextIndex() { + return curr; + } + public int previousIndex() { + return curr - 1; + } + } + /** Returns an iterator that iterates just over the given element. + * + * @param element the only element to be returned by a type-specific list iterator. + * @return an iterator that iterates just over element. + */ + public static LongListIterator singleton( final long element ) { + return new SingletonIterator ( element ); + } + /** A class to wrap arrays in iterators. */ + private static class ArrayIterator extends AbstractLongListIterator { + private final long[] array; + private final int offset, length; + private int curr; + public ArrayIterator( final long[] array, final int offset, final int length ) { + this.array = array; + this.offset = offset; + this.length = length; + } + public boolean hasNext() { return curr < length; } + public boolean hasPrevious() { return curr > 0; } + public long nextLong() { + if ( ! hasNext() ) throw new NoSuchElementException(); + return array[ offset + curr++ ]; + } + public long previousLong() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + return array[ offset + --curr ]; + } + public int skip( int n ) { + if ( n <= length - curr ) { + curr += n; + return n; + } + n = length - curr; + curr = length; + return n; + } + public int back( int n ) { + if ( n <= curr ) { + curr -= n; + return n; + } + n = curr; + curr = 0; + return n; + } + public int nextIndex() { + return curr; + } + public int previousIndex() { + return curr - 1; + } + } + /** Wraps the given part of an array into a type-specific list iterator. + * + *

The type-specific list iterator returned by this method will iterate + * length times, returning consecutive elements of the given + * array starting from the one with index offset. + * + * @param array an array to wrap into a type-specific list iterator. + * @param offset the first element of the array to be returned. + * @param length the number of elements to return. + * @return an iterator that will return length elements of array starting at position offset. + */ + public static LongListIterator wrap( final long[] array, final int offset, final int length ) { + LongArrays.ensureOffsetLength( array, offset, length ); + return new ArrayIterator ( array, offset, length ); + } + /** Wraps the given array into a type-specific list iterator. + * + *

The type-specific list iterator returned by this method will return + * all elements of the given array. + * + * @param array an array to wrap into a type-specific list iterator. + * @return an iterator that will the elements of array. + */ + public static LongListIterator wrap( final long[] array ) { + return new ArrayIterator ( array, 0, array.length ); + } + /** Unwraps an iterator into an array starting at a given offset for a given number of elements. + * + *

This method iterates over the given type-specific iterator and stores the elements + * returned, up to a maximum of length, in the given array starting at offset. + * The number of actually unwrapped elements is returned (it may be less than max if + * the iterator emits less than max elements). + * + * @param i a type-specific iterator. + * @param array an array to contain the output of the iterator. + * @param offset the first element of the array to be returned. + * @param max the maximum number of elements to unwrap. + * @return the number of elements unwrapped. + */ + public static int unwrap( final LongIterator i, final long array[], int offset, final int max ) { + if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" ); + if ( offset < 0 || offset + max > array.length ) throw new IllegalArgumentException(); + int j = max; + while( j-- != 0 && i.hasNext() ) array[ offset++ ] = i.nextLong(); + return max - j - 1; + } + /** Unwraps an iterator into an array. + * + *

This method iterates over the given type-specific iterator and stores the + * elements returned in the given array. The iteration will stop when the + * iterator has no more elements or when the end of the array has been reached. + * + * @param i a type-specific iterator. + * @param array an array to contain the output of the iterator. + * @return the number of elements unwrapped. + */ + public static int unwrap( final LongIterator i, final long array[] ) { + return unwrap( i, array, 0, array.length ); + } + /** Unwraps an iterator, returning an array, with a limit on the number of elements. + * + *

This method iterates over the given type-specific iterator and returns an array + * containing the elements returned by the iterator. At most max elements + * will be returned. + * + * @param i a type-specific iterator. + * @param max the maximum number of elements to be unwrapped. + * @return an array containing the elements returned by the iterator (at most max). + */ + + public static long[] unwrap( final LongIterator i, int max ) { + if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" ); + long array[] = new long[ 16 ]; + int j = 0; + while( max-- != 0 && i.hasNext() ) { + if ( j == array.length ) array = LongArrays.grow( array, j + 1 ); + array[ j++ ] = i.nextLong(); + } + return LongArrays.trim( array, j ); + } + /** Unwraps an iterator, returning an array. + * + *

This method iterates over the given type-specific iterator and returns an array + * containing the elements returned by the iterator. + * + * @param i a type-specific iterator. + * @return an array containing the elements returned by the iterator. + */ + public static long[] unwrap( final LongIterator i ) { + return unwrap( i, Integer.MAX_VALUE ); + } + /** Unwraps an iterator into a type-specific collection, with a limit on the number of elements. + * + *

This method iterates over the given type-specific iterator and stores the elements + * returned, up to a maximum of max, in the given type-specific collection. + * The number of actually unwrapped elements is returned (it may be less than max if + * the iterator emits less than max elements). + * + * @param i a type-specific iterator. + * @param c a type-specific collection array to contain the output of the iterator. + * @param max the maximum number of elements to unwrap. + * @return the number of elements unwrapped. Note that + * this is the number of elements returned by the iterator, which is not necessarily the number + * of elements that have been added to the collection (because of duplicates). + */ + public static int unwrap( final LongIterator i, final LongCollection c, final int max ) { + if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" ); + int j = max; + while( j-- != 0 && i.hasNext() ) c.add( i.nextLong() ); + return max - j - 1; + } + /** Unwraps an iterator into a type-specific collection. + * + *

This method iterates over the given type-specific iterator and stores the + * elements returned in the given type-specific collection. The returned count on the number + * unwrapped elements is a long, so that it will work also with very large collections. + * + * @param i a type-specific iterator. + * @param c a type-specific collection to contain the output of the iterator. + * @return the number of elements unwrapped. Note that + * this is the number of elements returned by the iterator, which is not necessarily the number + * of elements that have been added to the collection (because of duplicates). + */ + public static long unwrap( final LongIterator i, final LongCollection c ) { + long n = 0; + while( i.hasNext() ) { + c.add( i.nextLong() ); + n++; + } + return n; + } + /** Pours an iterator into a type-specific collection, with a limit on the number of elements. + * + *

This method iterates over the given type-specific iterator and adds + * the returned elements to the given collection (up to max). + * + * @param i a type-specific iterator. + * @param s a type-specific collection. + * @param max the maximum number of elements to be poured. + * @return the number of elements poured. Note that + * this is the number of elements returned by the iterator, which is not necessarily the number + * of elements that have been added to the collection (because of duplicates). + */ + public static int pour( final LongIterator i, final LongCollection s, final int max ) { + if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" ); + int j = max; + while( j-- != 0 && i.hasNext() ) s.add( i.nextLong() ); + return max - j - 1; + } + /** Pours an iterator into a type-specific collection. + * + *

This method iterates over the given type-specific iterator and adds + * the returned elements to the given collection. + * + * @param i a type-specific iterator. + * @param s a type-specific collection. + * @return the number of elements poured. Note that + * this is the number of elements returned by the iterator, which is not necessarily the number + * of elements that have been added to the collection (because of duplicates). + */ + public static int pour( final LongIterator i, final LongCollection s ) { + return pour( i, s, Integer.MAX_VALUE ); + } + /** Pours an iterator, returning a type-specific list, with a limit on the number of elements. + * + *

This method iterates over the given type-specific iterator and returns + * a type-specific list containing the returned elements (up to max). Iteration + * on the returned list is guaranteed to produce the elements in the same order + * in which they appeared in the iterator. + * + * + * @param i a type-specific iterator. + * @param max the maximum number of elements to be poured. + * @return a type-specific list containing the returned elements, up to max. + */ + public static LongList pour( final LongIterator i, int max ) { + final LongArrayList l = new LongArrayList (); + pour( i, l, max ); + l.trim(); + return l; + } + /** Pours an iterator, returning a type-specific list. + * + *

This method iterates over the given type-specific iterator and returns + * a list containing the returned elements. Iteration + * on the returned list is guaranteed to produce the elements in the same order + * in which they appeared in the iterator. + * + * @param i a type-specific iterator. + * @return a type-specific list containing the returned elements. + */ + public static LongList pour( final LongIterator i ) { + return pour( i, Integer.MAX_VALUE ); + } + private static class IteratorWrapper extends AbstractLongIterator { + final Iterator i; + public IteratorWrapper( final Iterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public void remove() { i.remove(); } + public long nextLong() { return ((i.next()).longValue()); } + } + /** Wraps a standard iterator into a type-specific iterator. + * + *

This method wraps a standard iterator into a type-specific one which will handle the + * type conversions for you. Of course, any attempt to wrap an iterator returning the + * instances of the wrong class will generate a {@link ClassCastException}. The + * returned iterator is backed by i: changes to one of the iterators + * will affect the other, too. + * + *

If i is already type-specific, it will returned and no new object + * will be generated. + * + * @param i an iterator. + * @return a type-specific iterator backed by i. + */ + @SuppressWarnings({"unchecked","rawtypes"}) + public static LongIterator asLongIterator( final Iterator i ) { + if ( i instanceof LongIterator ) return (LongIterator )i; + return new IteratorWrapper ( i ); + } + private static class ListIteratorWrapper extends AbstractLongListIterator { + final ListIterator i; + public ListIteratorWrapper( final ListIterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public boolean hasPrevious() { return i.hasPrevious(); } + public int nextIndex() { return i.nextIndex(); } + public int previousIndex() { return i.previousIndex(); } + public void set( long k ) { i.set( (Long.valueOf(k)) ); } + public void add( long k ) { i.add( (Long.valueOf(k)) ); } + public void remove() { i.remove(); } + public long nextLong() { return ((i.next()).longValue()); } + public long previousLong() { return ((i.previous()).longValue()); } + } + /** Wraps a standard list iterator into a type-specific list iterator. + * + *

This method wraps a standard list iterator into a type-specific one + * which will handle the type conversions for you. Of course, any attempt + * to wrap an iterator returning the instances of the wrong class will + * generate a {@link ClassCastException}. The + * returned iterator is backed by i: changes to one of the iterators + * will affect the other, too. + * + *

If i is already type-specific, it will returned and no new object + * will be generated. + * + * @param i a list iterator. + * @return a type-specific list iterator backed by i. + */ + @SuppressWarnings({"unchecked","rawtypes"}) + public static LongListIterator asLongIterator( final ListIterator i ) { + if ( i instanceof LongListIterator ) return (LongListIterator )i; + return new ListIteratorWrapper ( i ); + } + private static class IntervalIterator extends AbstractLongBidirectionalIterator { + private final long from, to; + long curr; + public IntervalIterator( final long from, final long to ) { + this.from = this.curr = from; + this.to = to; + } + public boolean hasNext() { return curr < to; } + public boolean hasPrevious() { return curr > from; } + public long nextLong() { + if ( ! hasNext() ) throw new NoSuchElementException(); + return curr++; + } + public long previousLong() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + return --curr; + } + public int skip( int n ) { + if ( curr + n <= to ) { + curr += n; + return n; + } + n = (int)( to - curr ); + curr = to; + return n; + } + public int back( int n ) { + if ( curr - n >= from ) { + curr -= n; + return n; + } + n = (int)( curr - from ); + curr = from; + return n; + } + } + /** Creates a type-specific bidirectional iterator over an interval. + * + *

The type-specific bidirectional iterator returned by this method will return the + * elements from, from+1,…, to-1. + * + *

Note that all other type-specific interval iterator are list + * iterators. Of course, this is not possible with longs as the index + * returned by {@link java.util.ListIterator#nextIndex() nextIndex()}/{@link + * java.util.ListIterator#previousIndex() previousIndex()} would exceed an integer. + * + * @param from the starting element (inclusive). + * @param to the ending element (exclusive). + * @return a type-specific bidirectional iterator enumerating the elements from from to to. + */ + public static LongBidirectionalIterator fromTo( final long from, final long to ) { + return new IntervalIterator( from, to ); + } + private static class IteratorConcatenator extends AbstractLongIterator { + final LongIterator a[]; + int offset, length, lastOffset = -1; + public IteratorConcatenator( final LongIterator a[], int offset, int length ) { + this.a = a; + this.offset = offset; + this.length = length; + advance(); + } + private void advance() { + while( length != 0 ) { + if ( a[ offset ].hasNext() ) break; + length--; + offset++; + } + return; + } + public boolean hasNext() { + return length > 0; + } + public long nextLong() { + if ( ! hasNext() ) throw new NoSuchElementException(); + long next = a[ lastOffset = offset ].nextLong(); + advance(); + return next; + } + public void remove() { + if ( lastOffset == -1 ) throw new IllegalStateException(); + a[ lastOffset ].remove(); + } + public int skip( int n ) { + lastOffset = -1; + int skipped = 0; + while( skipped < n && length != 0 ) { + skipped += a[ offset ].skip( n - skipped ); + if ( a[ offset ].hasNext() ) break; + length--; + offset++; + } + return skipped; + } + } + /** Concatenates all iterators contained in an array. + * + *

This method returns an iterator that will enumerate in order the elements returned + * by all iterators contained in the given array. + * + * @param a an array of iterators. + * @return an iterator obtained by concatenation. + */ + public static LongIterator concat( final LongIterator a[] ) { + return concat( a, 0, a.length ); + } + /** Concatenates a sequence of iterators contained in an array. + * + *

This method returns an iterator that will enumerate in order the elements returned + * by a[ offset ], then those returned + * by a[ offset + 1 ], and so on up to + * a[ offset + length - 1 ]. + * + * @param a an array of iterators. + * @param offset the index of the first iterator to concatenate. + * @param length the number of iterators to concatenate. + * @return an iterator obtained by concatenation of length elements of a starting at offset. + */ + public static LongIterator concat( final LongIterator a[], final int offset, final int length ) { + return new IteratorConcatenator ( a, offset, length ); + } + /** An unmodifiable wrapper class for iterators. */ + public static class UnmodifiableIterator extends AbstractLongIterator { + final protected LongIterator i; + public UnmodifiableIterator( final LongIterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public long nextLong() { return i.nextLong(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Long next() { return i.next(); } + } + /** Returns an unmodifiable iterator backed by the specified iterator. + * + * @param i the iterator to be wrapped in an unmodifiable iterator. + * @return an unmodifiable view of the specified iterator. + */ + public static LongIterator unmodifiable( final LongIterator i ) { return new UnmodifiableIterator ( i ); } + /** An unmodifiable wrapper class for bidirectional iterators. */ + public static class UnmodifiableBidirectionalIterator extends AbstractLongBidirectionalIterator { + final protected LongBidirectionalIterator i; + public UnmodifiableBidirectionalIterator( final LongBidirectionalIterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public boolean hasPrevious() { return i.hasPrevious(); } + public long nextLong() { return i.nextLong(); } + public long previousLong() { return i.previousLong(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Long next() { return i.next(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Long previous() { return i.previous(); } + } + /** Returns an unmodifiable bidirectional iterator backed by the specified bidirectional iterator. + * + * @param i the bidirectional iterator to be wrapped in an unmodifiable bidirectional iterator. + * @return an unmodifiable view of the specified bidirectional iterator. + */ + public static LongBidirectionalIterator unmodifiable( final LongBidirectionalIterator i ) { return new UnmodifiableBidirectionalIterator ( i ); } + /** An unmodifiable wrapper class for list iterators. */ + public static class UnmodifiableListIterator extends AbstractLongListIterator { + final protected LongListIterator i; + public UnmodifiableListIterator( final LongListIterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public boolean hasPrevious() { return i.hasPrevious(); } + public long nextLong() { return i.nextLong(); } + public long previousLong() { return i.previousLong(); } + public int nextIndex() { return i.nextIndex(); } + public int previousIndex() { return i.previousIndex(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Long next() { return i.next(); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + @Override + public Long previous() { return i.previous(); } + } + /** Returns an unmodifiable list iterator backed by the specified list iterator. + * + * @param i the list iterator to be wrapped in an unmodifiable list iterator. + * @return an unmodifiable view of the specified list iterator. + */ + public static LongListIterator unmodifiable( final LongListIterator i ) { return new UnmodifiableListIterator ( i ); } + + /** A wrapper promoting the results of an IntIterator. */ + protected static class IntIteratorWrapper implements LongIterator { + final it.unimi.dsi.fastutil.ints.IntIterator iterator; + public IntIteratorWrapper( final it.unimi.dsi.fastutil.ints.IntIterator iterator ) { + this.iterator = iterator; + } + public boolean hasNext() { return iterator.hasNext(); } + public Long next() { return Long.valueOf( iterator.nextInt() ); } + public long nextLong() { return iterator.nextInt(); } + public void remove() { iterator.remove(); } + public int skip( final int n ) { return iterator.skip( n ); } + } + /** Returns an iterator backed by the specified integer iterator. + * @return an iterator backed by the specified integer iterator. + */ + public static LongIterator wrap( final it.unimi.dsi.fastutil.ints.IntIterator iterator ) { + return new IntIteratorWrapper( iterator ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongList.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongList.java new file mode 100644 index 0000000..bc91a8f --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongList.java @@ -0,0 +1,210 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.List; +/** A type-specific {@link List}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Note that this type-specific interface extends {@link Comparable}: it is expected that implementing + * classes perform a lexicographical comparison using the standard operator "less then" for primitive types, + * and the usual {@link Comparable#compareTo(Object) compareTo()} method for objects. + * + *

Additionally, this interface strengthens {@link #listIterator()}, + * {@link #listIterator(int)} and {@link #subList(int,int)}. + * + *

Besides polymorphic methods, this interfaces specifies methods to copy into an array or remove contiguous + * sublists. Although the abstract implementation of this interface provides simple, one-by-one implementations + * of these methods, it is expected that concrete implementation override them with optimized versions. + * + * @see List + */ +public interface LongList extends List, Comparable>, LongCollection { + /** Returns a type-specific iterator on the elements of this list (in proper sequence). + * + * Note that this specification strengthens the one given in {@link List#iterator()}. + * It would not be normally necessary, but {@link java.lang.Iterable#iterator()} is bizarrily re-specified + * in {@link List}. + * + * @return an iterator on the elements of this list (in proper sequence). + */ + LongListIterator iterator(); + /** Returns a type-specific list iterator on the list. + * + * @see #listIterator() + * @deprecated As of fastutil 5, replaced by {@link #listIterator()}. + */ + @Deprecated + LongListIterator longListIterator(); + /** Returns a type-specific list iterator on the list starting at a given index. + * + * @see #listIterator(int) + * @deprecated As of fastutil 5, replaced by {@link #listIterator(int)}. + */ + @Deprecated + LongListIterator longListIterator( int index ); + /** Returns a type-specific list iterator on the list. + * + * @see List#listIterator() + */ + LongListIterator listIterator(); + /** Returns a type-specific list iterator on the list starting at a given index. + * + * @see List#listIterator(int) + */ + LongListIterator listIterator( int index ); + /** Returns a type-specific view of the portion of this list from the index from, inclusive, to the index to, exclusive. + * @see List#subList(int,int) + * @deprecated As of fastutil 5, replaced by {@link #subList(int,int)}. + */ + @Deprecated + LongList longSubList( int from, int to ); + /** Returns a type-specific view of the portion of this list from the index from, inclusive, to the index to, exclusive. + * + *

Note that this specification strengthens the one given in {@link List#subList(int,int)}. + * + * @see List#subList(int,int) + */ + LongList subList(int from, int to); + /** Sets the size of this list. + * + *

If the specified size is smaller than the current size, the last elements are + * discarded. Otherwise, they are filled with 0/null/false. + * + * @param size the new size. + */ + void size( int size ); + /** Copies (hopefully quickly) elements of this type-specific list into the given array. + * + * @param from the start index (inclusive). + * @param a the destination array. + * @param offset the offset into the destination array where to store the first element copied. + * @param length the number of elements to be copied. + */ + void getElements( int from, long a[], int offset, int length ); + /** Removes (hopefully quickly) elements of this type-specific list. + * + * @param from the start index (inclusive). + * @param to the end index (exclusive). + */ + void removeElements( int from, int to ); + /** Add (hopefully quickly) elements to this type-specific list. + * + * @param index the index at which to add elements. + * @param a the array containing the elements. + */ + void addElements( int index, long a[] ); + /** Add (hopefully quickly) elements to this type-specific list. + * + * @param index the index at which to add elements. + * @param a the array containing the elements. + * @param offset the offset of the first element to add. + * @param length the number of elements to add. + */ + void addElements( int index, long a[], int offset, int length ); + /** + * @see List#add(Object) + */ + boolean add( long key ); + /** + * @see List#add(int,Object) + */ + void add( int index, long key ); + /** + * @see List#add(int,Object) + */ + boolean addAll( int index, LongCollection c ); + /** + * @see List#add(int,Object) + */ + boolean addAll( int index, LongList c ); + /** + * @see List#add(int,Object) + */ + boolean addAll( LongList c ); + /** + * @see List#get(int) + */ + long getLong( int index ); + /** + * @see List#indexOf(Object) + */ + int indexOf( long k ); + /** + * @see List#lastIndexOf(Object) + */ + int lastIndexOf( long k ); + /** + * @see List#remove(int) + */ + long removeLong( int index ); + /** + * @see List#set(int,Object) + */ + long set( int index, long k ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongListIterator.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongListIterator.java new file mode 100644 index 0000000..e977a00 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongListIterator.java @@ -0,0 +1,85 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.ListIterator; +/** A type-specific bidirectional iterator that is also a {@link ListIterator}. + * + *

This interface merges the methods provided by a {@link ListIterator} and + * a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator}. Moreover, it provides + * type-specific versions of {@link java.util.ListIterator#add(Object) add()} + * and {@link java.util.ListIterator#set(Object) set()}. + * + * @see java.util.ListIterator + * @see it.unimi.dsi.fastutil.BidirectionalIterator + */ +public interface LongListIterator extends ListIterator, LongBidirectionalIterator { + void set( long k ); + void add( long k ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongLists.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongLists.java new file mode 100644 index 0000000..cff8a3c --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongLists.java @@ -0,0 +1,334 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.List; +import java.util.Collection; +import java.util.Random; +/** A class providing static methods and objects that do useful things with type-specific lists. + * + * @see java.util.Collections + */ +public class LongLists { + private LongLists() {} + /** Shuffles the specified list using the specified pseudorandom number generator. + * + * @param l the list to be shuffled. + * @param random a pseudorandom number generator (please use a XorShift* generator). + * @return l. + */ + public static LongList shuffle( final LongList l, final Random random ) { + for( int i = l.size(); i-- != 0; ) { + final int p = random.nextInt( i + 1 ); + final long t = l.getLong( i ); + l.set( i, l.getLong( p ) ); + l.set( p, t ); + } + return l; + } + /** An immutable class representing an empty type-specific list. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific list. + */ + public static class EmptyList extends LongCollections.EmptyCollection implements LongList , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptyList() {} + public void add( final int index, final long k ) { throw new UnsupportedOperationException(); } + public boolean add( final long k ) { throw new UnsupportedOperationException(); } + public long removeLong( int i ) { throw new UnsupportedOperationException(); } + public long set( final int index, final long k ) { throw new UnsupportedOperationException(); } + public int indexOf( long k ) { return -1; } + public int lastIndexOf( long k ) { return -1; } + public boolean addAll( Collection c ) { throw new UnsupportedOperationException(); } + public boolean addAll( int i, Collection c ) { throw new UnsupportedOperationException(); } + public boolean removeAll( Collection c ) { throw new UnsupportedOperationException(); } + public Long get( int i ) { throw new IndexOutOfBoundsException(); } + public boolean addAll( LongCollection c ) { throw new UnsupportedOperationException(); } + public boolean addAll( LongList c ) { throw new UnsupportedOperationException(); } + public boolean addAll( int i, LongCollection c ) { throw new UnsupportedOperationException(); } + public boolean addAll( int i, LongList c ) { throw new UnsupportedOperationException(); } + public void add( final int index, final Long k ) { throw new UnsupportedOperationException(); } + public boolean add( final Long k ) { throw new UnsupportedOperationException(); } + public Long set( final int index, final Long k ) { throw new UnsupportedOperationException(); } + public long getLong( int i ) { throw new IndexOutOfBoundsException(); } + public Long remove( int k ) { throw new UnsupportedOperationException(); } + public int indexOf( Object k ) { return -1; } + public int lastIndexOf( Object k ) { return -1; } + //SUPPRESS_WARNINGS_KEY_UNCHECKED + //public KEY_ITERATOR KEY_GENERIC iterator( int i ) { if ( i == 0 ) return ITERATORS.EMPTY_ITERATOR; throw new IndexOutOfBoundsException( String.valueOf( i ) ); } + @Deprecated + + public LongIterator longIterator() { return LongIterators.EMPTY_ITERATOR; } + + public LongListIterator listIterator() { return LongIterators.EMPTY_ITERATOR; } + + public LongListIterator iterator() { return LongIterators.EMPTY_ITERATOR; } + + public LongListIterator listIterator( int i ) { if ( i == 0 ) return LongIterators.EMPTY_ITERATOR; throw new IndexOutOfBoundsException( String.valueOf( i ) ); } + @Deprecated + public LongListIterator longListIterator() { return listIterator(); } + @Deprecated + public LongListIterator longListIterator( int i ) { return listIterator( i ); } + public LongList subList( int from, int to ) { if ( from == 0 && to == 0 ) return this; throw new IndexOutOfBoundsException(); } + @Deprecated + public LongList longSubList( int from, int to ) { return subList( from, to ); } + public void getElements( int from, long[] a, int offset, int length ) { if ( from == 0 && length == 0 && offset >= 0 && offset <= a.length ) return; throw new IndexOutOfBoundsException(); } + public void removeElements( int from, int to ) { throw new UnsupportedOperationException(); } + public void addElements( int index, final long a[], int offset, int length ) { throw new UnsupportedOperationException(); } + public void addElements( int index, final long a[] ) { throw new UnsupportedOperationException(); } + public void size( int s ) { throw new UnsupportedOperationException(); } + public int compareTo( final List o ) { + if ( o == this ) return 0; + return ((List)o).isEmpty() ? 0 : -1; + } + private Object readResolve() { return EMPTY_LIST; } + public Object clone() { return EMPTY_LIST; } + public int hashCode() { return 1; } + @SuppressWarnings("rawtypes") + public boolean equals( Object o ) { return o instanceof List && ((List)o).isEmpty(); } + public String toString() { return "[]"; } + } + /** An empty list (immutable). It is serializable and cloneable. + */ + + public static final EmptyList EMPTY_LIST = new EmptyList(); + /** An immutable class representing a type-specific singleton list. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific list. + */ + public static class Singleton extends AbstractLongList implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + private final long element; + private Singleton( final long element ) { + this.element = element; + } + public long getLong( final int i ) { if ( i == 0 ) return element; throw new IndexOutOfBoundsException(); } + public long removeLong( final int i ) { throw new UnsupportedOperationException(); } + public boolean contains( final long k ) { return ( (k) == (element) ); } + public boolean addAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean addAll( final int i, final Collection c ) { throw new UnsupportedOperationException(); } + public boolean removeAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( final Collection c ) { throw new UnsupportedOperationException(); } + /* Slightly optimized w.r.t. the one in ABSTRACT_SET. */ + public long[] toLongArray() { + long a[] = new long[ 1 ]; + a[ 0 ] = element; + return a; + } + public LongListIterator listIterator() { return LongIterators.singleton( element ); } + public LongListIterator iterator() { return listIterator(); } + public LongListIterator listIterator( int i ) { + if ( i > 1 || i < 0 ) throw new IndexOutOfBoundsException(); + LongListIterator l = listIterator(); + if ( i == 1 ) l.next(); + return l; + } + + public LongList subList( final int from, final int to ) { + ensureIndex( from ); + ensureIndex( to ); + if ( from > to ) throw new IndexOutOfBoundsException( "Start index (" + from + ") is greater than end index (" + to + ")" ); + if ( from != 0 || to != 1 ) return EMPTY_LIST; + return this; + } + public int size() { return 1; } + public void size( final int size ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + public Object clone() { return this; } + public boolean rem( final long k ) { throw new UnsupportedOperationException(); } + public boolean addAll( final LongCollection c ) { throw new UnsupportedOperationException(); } + public boolean addAll( final int i, final LongCollection c ) { throw new UnsupportedOperationException(); } + } + /** Returns a type-specific immutable list containing only the specified element. The returned list is serializable and cloneable. + * + * @param element the only element of the returned list. + * @return a type-specific immutable list containing just element. + */ + public static LongList singleton( final long element ) { return new Singleton ( element ); } + /** Returns a type-specific immutable list containing only the specified element. The returned list is serializable and cloneable. + * + * @param element the only element of the returned list. + * @return a type-specific immutable list containing just element. + */ + public static LongList singleton( final Object element ) { return new Singleton ( ((((Long)(element)).longValue())) ); } + /** A synchronized wrapper class for lists. */ + public static class SynchronizedList extends LongCollections.SynchronizedCollection implements LongList , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final LongList list; // Due to the large number of methods that are not in COLLECTION, this is worth caching. + protected SynchronizedList( final LongList l, final Object sync ) { + super( l, sync ); + this.list = l; + } + protected SynchronizedList( final LongList l ) { + super( l ); + this.list = l; + } + public long getLong( final int i ) { synchronized( sync ) { return list.getLong( i ); } } + public long set( final int i, final long k ) { synchronized( sync ) { return list.set( i, k ); } } + public void add( final int i, final long k ) { synchronized( sync ) { list.add( i, k ); } } + public long removeLong( final int i ) { synchronized( sync ) { return list.removeLong( i ); } } + public int indexOf( final long k ) { synchronized( sync ) { return list.indexOf( k ); } } + public int lastIndexOf( final long k ) { synchronized( sync ) { return list.lastIndexOf( k ); } } + public boolean addAll( final int index, final Collection c ) { synchronized( sync ) { return list.addAll( index, c ); } } + public void getElements( final int from, final long a[], final int offset, final int length ) { synchronized( sync ) { list.getElements( from, a, offset, length ); } } + public void removeElements( final int from, final int to ) { synchronized( sync ) { list.removeElements( from, to ); } } + public void addElements( int index, final long a[], int offset, int length ) { synchronized( sync ) { list.addElements( index, a, offset, length ); } } + public void addElements( int index, final long a[] ) { synchronized( sync ) { list.addElements( index, a ); } } + public void size( final int size ) { synchronized( sync ) { list.size( size ); } } + public LongListIterator iterator() { return list.listIterator(); } + public LongListIterator listIterator() { return list.listIterator(); } + public LongListIterator listIterator( final int i ) { return list.listIterator( i ); } + @Deprecated + public LongListIterator longListIterator() { return listIterator(); } + @Deprecated + public LongListIterator longListIterator( final int i ) { return listIterator( i ); } + public LongList subList( final int from, final int to ) { synchronized( sync ) { return synchronize( list.subList( from, to ), sync ); } } + @Deprecated + public LongList longSubList( final int from, final int to ) { return subList( from, to ); } + public boolean equals( final Object o ) { synchronized( sync ) { return collection.equals( o ); } } + public int hashCode() { synchronized( sync ) { return collection.hashCode(); } } + public int compareTo( final List o ) { synchronized( sync ) { return list.compareTo( o ); } } + public boolean addAll( final int index, final LongCollection c ) { synchronized( sync ) { return list.addAll( index, c ); } } + public boolean addAll( final int index, LongList l ) { synchronized( sync ) { return list.addAll( index, l ); } } + public boolean addAll( LongList l ) { synchronized( sync ) { return list.addAll( l ); } } + public Long get( final int i ) { synchronized( sync ) { return list.get( i ); } } + public void add( final int i, Long k ) { synchronized( sync ) { list.add( i, k ); } } + public Long set( final int index, Long k ) { synchronized( sync ) { return list.set( index, k ); } } + public Long remove( final int i ) { synchronized( sync ) { return list.remove( i ); } } + public int indexOf( final Object o ) { synchronized( sync ) { return list.indexOf( o ); } } + public int lastIndexOf( final Object o ) { synchronized( sync ) { return list.lastIndexOf( o ); } } + } + /** Returns a synchronized type-specific list backed by the given type-specific list. + * + * @param l the list to be wrapped in a synchronized list. + * @return a synchronized view of the specified list. + * @see java.util.Collections#synchronizedList(List) + */ + public static LongList synchronize( final LongList l ) { return new SynchronizedList ( l ); } + /** Returns a synchronized type-specific list backed by the given type-specific list, using an assigned object to synchronize. + * + * @param l the list to be wrapped in a synchronized list. + * @param sync an object that will be used to synchronize the access to the list. + * @return a synchronized view of the specified list. + * @see java.util.Collections#synchronizedList(List) + */ + public static LongList synchronize( final LongList l, final Object sync ) { return new SynchronizedList ( l, sync ); } + /** An unmodifiable wrapper class for lists. */ + public static class UnmodifiableList extends LongCollections.UnmodifiableCollection implements LongList , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final LongList list; // Due to the large number of methods that are not in COLLECTION, this is worth caching. + protected UnmodifiableList( final LongList l ) { + super( l ); + this.list = l; + } + public long getLong( final int i ) { return list.getLong( i ); } + public long set( final int i, final long k ) { throw new UnsupportedOperationException(); } + public void add( final int i, final long k ) { throw new UnsupportedOperationException(); } + public long removeLong( final int i ) { throw new UnsupportedOperationException(); } + public int indexOf( final long k ) { return list.indexOf( k ); } + public int lastIndexOf( final long k ) { return list.lastIndexOf( k ); } + public boolean addAll( final int index, final Collection c ) { throw new UnsupportedOperationException(); } + public void getElements( final int from, final long a[], final int offset, final int length ) { list.getElements( from, a, offset, length ); } + public void removeElements( final int from, final int to ) { throw new UnsupportedOperationException(); } + public void addElements( int index, final long a[], int offset, int length ) { throw new UnsupportedOperationException(); } + public void addElements( int index, final long a[] ) { throw new UnsupportedOperationException(); } + public void size( final int size ) { list.size( size ); } + public LongListIterator iterator() { return listIterator(); } + public LongListIterator listIterator() { return LongIterators.unmodifiable( list.listIterator() ); } + public LongListIterator listIterator( final int i ) { return LongIterators.unmodifiable( list.listIterator( i ) ); } + @Deprecated + public LongListIterator longListIterator() { return listIterator(); } + @Deprecated + public LongListIterator longListIterator( final int i ) { return listIterator( i ); } + public LongList subList( final int from, final int to ) { return unmodifiable( list.subList( from, to ) ); } + @Deprecated + public LongList longSubList( final int from, final int to ) { return subList( from, to ); } + public boolean equals( final Object o ) { return collection.equals( o ); } + public int hashCode() { return collection.hashCode(); } + public int compareTo( final List o ) { return list.compareTo( o ); } + public boolean addAll( final int index, final LongCollection c ) { throw new UnsupportedOperationException(); } + public boolean addAll( final LongList l ) { throw new UnsupportedOperationException(); } + public boolean addAll( final int index, final LongList l ) { throw new UnsupportedOperationException(); } + public Long get( final int i ) { return list.get( i ); } + public void add( final int i, Long k ) { throw new UnsupportedOperationException(); } + public Long set( final int index, Long k ) { throw new UnsupportedOperationException(); } + public Long remove( final int i ) { throw new UnsupportedOperationException(); } + public int indexOf( final Object o ) { return list.indexOf( o ); } + public int lastIndexOf( final Object o ) { return list.lastIndexOf( o ); } + } + /** Returns an unmodifiable type-specific list backed by the given type-specific list. + * + * @param l the list to be wrapped in an unmodifiable list. + * @return an unmodifiable view of the specified list. + * @see java.util.Collections#unmodifiableList(List) + */ + public static LongList unmodifiable( final LongList l ) { return new UnmodifiableList ( l ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongOpenCustomHashSet.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongOpenCustomHashSet.java new file mode 100644 index 0000000..b6a8b42 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongOpenCustomHashSet.java @@ -0,0 +1,661 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.HashCommon; +import static it.unimi.dsi.fastutil.HashCommon.arraySize; +import static it.unimi.dsi.fastutil.HashCommon.maxFill; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +/** A type-specific hash set with a fast, small-footprint implementation whose {@linkplain it.unimi.dsi.fastutil.Hash.Strategy hashing strategy} + * is specified at creation time. + * + *

Instances of this class use a hash table to represent a set. The table is + * filled up to a specified load factor, and then doubled in size to + * accommodate new entries. If the table is emptied below one fourth + * of the load factor, it is halved in size. However, halving is + * not performed when deleting entries from an iterator, as it would interfere + * with the iteration process. + * + *

Note that {@link #clear()} does not modify the hash table size. + * Rather, a family of {@linkplain #trim() trimming + * methods} lets you control the size of the table; this is particularly useful + * if you reuse instances of this class. + * + * @see Hash + * @see HashCommon + */ +public class LongOpenCustomHashSet extends AbstractLongSet implements java.io.Serializable, Cloneable, Hash { + private static final long serialVersionUID = 0L; + private static final boolean ASSERTS = false; + /** The array of keys. */ + protected transient long[] key; + /** The mask for wrapping a position counter. */ + protected transient int mask; + /** Whether this set contains the null key. */ + protected transient boolean containsNull; + /** The hash strategy of this custom set. */ + protected it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy; + /** The current table size. Note that an additional element is allocated for storing the null key. */ + protected transient int n; + /** Threshold after which we rehash. It must be the table size times {@link #f}. */ + protected transient int maxFill; + /** Number of entries in the set (including the null key, if present). */ + protected int size; + /** The acceptable load factor. */ + protected final float f; + /** Creates a new hash set. + * + *

The actual table size will be the least power of two greater than expected/f. + * + * @param expected the expected number of elements in the hash set. + * @param f the load factor. + * @param strategy the strategy. + */ + + public LongOpenCustomHashSet( final int expected, final float f, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this.strategy = strategy; + if ( f <= 0 || f > 1 ) throw new IllegalArgumentException( "Load factor must be greater than 0 and smaller than or equal to 1" ); + if ( expected < 0 ) throw new IllegalArgumentException( "The expected number of elements must be nonnegative" ); + this.f = f; + n = arraySize( expected, f ); + mask = n - 1; + maxFill = maxFill( n, f ); + key = new long[ n + 1 ]; + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * + * @param expected the expected number of elements in the hash set. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final int expected, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( expected, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash set with initial expected {@link Hash#DEFAULT_INITIAL_SIZE} elements + * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash set copying a given collection. + * + * @param c a {@link Collection} to be copied into the new hash set. + * @param f the load factor. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final Collection c, final float f, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( c.size(), f, strategy ); + addAll( c ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor + * copying a given collection. + * + * @param c a {@link Collection} to be copied into the new hash set. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final Collection c, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( c, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash set copying a given type-specific collection. + * + * @param c a type-specific collection to be copied into the new hash set. + * @param f the load factor. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final LongCollection c, final float f, it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( c.size(), f, strategy ); + addAll( c ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor + * copying a given type-specific collection. + * + * @param c a type-specific collection to be copied into the new hash set. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final LongCollection c, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( c, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash set using elements provided by a type-specific iterator. + * + * @param i a type-specific iterator whose elements will fill the set. + * @param f the load factor. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final LongIterator i, final float f, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( DEFAULT_INITIAL_SIZE, f, strategy ); + while( i.hasNext() ) add( i.nextLong() ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by a type-specific iterator. + * + * @param i a type-specific iterator whose elements will fill the set. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final LongIterator i, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( i, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash set using elements provided by an iterator. + * + * @param i an iterator whose elements will fill the set. + * @param f the load factor. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final Iterator i, final float f, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( LongIterators.asLongIterator( i ), f, strategy ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by an iterator. + * + * @param i an iterator whose elements will fill the set. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final Iterator i, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( LongIterators.asLongIterator( i ), strategy ); + } + /** Creates a new hash set and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the set. + * @param offset the first element to use. + * @param length the number of elements to use. + * @param f the load factor. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final long[] a, final int offset, final int length, final float f, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( length < 0 ? 0 : length, f, strategy ); + LongArrays.ensureOffsetLength( a, offset, length ); + for( int i = 0; i < length; i++ ) add( a[ offset + i ] ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the set. + * @param offset the first element to use. + * @param length the number of elements to use. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final long[] a, final int offset, final int length, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( a, offset, length, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Creates a new hash set copying the elements of an array. + * + * @param a an array to be copied into the new hash set. + * @param f the load factor. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final long[] a, final float f, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( a, 0, a.length, f, strategy ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor + * copying the elements of an array. + * + * @param a an array to be copied into the new hash set. + * @param strategy the strategy. + */ + public LongOpenCustomHashSet( final long[] a, final it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy ) { + this( a, DEFAULT_LOAD_FACTOR, strategy ); + } + /** Returns the hashing strategy. + * + * @return the hashing strategy of this custom hash set. + */ + public it.unimi.dsi.fastutil.longs.LongHash.Strategy strategy() { + return strategy; + } + private int realSize() { + return containsNull ? size - 1 : size; + } + private void ensureCapacity( final int capacity ) { + final int needed = arraySize( capacity, f ); + if ( needed > n ) rehash( needed ); + } + private void tryCapacity( final long capacity ) { + final int needed = (int)Math.min( 1 << 30, Math.max( 2, HashCommon.nextPowerOfTwo( (long)Math.ceil( capacity / f ) ) ) ); + if ( needed > n ) rehash( needed ); + } + /** {@inheritDoc} */ + public boolean addAll( LongCollection c ) { + if ( f <= .5 ) ensureCapacity( c.size() ); // The resulting collection will be sized for c.size() elements + else tryCapacity( size() + c.size() ); // The resulting collection will be tentatively sized for size() + c.size() elements + return super.addAll( c ); + } + /** {@inheritDoc} */ + public boolean addAll( Collection c ) { + // The resulting collection will be at least c.size() big + if ( f <= .5 ) ensureCapacity( c.size() ); // The resulting collection will be sized for c.size() elements + else tryCapacity( size() + c.size() ); // The resulting collection will be tentatively sized for size() + c.size() elements + return super.addAll( c ); + } + public boolean add( final long k ) { + int pos; + if ( ( strategy.equals( (k), (0) ) ) ) { + if ( containsNull ) return false; + containsNull = true; + key[ n ] = k; + } + else { + long curr; + final long[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) { + if ( ( strategy.equals( (curr), (k) ) ) ) return false; + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( strategy.equals( (curr), (k) ) ) ) return false; + } + key[ pos ] = k; + } + if ( size++ >= maxFill ) rehash( arraySize( size + 1, f ) ); + if ( ASSERTS ) checkTable(); + return true; + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + protected final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + long curr; + final long[] key = this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + } + } + private boolean removeEntry( final int pos ) { + size--; + shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return true; + } + private boolean removeNullEntry() { + containsNull = false; + key[ n ] = (0); + size--; + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return true; + } + + public boolean remove( final long k ) { + if ( ( strategy.equals( ( k), (0) ) ) ) { + if ( containsNull ) return removeNullEntry(); + return false; + } + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return removeEntry( pos ); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return removeEntry( pos ); + } + } + + public boolean contains( final long k ) { + if ( ( strategy.equals( ( k), (0) ) ) ) return containsNull; + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return true; + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( strategy.equals( (k), (curr) ) ) ) return true; + } + } + /* Removes all elements from this set. + * + *

To increase object reuse, this method does not change the table size. + * If you want to reduce the table size, you must use {@link #trim()}. + * + */ + public void clear() { + if ( size == 0 ) return; + size = 0; + containsNull = false; + Arrays.fill( key, (0) ); + } + public int size() { + return size; + } + public boolean isEmpty() { + return size == 0; + } + /** A no-op for backward compatibility. + * + * @param growthFactor unused. + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public void growthFactor( int growthFactor ) {} + /** Gets the growth factor (2). + * + * @return the growth factor of this set, which is fixed (2). + * @see #growthFactor(int) + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public int growthFactor() { + return 16; + } + /** An iterator over a hash set. */ + private class SetIterator extends AbstractLongIterator { + /** The index of the last entry returned, if positive or zero; initially, {@link #n}. If negative, the last + element returned was that of index {@code - pos - 1} from the {@link #wrapped} list. */ + int pos = n; + /** The index of the last entry that has been returned (more precisely, the value of {@link #pos} if {@link #pos} is positive, + or {@link Integer#MIN_VALUE} if {@link #pos} is negative). It is -1 if either + we did not return an entry yet, or the last returned entry has been removed. */ + int last = -1; + /** A downward counter measuring how many entries must still be returned. */ + int c = size; + /** A boolean telling us whether we should return the null key. */ + boolean mustReturnNull = LongOpenCustomHashSet.this.containsNull; + /** A lazily allocated list containing elements that have wrapped around the table because of removals. */ + LongArrayList wrapped; + public boolean hasNext() { + return c != 0; + } + public long nextLong() { + if ( ! hasNext() ) throw new NoSuchElementException(); + c--; + if ( mustReturnNull ) { + mustReturnNull = false; + last = n; + return key[ n ]; + } + final long key[] = LongOpenCustomHashSet.this.key; + for(;;) { + if ( --pos < 0 ) { + // We are just enumerating elements from the wrapped list. + last = Integer.MIN_VALUE; + return wrapped.getLong( - pos - 1 ); + } + if ( ! ( (key[ pos ]) == (0) ) ) return key[ last = pos ]; + } + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + private final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + long curr; + final long[] key = LongOpenCustomHashSet.this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + return; + } + slot = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(curr) ) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + if ( pos < last ) { // Wrapped entry. + if ( wrapped == null ) wrapped = new LongArrayList ( 2 ); + wrapped.add( key[ pos ] ); + } + key[ last ] = curr; + } + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + if ( last == n ) { + LongOpenCustomHashSet.this.containsNull = false; + LongOpenCustomHashSet.this.key[ n ] = (0); + } + else if ( pos >= 0 ) shiftKeys( last ); + else { + // We're removing wrapped entries. + LongOpenCustomHashSet.this.remove( wrapped.getLong( - pos - 1 ) ); + last = -1; // Note that we must not decrement size + return; + } + size--; + last = -1; // You can no longer remove this entry. + if ( ASSERTS ) checkTable(); + } + } + public LongIterator iterator() { + return new SetIterator(); + } + /** A no-op for backward compatibility. The kind of tables implemented by + * this class never need rehashing. + * + *

If you need to reduce the table size to fit exactly + * this set, use {@link #trim()}. + * + * @return true. + * @see #trim() + * @deprecated A no-op. + */ + @Deprecated + public boolean rehash() { + return true; + } + /** Rehashes this set, making the table as small as possible. + * + *

This method rehashes the table to the smallest size satisfying the + * load factor. It can be used when the set will not be changed anymore, so + * to optimize access speed and size. + * + *

If the table size is already the minimum possible, this method + * does nothing. + * + * @return true if there was enough memory to trim the set. + * @see #trim(int) + */ + public boolean trim() { + final int l = arraySize( size, f ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch(OutOfMemoryError cantDoIt) { return false; } + return true; + } + /** Rehashes this set if the table is too large. + * + *

Let N be the smallest table size that can hold + * max(n,{@link #size()}) entries, still satisfying the load factor. If the current + * table size is smaller than or equal to N, this method does + * nothing. Otherwise, it rehashes this set in a table of size + * N. + * + *

This method is useful when reusing sets. {@linkplain #clear() Clearing a + * set} leaves the table size untouched. If you are reusing a set + * many times, you can call this method with a typical + * size to avoid keeping around a very large table just + * because of a few large transient sets. + * + * @param n the threshold for the trimming. + * @return true if there was enough memory to trim the set. + * @see #trim() + */ + public boolean trim( final int n ) { + final int l = HashCommon.nextPowerOfTwo( (int)Math.ceil( n / f ) ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch( OutOfMemoryError cantDoIt ) { return false; } + return true; + } + /** Rehashes the set. + * + *

This method implements the basic rehashing strategy, and may be + * overriden by subclasses implementing different rehashing strategies (e.g., + * disk-based rehashing). However, you should not override this method + * unless you understand the internal workings of this class. + * + * @param newN the new size + */ + + protected void rehash( final int newN ) { + final long key[] = this.key; + final int mask = newN - 1; // Note that this is used by the hashing macro + final long newKey[] = new long[ newN + 1 ]; + int i = n, pos; + for( int j = realSize(); j-- != 0; ) { + while( ( (key[ --i ]) == (0) ) ); + if ( ! ( (newKey[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(key[ i ]) ) ) & mask ]) == (0) ) ) + while ( ! ( (newKey[ pos = ( pos + 1 ) & mask ]) == (0) ) ); + newKey[ pos ] = key[ i ]; + } + n = newN; + this.mask = mask; + maxFill = maxFill( n, f ); + this.key = newKey; + } + /** Returns a deep copy of this set. + * + *

This method performs a deep copy of this hash set; the data stored in the + * set, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this set. + */ + + public LongOpenCustomHashSet clone() { + LongOpenCustomHashSet c; + try { + c = (LongOpenCustomHashSet )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.key = key.clone(); + c.containsNull = containsNull; + c.strategy = strategy; + return c; + } + /** Returns a hash code for this set. + * + * This method overrides the generic method provided by the superclass. + * Since equals() is not overriden, it is important + * that the value returned by this method is the same value as + * the one returned by the overriden method. + * + * @return a hash code for this set. + */ + public int hashCode() { + int h = 0; + for( int j = realSize(), i = 0; j-- != 0; ) { + while( ( (key[ i ]) == (0) ) ) i++; + h += ( strategy.hashCode(key[ i ]) ); + i++; + } + // Zero / null have hash zero. + return h; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + final LongIterator i = iterator(); + s.defaultWriteObject(); + for( int j = size; j-- != 0; ) s.writeLong( i.nextLong() ); + } + + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + n = arraySize( size, f ); + maxFill = maxFill( n, f ); + mask = n - 1; + final long key[] = this.key = new long[ n + 1 ]; + long k; + for( int i = size, pos; i-- != 0; ) { + k = s.readLong(); + if ( ( strategy.equals( (k), (0) ) ) ) { + pos = n; + containsNull = true; + } + else { + if ( ! ( (key[ pos = ( it.unimi.dsi.fastutil.HashCommon.mix( strategy.hashCode(k) ) ) & mask ]) == (0) ) ) + while ( ! ( (key[ pos = ( pos + 1 ) & mask ]) == (0) ) ); + } + key[ pos ] = k; + } + if ( ASSERTS ) checkTable(); + } + private void checkTable() {} +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongOpenHashSet.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongOpenHashSet.java new file mode 100644 index 0000000..bcafa3e --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongOpenHashSet.java @@ -0,0 +1,627 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.Hash; +import it.unimi.dsi.fastutil.HashCommon; +import static it.unimi.dsi.fastutil.HashCommon.arraySize; +import static it.unimi.dsi.fastutil.HashCommon.maxFill; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +/** A type-specific hash set with with a fast, small-footprint implementation. + * + *

Instances of this class use a hash table to represent a set. The table is + * enlarged as needed by doubling its size when new entries are created, but it is never made + * smaller (even on a {@link #clear()}). A family of {@linkplain #trim() trimming + * methods} lets you control the size of the table; this is particularly useful + * if you reuse instances of this class. + * + * @see Hash + * @see HashCommon + */ +public class LongOpenHashSet extends AbstractLongSet implements java.io.Serializable, Cloneable, Hash { + private static final long serialVersionUID = 0L; + private static final boolean ASSERTS = false; + /** The array of keys. */ + protected transient long[] key; + /** The mask for wrapping a position counter. */ + protected transient int mask; + /** Whether this set contains the null key. */ + protected transient boolean containsNull; + /** The current table size. Note that an additional element is allocated for storing the null key. */ + protected transient int n; + /** Threshold after which we rehash. It must be the table size times {@link #f}. */ + protected transient int maxFill; + /** Number of entries in the set (including the null key, if present). */ + protected int size; + /** The acceptable load factor. */ + protected final float f; + /** Creates a new hash set. + * + *

The actual table size will be the least power of two greater than expected/f. + * + * @param expected the expected number of elements in the hash set. + * @param f the load factor. + */ + + public LongOpenHashSet( final int expected, final float f ) { + if ( f <= 0 || f > 1 ) throw new IllegalArgumentException( "Load factor must be greater than 0 and smaller than or equal to 1" ); + if ( expected < 0 ) throw new IllegalArgumentException( "The expected number of elements must be nonnegative" ); + this.f = f; + n = arraySize( expected, f ); + mask = n - 1; + maxFill = maxFill( n, f ); + key = new long[ n + 1 ]; + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + * + * @param expected the expected number of elements in the hash set. + */ + public LongOpenHashSet( final int expected ) { + this( expected, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash set with initial expected {@link Hash#DEFAULT_INITIAL_SIZE} elements + * and {@link Hash#DEFAULT_LOAD_FACTOR} as load factor. + */ + public LongOpenHashSet() { + this( DEFAULT_INITIAL_SIZE, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash set copying a given collection. + * + * @param c a {@link Collection} to be copied into the new hash set. + * @param f the load factor. + */ + public LongOpenHashSet( final Collection c, final float f ) { + this( c.size(), f ); + addAll( c ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor + * copying a given collection. + * + * @param c a {@link Collection} to be copied into the new hash set. + */ + public LongOpenHashSet( final Collection c ) { + this( c, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash set copying a given type-specific collection. + * + * @param c a type-specific collection to be copied into the new hash set. + * @param f the load factor. + */ + public LongOpenHashSet( final LongCollection c, final float f ) { + this( c.size(), f ); + addAll( c ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor + * copying a given type-specific collection. + * + * @param c a type-specific collection to be copied into the new hash set. + */ + public LongOpenHashSet( final LongCollection c ) { + this( c, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash set using elements provided by a type-specific iterator. + * + * @param i a type-specific iterator whose elements will fill the set. + * @param f the load factor. + */ + public LongOpenHashSet( final LongIterator i, final float f ) { + this( DEFAULT_INITIAL_SIZE, f ); + while( i.hasNext() ) add( i.nextLong() ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by a type-specific iterator. + * + * @param i a type-specific iterator whose elements will fill the set. + */ + public LongOpenHashSet( final LongIterator i ) { + this( i, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash set using elements provided by an iterator. + * + * @param i an iterator whose elements will fill the set. + * @param f the load factor. + */ + public LongOpenHashSet( final Iterator i, final float f ) { + this( LongIterators.asLongIterator( i ), f ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor using elements provided by an iterator. + * + * @param i an iterator whose elements will fill the set. + */ + public LongOpenHashSet( final Iterator i ) { + this( LongIterators.asLongIterator( i ) ); + } + /** Creates a new hash set and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the set. + * @param offset the first element to use. + * @param length the number of elements to use. + * @param f the load factor. + */ + public LongOpenHashSet( final long[] a, final int offset, final int length, final float f ) { + this( length < 0 ? 0 : length, f ); + LongArrays.ensureOffsetLength( a, offset, length ); + for( int i = 0; i < length; i++ ) add( a[ offset + i ] ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the set. + * @param offset the first element to use. + * @param length the number of elements to use. + */ + public LongOpenHashSet( final long[] a, final int offset, final int length ) { + this( a, offset, length, DEFAULT_LOAD_FACTOR ); + } + /** Creates a new hash set copying the elements of an array. + * + * @param a an array to be copied into the new hash set. + * @param f the load factor. + */ + public LongOpenHashSet( final long[] a, final float f ) { + this( a, 0, a.length, f ); + } + /** Creates a new hash set with {@link Hash#DEFAULT_LOAD_FACTOR} as load factor + * copying the elements of an array. + * + * @param a an array to be copied into the new hash set. + */ + public LongOpenHashSet( final long[] a ) { + this( a, DEFAULT_LOAD_FACTOR ); + } + private int realSize() { + return containsNull ? size - 1 : size; + } + private void ensureCapacity( final int capacity ) { + final int needed = arraySize( capacity, f ); + if ( needed > n ) rehash( needed ); + } + private void tryCapacity( final long capacity ) { + final int needed = (int)Math.min( 1 << 30, Math.max( 2, HashCommon.nextPowerOfTwo( (long)Math.ceil( capacity / f ) ) ) ); + if ( needed > n ) rehash( needed ); + } + /** {@inheritDoc} */ + public boolean addAll( LongCollection c ) { + if ( f <= .5 ) ensureCapacity( c.size() ); // The resulting collection will be sized for c.size() elements + else tryCapacity( size() + c.size() ); // The resulting collection will be tentatively sized for size() + c.size() elements + return super.addAll( c ); + } + /** {@inheritDoc} */ + public boolean addAll( Collection c ) { + // The resulting collection will be at least c.size() big + if ( f <= .5 ) ensureCapacity( c.size() ); // The resulting collection will be sized for c.size() elements + else tryCapacity( size() + c.size() ); // The resulting collection will be tentatively sized for size() + c.size() elements + return super.addAll( c ); + } + public boolean add( final long k ) { + int pos; + if ( ( (k) == (0) ) ) { + if ( containsNull ) return false; + containsNull = true; + } + else { + long curr; + final long[] key = this.key; + // The starting point. + if ( ! ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) { + if ( ( (curr) == (k) ) ) return false; + while( ! ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) + if ( ( (curr) == (k) ) ) return false; + } + key[ pos ] = k; + } + if ( size++ >= maxFill ) rehash( arraySize( size + 1, f ) ); + if ( ASSERTS ) checkTable(); + return true; + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + protected final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + long curr; + final long[] key = this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + return; + } + slot = (int)it.unimi.dsi.fastutil.HashCommon.mix( (curr) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + key[ last ] = curr; + } + } + private boolean removeEntry( final int pos ) { + size--; + shiftKeys( pos ); + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return true; + } + private boolean removeNullEntry() { + containsNull = false; + key[ n ] = (0); + size--; + if ( size < maxFill / 4 && n > DEFAULT_INITIAL_SIZE ) rehash( n / 2 ); + return true; + } + + public boolean remove( final long k ) { + if ( ( (k) == (0) ) ) { + if ( containsNull ) return removeNullEntry(); + return false; + } + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return removeEntry( pos ); + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return removeEntry( pos ); + } + } + + public boolean contains( final long k ) { + if ( ( (k) == (0) ) ) return containsNull; + long curr; + final long[] key = this.key; + int pos; + // The starting point. + if ( ( (curr = key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return true; + while( true ) { + if ( ( (curr = key[ pos = ( pos + 1 ) & mask ]) == (0) ) ) return false; + if ( ( (k) == (curr) ) ) return true; + } + } + /* Removes all elements from this set. + * + *

To increase object reuse, this method does not change the table size. + * If you want to reduce the table size, you must use {@link #trim()}. + * + */ + public void clear() { + if ( size == 0 ) return; + size = 0; + containsNull = false; + Arrays.fill( key, (0) ); + } + public int size() { + return size; + } + public boolean isEmpty() { + return size == 0; + } + /** A no-op for backward compatibility. + * + * @param growthFactor unused. + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public void growthFactor( int growthFactor ) {} + /** Gets the growth factor (2). + * + * @return the growth factor of this set, which is fixed (2). + * @see #growthFactor(int) + * @deprecated Since fastutil 6.1.0, hash tables are doubled when they are too full. + */ + @Deprecated + public int growthFactor() { + return 16; + } + /** An iterator over a hash set. */ + private class SetIterator extends AbstractLongIterator { + /** The index of the last entry returned, if positive or zero; initially, {@link #n}. If negative, the last + element returned was that of index {@code - pos - 1} from the {@link #wrapped} list. */ + int pos = n; + /** The index of the last entry that has been returned (more precisely, the value of {@link #pos} if {@link #pos} is positive, + or {@link Integer#MIN_VALUE} if {@link #pos} is negative). It is -1 if either + we did not return an entry yet, or the last returned entry has been removed. */ + int last = -1; + /** A downward counter measuring how many entries must still be returned. */ + int c = size; + /** A boolean telling us whether we should return the null key. */ + boolean mustReturnNull = LongOpenHashSet.this.containsNull; + /** A lazily allocated list containing elements that have wrapped around the table because of removals. */ + LongArrayList wrapped; + public boolean hasNext() { + return c != 0; + } + public long nextLong() { + if ( ! hasNext() ) throw new NoSuchElementException(); + c--; + if ( mustReturnNull ) { + mustReturnNull = false; + last = n; + return key[ n ]; + } + final long key[] = LongOpenHashSet.this.key; + for(;;) { + if ( --pos < 0 ) { + // We are just enumerating elements from the wrapped list. + last = Integer.MIN_VALUE; + return wrapped.getLong( - pos - 1 ); + } + if ( ! ( (key[ pos ]) == (0) ) ) return key[ last = pos ]; + } + } + /** Shifts left entries with the specified hash code, starting at the specified position, + * and empties the resulting free entry. + * + * @param pos a starting position. + */ + private final void shiftKeys( int pos ) { + // Shift entries with the same hash. + int last, slot; + long curr; + final long[] key = LongOpenHashSet.this.key; + for(;;) { + pos = ( ( last = pos ) + 1 ) & mask; + for(;;) { + if ( ( (curr = key[ pos ]) == (0) ) ) { + key[ last ] = (0); + return; + } + slot = (int)it.unimi.dsi.fastutil.HashCommon.mix( (curr) ) & mask; + if ( last <= pos ? last >= slot || slot > pos : last >= slot && slot > pos ) break; + pos = ( pos + 1 ) & mask; + } + if ( pos < last ) { // Wrapped entry. + if ( wrapped == null ) wrapped = new LongArrayList ( 2 ); + wrapped.add( key[ pos ] ); + } + key[ last ] = curr; + } + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + if ( last == n ) { + LongOpenHashSet.this.containsNull = false; + LongOpenHashSet.this.key[ n ] = (0); + } + else if ( pos >= 0 ) shiftKeys( last ); + else { + // We're removing wrapped entries. + LongOpenHashSet.this.remove( wrapped.getLong( - pos - 1 ) ); + last = -1; // Note that we must not decrement size + return; + } + size--; + last = -1; // You can no longer remove this entry. + if ( ASSERTS ) checkTable(); + } + } + public LongIterator iterator() { + return new SetIterator(); + } + /** A no-op for backward compatibility. The kind of tables implemented by + * this class never need rehashing. + * + *

If you need to reduce the table size to fit exactly + * this set, use {@link #trim()}. + * + * @return true. + * @see #trim() + * @deprecated A no-op. + */ + @Deprecated + public boolean rehash() { + return true; + } + /** Rehashes this set, making the table as small as possible. + * + *

This method rehashes the table to the smallest size satisfying the + * load factor. It can be used when the set will not be changed anymore, so + * to optimize access speed and size. + * + *

If the table size is already the minimum possible, this method + * does nothing. + * + * @return true if there was enough memory to trim the set. + * @see #trim(int) + */ + public boolean trim() { + final int l = arraySize( size, f ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch(OutOfMemoryError cantDoIt) { return false; } + return true; + } + /** Rehashes this set if the table is too large. + * + *

Let N be the smallest table size that can hold + * max(n,{@link #size()}) entries, still satisfying the load factor. If the current + * table size is smaller than or equal to N, this method does + * nothing. Otherwise, it rehashes this set in a table of size + * N. + * + *

This method is useful when reusing sets. {@linkplain #clear() Clearing a + * set} leaves the table size untouched. If you are reusing a set + * many times, you can call this method with a typical + * size to avoid keeping around a very large table just + * because of a few large transient sets. + * + * @param n the threshold for the trimming. + * @return true if there was enough memory to trim the set. + * @see #trim() + */ + public boolean trim( final int n ) { + final int l = HashCommon.nextPowerOfTwo( (int)Math.ceil( n / f ) ); + if ( l >= n || size > maxFill( l, f ) ) return true; + try { + rehash( l ); + } + catch( OutOfMemoryError cantDoIt ) { return false; } + return true; + } + /** Rehashes the set. + * + *

This method implements the basic rehashing strategy, and may be + * overriden by subclasses implementing different rehashing strategies (e.g., + * disk-based rehashing). However, you should not override this method + * unless you understand the internal workings of this class. + * + * @param newN the new size + */ + + protected void rehash( final int newN ) { + final long key[] = this.key; + final int mask = newN - 1; // Note that this is used by the hashing macro + final long newKey[] = new long[ newN + 1 ]; + int i = n, pos; + for( int j = realSize(); j-- != 0; ) { + while( ( (key[ --i ]) == (0) ) ); + if ( ! ( (newKey[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (key[ i ]) ) & mask ]) == (0) ) ) + while ( ! ( (newKey[ pos = ( pos + 1 ) & mask ]) == (0) ) ); + newKey[ pos ] = key[ i ]; + } + n = newN; + this.mask = mask; + maxFill = maxFill( n, f ); + this.key = newKey; + } + /** Returns a deep copy of this set. + * + *

This method performs a deep copy of this hash set; the data stored in the + * set, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this set. + */ + + public LongOpenHashSet clone() { + LongOpenHashSet c; + try { + c = (LongOpenHashSet )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.key = key.clone(); + c.containsNull = containsNull; + return c; + } + /** Returns a hash code for this set. + * + * This method overrides the generic method provided by the superclass. + * Since equals() is not overriden, it is important + * that the value returned by this method is the same value as + * the one returned by the overriden method. + * + * @return a hash code for this set. + */ + public int hashCode() { + int h = 0; + for( int j = realSize(), i = 0; j-- != 0; ) { + while( ( (key[ i ]) == (0) ) ) i++; + h += it.unimi.dsi.fastutil.HashCommon.long2int(key[ i ]); + i++; + } + // Zero / null have hash zero. + return h; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + final LongIterator i = iterator(); + s.defaultWriteObject(); + for( int j = size; j-- != 0; ) s.writeLong( i.nextLong() ); + } + + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + n = arraySize( size, f ); + maxFill = maxFill( n, f ); + mask = n - 1; + final long key[] = this.key = new long[ n + 1 ]; + long k; + for( int i = size, pos; i-- != 0; ) { + k = s.readLong(); + if ( ( (k) == (0) ) ) { + pos = n; + containsNull = true; + } + else { + if ( ! ( (key[ pos = (int)it.unimi.dsi.fastutil.HashCommon.mix( (k) ) & mask ]) == (0) ) ) + while ( ! ( (key[ pos = ( pos + 1 ) & mask ]) == (0) ) ); + } + key[ pos ] = k; + } + if ( ASSERTS ) checkTable(); + } + private void checkTable() {} +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongPriorityQueue.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongPriorityQueue.java new file mode 100644 index 0000000..de4db2d --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongPriorityQueue.java @@ -0,0 +1,108 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Paolo Boldi and Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.NoSuchElementException; +import it.unimi.dsi.fastutil.PriorityQueue; +/** A type-specific {@link PriorityQueue}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Additionally, this interface strengthens {@link #comparator()}. + */ +public interface LongPriorityQueue extends PriorityQueue { + /** Enqueues a new element. + * + * @param x the element to enqueue. + */ + void enqueue( long x ); + /** Dequeues the {@linkplain #first() first} element from the queue. + * + * @return the dequeued element. + * @throws NoSuchElementException if the queue is empty. + */ + long dequeueLong(); + /** Returns the first element of the queue. + * + * @return the first element. + * @throws NoSuchElementException if the queue is empty. + */ + long firstLong(); + /** Returns the last element of the queue, that is, the element the would be dequeued last (optional operation). + * + * @return the last element. + * @throws NoSuchElementException if the queue is empty. + */ + long lastLong(); + /** Returns the comparator associated with this sorted set, or null if it uses its elements' natural ordering. + * + *

Note that this specification strengthens the one given in {@link PriorityQueue#comparator()}. + * + * @see PriorityQueue#comparator() + */ + LongComparator comparator(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongPriorityQueues.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongPriorityQueues.java new file mode 100644 index 0000000..88dfc23 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongPriorityQueues.java @@ -0,0 +1,116 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +/** A class providing static methods and objects that do useful things with type-specific priority queues. + * + * @see it.unimi.dsi.fastutil.PriorityQueue + */ +public class LongPriorityQueues { + private LongPriorityQueues() {} + /** A synchronized wrapper class for priority queues. */ + public static class SynchronizedPriorityQueue implements LongPriorityQueue { + final protected LongPriorityQueue q; + final protected Object sync; + protected SynchronizedPriorityQueue( final LongPriorityQueue q, final Object sync ) { + this.q = q; + this.sync = sync; + } + protected SynchronizedPriorityQueue( final LongPriorityQueue q ) { + this.q = q; + this.sync = this; + } + public void enqueue( long x ) { synchronized( sync ) { q.enqueue( x ); } } + public long dequeueLong() { synchronized( sync ) { return q.dequeueLong(); } } + public long firstLong() { synchronized( sync ) { return q.firstLong(); } } + public long lastLong() { synchronized( sync ) { return q.lastLong(); } } + public boolean isEmpty() { synchronized( sync ) { return q.isEmpty(); } } + public int size() { synchronized( sync ) { return q.size(); } } + public void clear() { synchronized( sync ) { q.clear(); } } + public void changed() { synchronized( sync ) { q.changed(); } } + public LongComparator comparator() { synchronized( sync ) { return q.comparator(); } } + public void enqueue( Long x ) { synchronized( sync ) { q.enqueue( x ); } } + public Long dequeue() { synchronized( sync ) { return q.dequeue(); } } + public Long first() { synchronized( sync ) { return q.first(); } } + public Long last() { synchronized( sync ) { return q.last(); } } + } + /** Returns a synchronized type-specific priority queue backed by the specified type-specific priority queue. + * + * @param q the priority queue to be wrapped in a synchronized priority queue. + * @return a synchronized view of the specified priority queue. + */ + public static LongPriorityQueue synchronize( final LongPriorityQueue q ) { return new SynchronizedPriorityQueue( q ); } + /** Returns a synchronized type-specific priority queue backed by the specified type-specific priority queue, using an assigned object to synchronize. + * + * @param q the priority queue to be wrapped in a synchronized priority queue. + * @param sync an object that will be used to synchronize the access to the priority queue. + * @return a synchronized view of the specified priority queue. + */ + public static LongPriorityQueue synchronize( final LongPriorityQueue q, final Object sync ) { return new SynchronizedPriorityQueue( q, sync ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongSet.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongSet.java new file mode 100644 index 0000000..c7dad79 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongSet.java @@ -0,0 +1,97 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.Set; +/** A type-specific {@link Set}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Additionally, this interface strengthens (again) {@link #iterator()}. + * + * @see Set + */ +public interface LongSet extends LongCollection , Set { + /** Returns a type-specific iterator on the elements of this set. + * + *

Note that this specification strengthens the one given in {@link java.lang.Iterable#iterator()}, + * which was already strengthened in the corresponding type-specific class, + * but was weakened by the fact that this interface extends {@link Set}. + * + * @return a type-specific iterator on the elements of this set. + */ + LongIterator iterator(); + /** Removes an element from this set. + * + *

Note that the corresponding method of the type-specific collection is rem(). + * This unfortunate situation is caused by the clash + * with the similarly named index-based method in the {@link java.util.List} interface. + * + * @see java.util.Collection#remove(Object) + */ + public boolean remove( long k ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongSets.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongSets.java new file mode 100644 index 0000000..de7e3da --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongSets.java @@ -0,0 +1,186 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.Collection; +import java.util.Set; +/** A class providing static methods and objects that do useful things with type-specific sets. + * + * @see java.util.Collections + */ +public class LongSets { + private LongSets() {} + /** An immutable class representing the empty set and implementing a type-specific set interface. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific set. + */ + public static class EmptySet extends LongCollections.EmptyCollection implements LongSet , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptySet() {} + public boolean remove( long ok ) { throw new UnsupportedOperationException(); } + public Object clone() { return EMPTY_SET; } + @SuppressWarnings("rawtypes") + public boolean equals( final Object o ) { return o instanceof Set && ((Set)o).isEmpty(); } + private Object readResolve() { return EMPTY_SET; } + } + /** An empty set (immutable). It is serializable and cloneable. + */ + + public static final EmptySet EMPTY_SET = new EmptySet(); + /** An immutable class representing a type-specific singleton set. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific set. */ + public static class Singleton extends AbstractLongSet implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected final long element; + protected Singleton( final long element ) { + this.element = element; + } + public boolean add( final long k ) { throw new UnsupportedOperationException(); } + public boolean contains( final long k ) { return ( (k) == (element) ); } + public boolean addAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean removeAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( final Collection c ) { throw new UnsupportedOperationException(); } + /* Slightly optimized w.r.t. the one in ABSTRACT_SET. */ + public long[] toLongArray() { + long a[] = new long[ 1 ]; + a[ 0 ] = element; + return a; + } + public boolean addAll( final LongCollection c ) { throw new UnsupportedOperationException(); } + public boolean removeAll( final LongCollection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( final LongCollection c ) { throw new UnsupportedOperationException(); } + public LongListIterator iterator() { return LongIterators.singleton( element ); } + public int size() { return 1; } + public Object clone() { return this; } + } + /** Returns a type-specific immutable set containing only the specified element. The returned set is serializable and cloneable. + * + * @param element the only element of the returned set. + * @return a type-specific immutable set containing just element. + */ + public static LongSet singleton( final long element ) { + return new Singleton ( element ); + } + /** Returns a type-specific immutable set containing only the specified element. The returned set is serializable and cloneable. + * + * @param element the only element of the returned set. + * @return a type-specific immutable set containing just element. + */ + public static LongSet singleton( final Long element ) { + return new Singleton ( ((element).longValue()) ); + } + /** A synchronized wrapper class for sets. */ + public static class SynchronizedSet extends LongCollections.SynchronizedCollection implements LongSet , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected SynchronizedSet( final LongSet s, final Object sync ) { + super( s, sync ); + } + protected SynchronizedSet( final LongSet s ) { + super( s ); + } + public boolean remove( final long k ) { synchronized( sync ) { return collection.remove( (Long.valueOf(k)) ); } } + public boolean equals( final Object o ) { synchronized( sync ) { return collection.equals( o ); } } + public int hashCode() { synchronized( sync ) { return collection.hashCode(); } } + } + /** Returns a synchronized type-specific set backed by the given type-specific set. + * + * @param s the set to be wrapped in a synchronized set. + * @return a synchronized view of the specified set. + * @see java.util.Collections#synchronizedSet(Set) + */ + public static LongSet synchronize( final LongSet s ) { return new SynchronizedSet ( s ); } + /** Returns a synchronized type-specific set backed by the given type-specific set, using an assigned object to synchronize. + * + * @param s the set to be wrapped in a synchronized set. + * @param sync an object that will be used to synchronize the access to the set. + * @return a synchronized view of the specified set. + * @see java.util.Collections#synchronizedSet(Set) + */ + public static LongSet synchronize( final LongSet s, final Object sync ) { return new SynchronizedSet ( s, sync ); } + /** An unmodifiable wrapper class for sets. */ + public static class UnmodifiableSet extends LongCollections.UnmodifiableCollection implements LongSet , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected UnmodifiableSet( final LongSet s ) { + super( s ); + } + public boolean remove( final long k ) { throw new UnsupportedOperationException(); } + public boolean equals( final Object o ) { return collection.equals( o ); } + public int hashCode() { return collection.hashCode(); } + } + /** Returns an unmodifiable type-specific set backed by the given type-specific set. + * + * @param s the set to be wrapped in an unmodifiable set. + * @return an unmodifiable view of the specified set. + * @see java.util.Collections#unmodifiableSet(Set) + */ + public static LongSet unmodifiable( final LongSet s ) { return new UnmodifiableSet ( s ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongSortedSet.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongSortedSet.java new file mode 100644 index 0000000..7490285 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongSortedSet.java @@ -0,0 +1,179 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.SortedSet; +import java.util.Collection; +/** A type-specific {@link SortedSet}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Additionally, this interface strengthens {@link #iterator()}, + * {@link #comparator()} (for primitive types), {@link SortedSet#subSet(Object,Object)}, + * {@link SortedSet#headSet(Object)} and {@link SortedSet#tailSet(Object)}. + * + * @see SortedSet + */ +public interface LongSortedSet extends LongSet , SortedSet { + /** Returns a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator} on the elements in + * this set, starting from a given element of the domain (optional operation). + * + *

This method returns a type-specific bidirectional iterator with given + * starting point. The starting point is any element comparable to the + * elements of this set (even if it does not actually belong to the + * set). The next element of the returned iterator is the least element of + * the set that is greater than the starting point (if there are no + * elements greater than the starting point, {@link + * it.unimi.dsi.fastutil.BidirectionalIterator#hasNext() hasNext()} will return + * false). The previous element of the returned iterator is + * the greatest element of the set that is smaller than or equal to the + * starting point (if there are no elements smaller than or equal to the + * starting point, {@link it.unimi.dsi.fastutil.BidirectionalIterator#hasPrevious() + * hasPrevious()} will return false). + * + *

Note that passing the last element of the set as starting point and + * calling {@link it.unimi.dsi.fastutil.BidirectionalIterator#previous() previous()} you can traverse the + * entire set in reverse order. + * + * @param fromElement an element to start from. + * @return a bidirectional iterator on the element in this set, starting at the given element. + * @throws UnsupportedOperationException if this set does not support iterators with a starting point. + */ + LongBidirectionalIterator iterator( long fromElement ); + /** Returns a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator} iterator on the collection. + * + *

The iterator returned by the {@link #iterator()} method and by this + * method are identical; however, using this method you can save a type casting. + * + * Note that this specification strengthens the one given in the corresponding type-specific + * {@link Collection}. + * + * @deprecated As of fastutil 5, replaced by {@link #iterator()}. + */ + @Deprecated + LongBidirectionalIterator longIterator(); + /** Returns a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator} on the elements in + * this set. + * + *

This method returns a parameterised bidirectional iterator. The iterator + * can be moreover safely cast to a type-specific iterator. + * + * Note that this specification strengthens the one given in the corresponding type-specific + * {@link Collection}. + * + * @return a bidirectional iterator on the element in this set. + */ + LongBidirectionalIterator iterator(); + /** Returns a view of the portion of this sorted set whose elements range from fromElement, inclusive, to toElement, exclusive. + * + *

Note that this specification strengthens the one given in {@link SortedSet#subSet(Object,Object)}. + * + * @see SortedSet#subSet(Object,Object) + */ + LongSortedSet subSet( Long fromElement, Long toElement) ; + /** Returns a view of the portion of this sorted set whose elements are strictly less than toElement. + * + *

Note that this specification strengthens the one given in {@link SortedSet#headSet(Object)}. + * + * @see SortedSet#headSet(Object) + */ + LongSortedSet headSet( Long toElement ); + /** Returns a view of the portion of this sorted set whose elements are greater than or equal to fromElement. + * + *

Note that this specification strengthens the one given in {@link SortedSet#tailSet(Object)}. + * + * @see SortedSet#tailSet(Object) + */ + LongSortedSet tailSet( Long fromElement ); + /** Returns the comparator associated with this sorted set, or null if it uses its elements' natural ordering. + * + *

Note that this specification strengthens the one given in {@link SortedSet#comparator()}. + * + * @see SortedSet#comparator() + */ + LongComparator comparator(); + /** + * @see SortedSet#subSet(Object,Object) + */ + LongSortedSet subSet( long fromElement, long toElement) ; + /** + * @see SortedSet#headSet(Object) + */ + LongSortedSet headSet( long toElement ); + /** + * @see SortedSet#tailSet(Object) + */ + LongSortedSet tailSet( long fromElement ); + /** + * @see SortedSet#first() + */ + long firstLong(); + /** + * @see SortedSet#last() + */ + long lastLong(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongSortedSets.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongSortedSets.java new file mode 100644 index 0000000..73e7361 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongSortedSets.java @@ -0,0 +1,280 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import java.util.SortedSet; +import java.util.NoSuchElementException; +/** A class providing static methods and objects that do useful things with type-specific sorted sets. + * + * @see java.util.Collections + */ +public class LongSortedSets { + private LongSortedSets() {} + /** An immutable class representing the empty sorted set and implementing a type-specific set interface. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific sorted set. + */ + public static class EmptySet extends LongSets.EmptySet implements LongSortedSet , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptySet() {} + public boolean remove( long ok ) { throw new UnsupportedOperationException(); } + @Deprecated + public LongBidirectionalIterator longIterator() { return iterator(); } + + public LongBidirectionalIterator iterator( long from ) { return LongIterators.EMPTY_ITERATOR; } + + public LongSortedSet subSet( long from, long to ) { return EMPTY_SET; } + + public LongSortedSet headSet( long from ) { return EMPTY_SET; } + + public LongSortedSet tailSet( long to ) { return EMPTY_SET; } + public long firstLong() { throw new NoSuchElementException(); } + public long lastLong() { throw new NoSuchElementException(); } + public LongComparator comparator() { return null; } + public LongSortedSet subSet( Long from, Long to ) { return EMPTY_SET; } + public LongSortedSet headSet( Long from ) { return EMPTY_SET; } + public LongSortedSet tailSet( Long to ) { return EMPTY_SET; } + public Long first() { throw new NoSuchElementException(); } + public Long last() { throw new NoSuchElementException(); } + public Object clone() { return EMPTY_SET; } + private Object readResolve() { return EMPTY_SET; } + } + /** An empty sorted set (immutable). It is serializable and cloneable. + * + */ + + public static final EmptySet EMPTY_SET = new EmptySet(); + /** A class representing a singleton sorted set. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific sorted set. + */ + public static class Singleton extends LongSets.Singleton implements LongSortedSet , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + final LongComparator comparator; + private Singleton( final long element, final LongComparator comparator ) { + super( element ); + this.comparator = comparator; + } + private Singleton( final long element ) { + this( element, null ); + } + + final int compare( final long k1, final long k2 ) { + return comparator == null ? ( Long.compare((k1),(k2)) ) : comparator.compare( k1, k2 ); + } + @Deprecated + public LongBidirectionalIterator longIterator() { + return iterator(); + } + public LongBidirectionalIterator iterator( long from ) { + LongBidirectionalIterator i = iterator(); + if ( compare( element, from ) <= 0 ) i.next(); + return i; + } + public LongComparator comparator() { return comparator; } + + public LongSortedSet subSet( final long from, final long to ) { if ( compare( from, element ) <= 0 && compare( element, to ) < 0 ) return this; return EMPTY_SET; } + + public LongSortedSet headSet( final long to ) { if ( compare( element, to ) < 0 ) return this; return EMPTY_SET; } + + public LongSortedSet tailSet( final long from ) { if ( compare( from, element ) <= 0 ) return this; return EMPTY_SET; } + public long firstLong() { return element; } + public long lastLong() { return element; } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long first() { return (Long.valueOf(element)); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public Long last() { return (Long.valueOf(element)); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public LongSortedSet subSet( final Long from, final Long to ) { return subSet( ((from).longValue()), ((to).longValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public LongSortedSet headSet( final Long to ) { return headSet( ((to).longValue()) ); } + /** {@inheritDoc} + * @deprecated Please use the corresponding type-specific method instead. */ + @Deprecated + public LongSortedSet tailSet( final Long from ) { return tailSet( ((from).longValue()) ); } + } + /** Returns a type-specific immutable sorted set containing only the specified element. The returned sorted set is serializable and cloneable. + * + * @param element the only element of the returned sorted set. + * @return a type-specific immutable sorted set containing just element. + */ + public static LongSortedSet singleton( final long element ) { + return new Singleton ( element ); + } + /** Returns a type-specific immutable sorted set containing only the specified element, and using a specified comparator. The returned sorted set is serializable and cloneable. + * + * @param element the only element of the returned sorted set. + * @param comparator the comparator to use in the returned sorted set. + * @return a type-specific immutable sorted set containing just element. + */ + public static LongSortedSet singleton( final long element, final LongComparator comparator ) { + return new Singleton ( element, comparator ); + } + /** Returns a type-specific immutable sorted set containing only the specified element. The returned sorted set is serializable and cloneable. + * + * @param element the only element of the returned sorted set. + * @return a type-specific immutable sorted set containing just element. + */ + public static LongSortedSet singleton( final Object element ) { + return new Singleton( ((((Long)(element)).longValue())) ); + } + /** Returns a type-specific immutable sorted set containing only the specified element, and using a specified comparator. The returned sorted set is serializable and cloneable. + * + * @param element the only element of the returned sorted set. + * @param comparator the comparator to use in the returned sorted set. + * @return a type-specific immutable sorted set containing just element. + */ + public static LongSortedSet singleton( final Object element, final LongComparator comparator ) { + return new Singleton( ((((Long)(element)).longValue())), comparator ); + } + /** A synchronized wrapper class for sorted sets. */ + public static class SynchronizedSortedSet extends LongSets.SynchronizedSet implements LongSortedSet , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final LongSortedSet sortedSet; + protected SynchronizedSortedSet( final LongSortedSet s, final Object sync ) { + super( s, sync ); + sortedSet = s; + } + protected SynchronizedSortedSet( final LongSortedSet s ) { + super( s ); + sortedSet = s; + } + public LongComparator comparator() { synchronized( sync ) { return sortedSet.comparator(); } } + public LongSortedSet subSet( final long from, final long to ) { return new SynchronizedSortedSet ( sortedSet.subSet( from, to ), sync ); } + public LongSortedSet headSet( final long to ) { return new SynchronizedSortedSet ( sortedSet.headSet( to ), sync ); } + public LongSortedSet tailSet( final long from ) { return new SynchronizedSortedSet ( sortedSet.tailSet( from ), sync ); } + public LongBidirectionalIterator iterator() { return sortedSet.iterator(); } + public LongBidirectionalIterator iterator( final long from ) { return sortedSet.iterator( from ); } + @Deprecated + public LongBidirectionalIterator longIterator() { return sortedSet.iterator(); } + public long firstLong() { synchronized( sync ) { return sortedSet.firstLong(); } } + public long lastLong() { synchronized( sync ) { return sortedSet.lastLong(); } } + public Long first() { synchronized( sync ) { return sortedSet.first(); } } + public Long last() { synchronized( sync ) { return sortedSet.last(); } } + public LongSortedSet subSet( final Long from, final Long to ) { return new SynchronizedSortedSet( sortedSet.subSet( from, to ), sync ); } + public LongSortedSet headSet( final Long to ) { return new SynchronizedSortedSet( sortedSet.headSet( to ), sync ); } + public LongSortedSet tailSet( final Long from ) { return new SynchronizedSortedSet( sortedSet.tailSet( from ), sync ); } + } + /** Returns a synchronized type-specific sorted set backed by the given type-specific sorted set. + * + * @param s the sorted set to be wrapped in a synchronized sorted set. + * @return a synchronized view of the specified sorted set. + * @see java.util.Collections#synchronizedSortedSet(SortedSet) + */ + public static LongSortedSet synchronize( final LongSortedSet s ) { return new SynchronizedSortedSet ( s ); } + /** Returns a synchronized type-specific sorted set backed by the given type-specific sorted set, using an assigned object to synchronize. + * + * @param s the sorted set to be wrapped in a synchronized sorted set. + * @param sync an object that will be used to synchronize the access to the sorted set. + * @return a synchronized view of the specified sorted set. + * @see java.util.Collections#synchronizedSortedSet(SortedSet) + */ + public static LongSortedSet synchronize( final LongSortedSet s, final Object sync ) { return new SynchronizedSortedSet ( s, sync ); } + /** An unmodifiable wrapper class for sorted sets. */ + public static class UnmodifiableSortedSet extends LongSets.UnmodifiableSet implements LongSortedSet , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final LongSortedSet sortedSet; + protected UnmodifiableSortedSet( final LongSortedSet s ) { + super( s ); + sortedSet = s; + } + public LongComparator comparator() { return sortedSet.comparator(); } + public LongSortedSet subSet( final long from, final long to ) { return new UnmodifiableSortedSet ( sortedSet.subSet( from, to ) ); } + public LongSortedSet headSet( final long to ) { return new UnmodifiableSortedSet ( sortedSet.headSet( to ) ); } + public LongSortedSet tailSet( final long from ) { return new UnmodifiableSortedSet ( sortedSet.tailSet( from ) ); } + public LongBidirectionalIterator iterator() { return LongIterators.unmodifiable( sortedSet.iterator() ); } + public LongBidirectionalIterator iterator( final long from ) { return LongIterators.unmodifiable( sortedSet.iterator( from ) ); } + @Deprecated + public LongBidirectionalIterator longIterator() { return iterator(); } + public long firstLong() { return sortedSet.firstLong(); } + public long lastLong() { return sortedSet.lastLong(); } + public Long first() { return sortedSet.first(); } + public Long last() { return sortedSet.last(); } + public LongSortedSet subSet( final Long from, final Long to ) { return new UnmodifiableSortedSet( sortedSet.subSet( from, to ) ); } + public LongSortedSet headSet( final Long to ) { return new UnmodifiableSortedSet( sortedSet.headSet( to ) ); } + public LongSortedSet tailSet( final Long from ) { return new UnmodifiableSortedSet( sortedSet.tailSet( from ) ); } + } + /** Returns an unmodifiable type-specific sorted set backed by the given type-specific sorted set. + * + * @param s the sorted set to be wrapped in an unmodifiable sorted set. + * @return an unmodifiable view of the specified sorted set. + * @see java.util.Collections#unmodifiableSortedSet(SortedSet) + */ + public static LongSortedSet unmodifiable( final LongSortedSet s ) { return new UnmodifiableSortedSet ( s ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/LongStack.java b/src/main/java/it/unimi/dsi/fastutil/longs/LongStack.java new file mode 100644 index 0000000..3627a64 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/LongStack.java @@ -0,0 +1,91 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.longs; +import it.unimi.dsi.fastutil.Stack; +/** A type-specific {@link Stack}; provides some additional methods that use polymorphism to avoid (un)boxing. + */ +public interface LongStack extends Stack { + /** + * @see Stack#push(Object) + */ + void push( long k ); + /** + * @see Stack#pop() + */ + long popLong(); + /** + * @see Stack#top() + */ + long topLong(); + /** + * @see Stack#peek(int) + */ + long peekLong( int i ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/longs/package.html b/src/main/java/it/unimi/dsi/fastutil/longs/package.html new file mode 100644 index 0000000..772ffd4 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/longs/package.html @@ -0,0 +1,12 @@ + + + + fastutil + + + + +

Provides type-specific classes for long elements or keys. + + + diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectBidirectionalIterator.java b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectBidirectionalIterator.java new file mode 100644 index 0000000..4828c8c --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectBidirectionalIterator.java @@ -0,0 +1,90 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +/** An abstract class facilitating the creation of type-specific {@linkplain it.unimi.dsi.fastutil.BidirectionalIterator bidirectional iterators}. + * + *

To create a type-specific bidirectional iterator, besides what is needed + * for an iterator you need both a method returning the previous element as + * primitive type and a method returning the previous element as an + * object. However, if you inherit from this class you need just one (anyone). + * + *

This class implements also a trivial version of {@link #back(int)} that + * uses type-specific methods. + */ +public abstract class AbstractObjectBidirectionalIterator extends AbstractObjectIterator implements ObjectBidirectionalIterator { + protected AbstractObjectBidirectionalIterator() {} + /** This method just iterates the type-specific version of {@link #previous()} for + * at most n times, stopping if {@link + * #hasPrevious()} becomes false. */ + public int back( final int n ) { + int i = n; + while( i-- != 0 && hasPrevious() ) previous(); + return n - i - 1; + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectCollection.java b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectCollection.java new file mode 100644 index 0000000..bd437e7 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectCollection.java @@ -0,0 +1,175 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Iterator; +/** An abstract class providing basic methods for collections implementing a type-specific interface. + * + *

In particular, this class provide {@link #iterator()}, add(), {@link #remove(Object)} and + * {@link #contains(Object)} methods that just call the type-specific counterpart. + */ +public abstract class AbstractObjectCollection extends AbstractCollection implements ObjectCollection { + protected AbstractObjectCollection() {} + public Object[] toArray() { + final Object[] a = new Object[ size() ]; + it.unimi.dsi.fastutil.objects.ObjectIterators.unwrap( iterator(), a ); + return a; + } + @SuppressWarnings("unchecked") + public T[] toArray( T[] a ) { + final int size = size(); + if ( a.length < size ) a = (T[])java.lang.reflect.Array.newInstance( a.getClass().getComponentType(), size ); + it.unimi.dsi.fastutil.objects.ObjectIterators.unwrap( iterator(), a ); + if ( size < a.length ) a[ size ] = null; + return a; + } + /** Adds all elements of the given collection to this collection. + * + * @param c a collection. + * @return true if this collection changed as a result of the call. + */ + public boolean addAll( Collection c ) { + boolean retVal = false; + final Iterator i = c.iterator(); + int n = c.size(); + while( n-- != 0 ) if ( add( i.next() ) ) retVal = true; + return retVal; + } + public boolean add( K k ) { + throw new UnsupportedOperationException(); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public ObjectIterator objectIterator() { + return iterator(); + } + public abstract ObjectIterator iterator(); + /** Checks whether this collection contains all elements from the given collection. + * + * @param c a collection. + * @return true if this collection contains all elements of the argument. + */ + public boolean containsAll( Collection c ) { + int n = c.size(); + final Iterator i = c.iterator(); + while( n-- != 0 ) if ( ! contains( i.next() ) ) return false; + return true; + } + /** Retains in this collection only elements from the given collection. + * + * @param c a collection. + * @return true if this collection changed as a result of the call. + */ + public boolean retainAll( Collection c ) { + boolean retVal = false; + int n = size(); + final Iterator i = iterator(); + while( n-- != 0 ) { + if ( ! c.contains( i.next() ) ) { + i.remove(); + retVal = true; + } + } + return retVal; + } + /** Remove from this collection all elements in the given collection. + * If the collection is an instance of this class, it uses faster iterators. + * + * @param c a collection. + * @return true if this collection changed as a result of the call. + */ + public boolean removeAll( Collection c ) { + boolean retVal = false; + int n = c.size(); + final Iterator i = c.iterator(); + while( n-- != 0 ) if ( remove( i.next() ) ) retVal = true; + return retVal; + } + public boolean isEmpty() { + return size() == 0; + } + public String toString() { + final StringBuilder s = new StringBuilder(); + final ObjectIterator i = iterator(); + int n = size(); + Object k; + boolean first = true; + s.append("{"); + while(n-- != 0) { + if (first) first = false; + else s.append(", "); + k = i.next(); + if (this == k) s.append("(this collection)"); else + s.append(String.valueOf(k)); + } + s.append("}"); + return s.toString(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectIterator.java b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectIterator.java new file mode 100644 index 0000000..654db5f --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectIterator.java @@ -0,0 +1,93 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +/** An abstract class facilitating the creation of type-specific iterators. + * + *

To create a type-specific iterator you need both a method returning the + * next element as primitive type and a method returning the next element as an + * object. However, if you inherit from this class you need just one (anyone). + * + *

This class implements also a trivial version of {@link #skip(int)} that uses + * type-specific methods; moreover, {@link #remove()} will throw an {@link + * UnsupportedOperationException}. + * + * @see java.util.Iterator + */ +public abstract class AbstractObjectIterator implements ObjectIterator { + protected AbstractObjectIterator() {} + /** This method just throws an {@link UnsupportedOperationException}. */ + public void remove() { throw new UnsupportedOperationException(); } + /** This method just iterates the type-specific version of {@link #next()} for at most + * n times, stopping if {@link #hasNext()} becomes false.*/ + public int skip( final int n ) { + int i = n; + while( i-- != 0 && hasNext() ) next(); + return n - i - 1; + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectList.java b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectList.java new file mode 100644 index 0000000..41303ac --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectList.java @@ -0,0 +1,472 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import it.unimi.dsi.fastutil.Stack; +import java.util.List; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.Collection; +import java.util.NoSuchElementException; +/** An abstract class providing basic methods for lists implementing a type-specific list interface. + * + *

As an additional bonus, this class implements on top of the list operations a type-specific stack. + */ +public abstract class AbstractObjectList extends AbstractObjectCollection implements ObjectList , Stack { + protected AbstractObjectList() {} + /** Ensures that the given index is nonnegative and not greater than the list size. + * + * @param index an index. + * @throws IndexOutOfBoundsException if the given index is negative or greater than the list size. + */ + protected void ensureIndex( final int index ) { + if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" ); + if ( index > size() ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than list size (" + ( size() ) + ")" ); + } + /** Ensures that the given index is nonnegative and smaller than the list size. + * + * @param index an index. + * @throws IndexOutOfBoundsException if the given index is negative or not smaller than the list size. + */ + protected void ensureRestrictedIndex( final int index ) { + if ( index < 0 ) throw new IndexOutOfBoundsException( "Index (" + index + ") is negative" ); + if ( index >= size() ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + ( size() ) + ")" ); + } + public void add( final int index, final K k ) { + throw new UnsupportedOperationException(); + } + public boolean add( final K k ) { + add( size(), k ); + return true; + } + public K remove( int i ) { + throw new UnsupportedOperationException(); + } + public K set( final int index, final K k ) { + throw new UnsupportedOperationException(); + } + public boolean addAll( int index, final Collection c ) { + ensureIndex( index ); + int n = c.size(); + if ( n == 0 ) return false; + Iterator i = c.iterator(); + while( n-- != 0 ) add( index++, i.next() ); + return true; + } + /** Delegates to a more generic method. */ + public boolean addAll( final Collection c ) { + return addAll( size(), c ); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public ObjectListIterator objectListIterator() { + return listIterator(); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public ObjectListIterator objectListIterator( final int index ) { + return listIterator( index ); + } + public ObjectListIterator iterator() { + return listIterator(); + } + public ObjectListIterator listIterator() { + return listIterator( 0 ); + } + public ObjectListIterator listIterator( final int index ) { + ensureIndex( index ); + return new AbstractObjectListIterator () { + int pos = index, last = -1; + public boolean hasNext() { return pos < AbstractObjectList.this.size(); } + public boolean hasPrevious() { return pos > 0; } + public K next() { if ( ! hasNext() ) throw new NoSuchElementException(); return AbstractObjectList.this.get( last = pos++ ); } + public K previous() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return AbstractObjectList.this.get( last = --pos ); } + public int nextIndex() { return pos; } + public int previousIndex() { return pos - 1; } + public void add( K k ) { + AbstractObjectList.this.add( pos++, k ); + last = -1; + } + public void set( K k ) { + if ( last == -1 ) throw new IllegalStateException(); + AbstractObjectList.this.set( last, k ); + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + AbstractObjectList.this.remove( last ); + /* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */ + if ( last < pos ) pos--; + last = -1; + } + }; + } + public boolean contains( final Object k ) { + return indexOf( k ) >= 0; + } + public int indexOf( final Object k ) { + final ObjectListIterator i = listIterator(); + K e; + while( i.hasNext() ) { + e = i.next(); + if ( ( (k) == null ? (e) == null : (k).equals(e) ) ) return i.previousIndex(); + } + return -1; + } + public int lastIndexOf( final Object k ) { + ObjectListIterator i = listIterator( size() ); + K e; + while( i.hasPrevious() ) { + e = i.previous(); + if ( ( (k) == null ? (e) == null : (k).equals(e) ) ) return i.nextIndex(); + } + return -1; + } + public void size( final int size ) { + int i = size(); + if ( size > i ) while( i++ < size ) add( (null) ); + else while( i-- != size ) remove( i ); + } + public ObjectList subList( final int from, final int to ) { + ensureIndex( from ); + ensureIndex( to ); + if ( from > to ) throw new IndexOutOfBoundsException( "Start index (" + from + ") is greater than end index (" + to + ")" ); + return new ObjectSubList ( this, from, to ); + } + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public ObjectList objectSubList( final int from, final int to ) { + return subList( from, to ); + } + /** Removes elements of this type-specific list one-by-one. + * + *

This is a trivial iterator-based implementation. It is expected that + * implementations will override this method with a more optimized version. + * + * + * @param from the start index (inclusive). + * @param to the end index (exclusive). + */ + public void removeElements( final int from, final int to ) { + ensureIndex( to ); + ObjectListIterator i = listIterator( from ); + int n = to - from; + if ( n < 0 ) throw new IllegalArgumentException( "Start index (" + from + ") is greater than end index (" + to + ")" ); + while( n-- != 0 ) { + i.next(); + i.remove(); + } + } + /** Adds elements to this type-specific list one-by-one. + * + *

This is a trivial iterator-based implementation. It is expected that + * implementations will override this method with a more optimized version. + * + * @param index the index at which to add elements. + * @param a the array containing the elements. + * @param offset the offset of the first element to add. + * @param length the number of elements to add. + */ + public void addElements( int index, final K a[], int offset, int length ) { + ensureIndex( index ); + if ( offset < 0 ) throw new ArrayIndexOutOfBoundsException( "Offset (" + offset + ") is negative" ); + if ( offset + length > a.length ) throw new ArrayIndexOutOfBoundsException( "End index (" + ( offset + length ) + ") is greater than array length (" + a.length + ")" ); + while( length-- != 0 ) add( index++, a[ offset++ ] ); + } + public void addElements( final int index, final K a[] ) { + addElements( index, a, 0, a.length ); + } + /** Copies element of this type-specific list into the given array one-by-one. + * + *

This is a trivial iterator-based implementation. It is expected that + * implementations will override this method with a more optimized version. + * + * @param from the start index (inclusive). + * @param a the destination array. + * @param offset the offset into the destination array where to store the first element copied. + * @param length the number of elements to be copied. + */ + public void getElements( final int from, final Object a[], int offset, int length ) { + ObjectListIterator i = listIterator( from ); + if ( offset < 0 ) throw new ArrayIndexOutOfBoundsException( "Offset (" + offset + ") is negative" ); + if ( offset + length > a.length ) throw new ArrayIndexOutOfBoundsException( "End index (" + ( offset + length ) + ") is greater than array length (" + a.length + ")" ); + if ( from + length > size() ) throw new IndexOutOfBoundsException( "End index (" + ( from + length ) + ") is greater than list size (" + size() + ")" ); + while( length-- != 0 ) a[ offset++ ] = i.next(); + } + private boolean valEquals( final Object a, final Object b ) { + return a == null ? b == null : a.equals( b ); + } + public boolean equals( final Object o ) { + if ( o == this ) return true; + if ( ! ( o instanceof List ) ) return false; + final List l = (List)o; + int s = size(); + if ( s != l.size() ) return false; + final ListIterator i1 = listIterator(), i2 = l.listIterator(); + while( s-- != 0 ) if ( ! valEquals( i1.next(), i2.next() ) ) return false; + return true; + } + /** Compares this list to another object. If the + * argument is a {@link java.util.List}, this method performs a lexicographical comparison; otherwise, + * it throws a ClassCastException. + * + * @param l a list. + * @return if the argument is a {@link java.util.List}, a negative integer, + * zero, or a positive integer as this list is lexicographically less than, equal + * to, or greater than the argument. + * @throws ClassCastException if the argument is not a list. + */ + @SuppressWarnings("unchecked") + public int compareTo( final List l ) { + if ( l == this ) return 0; + if ( l instanceof ObjectList ) { + final ObjectListIterator i1 = listIterator(), i2 = ((ObjectList )l).listIterator(); + int r; + K e1, e2; + while( i1.hasNext() && i2.hasNext() ) { + e1 = i1.next(); + e2 = i2.next(); + if ( ( r = ( ((Comparable)(e1)).compareTo(e2) ) ) != 0 ) return r; + } + return i2.hasNext() ? -1 : ( i1.hasNext() ? 1 : 0 ); + } + ListIterator i1 = listIterator(), i2 = l.listIterator(); + int r; + while( i1.hasNext() && i2.hasNext() ) { + if ( ( r = ((Comparable)i1.next()).compareTo( i2.next() ) ) != 0 ) return r; + } + return i2.hasNext() ? -1 : ( i1.hasNext() ? 1 : 0 ); + } + /** Returns the hash code for this list, which is identical to {@link java.util.List#hashCode()}. + * + * @return the hash code for this list. + */ + public int hashCode() { + ObjectIterator i = iterator(); + int h = 1, s = size(); + while ( s-- != 0 ) { + K k = i.next(); + h = 31 * h + ( (k) == null ? 0 : (k).hashCode() ); + } + return h; + } + public void push( K o ) { + add( o ); + } + public K pop() { + if ( isEmpty() ) throw new NoSuchElementException(); + return remove( size() - 1 ); + } + public K top() { + if ( isEmpty() ) throw new NoSuchElementException(); + return get( size() - 1 ); + } + public K peek( int i ) { + return get( size() - 1 - i ); + } + public String toString() { + final StringBuilder s = new StringBuilder(); + final ObjectIterator i = iterator(); + int n = size(); + K k; + boolean first = true; + s.append("["); + while( n-- != 0 ) { + if (first) first = false; + else s.append(", "); + k = i.next(); + if (this == k) s.append("(this list)"); else + s.append( String.valueOf( k ) ); + } + s.append("]"); + return s.toString(); + } + public static class ObjectSubList extends AbstractObjectList implements java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + /** The list this sublist restricts. */ + protected final ObjectList l; + /** Initial (inclusive) index of this sublist. */ + protected final int from; + /** Final (exclusive) index of this sublist. */ + protected int to; + private static final boolean ASSERTS = false; + public ObjectSubList( final ObjectList l, final int from, final int to ) { + this.l = l; + this.from = from; + this.to = to; + } + private void assertRange() { + if ( ASSERTS ) { + assert from <= l.size(); + assert to <= l.size(); + assert to >= from; + } + } + public boolean add( final K k ) { + l.add( to, k ); + to++; + if ( ASSERTS ) assertRange(); + return true; + } + public void add( final int index, final K k ) { + ensureIndex( index ); + l.add( from + index, k ); + to++; + if ( ASSERTS ) assertRange(); + } + public boolean addAll( final int index, final Collection c ) { + ensureIndex( index ); + to += c.size(); + if ( ASSERTS ) { + boolean retVal = l.addAll( from + index, c ); + assertRange(); + return retVal; + } + return l.addAll( from + index, c ); + } + public K get( int index ) { + ensureRestrictedIndex( index ); + return l.get( from + index ); + } + public K remove( int index ) { + ensureRestrictedIndex( index ); + to--; + return l.remove( from + index ); + } + public K set( int index, K k ) { + ensureRestrictedIndex( index ); + return l.set( from + index, k ); + } + public void clear() { + removeElements( 0, size() ); + if ( ASSERTS ) assertRange(); + } + public int size() { + return to - from; + } + public void getElements( final int from, final Object[] a, final int offset, final int length ) { + ensureIndex( from ); + if ( from + length > size() ) throw new IndexOutOfBoundsException( "End index (" + from + length + ") is greater than list size (" + size() + ")" ); + l.getElements( this.from + from, a, offset, length ); + } + public void removeElements( final int from, final int to ) { + ensureIndex( from ); + ensureIndex( to ); + l.removeElements( this.from + from, this.from + to ); + this.to -= ( to - from ); + if ( ASSERTS ) assertRange(); + } + public void addElements( int index, final K a[], int offset, int length ) { + ensureIndex( index ); + l.addElements( this.from + index, a, offset, length ); + this.to += length; + if ( ASSERTS ) assertRange(); + } + public ObjectListIterator listIterator( final int index ) { + ensureIndex( index ); + return new AbstractObjectListIterator () { + int pos = index, last = -1; + public boolean hasNext() { return pos < size(); } + public boolean hasPrevious() { return pos > 0; } + public K next() { if ( ! hasNext() ) throw new NoSuchElementException(); return l.get( from + ( last = pos++ ) ); } + public K previous() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return l.get( from + ( last = --pos ) ); } + public int nextIndex() { return pos; } + public int previousIndex() { return pos - 1; } + public void add( K k ) { + if ( last == -1 ) throw new IllegalStateException(); + ObjectSubList.this.add( pos++, k ); + last = -1; + if ( ASSERTS ) assertRange(); + } + public void set( K k ) { + if ( last == -1 ) throw new IllegalStateException(); + ObjectSubList.this.set( last, k ); + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + ObjectSubList.this.remove( last ); + /* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */ + if ( last < pos ) pos--; + last = -1; + if ( ASSERTS ) assertRange(); + } + }; + } + public ObjectList subList( final int from, final int to ) { + ensureIndex( from ); + ensureIndex( to ); + if ( from > to ) throw new IllegalArgumentException( "Start index (" + from + ") is greater than end index (" + to + ")" ); + return new ObjectSubList ( this, from, to ); + } + public boolean remove( final Object o ) { + int index = indexOf( o ); + if ( index == -1 ) return false; + remove( index ); + return true; + } + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectListIterator.java b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectListIterator.java new file mode 100644 index 0000000..b7de919 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectListIterator.java @@ -0,0 +1,87 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +/** An abstract class facilitating the creation of type-specific {@linkplain java.util.ListIterator list iterators}. + * + *

This class provides trivial type-specific implementations of {@link + * java.util.ListIterator#set(Object) set()} and {@link java.util.ListIterator#add(Object) add()} which + * throw an {@link UnsupportedOperationException}. For primitive types, it also + * provides a trivial implementation of {@link java.util.ListIterator#set(Object) set()} and {@link + * java.util.ListIterator#add(Object) add()} that just invokes the type-specific one. + * + * + * @see java.util.ListIterator + */ +public abstract class AbstractObjectListIterator extends AbstractObjectBidirectionalIterator implements ObjectListIterator { + protected AbstractObjectListIterator() {} + /** This method just throws an {@link UnsupportedOperationException}. */ + public void set( K k ) { throw new UnsupportedOperationException(); } + /** This method just throws an {@link UnsupportedOperationException}. */ + public void add( K k ) { throw new UnsupportedOperationException(); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectSet.java b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectSet.java new file mode 100644 index 0000000..7bb6799 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectSet.java @@ -0,0 +1,102 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.Set; +/** An abstract class providing basic methods for sets implementing a type-specific interface. */ +public abstract class AbstractObjectSet extends AbstractObjectCollection implements Cloneable, ObjectSet { + protected AbstractObjectSet() {} + public abstract ObjectIterator iterator(); + public boolean equals( final Object o ) { + if ( o == this ) return true; + if ( !( o instanceof Set ) ) return false; + Set s = (Set) o; + if ( s.size() != size() ) return false; + return containsAll(s); + } + /** Returns a hash code for this set. + * + * The hash code of a set is computed by summing the hash codes of + * its elements. + * + * @return a hash code for this set. + */ + public int hashCode() { + int h = 0, n = size(); + ObjectIterator i = iterator(); + K k; + while( n-- != 0 ) { + k = i.next(); // We need k because KEY2JAVAHASH() is a macro with repeated evaluation. + h += ( (k) == null ? 0 : (k).hashCode() ); + } + return h; + } + public boolean remove( Object k ) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectSortedSet.java b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectSortedSet.java new file mode 100644 index 0000000..6712d6d --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/AbstractObjectSortedSet.java @@ -0,0 +1,79 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2003-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +/** An abstract class providing basic methods for sorted sets implementing a type-specific interface. */ +public abstract class AbstractObjectSortedSet extends AbstractObjectSet implements ObjectSortedSet { + protected AbstractObjectSortedSet() {} + /** Delegates to the new covariantly stronger generic method. */ + @Deprecated + public ObjectBidirectionalIterator objectIterator() { + return iterator(); + } + public abstract ObjectBidirectionalIterator iterator(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectArrayList.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectArrayList.java new file mode 100644 index 0000000..bce9171 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectArrayList.java @@ -0,0 +1,510 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.RandomAccess; +import java.util.NoSuchElementException; +/** A type-specific array-based list; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

This class implements a lightweight, fast, open, optimized, + * reuse-oriented version of array-based lists. Instances of this class + * represent a list with an array that is enlarged as needed when new entries + * are created (by doubling the current length), but is + * never made smaller (even on a {@link #clear()}). A family of + * {@linkplain #trim() trimming methods} lets you control the size of the + * backing array; this is particularly useful if you reuse instances of this class. + * Range checks are equivalent to those of {@link java.util}'s classes, but + * they are delayed as much as possible. + * + *

The backing array is exposed by the {@link #elements()} method. If an instance + * of this class was created {@linkplain #wrap(Object[],int) by wrapping}, + * backing-array reallocations will be performed using reflection, so that + * {@link #elements()} can return an array of the same type of the original array: the comments + * about efficiency made in {@link it.unimi.dsi.fastutil.objects.ObjectArrays} apply here. + * Moreover, you must take into consideration that assignment to an array + * not of type {@code Object[]} is slower due to type checking. + * + *

This class implements the bulk methods removeElements(), + * addElements() and getElements() using + * high-performance system calls (e.g., {@link + * System#arraycopy(Object,int,Object,int,int) System.arraycopy()} instead of + * expensive loops. + * + * @see java.util.ArrayList + */ +public class ObjectArrayList extends AbstractObjectList implements RandomAccess, Cloneable, java.io.Serializable { + private static final long serialVersionUID = -7046029254386353131L; + /** The initial default capacity of an array list. */ + public final static int DEFAULT_INITIAL_CAPACITY = 16; + /** Whether the backing array was passed to wrap(). In + * this case, we must reallocate with the same type of array. */ + protected final boolean wrapped; + /** The backing array. */ + protected transient K a[]; + /** The current actual size of the list (never greater than the backing-array length). */ + protected int size; + private static final boolean ASSERTS = false; + /** Creates a new array list using a given array. + * + *

This constructor is only meant to be used by the wrapping methods. + * + * @param a the array that will be used to back this array list. + */ + @SuppressWarnings("unused") + protected ObjectArrayList( final K a[], boolean dummy ) { + this.a = a; + this.wrapped = true; + } + /** Creates a new array list with given capacity. + * + * @param capacity the initial capacity of the array list (may be 0). + */ + @SuppressWarnings("unchecked") + public ObjectArrayList( final int capacity ) { + if ( capacity < 0 ) throw new IllegalArgumentException( "Initial capacity (" + capacity + ") is negative" ); + a = (K[]) new Object[ capacity ]; + wrapped = false; + } + /** Creates a new array list with {@link #DEFAULT_INITIAL_CAPACITY} capacity. + */ + public ObjectArrayList() { + this( DEFAULT_INITIAL_CAPACITY ); + } + /** Creates a new array list and fills it with a given collection. + * + * @param c a collection that will be used to fill the array list. + */ + public ObjectArrayList( final Collection c ) { + this( c.size() ); + size = ObjectIterators.unwrap( c.iterator(), a ); + } + /** Creates a new array list and fills it with a given type-specific collection. + * + * @param c a type-specific collection that will be used to fill the array list. + */ + public ObjectArrayList( final ObjectCollection c ) { + this( c.size() ); + size = ObjectIterators.unwrap( c.iterator(), a ); + } + /** Creates a new array list and fills it with a given type-specific list. + * + * @param l a type-specific list that will be used to fill the array list. + */ + public ObjectArrayList( final ObjectList l ) { + this( l.size() ); + l.getElements( 0, a, 0, size = l.size() ); + } + /** Creates a new array list and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the array list. + */ + public ObjectArrayList( final K a[] ) { + this( a, 0, a.length ); + } + /** Creates a new array list and fills it with the elements of a given array. + * + * @param a an array whose elements will be used to fill the array list. + * @param offset the first element to use. + * @param length the number of elements to use. + */ + public ObjectArrayList( final K a[], final int offset, final int length ) { + this( length ); + System.arraycopy( a, offset, this.a, 0, length ); + size = length; + } + /** Creates a new array list and fills it with the elements returned by an iterator.. + * + * @param i an iterator whose returned elements will fill the array list. + */ + public ObjectArrayList( final Iterator i ) { + this(); + while( i.hasNext() ) this.add( i.next() ); + } + /** Creates a new array list and fills it with the elements returned by a type-specific iterator.. + * + * @param i a type-specific iterator whose returned elements will fill the array list. + */ + public ObjectArrayList( final ObjectIterator i ) { + this(); + while( i.hasNext() ) this.add( i.next() ); + } + /** Returns the backing array of this list. + * + *

If this array list was created by wrapping a given array, it is guaranteed + * that the type of the returned array will be the same. Otherwise, the returned + * array will be of type {@link Object Object[]} (in spite of the declared return type). + * + *

Warning: This behaviour may cause (unfathomable) + * run-time errors if a method expects an array + * actually of type K[], but this methods returns an array + * of type {@link Object Object[]}. + * + * @return the backing array. + */ + public K[] elements() { + return a; + } + /** Wraps a given array into an array list of given size. + * + *

Note it is guaranteed + * that the type of the array returned by {@link #elements()} will be the same + * (see the comments in the class documentation). + * + * @param a an array to wrap. + * @param length the length of the resulting array list. + * @return a new array list of the given size, wrapping the given array. + */ + public static ObjectArrayList wrap( final K a[], final int length ) { + if ( length > a.length ) throw new IllegalArgumentException( "The specified length (" + length + ") is greater than the array size (" + a.length + ")" ); + final ObjectArrayList l = new ObjectArrayList ( a, false ); + l.size = length; + return l; + } + /** Wraps a given array into an array list. + * + *

Note it is guaranteed + * that the type of the array returned by {@link #elements()} will be the same + * (see the comments in the class documentation). + * + * @param a an array to wrap. + * @return a new array list wrapping the given array. + */ + public static ObjectArrayList wrap( final K a[] ) { + return wrap( a, a.length ); + } + /** Ensures that this array list can contain the given number of entries without resizing. + * + * @param capacity the new minimum capacity for this array list. + */ + @SuppressWarnings("unchecked") + public void ensureCapacity( final int capacity ) { + if ( wrapped ) a = ObjectArrays.ensureCapacity( a, capacity, size ); + else { + if ( capacity > a.length ) { + final Object t[] = new Object[ capacity ]; + System.arraycopy( a, 0, t, 0, size ); + a = (K[])t; + } + } + if ( ASSERTS ) assert size <= a.length; + } + /** Grows this array list, ensuring that it can contain the given number of entries without resizing, + * and in case enlarging it at least by a factor of two. + * + * @param capacity the new minimum capacity for this array list. + */ + @SuppressWarnings("unchecked") + private void grow( final int capacity ) { + if ( wrapped ) a = ObjectArrays.grow( a, capacity, size ); + else { + if ( capacity > a.length ) { + final int newLength = (int)Math.max( Math.min( 2L * a.length, it.unimi.dsi.fastutil.Arrays.MAX_ARRAY_SIZE ), capacity ); + final Object t[] = new Object[ newLength ]; + System.arraycopy( a, 0, t, 0, size ); + a = (K[])t; + } + } + if ( ASSERTS ) assert size <= a.length; + } + public void add( final int index, final K k ) { + ensureIndex( index ); + grow( size + 1 ); + if ( index != size ) System.arraycopy( a, index, a, index + 1, size - index ); + a[ index ] = k; + size++; + if ( ASSERTS ) assert size <= a.length; + } + public boolean add( final K k ) { + grow( size + 1 ); + a[ size++ ] = k; + if ( ASSERTS ) assert size <= a.length; + return true; + } + public K get( final int index ) { + if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" ); + return a[ index ]; + } + public int indexOf( final Object k ) { + for( int i = 0; i < size; i++ ) if ( ( (k) == null ? (a[ i ]) == null : (k).equals(a[ i ]) ) ) return i; + return -1; + } + public int lastIndexOf( final Object k ) { + for( int i = size; i-- != 0; ) if ( ( (k) == null ? (a[ i ]) == null : (k).equals(a[ i ]) ) ) return i; + return -1; + } + public K remove( final int index ) { + if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" ); + final K old = a[ index ]; + size--; + if ( index != size ) System.arraycopy( a, index + 1, a, index, size - index ); + a[ size ] = null; + if ( ASSERTS ) assert size <= a.length; + return old; + } + public boolean rem( final Object k ) { + int index = indexOf( k ); + if ( index == -1 ) return false; + remove( index ); + if ( ASSERTS ) assert size <= a.length; + return true; + } + public boolean remove( final Object o ) { + return rem( o ); + } + public K set( final int index, final K k ) { + if ( index >= size ) throw new IndexOutOfBoundsException( "Index (" + index + ") is greater than or equal to list size (" + size + ")" ); + K old = a[ index ]; + a[ index ] = k; + return old; + } + public void clear() { + Arrays.fill( a, 0, size, null ); + size = 0; + if ( ASSERTS ) assert size <= a.length; + } + public int size() { + return size; + } + public void size( final int size ) { + if ( size > a.length ) ensureCapacity( size ); + if ( size > this.size ) Arrays.fill( a, this.size, size, (null) ); + else Arrays.fill( a, size, this.size, (null) ); + this.size = size; + } + public boolean isEmpty() { + return size == 0; + } + /** Trims this array list so that the capacity is equal to the size. + * + * @see java.util.ArrayList#trimToSize() + */ + public void trim() { + trim( 0 ); + } + /** Trims the backing array if it is too large. + * + * If the current array length is smaller than or equal to + * n, this method does nothing. Otherwise, it trims the + * array length to the maximum between n and {@link #size()}. + * + *

This method is useful when reusing lists. {@linkplain #clear() Clearing a + * list} leaves the array length untouched. If you are reusing a list + * many times, you can call this method with a typical + * size to avoid keeping around a very large array just + * because of a few large transient lists. + * + * @param n the threshold for the trimming. + */ + @SuppressWarnings("unchecked") + public void trim( final int n ) { + // TODO: use Arrays.trim() and preserve type only if necessary + if ( n >= a.length || size == a.length ) return; + final K t[] = (K[]) new Object[ Math.max( n, size ) ]; + System.arraycopy( a, 0, t, 0, size ); + a = t; + if ( ASSERTS ) assert size <= a.length; + } + /** Copies element of this type-specific list into the given array using optimized system calls. + * + * @param from the start index (inclusive). + * @param a the destination array. + * @param offset the offset into the destination array where to store the first element copied. + * @param length the number of elements to be copied. + */ + public void getElements( final int from, final Object[] a, final int offset, final int length ) { + ObjectArrays.ensureOffsetLength( a, offset, length ); + System.arraycopy( this.a, from, a, offset, length ); + } + /** Removes elements of this type-specific list using optimized system calls. + * + * @param from the start index (inclusive). + * @param to the end index (exclusive). + */ + public void removeElements( final int from, final int to ) { + it.unimi.dsi.fastutil.Arrays.ensureFromTo( size, from, to ); + System.arraycopy( a, to, a, from, size - to ); + size -= ( to - from ); + int i = to - from; + while( i-- != 0 ) a[ size + i ] = null; + } + /** Adds elements to this type-specific list using optimized system calls. + * + * @param index the index at which to add elements. + * @param a the array containing the elements. + * @param offset the offset of the first element to add. + * @param length the number of elements to add. + */ + public void addElements( final int index, final K a[], final int offset, final int length ) { + ensureIndex( index ); + ObjectArrays.ensureOffsetLength( a, offset, length ); + grow( size + length ); + System.arraycopy( this.a, index, this.a, index + length, size - index ); + System.arraycopy( a, offset, this.a, index, length ); + size += length; + } + @Override + public boolean removeAll( final Collection c ) { + final Object[] a = this.a; + int j = 0; + for( int i = 0; i < size; i++ ) + if ( ! c.contains( a[ i ] ) ) a[ j++ ] = a[ i ]; + Arrays.fill( a, j, size, null ); + final boolean modified = size != j; + size = j; + return modified; + } + public ObjectListIterator listIterator( final int index ) { + ensureIndex( index ); + return new AbstractObjectListIterator () { + int pos = index, last = -1; + public boolean hasNext() { return pos < size; } + public boolean hasPrevious() { return pos > 0; } + public K next() { if ( ! hasNext() ) throw new NoSuchElementException(); return a[ last = pos++ ]; } + public K previous() { if ( ! hasPrevious() ) throw new NoSuchElementException(); return a[ last = --pos ]; } + public int nextIndex() { return pos; } + public int previousIndex() { return pos - 1; } + public void add( K k ) { + ObjectArrayList.this.add( pos++, k ); + last = -1; + } + public void set( K k ) { + if ( last == -1 ) throw new IllegalStateException(); + ObjectArrayList.this.set( last, k ); + } + public void remove() { + if ( last == -1 ) throw new IllegalStateException(); + ObjectArrayList.this.remove( last ); + /* If the last operation was a next(), we are removing an element *before* us, and we must decrease pos correspondingly. */ + if ( last < pos ) pos--; + last = -1; + } + }; + } + public ObjectArrayList clone() { + ObjectArrayList c = new ObjectArrayList ( size ); + System.arraycopy( a, 0, c.a, 0, size ); + c.size = size; + return c; + } + private boolean valEquals( final K a, final K b ) { + return a == null ? b == null : a.equals( b ); + } + /** Compares this type-specific array list to another one. + * + *

This method exists only for sake of efficiency. The implementation + * inherited from the abstract implementation would already work. + * + * @param l a type-specific array list. + * @return true if the argument contains the same elements of this type-specific array list. + */ + public boolean equals( final ObjectArrayList l ) { + if ( l == this ) return true; + int s = size(); + if ( s != l.size() ) return false; + final K[] a1 = a; + final K[] a2 = l.a; + while( s-- != 0 ) if ( ! valEquals( a1[ s ], a2[ s ] ) ) return false; + return true; + } + /** Compares this array list to another array list. + * + *

This method exists only for sake of efficiency. The implementation + * inherited from the abstract implementation would already work. + * + * @param l an array list. + * @return a negative integer, + * zero, or a positive integer as this list is lexicographically less than, equal + * to, or greater than the argument. + */ + @SuppressWarnings("unchecked") + public int compareTo( final ObjectArrayList l ) { + final int s1 = size(), s2 = l.size(); + final K a1[] = a, a2[] = l.a; + K e1, e2; + int r, i; + for( i = 0; i < s1 && i < s2; i++ ) { + e1 = a1[ i ]; + e2 = a2[ i ]; + if ( ( r = ( ((Comparable)(e1)).compareTo(e2) ) ) != 0 ) return r; + } + return i < s2 ? -1 : ( i < s1 ? 1 : 0 ); + } + private void writeObject( java.io.ObjectOutputStream s ) throws java.io.IOException { + s.defaultWriteObject(); + for( int i = 0; i < size; i++ ) s.writeObject( a[ i ] ); + } + @SuppressWarnings("unchecked") + private void readObject( java.io.ObjectInputStream s ) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + a = (K[]) new Object[ size ]; + for( int i = 0; i < size; i++ ) a[ i ] = (K) s.readObject(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectArraySet.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectArraySet.java new file mode 100644 index 0000000..8b8dd8e --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectArraySet.java @@ -0,0 +1,220 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2007-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.Collection; +import java.util.NoSuchElementException; +/** A simple, brute-force implementation of a set based on a backing array. + * + *

The main purpose of this + * implementation is that of wrapping cleanly the brute-force approach to the storage of a very + * small number of items: just put them into an array and scan linearly to find an item. + */ +public class ObjectArraySet extends AbstractObjectSet implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = 1L; + /** The backing array (valid up to {@link #size}, excluded). */ + private transient Object[] a; + /** The number of valid entries in {@link #a}. */ + private int size; + /** Creates a new array set using the given backing array. The resulting set will have as many elements as the array. + * + *

It is responsibility of the caller that the elements of a are distinct. + * + * @param a the backing array. + */ + public ObjectArraySet( final Object[] a ) { + this.a = a; + size = a.length; + } + /** Creates a new empty array set. + */ + public ObjectArraySet() { + this.a = ObjectArrays.EMPTY_ARRAY; + } + /** Creates a new empty array set of given initial capacity. + * + * @param capacity the initial capacity. + */ + public ObjectArraySet( final int capacity ) { + this.a = new Object[ capacity ]; + } + /** Creates a new array set copying the contents of a given collection. + * @param c a collection. + */ + public ObjectArraySet( ObjectCollection c ) { + this( c.size () ); + addAll( c ); + } + /** Creates a new array set copying the contents of a given set. + * @param c a collection. + */ + public ObjectArraySet( final Collection c ) { + this( c.size() ); + addAll( c ); + } + /** Creates a new array set using the given backing array and the given number of elements of the array. + * + *

It is responsibility of the caller that the first size elements of a are distinct. + * + * @param a the backing array. + * @param size the number of valid elements in a. + */ + public ObjectArraySet( final Object[] a, final int size ) { + this.a = a; + this.size = size; + if ( size > a.length ) throw new IllegalArgumentException( "The provided size (" + size + ") is larger than or equal to the array size (" + a.length + ")" ); + } + private int findKey( final Object o ) { + for( int i = size; i-- != 0; ) if ( ( (a[ i ]) == null ? (o) == null : (a[ i ]).equals(o) ) ) return i; + return -1; + } + @Override + @SuppressWarnings("unchecked") + public ObjectIterator iterator() { + return new AbstractObjectIterator () { + int next = 0; + public boolean hasNext() { + return next < size; + } + public K next() { + if ( ! hasNext() ) throw new NoSuchElementException(); + return (K) a[ next++ ]; + } + public void remove() { + final int tail = size-- - next--; + System.arraycopy( a, next + 1, a, next, tail ); + a[ size ] = null; + } + }; + } + public boolean contains( final Object k ) { + return findKey( k ) != -1; + } + public int size() { + return size; + } + @Override + public boolean remove( final Object k ) { + final int pos = findKey( k ); + if ( pos == -1 ) return false; + final int tail = size - pos - 1; + for( int i = 0; i < tail; i++ ) a[ pos + i ] = a[ pos + i + 1 ]; + size--; + a[ size ] = null; + return true; + } + @Override + public boolean add( final K k ) { + final int pos = findKey( k ); + if ( pos != -1 ) return false; + if ( size == a.length ) { + final Object[] b = new Object[ size == 0 ? 2 : size * 2 ]; + for( int i = size; i-- != 0; ) b[ i ] = a[ i ]; + a = b; + } + a[ size++ ] = k; + return true; + } + @Override + public void clear() { + for( int i = size; i-- != 0; ) a[ i ] = null; + size = 0; + } + @Override + public boolean isEmpty() { + return size == 0; + } + /** Returns a deep copy of this set. + * + *

This method performs a deep copy of this hash set; the data stored in the + * set, however, is not cloned. Note that this makes a difference only for object keys. + * + * @return a deep copy of this set. + */ + @SuppressWarnings("unchecked") + public ObjectArraySet clone() { + ObjectArraySet c; + try { + c = (ObjectArraySet )super.clone(); + } + catch(CloneNotSupportedException cantHappen) { + throw new InternalError(); + } + c.a = a.clone(); + return c; + } + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { + s.defaultWriteObject(); + for( int i = 0; i < size; i++ ) s.writeObject( a[ i ] ); + } + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + a = new Object[ size ]; + for( int i = 0; i < size; i++ ) a[ i ] = s.readObject(); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectArrays.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectArrays.java new file mode 100644 index 0000000..e56a0f8 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectArrays.java @@ -0,0 +1,1594 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * + * + * For the sorting and binary search code: + * + * Copyright (C) 1999 CERN - European Organization for Nuclear Research. + * + * Permission to use, copy, modify, distribute and sell this software and + * its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation. CERN makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without expressed or implied warranty. + */ +package it.unimi.dsi.fastutil.objects; +import it.unimi.dsi.fastutil.Arrays; +import it.unimi.dsi.fastutil.Hash; +import java.util.Random; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.RecursiveAction; +import it.unimi.dsi.fastutil.ints.IntArrays; +import java.util.Comparator; +/** A class providing static methods and objects that do useful things with type-specific arrays. + * + * In particular, the ensureCapacity(), grow(), + * trim() and setLength() methods allow to handle + * arrays much like array lists. This can be very useful when efficiency (or + * syntactic simplicity) reasons make array lists unsuitable. + * + *

Warning: if your array is not of type {@code Object[]}, + * {@link #ensureCapacity(Object[],int,int)} and {@link #grow(Object[],int,int)} + * will use {@linkplain java.lang.reflect.Array#newInstance(Class,int) reflection} + * to preserve your array type. Reflection is significantly slower than using new. + * This phenomenon is particularly + * evident in the first growth phases of an array reallocated with doubling (or similar) logic. + * + *

Sorting

+ * + *

There are several sorting methods available. The main theme is that of letting you choose + * the sorting algorithm you prefer (i.e., trading stability of mergesort for no memory allocation in quicksort). + * Several algorithms provide a parallel version, that will use the {@linkplain Runtime#availableProcessors() number of cores available}. + * + *

All comparison-based algorithm have an implementation based on a type-specific comparator. + * + *

If you are fine with not knowing exactly which algorithm will be run (in particular, not knowing exactly whether a support array will be allocated), + * the dual-pivot parallel sorts in {@link java.util.Arrays} + * are about 50% faster than the classical single-pivot implementation used here. + * + *

In any case, if sorting time is important I suggest that you benchmark your sorting load + * with your data distribution and on your architecture. + * + * @see java.util.Arrays + */ +public class ObjectArrays { + private ObjectArrays() {} + /** A static, final, empty array. */ + public final static Object[] EMPTY_ARRAY = {}; + /** Creates a new array using a the given one as prototype. + * + *

This method returns a new array of the given length whose element + * are of the same class as of those of prototype. In case + * of an empty array, it tries to return {@link #EMPTY_ARRAY}, if possible. + * + * @param prototype an array that will be used to type the new one. + * @param length the length of the new array. + * @return a new array of given type and length. + */ + @SuppressWarnings("unchecked") + private static K[] newArray( final K[] prototype, final int length ) { + final Class klass = prototype.getClass(); + if ( klass == Object[].class ) return (K[])( length == 0 ? EMPTY_ARRAY : new Object[ length ] ); + return (K[])java.lang.reflect.Array.newInstance( klass.getComponentType(), length ); + } + /** Ensures that an array can contain the given number of entries. + * + *

If you cannot foresee whether this array will need again to be + * enlarged, you should probably use grow() instead. + * + * @param array an array. + * @param length the new minimum length for this array. + * @return array, if it contains length entries or more; otherwise, + * an array with length entries whose first array.length + * entries are the same as those of array. + */ + public static K[] ensureCapacity( final K[] array, final int length ) { + if ( length > array.length ) { + final K t[] = + newArray( array, length ); + System.arraycopy( array, 0, t, 0, array.length ); + return t; + } + return array; + } + /** Ensures that an array can contain the given number of entries, preserving just a part of the array. + * + * @param array an array. + * @param length the new minimum length for this array. + * @param preserve the number of elements of the array that must be preserved in case a new allocation is necessary. + * @return array, if it can contain length entries or more; otherwise, + * an array with length entries whose first preserve + * entries are the same as those of array. + */ + public static K[] ensureCapacity( final K[] array, final int length, final int preserve ) { + if ( length > array.length ) { + final K t[] = + newArray( array, length ); + System.arraycopy( array, 0, t, 0, preserve ); + return t; + } + return array; + } + /** Grows the given array to the maximum between the given length and + * the current length multiplied by two, provided that the given + * length is larger than the current length. + * + *

If you want complete control on the array growth, you + * should probably use ensureCapacity() instead. + * + * @param array an array. + * @param length the new minimum length for this array. + * @return array, if it can contain length + * entries; otherwise, an array with + * max(length,array.length/φ) entries whose first + * array.length entries are the same as those of array. + * */ + public static K[] grow( final K[] array, final int length ) { + if ( length > array.length ) { + final int newLength = (int)Math.max( Math.min( 2L * array.length, Arrays.MAX_ARRAY_SIZE ), length ); + final K t[] = + newArray( array, newLength ); + System.arraycopy( array, 0, t, 0, array.length ); + return t; + } + return array; + } + /** Grows the given array to the maximum between the given length and + * the current length multiplied by two, provided that the given + * length is larger than the current length, preserving just a part of the array. + * + *

If you want complete control on the array growth, you + * should probably use ensureCapacity() instead. + * + * @param array an array. + * @param length the new minimum length for this array. + * @param preserve the number of elements of the array that must be preserved in case a new allocation is necessary. + * @return array, if it can contain length + * entries; otherwise, an array with + * max(length,array.length/φ) entries whose first + * preserve entries are the same as those of array. + * */ + public static K[] grow( final K[] array, final int length, final int preserve ) { + if ( length > array.length ) { + final int newLength = (int)Math.max( Math.min( 2L * array.length, Arrays.MAX_ARRAY_SIZE ), length ); + final K t[] = + newArray( array, newLength ); + System.arraycopy( array, 0, t, 0, preserve ); + return t; + } + return array; + } + /** Trims the given array to the given length. + * + * @param array an array. + * @param length the new maximum length for the array. + * @return array, if it contains length + * entries or less; otherwise, an array with + * length entries whose entries are the same as + * the first length entries of array. + * + */ + public static K[] trim( final K[] array, final int length ) { + if ( length >= array.length ) return array; + final K t[] = + newArray( array, length ); + System.arraycopy( array, 0, t, 0, length ); + return t; + } + /** Sets the length of the given array. + * + * @param array an array. + * @param length the new length for the array. + * @return array, if it contains exactly length + * entries; otherwise, if it contains more than + * length entries, an array with length entries + * whose entries are the same as the first length entries of + * array; otherwise, an array with length entries + * whose first array.length entries are the same as those of + * array. + * + */ + public static K[] setLength( final K[] array, final int length ) { + if ( length == array.length ) return array; + if ( length < array.length ) return trim( array, length ); + return ensureCapacity( array, length ); + } + /** Returns a copy of a portion of an array. + * + * @param array an array. + * @param offset the first element to copy. + * @param length the number of elements to copy. + * @return a new array containing length elements of array starting at offset. + */ + public static K[] copy( final K[] array, final int offset, final int length ) { + ensureOffsetLength( array, offset, length ); + final K[] a = + newArray( array, length ); + System.arraycopy( array, offset, a, 0, length ); + return a; + } + /** Returns a copy of an array. + * + * @param array an array. + * @return a copy of array. + */ + public static K[] copy( final K[] array ) { + return array.clone(); + } + /** Fills the given array with the given value. + * + * @param array an array. + * @param value the new value for all elements of the array. + * @deprecated Please use the corresponding {@link java.util.Arrays} method. + */ + @Deprecated + public static void fill( final K[] array, final K value ) { + int i = array.length; + while( i-- != 0 ) array[ i ] = value; + } + /** Fills a portion of the given array with the given value. + * + * @param array an array. + * @param from the starting index of the portion to fill (inclusive). + * @param to the end index of the portion to fill (exclusive). + * @param value the new value for all elements of the specified portion of the array. + * @deprecated Please use the corresponding {@link java.util.Arrays} method. + */ + @Deprecated + public static void fill( final K[] array, final int from, int to, final K value ) { + ensureFromTo( array, from, to ); + if ( from == 0 ) while( to-- != 0 ) array[ to ] = value; + else for( int i = from; i < to; i++ ) array[ i ] = value; + } + /** Returns true if the two arrays are elementwise equal. + * + * @param a1 an array. + * @param a2 another array. + * @return true if the two arrays are of the same length, and their elements are equal. + * @deprecated Please use the corresponding {@link java.util.Arrays} method, which is intrinsified in recent JVMs. + */ + @Deprecated + public static boolean equals( final K[] a1, final K a2[] ) { + int i = a1.length; + if ( i != a2.length ) return false; + while( i-- != 0 ) if (! ( (a1[ i ]) == null ? (a2[ i ]) == null : (a1[ i ]).equals(a2[ i ]) ) ) return false; + return true; + } + /** Ensures that a range given by its first (inclusive) and last (exclusive) elements fits an array. + * + *

This method may be used whenever an array range check is needed. + * + * @param a an array. + * @param from a start index (inclusive). + * @param to an end index (exclusive). + * @throws IllegalArgumentException if from is greater than to. + * @throws ArrayIndexOutOfBoundsException if from or to are greater than the array length or negative. + */ + public static void ensureFromTo( final K[] a, final int from, final int to ) { + Arrays.ensureFromTo( a.length, from, to ); + } + /** Ensures that a range given by an offset and a length fits an array. + * + *

This method may be used whenever an array range check is needed. + * + * @param a an array. + * @param offset a start index. + * @param length a length (the number of elements in the range). + * @throws IllegalArgumentException if length is negative. + * @throws ArrayIndexOutOfBoundsException if offset is negative or offset+length is greater than the array length. + */ + public static void ensureOffsetLength( final K[] a, final int offset, final int length ) { + Arrays.ensureOffsetLength( a.length, offset, length ); + } + /** Ensures that two arrays are of the same length. + * + * @param a an array. + * @param b another array. + * @throws IllegalArgumentException if the two argument arrays are not of the same length. + */ + public static void ensureSameLength( final K[] a, final K[] b ) { + if ( a.length != b.length ) throw new IllegalArgumentException( "Array size mismatch: " + a.length + " != " + b.length ); + } + private static final int QUICKSORT_NO_REC = 16; + private static final int PARALLEL_QUICKSORT_NO_FORK = 8192; + private static final int QUICKSORT_MEDIAN_OF_9 = 128; + private static final int MERGESORT_NO_REC = 16; + /** Swaps two elements of an anrray. + * + * @param x an array. + * @param a a position in {@code x}. + * @param b another position in {@code x}. + */ + public static void swap( final K x[], final int a, final int b ) { + final K t = x[ a ]; + x[ a ] = x[ b ]; + x[ b ] = t; + } + /** Swaps two sequences of elements of an array. + * + * @param x an array. + * @param a a position in {@code x}. + * @param b another position in {@code x}. + * @param n the number of elements to exchange starting at {@code a} and {@code b}. + */ + public static void swap( final K[] x, int a, int b, final int n ) { + for( int i = 0; i < n; i++, a++, b++ ) swap( x, a, b ); + } + private static int med3( final K x[], final int a, final int b, final int c, Comparator comp ) { + final int ab = comp.compare( x[ a ], x[ b ] ); + final int ac = comp.compare( x[ a ], x[ c ] ); + final int bc = comp.compare( x[ b ], x[ c ] ); + return ( ab < 0 ? + ( bc < 0 ? b : ac < 0 ? c : a ) : + ( bc > 0 ? b : ac > 0 ? c : a ) ); + } + private static void selectionSort( final K[] a, final int from, final int to, final Comparator comp ) { + for( int i = from; i < to - 1; i++ ) { + int m = i; + for( int j = i + 1; j < to; j++ ) if ( comp.compare( a[ j ], a[ m ] ) < 0 ) m = j; + if ( m != i ) { + final K u = a[ i ]; + a[ i ] = a[ m ]; + a[ m ] = u; + } + } + } + private static void insertionSort( final K[] a, final int from, final int to, final Comparator comp ) { + for ( int i = from; ++i < to; ) { + K t = a[ i ]; + int j = i; + for ( K u = a[ j - 1 ]; comp.compare( t, u ) < 0; u = a[ --j - 1 ] ) { + a[ j ] = u; + if ( from == j - 1 ) { + --j; + break; + } + } + a[ j ] = t; + } + } + /** Sorts the specified range of elements according to the order induced by the specified + * comparator using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param comp the comparator to determine the sorting order. + * + */ + public static void quickSort( final K[] x, final int from, final int to, final Comparator comp ) { + final int len = to - from; + // Selection sort on smallest arrays + if ( len < QUICKSORT_NO_REC ) { + selectionSort( x, from, to, comp ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9 + int s = len / 8; + l = med3( x, l, l + s, l + 2 * s, comp ); + m = med3( x, m - s, m, m + s, comp ); + n = med3( x, n - 2 * s, n - s, n, comp ); + } + m = med3( x, l, m, n, comp ); // Mid-size, med of 3 + final K v = x[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while( true ) { + int comparison; + while ( b <= c && ( comparison = comp.compare( x[ b ], v ) ) <= 0 ) { + if ( comparison == 0 ) swap( x, a++, b ); + b++; + } + while ( c >= b && ( comparison = comp.compare( x[ c ], v ) ) >=0 ) { + if ( comparison == 0 ) swap( x, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, b++, c-- ); + } + // Swap partition elements back to middle + int s; + s = Math.min( a - from, b - a ); + swap( x, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, b, to - s, s ); + // Recursively sort non-partition-elements + if ( ( s = b - a ) > 1 ) quickSort( x, from, from + s, comp ); + if ( ( s = d - c ) > 1 ) quickSort( x, to - s, to, comp ); + } + /** Sorts an array 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. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param x the array to be sorted. + * @param comp the comparator to determine the sorting order. + * + */ + public static void quickSort( final K[] x, final Comparator comp ) { + quickSort( x, 0, x.length, comp ); + } + protected static class ForkJoinQuickSortComp extends RecursiveAction { + private static final long serialVersionUID = 1L; + private final int from; + private final int to; + private final K[] x; + private final Comparator comp; + public ForkJoinQuickSortComp( final K[] x , final int from , final int to, final Comparator comp ) { + this.from = from; + this.to = to; + this.x = x; + this.comp = comp; + } + @Override + protected void compute() { + final K[] x = this.x; + final int len = to - from; + if ( len < PARALLEL_QUICKSORT_NO_FORK ) { + quickSort( x, from, to, comp ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + int s = len / 8; + l = med3( x, l, l + s, l + 2 * s ); + m = med3( x, m - s, m, m + s ); + n = med3( x, n - 2 * s, n - s, n ); + m = med3( x, l, m, n ); + final K v = x[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison; + while ( b <= c && ( comparison = comp.compare( x[ b ], v ) ) <= 0 ) { + if ( comparison == 0 ) swap( x, a++, b ); + b++; + } + while ( c >= b && ( comparison = comp.compare( x[ c ], v ) ) >= 0 ) { + if ( comparison == 0 ) swap( x, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, b++, c-- ); + } + // Swap partition elements back to middle + int t; + s = Math.min( a - from, b - a ); + swap( x, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, b, to - s, s ); + // Recursively sort non-partition-elements + s = b - a; + t = d - c; + if ( s > 1 && t > 1 ) invokeAll( new ForkJoinQuickSortComp ( x, from, from + s, comp ), new ForkJoinQuickSortComp ( x, to - t, to, comp ) ); + else if ( s > 1 ) invokeAll( new ForkJoinQuickSortComp ( x, from, from + s, comp ) ); + else invokeAll( new ForkJoinQuickSortComp ( x, to - t, to, comp ) ); + } + } + /** Sorts the specified range of elements according to the order induced by the specified + * comparator using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param comp the comparator to determine the sorting order. + */ + public static void parallelQuickSort( final K[] x, final int from, final int to, final Comparator comp ) { + if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSort( x, from, to, comp ); + else { + final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() ); + pool.invoke( new ForkJoinQuickSortComp ( x, from, to, comp ) ); + pool.shutdown(); + } + } + /** Sorts an array according to the order induced by the specified + * comparator using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the array to be sorted. + * @param comp the comparator to determine the sorting order. + */ + public static void parallelQuickSort( final K[] x, final Comparator comp ) { + parallelQuickSort( x, 0, x.length, comp ); + } + @SuppressWarnings("unchecked") + private static int med3( final K x[], final int a, final int b, final int c ) { + final int ab = ( ((Comparable)(x[ a ])).compareTo(x[ b ]) ); + final int ac = ( ((Comparable)(x[ a ])).compareTo(x[ c ]) ); + final int bc = ( ((Comparable)(x[ b ])).compareTo(x[ c ]) ); + return ( ab < 0 ? + ( bc < 0 ? b : ac < 0 ? c : a ) : + ( bc > 0 ? b : ac > 0 ? c : a ) ); + } + @SuppressWarnings("unchecked") + private static void selectionSort( final K[] a, final int from, final int to ) { + for( int i = from; i < to - 1; i++ ) { + int m = i; + for( int j = i + 1; j < to; j++ ) if ( ( ((Comparable)(a[ j ])).compareTo(a[ m ]) < 0 ) ) m = j; + if ( m != i ) { + final K u = a[ i ]; + a[ i ] = a[ m ]; + a[ m ] = u; + } + } + } + @SuppressWarnings("unchecked") + private static void insertionSort( final K[] a, final int from, final int to ) { + for ( int i = from; ++i < to; ) { + K t = a[ i ]; + int j = i; + for ( K u = a[ j - 1 ]; ( ((Comparable)(t)).compareTo(u) < 0 ); u = a[ --j - 1 ] ) { + a[ j ] = u; + if ( from == j - 1 ) { + --j; + break; + } + } + a[ j ] = t; + } + } + /** Sorts the specified range of elements according to the natural ascending order using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + @SuppressWarnings("unchecked") + public static void quickSort( final K[] x, final int from, final int to ) { + final int len = to - from; + // Selection sort on smallest arrays + if ( len < QUICKSORT_NO_REC ) { + selectionSort( x, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9 + int s = len / 8; + l = med3( x, l, l + s, l + 2 * s ); + m = med3( x, m - s, m, m + s ); + n = med3( x, n - 2 * s, n - s, n ); + } + m = med3( x, l, m, n ); // Mid-size, med of 3 + final K v = x[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while(true) { + int comparison; + while ( b <= c && ( comparison = ( ((Comparable)(x[ b ])).compareTo(v) ) ) <= 0 ) { + if ( comparison == 0 ) swap( x, a++, b ); + b++; + } + while (c >= b && ( comparison = ( ((Comparable)(x[ c ])).compareTo(v) ) ) >=0 ) { + if ( comparison == 0 ) swap( x, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, b++, c-- ); + } + // Swap partition elements back to middle + int s; + s = Math.min( a - from, b - a ); + swap( x, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, b, to - s, s ); + // Recursively sort non-partition-elements + if ( ( s = b - a ) > 1 ) quickSort( x, from, from + s ); + if ( ( s = d - c ) > 1 ) quickSort( x, to - s, to ); + } + /** Sorts an array according to the natural ascending order using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param x the array to be sorted. + * + */ + public static void quickSort( final K[] x ) { + quickSort( x, 0, x.length ); + } + protected static class ForkJoinQuickSort extends RecursiveAction { + private static final long serialVersionUID = 1L; + private final int from; + private final int to; + private final K[] x; + public ForkJoinQuickSort( final K[] x , final int from , final int to ) { + this.from = from; + this.to = to; + this.x = x; + } + @Override + @SuppressWarnings("unchecked") + protected void compute() { + final K[] x = this.x; + final int len = to - from; + if ( len < PARALLEL_QUICKSORT_NO_FORK ) { + quickSort( x, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + int s = len / 8; + l = med3( x, l, l + s, l + 2 * s ); + m = med3( x, m - s, m, m + s ); + n = med3( x, n - 2 * s, n - s, n ); + m = med3( x, l, m, n ); + final K v = x[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison; + while ( b <= c && ( comparison = ( ((Comparable)(x[ b ])).compareTo(v) ) ) <= 0 ) { + if ( comparison == 0 ) swap( x, a++, b ); + b++; + } + while ( c >= b && ( comparison = ( ((Comparable)(x[ c ])).compareTo(v) ) ) >= 0 ) { + if ( comparison == 0 ) swap( x, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, b++, c-- ); + } + // Swap partition elements back to middle + int t; + s = Math.min( a - from, b - a ); + swap( x, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, b, to - s, s ); + // Recursively sort non-partition-elements + s = b - a; + t = d - c; + if ( s > 1 && t > 1 ) invokeAll( new ForkJoinQuickSort ( x, from, from + s ), new ForkJoinQuickSort ( x, to - t, to ) ); + else if ( s > 1 ) invokeAll( new ForkJoinQuickSort ( x, from, from + s ) ); + else invokeAll( new ForkJoinQuickSort ( x, to - t, to ) ); + } + } + /** Sorts the specified range of elements according to the natural ascending order using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void parallelQuickSort( final K[] x, final int from, final int to ) { + if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSort( x, from, to ); + else { + final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() ); + pool.invoke( new ForkJoinQuickSort ( x, from, to ) ); + pool.shutdown(); + } + } + /** Sorts an array according to the natural ascending order using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the array to be sorted. + * + */ + public static void parallelQuickSort( final K[] x ) { + parallelQuickSort( x, 0, x.length ); + } + @SuppressWarnings("unchecked") + private static int med3Indirect( final int perm[], final K x[], final int a, final int b, final int c ) { + final K aa = x[ perm[ a ] ]; + final K bb = x[ perm[ b ] ]; + final K cc = x[ perm[ c ] ]; + final int ab = ( ((Comparable)(aa)).compareTo(bb) ); + final int ac = ( ((Comparable)(aa)).compareTo(cc) ); + final int bc = ( ((Comparable)(bb)).compareTo(cc) ); + return ( ab < 0 ? + ( bc < 0 ? b : ac < 0 ? c : a ) : + ( bc > 0 ? b : ac > 0 ? c : a ) ); + } + @SuppressWarnings("unchecked") + private static void insertionSortIndirect( final int[] perm, final K[] a, final int from, final int to ) { + for ( int i = from; ++i < to; ) { + int t = perm[ i ]; + int j = i; + for ( int u = perm[ j - 1 ]; ( ((Comparable)(a[ t ])).compareTo(a[ u ]) < 0 ); u = perm[ --j - 1 ] ) { + perm[ j ] = u; + if ( from == j - 1 ) { + --j; + break; + } + } + perm[ j ] = t; + } + } + /** Sorts the specified range of elements according to the natural ascending order using indirect quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param perm a permutation array indexing {@code x}. + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + @SuppressWarnings("unchecked") + public static void quickSortIndirect( final int[] perm, final K[] x, final int from, final int to ) { + final int len = to - from; + // Selection sort on smallest arrays + if ( len < QUICKSORT_NO_REC ) { + insertionSortIndirect( perm, x, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9 + int s = len / 8; + l = med3Indirect( perm, x, l, l + s, l + 2 * s ); + m = med3Indirect( perm, x, m - s, m, m + s ); + n = med3Indirect( perm, x, n - 2 * s, n - s, n ); + } + m = med3Indirect( perm, x, l, m, n ); // Mid-size, med of 3 + final K v = x[ perm[ m ] ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while(true) { + int comparison; + while ( b <= c && ( comparison = ( ((Comparable)(x[ perm[ b ] ])).compareTo(v) ) ) <= 0 ) { + if ( comparison == 0 ) IntArrays.swap( perm, a++, b ); + b++; + } + while (c >= b && ( comparison = ( ((Comparable)(x[ perm[ c ] ])).compareTo(v) ) ) >=0 ) { + if ( comparison == 0 ) IntArrays.swap( perm, c, d-- ); + c--; + } + if ( b > c ) break; + IntArrays.swap( perm, b++, c-- ); + } + // Swap partition elements back to middle + int s; + s = Math.min( a - from, b - a ); + IntArrays.swap( perm, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + IntArrays.swap( perm, b, to - s, s ); + // Recursively sort non-partition-elements + if ( ( s = b - a ) > 1 ) quickSortIndirect( perm, x, from, from + s ); + if ( ( s = d - c ) > 1 ) quickSortIndirect( perm, x, to - s, to ); + } + /** Sorts an array according to the natural ascending order using indirect quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]. + * + *

Note that this implementation does not allocate any object, contrarily to the implementation + * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs. + * + * @param perm a permutation array indexing {@code x}. + * @param x the array to be sorted. + */ + public static void quickSortIndirect( final int perm[], final K[] x ) { + quickSortIndirect( perm, x, 0, x.length ); + } + protected static class ForkJoinQuickSortIndirect extends RecursiveAction { + private static final long serialVersionUID = 1L; + private final int from; + private final int to; + private final int[] perm; + private final K[] x; + public ForkJoinQuickSortIndirect( final int perm[], final K[] x , final int from , final int to ) { + this.from = from; + this.to = to; + this.x = x; + this.perm = perm; + } + @Override + @SuppressWarnings("unchecked") + protected void compute() { + final K[] x = this.x; + final int len = to - from; + if ( len < PARALLEL_QUICKSORT_NO_FORK ) { + quickSortIndirect( perm, x, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + int s = len / 8; + l = med3Indirect( perm, x, l, l + s, l + 2 * s ); + m = med3Indirect( perm, x, m - s, m, m + s ); + n = med3Indirect( perm, x, n - 2 * s, n - s, n ); + m = med3Indirect( perm, x, l, m, n ); + final K v = x[ perm[ m ] ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison; + while ( b <= c && ( comparison = ( ((Comparable)(x[ perm[ b ] ])).compareTo(v) ) ) <= 0 ) { + if ( comparison == 0 ) IntArrays.swap( perm, a++, b ); + b++; + } + while ( c >= b && ( comparison = ( ((Comparable)(x[ perm[ c ] ])).compareTo(v) ) ) >= 0 ) { + if ( comparison == 0 ) IntArrays.swap( perm, c, d-- ); + c--; + } + if ( b > c ) break; + IntArrays.swap( perm, b++, c-- ); + } + // Swap partition elements back to middle + int t; + s = Math.min( a - from, b - a ); + IntArrays.swap( perm, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + IntArrays.swap( perm, b, to - s, s ); + // Recursively sort non-partition-elements + s = b - a; + t = d - c; + if ( s > 1 && t > 1 ) invokeAll( new ForkJoinQuickSortIndirect ( perm, x, from, from + s ), new ForkJoinQuickSortIndirect ( perm, x, to - t, to ) ); + else if ( s > 1 ) invokeAll( new ForkJoinQuickSortIndirect ( perm, x, from, from + s ) ); + else invokeAll( new ForkJoinQuickSortIndirect ( perm, x, to - t, to ) ); + } + } + /** Sorts the specified range of elements according to the natural ascending order using a parallel indirect quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param perm a permutation array indexing {@code x}. + * @param x the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void parallelQuickSortIndirect( final int[] perm, final K[] x, final int from, final int to ) { + if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSortIndirect( perm, x, from, to ); + else { + final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() ); + pool.invoke( new ForkJoinQuickSortIndirect ( perm, x, from, to ) ); + pool.shutdown(); + } + } + /** Sorts an array according to the natural ascending order using a parallel indirect quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implement an indirect sort. The elements of perm (which must + * be exactly the numbers in the interval [0..perm.length)) will be permuted so that + * x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ]. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param perm a permutation array indexing {@code x}. + * @param x the array to be sorted. + * + */ + public static void parallelQuickSortIndirect( final int perm[], final K[] x ) { + parallelQuickSortIndirect( perm, x, 0, x.length ); + } + /** Stabilizes a permutation. + * + *

This method can be used to stabilize the permutation generated by an indirect sorting, assuming that + * initially the permutation array was in ascending order (e.g., the identity, as usually happens). This method + * scans the permutation, and for each non-singleton block of elements with the same associated values in {@code x}, + * permutes them in ascending order. The resulting permutation corresponds to a stable sort. + * + *

Usually combining an unstable indirect sort and this method is more efficient than using a stable sort, + * as most stable sort algorithms require a support array. + * + *

More precisely, assuming that x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ], after + * stabilization we will also have that x[ perm[ i ] ] = x[ perm[ i + 1 ] ] implies + * perm[ i ] ≤ perm[ i + 1 ]. + * + * @param perm a permutation array indexing {@code x} so that it is sorted. + * @param x the sorted array to be stabilized. + * @param from the index of the first element (inclusive) to be stabilized. + * @param to the index of the last element (exclusive) to be stabilized. + */ + public static void stabilize( final int perm[], final K[] x, final int from, final int to ) { + int curr = from; + for( int i = from + 1; i < to; i++ ) { + if ( x[ perm[ i ] ] != x[ perm[ curr ] ] ) { + if ( i - curr > 1 ) IntArrays.parallelQuickSort( perm, curr, i ); + curr = i; + } + } + if ( to - curr > 1 ) IntArrays.parallelQuickSort( perm, curr, to ); + } + /** Stabilizes a permutation. + * + *

This method can be used to stabilize the permutation generated by an indirect sorting, assuming that + * initially the permutation array was in ascending order (e.g., the identity, as usually happens). This method + * scans the permutation, and for each non-singleton block of elements with the same associated values in {@code x}, + * permutes them in ascending order. The resulting permutation corresponds to a stable sort. + * + *

Usually combining an unstable indirect sort and this method is more efficient than using a stable sort, + * as most stable sort algorithms require a support array. + * + *

More precisely, assuming that x[ perm[ i ] ] ≤ x[ perm[ i + 1 ] ], after + * stabilization we will also have that x[ perm[ i ] ] = x[ perm[ i + 1 ] ] implies + * perm[ i ] ≤ perm[ i + 1 ]. + * + * @param perm a permutation array indexing {@code x} so that it is sorted. + * @param x the sorted array to be stabilized. + */ + public static void stabilize( final int perm[], final K[] x ) { + stabilize( perm, x, 0, perm.length ); + } + @SuppressWarnings("unchecked") + private static int med3( final K x[], final K[] y, final int a, final int b, final int c ) { + int t; + final int ab = ( t = ( ((Comparable)(x[ a ])).compareTo(x[ b ]) ) ) == 0 ? ( ((Comparable)(y[ a ])).compareTo(y[ b ]) ) : t; + final int ac = ( t = ( ((Comparable)(x[ a ])).compareTo(x[ c ]) ) ) == 0 ? ( ((Comparable)(y[ a ])).compareTo(y[ c ]) ) : t; + final int bc = ( t = ( ((Comparable)(x[ b ])).compareTo(x[ c ]) ) ) == 0 ? ( ((Comparable)(y[ b ])).compareTo(y[ c ]) ) : t; + return ( ab < 0 ? + ( bc < 0 ? b : ac < 0 ? c : a ) : + ( bc > 0 ? b : ac > 0 ? c : a ) ); + } + private static void swap( final K x[], final K[] y, final int a, final int b ) { + final K t = x[ a ]; + final K u = y[ a ]; + x[ a ] = x[ b ]; + y[ a ] = y[ b ]; + x[ b ] = t; + y[ b ] = u; + } + private static void swap( final K[] x, final K[] y, int a, int b, final int n ) { + for ( int i = 0; i < n; i++, a++, b++ ) swap( x, y, a, b ); + } + @SuppressWarnings("unchecked") + private static void selectionSort( final K[] a, final K[] b, final int from, final int to ) { + for( int i = from; i < to - 1; i++ ) { + int m = i, u; + for( int j = i + 1; j < to; j++ ) + if ( ( u = ( ((Comparable)(a[ j ])).compareTo(a[ m ]) ) ) < 0 || u == 0 && ( ((Comparable)(b[ j ])).compareTo(b[ m ]) < 0 ) ) m = j; + if ( m != i ) { + K t = a[ i ]; + a[ i ] = a[ m ]; + a[ m ] = t; + t = b[ i ]; + b[ i ] = b[ m ]; + b[ m ] = t; + } + } + } + /** Sorts the specified range of elements of two arrays according to the natural lexicographical + * ascending order using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implements a lexicographical sorting of the arguments. Pairs of + * elements in the same position in the two provided arrays will be considered a single key, and + * permuted accordingly. In the end, either x[ i ] < x[ i + 1 ] or x[ i ] + * == x[ i + 1 ] and y[ i ] ≤ y[ i + 1 ]. + * + * @param x the first array to be sorted. + * @param y the second array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + @SuppressWarnings("unchecked") + public static void quickSort( final K[] x, final K[] y, final int from, final int to ) { + final int len = to - from; + if ( len < QUICKSORT_NO_REC ) { + selectionSort( x, y, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + if ( len > QUICKSORT_MEDIAN_OF_9 ) { // Big arrays, pseudomedian of 9 + int s = len / 8; + l = med3( x, y, l, l + s, l + 2 * s ); + m = med3( x, y, m - s, m, m + s ); + n = med3( x, y, n - 2 * s, n - s, n ); + } + m = med3( x, y, l, m, n ); // Mid-size, med of 3 + final K v = x[ m ], w = y[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison, t; + while ( b <= c && ( comparison = ( t = ( ((Comparable)(x[ b ])).compareTo(v) ) ) == 0 ? ( ((Comparable)(y[ b ])).compareTo(w) ) : t ) <= 0 ) { + if ( comparison == 0 ) swap( x, y, a++, b ); + b++; + } + while ( c >= b && ( comparison = ( t = ( ((Comparable)(x[ c ])).compareTo(v) ) ) == 0 ? ( ((Comparable)(y[ c ])).compareTo(w) ) : t ) >= 0 ) { + if ( comparison == 0 ) swap( x, y, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, y, b++, c-- ); + } + // Swap partition elements back to middle + int s; + s = Math.min( a - from, b - a ); + swap( x, y, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, y, b, to - s, s ); + // Recursively sort non-partition-elements + if ( ( s = b - a ) > 1 ) quickSort( x, y, from, from + s ); + if ( ( s = d - c ) > 1 ) quickSort( x, y, to - s, to ); + } + /** Sorts two arrays according to the natural lexicographical ascending order using quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implements a lexicographical sorting of the arguments. Pairs of + * elements in the same position in the two provided arrays will be considered a single key, and + * permuted accordingly. In the end, either x[ i ] < x[ i + 1 ] or x[ i ] + * == x[ i + 1 ] and y[ i ] ≤ y[ i + 1 ]. + * + * @param x the first array to be sorted. + * @param y the second array to be sorted. + */ + public static void quickSort( final K[] x, final K[] y ) { + ensureSameLength( x, y ); + quickSort( x, y, 0, x.length ); + } + protected static class ForkJoinQuickSort2 extends RecursiveAction { + private static final long serialVersionUID = 1L; + private final int from; + private final int to; + private final K[] x, y; + public ForkJoinQuickSort2( final K[] x, final K[] y, final int from , final int to ) { + this.from = from; + this.to = to; + this.x = x; + this.y = y; + } + @Override + @SuppressWarnings("unchecked") + protected void compute() { + final K[] x = this.x; + final K[] y = this.y; + final int len = to - from; + if ( len < PARALLEL_QUICKSORT_NO_FORK ) { + quickSort( x, y, from, to ); + return; + } + // Choose a partition element, v + int m = from + len / 2; + int l = from; + int n = to - 1; + int s = len / 8; + l = med3( x, y, l, l + s, l + 2 * s ); + m = med3( x, y, m - s, m, m + s ); + n = med3( x, y, n - 2 * s, n - s, n ); + m = med3( x, y, l, m, n ); + final K v = x[ m ], w = y[ m ]; + // Establish Invariant: v* (v)* v* + int a = from, b = a, c = to - 1, d = c; + while ( true ) { + int comparison, t; + while ( b <= c && ( comparison = ( t = ( ((Comparable)(x[ b ])).compareTo(v) ) ) == 0 ? ( ((Comparable)(y[ b ])).compareTo(w) ) : t ) <= 0 ) { + if ( comparison == 0 ) swap( x, y, a++, b ); + b++; + } + while ( c >= b && ( comparison = ( t = ( ((Comparable)(x[ c ])).compareTo(v) ) ) == 0 ? ( ((Comparable)(y[ c ])).compareTo(w) ) : t ) >= 0 ) { + if ( comparison == 0 ) swap( x, y, c, d-- ); + c--; + } + if ( b > c ) break; + swap( x, y, b++, c-- ); + } + // Swap partition elements back to middle + int t; + s = Math.min( a - from, b - a ); + swap( x, y, from, b - s, s ); + s = Math.min( d - c, to - d - 1 ); + swap( x, y, b, to - s, s ); + s = b - a; + t = d - c; + // Recursively sort non-partition-elements + if ( s > 1 && t > 1 ) invokeAll( new ForkJoinQuickSort2 ( x, y, from, from + s ), new ForkJoinQuickSort2 ( x, y, to - t, to ) ); + else if ( s > 1 ) invokeAll( new ForkJoinQuickSort2 ( x, y, from, from + s ) ); + else invokeAll( new ForkJoinQuickSort2 ( x, y, to - t, to ) ); + } + } + /** Sorts the specified range of elements of two arrays according to the natural lexicographical + * ascending order using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implements a lexicographical sorting of the arguments. Pairs of + * elements in the same position in the two provided arrays will be considered a single key, and + * permuted accordingly. In the end, either x[ i ] < x[ i + 1 ] or x[ i ] + * == x[ i + 1 ] and y[ i ] ≤ y[ i + 1 ]. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the first array to be sorted. + * @param y the second array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void parallelQuickSort( final K[] x, final K[] y, final int from, final int to ) { + if ( to - from < PARALLEL_QUICKSORT_NO_FORK ) quickSort( x, y, from, to ); + final ForkJoinPool pool = new ForkJoinPool( Runtime.getRuntime().availableProcessors() ); + pool.invoke( new ForkJoinQuickSort2 ( x, y, from, to ) ); + pool.shutdown(); + } + /** Sorts two arrays according to the natural lexicographical + * ascending order using a parallel quicksort. + * + *

The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas + * McIlroy, “Engineering a Sort Function”, Software: Practice and Experience, 23(11), pages + * 1249−1265, 1993. + * + *

This method implements a lexicographical sorting of the arguments. Pairs of + * elements in the same position in the two provided arrays will be considered a single key, and + * permuted accordingly. In the end, either x[ i ] < x[ i + 1 ] or x[ i ] + * == x[ i + 1 ] and y[ i ] ≤ y[ i + 1 ]. + * + *

This implementation uses a {@link ForkJoinPool} executor service with + * {@link Runtime#availableProcessors()} parallel threads. + * + * @param x the first array to be sorted. + * @param y the second array to be sorted. + */ + public static void parallelQuickSort( final K[] x, final K[] y ) { + ensureSameLength( x, y ); + parallelQuickSort( x, y, 0, x.length ); + } + /** Sorts the specified range of elements according to the natural ascending order using mergesort, using a given pre-filled support array. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. Moreover, no support arrays will be allocated. + + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param supp a support array containing at least to elements, and whose entries are identical to those + * of {@code a} in the specified range. + */ + @SuppressWarnings("unchecked") + public static void mergeSort( final K a[], final int from, final int to, final K supp[] ) { + int len = to - from; + // Insertion sort on smallest arrays + if ( len < MERGESORT_NO_REC ) { + insertionSort( a, from, to ); + return; + } + // Recursively sort halves of a into supp + final int mid = ( from + to ) >>> 1; + mergeSort( supp, from, mid, a ); + mergeSort( supp, mid, to, a ); + // If list is already sorted, just copy from supp to a. This is an + // optimization that results in faster sorts for nearly ordered lists. + if ( ( ((Comparable)(supp[ mid - 1 ])).compareTo(supp[ mid ]) <= 0 ) ) { + System.arraycopy( supp, from, a, from, len ); + return; + } + // Merge sorted halves (now in supp) into a + for( int i = from, p = from, q = mid; i < to; i++ ) { + if ( q >= to || p < mid && ( ((Comparable)(supp[ p ])).compareTo(supp[ q ]) <= 0 ) ) a[ i ] = supp[ p++ ]; + else a[ i ] = supp[ q++ ]; + } + } + /** Sorts the specified range of elements according to the natural ascending order using mergesort. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. An array as large as a will be allocated by this method. + + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + */ + public static void mergeSort( final K a[], final int from, final int to ) { + mergeSort( a, from, to, a.clone() ); + } + /** Sorts an array according to the natural ascending order using mergesort. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. An array as large as a will be allocated by this method. + + * @param a the array to be sorted. + */ + public static void mergeSort( final K a[] ) { + mergeSort( a, 0, a.length ); + } + /** Sorts the specified range of elements according to the order induced by the specified + * comparator using mergesort, using a given pre-filled support array. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. Moreover, no support arrays will be allocated. + + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param comp the comparator to determine the sorting order. + * @param supp a support array containing at least to elements, and whose entries are identical to those + * of {@code a} in the specified range. + */ + public static void mergeSort( final K a[], final int from, final int to, Comparator comp, final K supp[] ) { + int len = to - from; + // Insertion sort on smallest arrays + if ( len < MERGESORT_NO_REC ) { + insertionSort( a, from, to, comp ); + return; + } + // Recursively sort halves of a into supp + final int mid = ( from + to ) >>> 1; + mergeSort( supp, from, mid, comp, a ); + mergeSort( supp, mid, to, comp, a ); + // If list is already sorted, just copy from supp to a. This is an + // optimization that results in faster sorts for nearly ordered lists. + if ( comp.compare( supp[ mid - 1 ], supp[ mid ] ) <= 0 ) { + System.arraycopy( supp, from, a, from, len ); + return; + } + // Merge sorted halves (now in supp) into a + for( int i = from, p = from, q = mid; i < to; i++ ) { + if ( q >= to || p < mid && comp.compare( supp[ p ], supp[ q ] ) <= 0 ) a[ i ] = supp[ p++ ]; + else a[ i ] = supp[ q++ ]; + } + } + /** Sorts the specified range of elements according to the order induced by the specified + * comparator using mergesort. + * + *

This sort is guaranteed to be stable: equal elements will not be reordered as a result + * of the sort. An array as large as a will be allocated by this method. + * + * @param a the array to be sorted. + * @param from the index of the first element (inclusive) to be sorted. + * @param to the index of the last element (exclusive) to be sorted. + * @param comp the comparator to determine the sorting order. + */ + public static void mergeSort( final K a[], final int from, final int to, Comparator comp ) { + mergeSort( a, from, to, comp, a.clone() ); + } + /** Sorts an array 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. An array as large as a will be allocated by this method. + + * @param a the array to be sorted. + * @param comp the comparator to determine the sorting order. + */ + public static void mergeSort( final K a[], Comparator comp ) { + mergeSort( a, 0, a.length, comp ); + } + /** + * Searches a range of the specified array for the specified value using + * the binary search algorithm. The range must be sorted prior to making this call. + * If it is not sorted, the results are undefined. If the range contains multiple elements with + * the specified value, there is no guarantee which one will be found. + * + * @param a the array to be searched. + * @param from the index of the first element (inclusive) to be searched. + * @param to the index of the last element (exclusive) to be searched. + * @param key the value to be searched for. + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The insertion + * point is defined as the the point at which the value would + * be inserted into the array: the index of the first + * element greater than the key, or the length of the array, if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be ≥ 0 if + * and only if the key is found. + * @see java.util.Arrays + */ + @SuppressWarnings("unchecked") + public static int binarySearch( final K[] a, int from, int to, final K key ) { + K midVal; + to--; + while (from <= to) { + final int mid = (from + to) >>> 1; + midVal = a[ mid ]; + final int cmp = ((Comparable )midVal).compareTo( key ); + if ( cmp < 0 ) from = mid + 1; + else if (cmp > 0) to = mid - 1; + else return mid; + } + return -( from + 1 ); + } + /** + * Searches an array for the specified value using + * the binary search algorithm. The range must be sorted prior to making this call. + * If it is not sorted, the results are undefined. If the range contains multiple elements with + * the specified value, there is no guarantee which one will be found. + * + * @param a the array to be searched. + * @param key the value to be searched for. + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The insertion + * point is defined as the the point at which the value would + * be inserted into the array: the index of the first + * element greater than the key, or the length of the array, if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be ≥ 0 if + * and only if the key is found. + * @see java.util.Arrays + */ + public static int binarySearch( final K[] a, final K key ) { + return binarySearch( a, 0, a.length, key ); + } + /** + * Searches a range of the specified array for the specified value using + * the binary search algorithm and a specified comparator. The range must be sorted following the comparator prior to making this call. + * If it is not sorted, the results are undefined. If the range contains multiple elements with + * the specified value, there is no guarantee which one will be found. + * + * @param a the array to be searched. + * @param from the index of the first element (inclusive) to be searched. + * @param to the index of the last element (exclusive) to be searched. + * @param key the value to be searched for. + * @param c a comparator. + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The insertion + * point is defined as the the point at which the value would + * be inserted into the array: the index of the first + * element greater than the key, or the length of the array, if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be ≥ 0 if + * and only if the key is found. + * @see java.util.Arrays + */ + public static int binarySearch( final K[] a, int from, int to, final K key, final Comparator c ) { + K midVal; + to--; + while (from <= to) { + final int mid = (from + to) >>> 1; + midVal = a[ mid ]; + final int cmp = c.compare( midVal, key ); + if ( cmp < 0 ) from = mid + 1; + else if (cmp > 0) to = mid - 1; + else return mid; // key found + } + return -( from + 1 ); + } + /** + * Searches an array for the specified value using + * the binary search algorithm and a specified comparator. The range must be sorted following the comparator prior to making this call. + * If it is not sorted, the results are undefined. If the range contains multiple elements with + * the specified value, there is no guarantee which one will be found. + * + * @param a the array to be searched. + * @param key the value to be searched for. + * @param c a comparator. + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The insertion + * point is defined as the the point at which the value would + * be inserted into the array: the index of the first + * element greater than the key, or the length of the array, if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be ≥ 0 if + * and only if the key is found. + * @see java.util.Arrays + */ + public static int binarySearch( final K[] a, final K key, final Comparator c ) { + return binarySearch( a, 0, a.length, key, c ); + } + /** Shuffles the specified array fragment using the specified pseudorandom number generator. + * + * @param a the array to be shuffled. + * @param from the index of the first element (inclusive) to be shuffled. + * @param to the index of the last element (exclusive) to be shuffled. + * @param random a pseudorandom number generator (please use a XorShift* generator). + * @return a. + */ + public static K[] shuffle( final K[] a, final int from, final int to, final Random random ) { + for( int i = to - from; i-- != 0; ) { + final int p = random.nextInt( i + 1 ); + final K t = a[ from + i ]; + a[ from + i ] = a[ from + p ]; + a[ from + p ] = t; + } + return a; + } + /** Shuffles the specified array using the specified pseudorandom number generator. + * + * @param a the array to be shuffled. + * @param random a pseudorandom number generator (please use a XorShift* generator). + * @return a. + */ + public static K[] shuffle( final K[] a, final Random random ) { + for( int i = a.length; i-- != 0; ) { + final int p = random.nextInt( i + 1 ); + final K t = a[ i ]; + a[ i ] = a[ p ]; + a[ p ] = t; + } + return a; + } + /** Reverses the order of the elements in the specified array. + * + * @param a the array to be reversed. + * @return a. + */ + public static K[] reverse( final K[] a ) { + final int length = a.length; + for( int i = length / 2; i-- != 0; ) { + final K t = a[ length - i - 1 ]; + a[ length - i - 1 ] = a[ i ]; + a[ i ] = t; + } + return a; + } + /** Reverses the order of the elements in the specified array fragment. + * + * @param a the array to be reversed. + * @param from the index of the first element (inclusive) to be reversed. + * @param to the index of the last element (exclusive) to be reversed. + * @return a. + */ + public static K[] reverse( final K[] a, final int from, final int to ) { + final int length = to - from; + for( int i = length / 2; i-- != 0; ) { + final K t = a[ from + length - i - 1 ]; + a[ from + length - i - 1 ] = a[ from + i ]; + a[ from + i ] = t; + } + return a; + } + /** A type-specific content-based hash strategy for arrays. */ + private static final class ArrayHashStrategy implements Hash.Strategy, java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + public int hashCode( final K[] o ) { + return java.util.Arrays.hashCode( o ); + } + public boolean equals( final K[] a, final K[] b ) { + return java.util.Arrays.equals( a, b ); + } + } + /** A type-specific content-based hash strategy for arrays. + * + *

This hash strategy may be used in custom hash collections whenever keys are + * arrays, and they must be considered equal by content. This strategy + * will handle null correctly, and it is serializable. + */ + @SuppressWarnings({"rawtypes"}) + public final static Hash.Strategy HASH_STRATEGY = new ArrayHashStrategy(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectBidirectionalIterator.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectBidirectionalIterator.java new file mode 100644 index 0000000..2dc5150 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectBidirectionalIterator.java @@ -0,0 +1,88 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import it.unimi.dsi.fastutil.BidirectionalIterator; +/** A type-specific bidirectional iterator; provides an additional method to avoid (un)boxing, + * and the possibility to skip elements backwards. + * + * @see BidirectionalIterator + */ +public interface ObjectBidirectionalIterator extends ObjectIterator , BidirectionalIterator { + /** Moves back for the given number of elements. + * + *

The effect of this call is exactly the same as that of + * calling {@link #previous()} for n times (possibly stopping + * if {@link #hasPrevious()} becomes false). + * + * @param n the number of elements to skip back. + * @return the number of elements actually skipped. + * @see java.util.Iterator#next() + */ + int back( int n ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectCollection.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectCollection.java new file mode 100644 index 0000000..e169594 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectCollection.java @@ -0,0 +1,109 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.Collection; +/** A type-specific {@link Collection}; provides some additional methods + * that use polymorphism to avoid (un)boxing. + * + *

Additionally, this class defines strengthens (again) {@link #iterator()} and defines + * a slightly different semantics for {@link #toArray(Object[])}. + * + * @see Collection + */ +public interface ObjectCollection extends Collection, ObjectIterable { + /** Returns a type-specific iterator on the elements of this collection. + * + *

Note that this specification strengthens the one given in + * {@link java.lang.Iterable#iterator()}, which was already + * strengthened in the corresponding type-specific class, + * but was weakened by the fact that this interface extends {@link Collection}. + * + * @return a type-specific iterator on the elements of this collection. + */ + ObjectIterator iterator(); + /** Returns a type-specific iterator on this elements of this collection. + * + * @see #iterator() + * @deprecated As of fastutil 5, replaced by {@link #iterator()}. + */ + @Deprecated + ObjectIterator objectIterator(); + /** Returns an containing the items of this collection; + * the runtime type of the returned array is that of the specified array. + * + *

Warning: Note that, contrarily to {@link Collection#toArray(Object[])}, this + * methods just writes all elements of this collection: no special + * value will be added after the last one. + * + * @param a if this array is big enough, it will be used to store this collection. + * @return a primitive type array containing the items of this collection. + * @see Collection#toArray(Object[]) + */ + T[] toArray(T[] a); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectCollections.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectCollections.java new file mode 100644 index 0000000..e6c2991 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectCollections.java @@ -0,0 +1,212 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.Collection; +import it.unimi.dsi.fastutil.objects.ObjectArrays; +/** A class providing static methods and objects that do useful things with type-specific collections. + * + * @see java.util.Collections + */ +public class ObjectCollections { + private ObjectCollections() {} + /** An immutable class representing an empty type-specific collection. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific collection. + */ + public abstract static class EmptyCollection extends AbstractObjectCollection { + protected EmptyCollection() {} + public boolean add( K k ) { throw new UnsupportedOperationException(); } + public boolean contains( Object k ) { return false; } + public Object[] toArray() { return ObjectArrays.EMPTY_ARRAY; } + public boolean remove( final Object k ) { throw new UnsupportedOperationException(); } + public T[] toArray( T[] a ) { return a; } + @SuppressWarnings("unchecked") + public ObjectBidirectionalIterator iterator() { return ObjectIterators.EMPTY_ITERATOR; } + public int size() { return 0; } + public void clear() {} + public int hashCode() { return 0; } + public boolean equals( Object o ) { + if ( o == this ) return true; + if ( ! ( o instanceof Collection ) ) return false; + return ((Collection)o).isEmpty(); + } + } + /** A synchronized wrapper class for collections. */ + public static class SynchronizedCollection implements ObjectCollection , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final ObjectCollection collection; + protected final Object sync; + protected SynchronizedCollection( final ObjectCollection c, final Object sync ) { + if ( c == null ) throw new NullPointerException(); + this.collection = c; + this.sync = sync; + } + protected SynchronizedCollection( final ObjectCollection c ) { + if ( c == null ) throw new NullPointerException(); + this.collection = c; + this.sync = this; + } + public int size() { synchronized( sync ) { return collection.size(); } } + public boolean isEmpty() { synchronized( sync ) { return collection.isEmpty(); } } + public boolean contains( final Object o ) { synchronized( sync ) { return collection.contains( o ); } } + public Object[] toArray() { synchronized( sync ) { return collection.toArray(); } } + public T[] toArray( final T[] a ) { synchronized( sync ) { return collection.toArray( a ); } } + public ObjectIterator iterator() { return collection.iterator(); } + @Deprecated + public ObjectIterator objectIterator() { return iterator(); } + public boolean add( final K k ) { synchronized( sync ) { return collection.add( k ); } } + public boolean rem( final Object k ) { synchronized( sync ) { return collection.remove( k ); } } + public boolean remove( final Object ok ) { synchronized( sync ) { return collection.remove( ok ); } } + public boolean addAll( final Collection c ) { synchronized( sync ) { return collection.addAll( c ); } } + public boolean containsAll( final Collection c ) { synchronized( sync ) { return collection.containsAll( c ); } } + public boolean removeAll( final Collection c ) { synchronized( sync ) { return collection.removeAll( c ); } } + public boolean retainAll( final Collection c ) { synchronized( sync ) { return collection.retainAll( c ); } } + public void clear() { synchronized( sync ) { collection.clear(); } } + public String toString() { synchronized( sync ) { return collection.toString(); } } + } + /** Returns a synchronized collection backed by the specified collection. + * + * @param c the collection to be wrapped in a synchronized collection. + * @return a synchronized view of the specified collection. + * @see java.util.Collections#synchronizedCollection(Collection) + */ + public static ObjectCollection synchronize( final ObjectCollection c ) { return new SynchronizedCollection ( c ); } + /** Returns a synchronized collection backed by the specified collection, using an assigned object to synchronize. + * + * @param c the collection to be wrapped in a synchronized collection. + * @param sync an object that will be used to synchronize the list access. + * @return a synchronized view of the specified collection. + * @see java.util.Collections#synchronizedCollection(Collection) + */ + public static ObjectCollection synchronize( final ObjectCollection c, final Object sync ) { return new SynchronizedCollection ( c, sync ); } + /** An unmodifiable wrapper class for collections. */ + public static class UnmodifiableCollection implements ObjectCollection , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final ObjectCollection collection; + protected UnmodifiableCollection( final ObjectCollection c ) { + if ( c == null ) throw new NullPointerException(); + this.collection = c; + } + public int size() { return collection.size(); } + public boolean isEmpty() { return collection.isEmpty(); } + public boolean contains( final Object o ) { return collection.contains( o ); } + public ObjectIterator iterator() { return ObjectIterators.unmodifiable( collection.iterator() ); } + @Deprecated + public ObjectIterator objectIterator() { return iterator(); } + public boolean add( final K k ) { throw new UnsupportedOperationException(); } + public boolean remove( final Object ok ) { throw new UnsupportedOperationException(); } + public boolean addAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean containsAll( final Collection c ) { return collection.containsAll( c ); } + public boolean removeAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( final Collection c ) { throw new UnsupportedOperationException(); } + public void clear() { throw new UnsupportedOperationException(); } + public String toString() { return collection.toString(); } + public T[] toArray( final T[] a ) { return collection.toArray( a ); } + public Object[] toArray() { return collection.toArray(); } + } + /** Returns an unmodifiable collection backed by the specified collection. + * + * @param c the collection to be wrapped in an unmodifiable collection. + * @return an unmodifiable view of the specified collection. + * @see java.util.Collections#unmodifiableCollection(Collection) + */ + public static ObjectCollection unmodifiable( final ObjectCollection c ) { return new UnmodifiableCollection ( c ); } + /** A collection wrapper class for iterables. */ + public static class IterableCollection extends AbstractObjectCollection implements java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final ObjectIterable iterable; + protected IterableCollection( final ObjectIterable iterable ) { + if ( iterable == null ) throw new NullPointerException(); + this.iterable = iterable; + } + public int size() { + int c = 0; + final ObjectIterator iterator = iterator(); + while( iterator.hasNext() ) { + iterator.next(); + c++; + } + return c; + } + public boolean isEmpty() { return iterable.iterator().hasNext(); } + public ObjectIterator iterator() { return iterable.iterator(); } + @Deprecated + public ObjectIterator objectIterator() { return iterator(); } + } + /** Returns an unmodifiable collection backed by the specified iterable. + * + * @param iterable the iterable object to be wrapped in an unmodifiable collection. + * @return an unmodifiable collection view of the specified iterable. + */ + public static ObjectCollection asCollection( final ObjectIterable iterable ) { + if ( iterable instanceof ObjectCollection ) return (ObjectCollection )iterable; + return new IterableCollection ( iterable ); + } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectIterable.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectIterable.java new file mode 100644 index 0000000..5835740 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectIterable.java @@ -0,0 +1,87 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.lang.Iterable; +/** A type-specific {@link Iterable} that strengthens that specification of {@link Iterable#iterator()}. + * + *

Warning: Java will let you write “colon” for statements with primitive-type + * loop variables; however, what is (unfortunately) really happening is that at each iteration an + * unboxing (and, in the case of fastutil type-specific data structures, a boxing) will be performed. Watch out. + * + * @see Iterable + */ +public interface ObjectIterable extends Iterable { + /** Returns a type-specific iterator. + * + * Note that this specification strengthens the one given in {@link Iterable#iterator()}. + * + * @return a type-specific iterator. + */ + ObjectIterator iterator(); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectIterator.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectIterator.java new file mode 100644 index 0000000..b3af95f --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectIterator.java @@ -0,0 +1,88 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.Iterator; +/** A type-specific {@link Iterator}; provides an additional method to avoid (un)boxing, and + * the possibility to skip elements. + * + * @see Iterator + */ +public interface ObjectIterator extends Iterator { + /** Skips the given number of elements. + * + *

The effect of this call is exactly the same as that of + * calling {@link #next()} for n times (possibly stopping + * if {@link #hasNext()} becomes false). + * + * @param n the number of elements to skip. + * @return the number of elements actually skipped. + * @see Iterator#next() + */ + int skip( int n ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectIterators.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectIterators.java new file mode 100644 index 0000000..f4c7afd --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectIterators.java @@ -0,0 +1,558 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.NoSuchElementException; +/** A class providing static methods and objects that do useful things with type-specific iterators. + * + * @see Iterator + */ +public class ObjectIterators { + private ObjectIterators() {} + /** A class returning no elements and a type-specific iterator interface. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific iterator. + */ + public static class EmptyIterator extends AbstractObjectListIterator implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptyIterator() {} + public boolean hasNext() { return false; } + public boolean hasPrevious() { return false; } + public K next() { throw new NoSuchElementException(); } + public K previous() { throw new NoSuchElementException(); } + public int nextIndex() { return 0; } + public int previousIndex() { return -1; } + public int skip( int n ) { return 0; }; + public int back( int n ) { return 0; }; + public Object clone() { return EMPTY_ITERATOR; } + private Object readResolve() { return EMPTY_ITERATOR; } + } + /** An empty iterator (immutable). It is serializable and cloneable. + * + *

The class of this objects represent an abstract empty iterator + * that can iterate as a type-specific (list) iterator. + */ + @SuppressWarnings("rawtypes") + public final static EmptyIterator EMPTY_ITERATOR = new EmptyIterator(); + /** An iterator returning a single element. */ + private static class SingletonIterator extends AbstractObjectListIterator { + private final K element; + private int curr; + public SingletonIterator( final K element ) { + this.element = element; + } + public boolean hasNext() { return curr == 0; } + public boolean hasPrevious() { return curr == 1; } + public K next() { + if ( ! hasNext() ) throw new NoSuchElementException(); + curr = 1; + return element; + } + public K previous() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + curr = 0; + return element; + } + public int nextIndex() { + return curr; + } + public int previousIndex() { + return curr - 1; + } + } + /** Returns an iterator that iterates just over the given element. + * + * @param element the only element to be returned by a type-specific list iterator. + * @return an iterator that iterates just over element. + */ + public static ObjectListIterator singleton( final K element ) { + return new SingletonIterator ( element ); + } + /** A class to wrap arrays in iterators. */ + private static class ArrayIterator extends AbstractObjectListIterator { + private final K[] array; + private final int offset, length; + private int curr; + public ArrayIterator( final K[] array, final int offset, final int length ) { + this.array = array; + this.offset = offset; + this.length = length; + } + public boolean hasNext() { return curr < length; } + public boolean hasPrevious() { return curr > 0; } + public K next() { + if ( ! hasNext() ) throw new NoSuchElementException(); + return array[ offset + curr++ ]; + } + public K previous() { + if ( ! hasPrevious() ) throw new NoSuchElementException(); + return array[ offset + --curr ]; + } + public int skip( int n ) { + if ( n <= length - curr ) { + curr += n; + return n; + } + n = length - curr; + curr = length; + return n; + } + public int back( int n ) { + if ( n <= curr ) { + curr -= n; + return n; + } + n = curr; + curr = 0; + return n; + } + public int nextIndex() { + return curr; + } + public int previousIndex() { + return curr - 1; + } + } + /** Wraps the given part of an array into a type-specific list iterator. + * + *

The type-specific list iterator returned by this method will iterate + * length times, returning consecutive elements of the given + * array starting from the one with index offset. + * + * @param array an array to wrap into a type-specific list iterator. + * @param offset the first element of the array to be returned. + * @param length the number of elements to return. + * @return an iterator that will return length elements of array starting at position offset. + */ + public static ObjectListIterator wrap( final K[] array, final int offset, final int length ) { + ObjectArrays.ensureOffsetLength( array, offset, length ); + return new ArrayIterator ( array, offset, length ); + } + /** Wraps the given array into a type-specific list iterator. + * + *

The type-specific list iterator returned by this method will return + * all elements of the given array. + * + * @param array an array to wrap into a type-specific list iterator. + * @return an iterator that will the elements of array. + */ + public static ObjectListIterator wrap( final K[] array ) { + return new ArrayIterator ( array, 0, array.length ); + } + /** Unwraps an iterator into an array starting at a given offset for a given number of elements. + * + *

This method iterates over the given type-specific iterator and stores the elements + * returned, up to a maximum of length, in the given array starting at offset. + * The number of actually unwrapped elements is returned (it may be less than max if + * the iterator emits less than max elements). + * + * @param i a type-specific iterator. + * @param array an array to contain the output of the iterator. + * @param offset the first element of the array to be returned. + * @param max the maximum number of elements to unwrap. + * @return the number of elements unwrapped. + */ + public static int unwrap( final Iterator i, final K array[], int offset, final int max ) { + if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" ); + if ( offset < 0 || offset + max > array.length ) throw new IllegalArgumentException(); + int j = max; + while( j-- != 0 && i.hasNext() ) array[ offset++ ] = i.next(); + return max - j - 1; + } + /** Unwraps an iterator into an array. + * + *

This method iterates over the given type-specific iterator and stores the + * elements returned in the given array. The iteration will stop when the + * iterator has no more elements or when the end of the array has been reached. + * + * @param i a type-specific iterator. + * @param array an array to contain the output of the iterator. + * @return the number of elements unwrapped. + */ + public static int unwrap( final Iterator i, final K array[] ) { + return unwrap( i, array, 0, array.length ); + } + /** Unwraps an iterator, returning an array, with a limit on the number of elements. + * + *

This method iterates over the given type-specific iterator and returns an array + * containing the elements returned by the iterator. At most max elements + * will be returned. + * + * @param i a type-specific iterator. + * @param max the maximum number of elements to be unwrapped. + * @return an array containing the elements returned by the iterator (at most max). + */ + @SuppressWarnings("unchecked") + public static K[] unwrap( final Iterator i, int max ) { + if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" ); + K array[] = (K[]) new Object[ 16 ]; + int j = 0; + while( max-- != 0 && i.hasNext() ) { + if ( j == array.length ) array = ObjectArrays.grow( array, j + 1 ); + array[ j++ ] = i.next(); + } + return ObjectArrays.trim( array, j ); + } + /** Unwraps an iterator, returning an array. + * + *

This method iterates over the given type-specific iterator and returns an array + * containing the elements returned by the iterator. + * + * @param i a type-specific iterator. + * @return an array containing the elements returned by the iterator. + */ + public static K[] unwrap( final Iterator i ) { + return unwrap( i, Integer.MAX_VALUE ); + } + /** Unwraps an iterator into a type-specific collection, with a limit on the number of elements. + * + *

This method iterates over the given type-specific iterator and stores the elements + * returned, up to a maximum of max, in the given type-specific collection. + * The number of actually unwrapped elements is returned (it may be less than max if + * the iterator emits less than max elements). + * + * @param i a type-specific iterator. + * @param c a type-specific collection array to contain the output of the iterator. + * @param max the maximum number of elements to unwrap. + * @return the number of elements unwrapped. Note that + * this is the number of elements returned by the iterator, which is not necessarily the number + * of elements that have been added to the collection (because of duplicates). + */ + public static int unwrap( final Iterator i, final ObjectCollection c, final int max ) { + if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" ); + int j = max; + while( j-- != 0 && i.hasNext() ) c.add( i.next() ); + return max - j - 1; + } + /** Unwraps an iterator into a type-specific collection. + * + *

This method iterates over the given type-specific iterator and stores the + * elements returned in the given type-specific collection. The returned count on the number + * unwrapped elements is a long, so that it will work also with very large collections. + * + * @param i a type-specific iterator. + * @param c a type-specific collection to contain the output of the iterator. + * @return the number of elements unwrapped. Note that + * this is the number of elements returned by the iterator, which is not necessarily the number + * of elements that have been added to the collection (because of duplicates). + */ + public static long unwrap( final Iterator i, final ObjectCollection c ) { + long n = 0; + while( i.hasNext() ) { + c.add( i.next() ); + n++; + } + return n; + } + /** Pours an iterator into a type-specific collection, with a limit on the number of elements. + * + *

This method iterates over the given type-specific iterator and adds + * the returned elements to the given collection (up to max). + * + * @param i a type-specific iterator. + * @param s a type-specific collection. + * @param max the maximum number of elements to be poured. + * @return the number of elements poured. Note that + * this is the number of elements returned by the iterator, which is not necessarily the number + * of elements that have been added to the collection (because of duplicates). + */ + public static int pour( final Iterator i, final ObjectCollection s, final int max ) { + if ( max < 0 ) throw new IllegalArgumentException( "The maximum number of elements (" + max + ") is negative" ); + int j = max; + while( j-- != 0 && i.hasNext() ) s.add( i.next() ); + return max - j - 1; + } + /** Pours an iterator into a type-specific collection. + * + *

This method iterates over the given type-specific iterator and adds + * the returned elements to the given collection. + * + * @param i a type-specific iterator. + * @param s a type-specific collection. + * @return the number of elements poured. Note that + * this is the number of elements returned by the iterator, which is not necessarily the number + * of elements that have been added to the collection (because of duplicates). + */ + public static int pour( final Iterator i, final ObjectCollection s ) { + return pour( i, s, Integer.MAX_VALUE ); + } + /** Pours an iterator, returning a type-specific list, with a limit on the number of elements. + * + *

This method iterates over the given type-specific iterator and returns + * a type-specific list containing the returned elements (up to max). Iteration + * on the returned list is guaranteed to produce the elements in the same order + * in which they appeared in the iterator. + * + * + * @param i a type-specific iterator. + * @param max the maximum number of elements to be poured. + * @return a type-specific list containing the returned elements, up to max. + */ + public static ObjectList pour( final Iterator i, int max ) { + final ObjectArrayList l = new ObjectArrayList (); + pour( i, l, max ); + l.trim(); + return l; + } + /** Pours an iterator, returning a type-specific list. + * + *

This method iterates over the given type-specific iterator and returns + * a list containing the returned elements. Iteration + * on the returned list is guaranteed to produce the elements in the same order + * in which they appeared in the iterator. + * + * @param i a type-specific iterator. + * @return a type-specific list containing the returned elements. + */ + public static ObjectList pour( final Iterator i ) { + return pour( i, Integer.MAX_VALUE ); + } + private static class IteratorWrapper extends AbstractObjectIterator { + final Iterator i; + public IteratorWrapper( final Iterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public void remove() { i.remove(); } + public K next() { return (i.next()); } + } + /** Wraps a standard iterator into a type-specific iterator. + * + *

This method wraps a standard iterator into a type-specific one which will handle the + * type conversions for you. Of course, any attempt to wrap an iterator returning the + * instances of the wrong class will generate a {@link ClassCastException}. The + * returned iterator is backed by i: changes to one of the iterators + * will affect the other, too. + * + *

If i is already type-specific, it will returned and no new object + * will be generated. + * + * @param i an iterator. + * @return a type-specific iterator backed by i. + */ + public static ObjectIterator asObjectIterator( final Iterator i ) { + if ( i instanceof ObjectIterator ) return (ObjectIterator )i; + return new IteratorWrapper ( i ); + } + private static class ListIteratorWrapper extends AbstractObjectListIterator { + final ListIterator i; + public ListIteratorWrapper( final ListIterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public boolean hasPrevious() { return i.hasPrevious(); } + public int nextIndex() { return i.nextIndex(); } + public int previousIndex() { return i.previousIndex(); } + public void set( K k ) { i.set( (k) ); } + public void add( K k ) { i.add( (k) ); } + public void remove() { i.remove(); } + public K next() { return (i.next()); } + public K previous() { return (i.previous()); } + } + /** Wraps a standard list iterator into a type-specific list iterator. + * + *

This method wraps a standard list iterator into a type-specific one + * which will handle the type conversions for you. Of course, any attempt + * to wrap an iterator returning the instances of the wrong class will + * generate a {@link ClassCastException}. The + * returned iterator is backed by i: changes to one of the iterators + * will affect the other, too. + * + *

If i is already type-specific, it will returned and no new object + * will be generated. + * + * @param i a list iterator. + * @return a type-specific list iterator backed by i. + */ + public static ObjectListIterator asObjectIterator( final ListIterator i ) { + if ( i instanceof ObjectListIterator ) return (ObjectListIterator )i; + return new ListIteratorWrapper ( i ); + } + private static class IteratorConcatenator extends AbstractObjectIterator { + final ObjectIterator a[]; + int offset, length, lastOffset = -1; + public IteratorConcatenator( final ObjectIterator a[], int offset, int length ) { + this.a = a; + this.offset = offset; + this.length = length; + advance(); + } + private void advance() { + while( length != 0 ) { + if ( a[ offset ].hasNext() ) break; + length--; + offset++; + } + return; + } + public boolean hasNext() { + return length > 0; + } + public K next() { + if ( ! hasNext() ) throw new NoSuchElementException(); + K next = a[ lastOffset = offset ].next(); + advance(); + return next; + } + public void remove() { + if ( lastOffset == -1 ) throw new IllegalStateException(); + a[ lastOffset ].remove(); + } + public int skip( int n ) { + lastOffset = -1; + int skipped = 0; + while( skipped < n && length != 0 ) { + skipped += a[ offset ].skip( n - skipped ); + if ( a[ offset ].hasNext() ) break; + length--; + offset++; + } + return skipped; + } + } + /** Concatenates all iterators contained in an array. + * + *

This method returns an iterator that will enumerate in order the elements returned + * by all iterators contained in the given array. + * + * @param a an array of iterators. + * @return an iterator obtained by concatenation. + */ + public static ObjectIterator concat( final ObjectIterator a[] ) { + return concat( a, 0, a.length ); + } + /** Concatenates a sequence of iterators contained in an array. + * + *

This method returns an iterator that will enumerate in order the elements returned + * by a[ offset ], then those returned + * by a[ offset + 1 ], and so on up to + * a[ offset + length - 1 ]. + * + * @param a an array of iterators. + * @param offset the index of the first iterator to concatenate. + * @param length the number of iterators to concatenate. + * @return an iterator obtained by concatenation of length elements of a starting at offset. + */ + public static ObjectIterator concat( final ObjectIterator a[], final int offset, final int length ) { + return new IteratorConcatenator ( a, offset, length ); + } + /** An unmodifiable wrapper class for iterators. */ + public static class UnmodifiableIterator extends AbstractObjectIterator { + final protected ObjectIterator i; + public UnmodifiableIterator( final ObjectIterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public K next() { return i.next(); } + } + /** Returns an unmodifiable iterator backed by the specified iterator. + * + * @param i the iterator to be wrapped in an unmodifiable iterator. + * @return an unmodifiable view of the specified iterator. + */ + public static ObjectIterator unmodifiable( final ObjectIterator i ) { return new UnmodifiableIterator ( i ); } + /** An unmodifiable wrapper class for bidirectional iterators. */ + public static class UnmodifiableBidirectionalIterator extends AbstractObjectBidirectionalIterator { + final protected ObjectBidirectionalIterator i; + public UnmodifiableBidirectionalIterator( final ObjectBidirectionalIterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public boolean hasPrevious() { return i.hasPrevious(); } + public K next() { return i.next(); } + public K previous() { return i.previous(); } + } + /** Returns an unmodifiable bidirectional iterator backed by the specified bidirectional iterator. + * + * @param i the bidirectional iterator to be wrapped in an unmodifiable bidirectional iterator. + * @return an unmodifiable view of the specified bidirectional iterator. + */ + public static ObjectBidirectionalIterator unmodifiable( final ObjectBidirectionalIterator i ) { return new UnmodifiableBidirectionalIterator ( i ); } + /** An unmodifiable wrapper class for list iterators. */ + public static class UnmodifiableListIterator extends AbstractObjectListIterator { + final protected ObjectListIterator i; + public UnmodifiableListIterator( final ObjectListIterator i ) { + this.i = i; + } + public boolean hasNext() { return i.hasNext(); } + public boolean hasPrevious() { return i.hasPrevious(); } + public K next() { return i.next(); } + public K previous() { return i.previous(); } + public int nextIndex() { return i.nextIndex(); } + public int previousIndex() { return i.previousIndex(); } + } + /** Returns an unmodifiable list iterator backed by the specified list iterator. + * + * @param i the list iterator to be wrapped in an unmodifiable list iterator. + * @return an unmodifiable view of the specified list iterator. + */ + public static ObjectListIterator unmodifiable( final ObjectListIterator i ) { return new UnmodifiableListIterator ( i ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectList.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectList.java new file mode 100644 index 0000000..7b376b7 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectList.java @@ -0,0 +1,169 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.List; +/** A type-specific {@link List}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Note that this type-specific interface extends {@link Comparable}: it is expected that implementing + * classes perform a lexicographical comparison using the standard operator "less then" for primitive types, + * and the usual {@link Comparable#compareTo(Object) compareTo()} method for objects. + * + *

Additionally, this interface strengthens {@link #listIterator()}, + * {@link #listIterator(int)} and {@link #subList(int,int)}. + * + *

Besides polymorphic methods, this interfaces specifies methods to copy into an array or remove contiguous + * sublists. Although the abstract implementation of this interface provides simple, one-by-one implementations + * of these methods, it is expected that concrete implementation override them with optimized versions. + * + * @see List + */ +public interface ObjectList extends List, Comparable>, ObjectCollection { + /** Returns a type-specific iterator on the elements of this list (in proper sequence). + * + * Note that this specification strengthens the one given in {@link List#iterator()}. + * It would not be normally necessary, but {@link java.lang.Iterable#iterator()} is bizarrily re-specified + * in {@link List}. + * + * @return an iterator on the elements of this list (in proper sequence). + */ + ObjectListIterator iterator(); + /** Returns a type-specific list iterator on the list. + * + * @see #listIterator() + * @deprecated As of fastutil 5, replaced by {@link #listIterator()}. + */ + @Deprecated + ObjectListIterator objectListIterator(); + /** Returns a type-specific list iterator on the list starting at a given index. + * + * @see #listIterator(int) + * @deprecated As of fastutil 5, replaced by {@link #listIterator(int)}. + */ + @Deprecated + ObjectListIterator objectListIterator( int index ); + /** Returns a type-specific list iterator on the list. + * + * @see List#listIterator() + */ + ObjectListIterator listIterator(); + /** Returns a type-specific list iterator on the list starting at a given index. + * + * @see List#listIterator(int) + */ + ObjectListIterator listIterator( int index ); + /** Returns a type-specific view of the portion of this list from the index from, inclusive, to the index to, exclusive. + * @see List#subList(int,int) + * @deprecated As of fastutil 5, replaced by {@link #subList(int,int)}. + */ + @Deprecated + ObjectList objectSubList( int from, int to ); + /** Returns a type-specific view of the portion of this list from the index from, inclusive, to the index to, exclusive. + * + *

Note that this specification strengthens the one given in {@link List#subList(int,int)}. + * + * @see List#subList(int,int) + */ + ObjectList subList(int from, int to); + /** Sets the size of this list. + * + *

If the specified size is smaller than the current size, the last elements are + * discarded. Otherwise, they are filled with 0/null/false. + * + * @param size the new size. + */ + void size( int size ); + /** Copies (hopefully quickly) elements of this type-specific list into the given array. + * + * @param from the start index (inclusive). + * @param a the destination array. + * @param offset the offset into the destination array where to store the first element copied. + * @param length the number of elements to be copied. + */ + void getElements( int from, Object a[], int offset, int length ); + /** Removes (hopefully quickly) elements of this type-specific list. + * + * @param from the start index (inclusive). + * @param to the end index (exclusive). + */ + void removeElements( int from, int to ); + /** Add (hopefully quickly) elements to this type-specific list. + * + * @param index the index at which to add elements. + * @param a the array containing the elements. + */ + void addElements( int index, K a[] ); + /** Add (hopefully quickly) elements to this type-specific list. + * + * @param index the index at which to add elements. + * @param a the array containing the elements. + * @param offset the offset of the first element to add. + * @param length the number of elements to add. + */ + void addElements( int index, K a[], int offset, int length ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectListIterator.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectListIterator.java new file mode 100644 index 0000000..f7f0b36 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectListIterator.java @@ -0,0 +1,82 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.ListIterator; +/** A type-specific bidirectional iterator that is also a {@link ListIterator}. + * + *

This interface merges the methods provided by a {@link ListIterator} and + * a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator}. Moreover, it provides + * type-specific versions of {@link java.util.ListIterator#add(Object) add()} + * and {@link java.util.ListIterator#set(Object) set()}. + * + * @see java.util.ListIterator + * @see it.unimi.dsi.fastutil.BidirectionalIterator + */ +public interface ObjectListIterator extends ListIterator, ObjectBidirectionalIterator { +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectSet.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectSet.java new file mode 100644 index 0000000..02fa79f --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectSet.java @@ -0,0 +1,96 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.Set; +/** A type-specific {@link Set}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Additionally, this interface strengthens (again) {@link #iterator()}. + * + * @see Set + */ +public interface ObjectSet extends ObjectCollection , Set { + /** Returns a type-specific iterator on the elements of this set. + * + *

Note that this specification strengthens the one given in {@link java.lang.Iterable#iterator()}, + * which was already strengthened in the corresponding type-specific class, + * but was weakened by the fact that this interface extends {@link Set}. + * + * @return a type-specific iterator on the elements of this set. + */ + ObjectIterator iterator(); + /** Removes an element from this set. + * + *

Note that the corresponding method of the type-specific collection is rem(). + * This unfortunate situation is caused by the clash + * with the similarly named index-based method in the {@link java.util.List} interface. + * + * @see java.util.Collection#remove(Object) + */ + public boolean remove( Object k ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectSets.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectSets.java new file mode 100644 index 0000000..63e5049 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectSets.java @@ -0,0 +1,177 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.Collection; +import java.util.Set; +/** A class providing static methods and objects that do useful things with type-specific sets. + * + * @see java.util.Collections + */ +public class ObjectSets { + private ObjectSets() {} + /** An immutable class representing the empty set and implementing a type-specific set interface. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific set. + */ + public static class EmptySet extends ObjectCollections.EmptyCollection implements ObjectSet , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptySet() {} + public boolean remove( Object ok ) { throw new UnsupportedOperationException(); } + public Object clone() { return EMPTY_SET; } + @SuppressWarnings("rawtypes") + public boolean equals( final Object o ) { return o instanceof Set && ((Set)o).isEmpty(); } + private Object readResolve() { return EMPTY_SET; } + } + /** An empty set (immutable). It is serializable and cloneable. + */ + @SuppressWarnings("rawtypes") + public static final EmptySet EMPTY_SET = new EmptySet(); + /** Return an empty set (immutable). It is serializable and cloneable. + * + *

This method provides a typesafe access to {@link #EMPTY_SET}. + * @return an empty set (immutable). + */ + @SuppressWarnings("unchecked") + public static ObjectSet emptySet() { + return EMPTY_SET; + } + /** An immutable class representing a type-specific singleton set. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific set. */ + public static class Singleton extends AbstractObjectSet implements java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected final K element; + protected Singleton( final K element ) { + this.element = element; + } + public boolean add( final K k ) { throw new UnsupportedOperationException(); } + public boolean contains( final Object k ) { return ( (k) == null ? (element) == null : (k).equals(element) ); } + public boolean addAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean removeAll( final Collection c ) { throw new UnsupportedOperationException(); } + public boolean retainAll( final Collection c ) { throw new UnsupportedOperationException(); } + public ObjectListIterator iterator() { return ObjectIterators.singleton( element ); } + public int size() { return 1; } + public Object clone() { return this; } + } + /** Returns a type-specific immutable set containing only the specified element. The returned set is serializable and cloneable. + * + * @param element the only element of the returned set. + * @return a type-specific immutable set containing just element. + */ + public static ObjectSet singleton( final K element ) { + return new Singleton ( element ); + } + /** A synchronized wrapper class for sets. */ + public static class SynchronizedSet extends ObjectCollections.SynchronizedCollection implements ObjectSet , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected SynchronizedSet( final ObjectSet s, final Object sync ) { + super( s, sync ); + } + protected SynchronizedSet( final ObjectSet s ) { + super( s ); + } + public boolean remove( final Object k ) { synchronized( sync ) { return collection.remove( (k) ); } } + public boolean equals( final Object o ) { synchronized( sync ) { return collection.equals( o ); } } + public int hashCode() { synchronized( sync ) { return collection.hashCode(); } } + } + /** Returns a synchronized type-specific set backed by the given type-specific set. + * + * @param s the set to be wrapped in a synchronized set. + * @return a synchronized view of the specified set. + * @see java.util.Collections#synchronizedSet(Set) + */ + public static ObjectSet synchronize( final ObjectSet s ) { return new SynchronizedSet ( s ); } + /** Returns a synchronized type-specific set backed by the given type-specific set, using an assigned object to synchronize. + * + * @param s the set to be wrapped in a synchronized set. + * @param sync an object that will be used to synchronize the access to the set. + * @return a synchronized view of the specified set. + * @see java.util.Collections#synchronizedSet(Set) + */ + public static ObjectSet synchronize( final ObjectSet s, final Object sync ) { return new SynchronizedSet ( s, sync ); } + /** An unmodifiable wrapper class for sets. */ + public static class UnmodifiableSet extends ObjectCollections.UnmodifiableCollection implements ObjectSet , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected UnmodifiableSet( final ObjectSet s ) { + super( s ); + } + public boolean remove( final Object k ) { throw new UnsupportedOperationException(); } + public boolean equals( final Object o ) { return collection.equals( o ); } + public int hashCode() { return collection.hashCode(); } + } + /** Returns an unmodifiable type-specific set backed by the given type-specific set. + * + * @param s the set to be wrapped in an unmodifiable set. + * @return an unmodifiable view of the specified set. + * @see java.util.Collections#unmodifiableSet(Set) + */ + public static ObjectSet unmodifiable( final ObjectSet s ) { return new UnmodifiableSet ( s ); } +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectSortedSet.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectSortedSet.java new file mode 100644 index 0000000..d2777fb --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectSortedSet.java @@ -0,0 +1,151 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.SortedSet; +import java.util.Collection; +/** A type-specific {@link SortedSet}; provides some additional methods that use polymorphism to avoid (un)boxing. + * + *

Additionally, this interface strengthens {@link #iterator()}, + * {@link #comparator()} (for primitive types), {@link SortedSet#subSet(Object,Object)}, + * {@link SortedSet#headSet(Object)} and {@link SortedSet#tailSet(Object)}. + * + * @see SortedSet + */ +public interface ObjectSortedSet extends ObjectSet , SortedSet { + /** Returns a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator} on the elements in + * this set, starting from a given element of the domain (optional operation). + * + *

This method returns a type-specific bidirectional iterator with given + * starting point. The starting point is any element comparable to the + * elements of this set (even if it does not actually belong to the + * set). The next element of the returned iterator is the least element of + * the set that is greater than the starting point (if there are no + * elements greater than the starting point, {@link + * it.unimi.dsi.fastutil.BidirectionalIterator#hasNext() hasNext()} will return + * false). The previous element of the returned iterator is + * the greatest element of the set that is smaller than or equal to the + * starting point (if there are no elements smaller than or equal to the + * starting point, {@link it.unimi.dsi.fastutil.BidirectionalIterator#hasPrevious() + * hasPrevious()} will return false). + * + *

Note that passing the last element of the set as starting point and + * calling {@link it.unimi.dsi.fastutil.BidirectionalIterator#previous() previous()} you can traverse the + * entire set in reverse order. + * + * @param fromElement an element to start from. + * @return a bidirectional iterator on the element in this set, starting at the given element. + * @throws UnsupportedOperationException if this set does not support iterators with a starting point. + */ + ObjectBidirectionalIterator iterator( K fromElement ); + /** Returns a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator} iterator on the collection. + * + *

The iterator returned by the {@link #iterator()} method and by this + * method are identical; however, using this method you can save a type casting. + * + * Note that this specification strengthens the one given in the corresponding type-specific + * {@link Collection}. + * + * @deprecated As of fastutil 5, replaced by {@link #iterator()}. + */ + @Deprecated + ObjectBidirectionalIterator objectIterator(); + /** Returns a type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator} on the elements in + * this set. + * + *

This method returns a parameterised bidirectional iterator. The iterator + * can be moreover safely cast to a type-specific iterator. + * + * Note that this specification strengthens the one given in the corresponding type-specific + * {@link Collection}. + * + * @return a bidirectional iterator on the element in this set. + */ + ObjectBidirectionalIterator iterator(); + /** Returns a view of the portion of this sorted set whose elements range from fromElement, inclusive, to toElement, exclusive. + * + *

Note that this specification strengthens the one given in {@link SortedSet#subSet(Object,Object)}. + * + * @see SortedSet#subSet(Object,Object) + */ + ObjectSortedSet subSet( K fromElement, K toElement) ; + /** Returns a view of the portion of this sorted set whose elements are strictly less than toElement. + * + *

Note that this specification strengthens the one given in {@link SortedSet#headSet(Object)}. + * + * @see SortedSet#headSet(Object) + */ + ObjectSortedSet headSet( K toElement ); + /** Returns a view of the portion of this sorted set whose elements are greater than or equal to fromElement. + * + *

Note that this specification strengthens the one given in {@link SortedSet#tailSet(Object)}. + * + * @see SortedSet#tailSet(Object) + */ + ObjectSortedSet tailSet( K fromElement ); +} diff --git a/src/main/java/it/unimi/dsi/fastutil/objects/ObjectSortedSets.java b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectSortedSets.java new file mode 100644 index 0000000..b6142a0 --- /dev/null +++ b/src/main/java/it/unimi/dsi/fastutil/objects/ObjectSortedSets.java @@ -0,0 +1,237 @@ +/* Copyright (C) 1991-2014 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ +/* This header is separate from features.h so that the compiler can + include it implicitly at the start of every compilation. It must + not itself include or any other header that includes + because the implicit include comes before any feature + test macros that may be defined in a source file before it first + explicitly includes a system header. GCC knows the name of this + header in order to preinclude it. */ +/* glibc's intent is to support the IEC 559 math functionality, real + and complex. If the GCC (4.9 and later) predefined macros + specifying compiler intent are available, use them to determine + whether the overall intent is to support these features; otherwise, + presume an older compiler has intent to support these features and + define these macros by default. */ +/* wchar_t uses ISO/IEC 10646 (2nd ed., published 2011-03-15) / + Unicode 6.0. */ +/* We do not support C11 . */ +/* Generic definitions */ +/* Assertions (useful to generate conditional code) */ +/* Current type and class (and size, if applicable) */ +/* Value methods */ +/* Interfaces (keys) */ +/* Interfaces (values) */ +/* 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) */ +/* + * Copyright (C) 2002-2016 Sebastiano Vigna + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package it.unimi.dsi.fastutil.objects; +import java.util.SortedSet; +import java.util.NoSuchElementException; +import java.util.Comparator; +/** A class providing static methods and objects that do useful things with type-specific sorted sets. + * + * @see java.util.Collections + */ +public class ObjectSortedSets { + private ObjectSortedSets() {} + /** An immutable class representing the empty sorted set and implementing a type-specific set interface. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific sorted set. + */ + public static class EmptySet extends ObjectSets.EmptySet implements ObjectSortedSet , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + protected EmptySet() {} + public boolean remove( Object ok ) { throw new UnsupportedOperationException(); } + @Deprecated + public ObjectBidirectionalIterator objectIterator() { return iterator(); } + @SuppressWarnings("unchecked") + public ObjectBidirectionalIterator iterator( K from ) { return ObjectIterators.EMPTY_ITERATOR; } + @SuppressWarnings("unchecked") + public ObjectSortedSet subSet( K from, K to ) { return EMPTY_SET; } + @SuppressWarnings("unchecked") + public ObjectSortedSet headSet( K from ) { return EMPTY_SET; } + @SuppressWarnings("unchecked") + public ObjectSortedSet tailSet( K to ) { return EMPTY_SET; } + public K first() { throw new NoSuchElementException(); } + public K last() { throw new NoSuchElementException(); } + public Comparator comparator() { return null; } + public Object clone() { return EMPTY_SET; } + private Object readResolve() { return EMPTY_SET; } + } + /** An empty sorted set (immutable). It is serializable and cloneable. + * + */ + @SuppressWarnings("rawtypes") + public static final EmptySet EMPTY_SET = new EmptySet(); + /** Return an empty sorted set (immutable). It is serializable and cloneable. + * + *

This method provides a typesafe access to {@link #EMPTY_SET}. + * @return an empty sorted set (immutable). + */ + @SuppressWarnings("unchecked") + public static ObjectSet emptySet() { + return EMPTY_SET; + } + /** A class representing a singleton sorted set. + * + *

This class may be useful to implement your own in case you subclass + * a type-specific sorted set. + */ + public static class Singleton extends ObjectSets.Singleton implements ObjectSortedSet , java.io.Serializable, Cloneable { + private static final long serialVersionUID = -7046029254386353129L; + final Comparator comparator; + private Singleton( final K element, final Comparator comparator ) { + super( element ); + this.comparator = comparator; + } + private Singleton( final K element ) { + this( element, null ); + } + @SuppressWarnings("unchecked") + final int compare( final K k1, final K k2 ) { + return comparator == null ? ( ((Comparable)(k1)).compareTo(k2) ) : comparator.compare( k1, k2 ); + } + @Deprecated + public ObjectBidirectionalIterator objectIterator() { + return iterator(); + } + public ObjectBidirectionalIterator iterator( K from ) { + ObjectBidirectionalIterator i = iterator(); + if ( compare( element, from ) <= 0 ) i.next(); + return i; + } + public Comparator comparator() { return comparator; } + @SuppressWarnings("unchecked") + public ObjectSortedSet subSet( final K from, final K to ) { if ( compare( from, element ) <= 0 && compare( element, to ) < 0 ) return this; return EMPTY_SET; } + @SuppressWarnings("unchecked") + public ObjectSortedSet headSet( final K to ) { if ( compare( element, to ) < 0 ) return this; return EMPTY_SET; } + @SuppressWarnings("unchecked") + public ObjectSortedSet tailSet( final K from ) { if ( compare( from, element ) <= 0 ) return this; return EMPTY_SET; } + public K first() { return element; } + public K last() { return element; } + } + /** Returns a type-specific immutable sorted set containing only the specified element. The returned sorted set is serializable and cloneable. + * + * @param element the only element of the returned sorted set. + * @return a type-specific immutable sorted set containing just element. + */ + public static ObjectSortedSet singleton( final K element ) { + return new Singleton ( element ); + } + /** Returns a type-specific immutable sorted set containing only the specified element, and using a specified comparator. The returned sorted set is serializable and cloneable. + * + * @param element the only element of the returned sorted set. + * @param comparator the comparator to use in the returned sorted set. + * @return a type-specific immutable sorted set containing just element. + */ + public static ObjectSortedSet singleton( final K element, final Comparator comparator ) { + return new Singleton ( element, comparator ); + } + /** A synchronized wrapper class for sorted sets. */ + public static class SynchronizedSortedSet extends ObjectSets.SynchronizedSet implements ObjectSortedSet , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final ObjectSortedSet sortedSet; + protected SynchronizedSortedSet( final ObjectSortedSet s, final Object sync ) { + super( s, sync ); + sortedSet = s; + } + protected SynchronizedSortedSet( final ObjectSortedSet s ) { + super( s ); + sortedSet = s; + } + public Comparator comparator() { synchronized( sync ) { return sortedSet.comparator(); } } + public ObjectSortedSet subSet( final K from, final K to ) { return new SynchronizedSortedSet ( sortedSet.subSet( from, to ), sync ); } + public ObjectSortedSet headSet( final K to ) { return new SynchronizedSortedSet ( sortedSet.headSet( to ), sync ); } + public ObjectSortedSet tailSet( final K from ) { return new SynchronizedSortedSet ( sortedSet.tailSet( from ), sync ); } + public ObjectBidirectionalIterator iterator() { return sortedSet.iterator(); } + public ObjectBidirectionalIterator iterator( final K from ) { return sortedSet.iterator( from ); } + @Deprecated + public ObjectBidirectionalIterator objectIterator() { return sortedSet.iterator(); } + public K first() { synchronized( sync ) { return sortedSet.first(); } } + public K last() { synchronized( sync ) { return sortedSet.last(); } } + } + /** Returns a synchronized type-specific sorted set backed by the given type-specific sorted set. + * + * @param s the sorted set to be wrapped in a synchronized sorted set. + * @return a synchronized view of the specified sorted set. + * @see java.util.Collections#synchronizedSortedSet(SortedSet) + */ + public static ObjectSortedSet synchronize( final ObjectSortedSet s ) { return new SynchronizedSortedSet ( s ); } + /** Returns a synchronized type-specific sorted set backed by the given type-specific sorted set, using an assigned object to synchronize. + * + * @param s the sorted set to be wrapped in a synchronized sorted set. + * @param sync an object that will be used to synchronize the access to the sorted set. + * @return a synchronized view of the specified sorted set. + * @see java.util.Collections#synchronizedSortedSet(SortedSet) + */ + public static ObjectSortedSet synchronize( final ObjectSortedSet s, final Object sync ) { return new SynchronizedSortedSet ( s, sync ); } + /** An unmodifiable wrapper class for sorted sets. */ + public static class UnmodifiableSortedSet extends ObjectSets.UnmodifiableSet implements ObjectSortedSet , java.io.Serializable { + private static final long serialVersionUID = -7046029254386353129L; + protected final ObjectSortedSet sortedSet; + protected UnmodifiableSortedSet( final ObjectSortedSet s ) { + super( s ); + sortedSet = s; + } + public Comparator comparator() { return sortedSet.comparator(); } + public ObjectSortedSet subSet( final K from, final K to ) { return new UnmodifiableSortedSet ( sortedSet.subSet( from, to ) ); } + public ObjectSortedSet headSet( final K to ) { return new UnmodifiableSortedSet ( sortedSet.headSet( to ) ); } + public ObjectSortedSet tailSet( final K from ) { return new UnmodifiableSortedSet ( sortedSet.tailSet( from ) ); } + public ObjectBidirectionalIterator iterator() { return ObjectIterators.unmodifiable( sortedSet.iterator() ); } + public ObjectBidirectionalIterator iterator( final K from ) { return ObjectIterators.unmodifiable( sortedSet.iterator( from ) ); } + @Deprecated + public ObjectBidirectionalIterator objectIterator() { return iterator(); } + public K first() { return sortedSet.first(); } + public K last() { return sortedSet.last(); } + } + /** Returns an unmodifiable type-specific sorted set backed by the given type-specific sorted set. + * + * @param s the sorted set to be wrapped in an unmodifiable sorted set. + * @return an unmodifiable view of the specified sorted set. + * @see java.util.Collections#unmodifiableSortedSet(SortedSet) + */ + public static ObjectSortedSet unmodifiable( final ObjectSortedSet s ) { return new UnmodifiableSortedSet ( s ); } +} -- 2.8.0