001/*
002 * Copyright 2013 Alex Kasko (alexkasko.com)
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.alexkasko.unsafe.offheapstruct;
018
019import com.alexkasko.unsafe.offheap.OffHeapDisposableIterable;
020import com.alexkasko.unsafe.offheap.OffHeapDisposableIterator;
021
022import java.util.*;
023import java.util.concurrent.Executor;
024import java.util.concurrent.ExecutorService;
025
026import static com.alexkasko.unsafe.offheap.OffHeapUtils.emptyDisposableIterator;
027
028/**
029 * <p>alexkasko: borrowed from {@code https://android.googlesource.com/platform/libcore/+/android-4.2.2_r1/luni/src/main/java/java/util/DualPivotQuicksort.java}
030 * and adapted to {@link OffHeapStructCollection}.
031 *
032 * <p>This class implements the Dual-Pivot Quicksort algorithm by
033 * Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. The algorithm
034 * offers O(n log(n)) performance on many data sets that cause other
035 * quicksorts to degrade to quadratic performance, and is typically
036 * faster than traditional (one-pivot) Quicksort implementations.
037 *
038 * @author Vladimir Yaroslavskiy
039 * @author Jon Bentley
040 * @author Josh Bloch
041 *
042 * @version 2009.11.29 m765.827.12i
043 */
044public class OffHeapStructSorter {
045
046    /**
047     * If the length of an collection to be sorted is less than this
048     * constant, insertion sort is used in preference to Quicksort.
049     */
050    static final int INSERTION_SORT_THRESHOLD = 32;
051
052    /**
053     * Sorts collection using comparator.
054     *
055     * @param collection off-heap struct collection
056     * @param comparator structs comparator
057     */
058    public static void sort(OffHeapStructCollection collection, Comparator<OffHeapStructAccessor> comparator) {
059        OffHeapStructSorterWithComparator.sort(collection, comparator);
060    }
061
062    /**
063     * Sorts collection using comparator.
064     *
065     * @param collection off-heap struct collection
066     * @param comparator structs comparator
067     * @param fromIndex start sort collection index
068     * @param toIndex end sort collection index
069     */
070    public static void sort(OffHeapStructCollection collection, Comparator<OffHeapStructAccessor> comparator, long fromIndex, long toIndex) {
071        if(fromIndex == toIndex) return; // nothing to sort here
072        OffHeapStructSorterWithComparator.sort(collection, fromIndex, toIndex, comparator);
073    }
074
075    /**
076     * Partially sorts collection and returns fully sorted iterator over it
077     *
078     * @param executor executor service for parallel sorting
079     * @param threadsCount number of worker threads to use
080     * @param collection the off-heap struct collection to be sorted
081     * @param comparator structs comparator
082     * @return sorted iterator over the collection
083     * @throws IllegalArgumentException {@code if (fromIndex < 0 || fromIndex > toIndex || toIndex > a.size())}
084     * @throws RuntimeException on worker thread error
085     */
086    public static OffHeapDisposableIterator<byte[]> sortedIterator(ExecutorService executor, int threadsCount, OffHeapStructCollection collection,
087                                                  Comparator<OffHeapStructAccessor> comparator) {
088        return OffHeapStructSorterWithComparator.sortedIterator(executor, threadsCount, collection, comparator);
089    }
090
091    /**
092     * Partially sorts part of the collection and returns fully sorted iterator over it
093     *
094     * @param executor executor service for parallel sorting
095     * @param threadsCount number of worker threads to use
096     * @param collection the off-heap struct collection to be sorted
097     * @param fromIndex the index of the first element, inclusive, to be sorted
098     * @param toIndex the index of the last element, exclusive, to be sorted
099     * @param comparator structs comparator
100     * @return sorted iterator over the collection part
101     * @throws IllegalArgumentException {@code if (fromIndex < 0 || fromIndex > toIndex || toIndex > a.size())}
102     * @throws RuntimeException on worker thread error
103     */
104    public static OffHeapDisposableIterator<byte[]> sortedIterator(ExecutorService executor, int threadsCount, OffHeapStructCollection collection,
105                                                  Comparator<OffHeapStructAccessor> comparator, long fromIndex, long toIndex) {
106        if(fromIndex == toIndex) return emptyDisposableIterator(); // nothing to sort here
107        return OffHeapStructSorterWithComparator.sortedIterator(executor, threadsCount, collection, fromIndex, toIndex, comparator);
108    }
109
110    /**
111     * Partially sorts collection and returns fully sorted iterator over it
112     *
113     * @param executor executor service for parallel sorting
114     * @param threadsCount number of worker threads to use
115     * @param collection the off-heap struct collection to be sorted
116     * @param keyOffset key offset
117     * @return sorted iterator over the collection
118     * @throws IllegalArgumentException {@code if (fromIndex < 0 || fromIndex > toIndex || toIndex > a.size())}
119     * @throws RuntimeException on worker thread error
120     */
121    public static OffHeapDisposableIterator<byte[]> sortedIteratorByLongKey(ExecutorService executor, int threadsCount, OffHeapStructCollection collection,
122                                                  int keyOffset) {
123        return OffHeapStructSorterLong.sortedIterator(executor, threadsCount, collection, keyOffset);
124    }
125
126    /**
127     * Partially sorts part of the collection and returns fully sorted iterator over it
128     *
129     * @param executor executor service for parallel sorting
130     * @param threadsCount number of worker threads to use
131     * @param collection the off-heap struct collection to be sorted
132     * @param fromIndex the index of the first element, inclusive, to be sorted
133     * @param toIndex the index of the last element, exclusive, to be sorted
134     * @param keyOffset key offset
135     * @return sorted iterator over the collection part
136     * @throws IllegalArgumentException {@code if (fromIndex < 0 || fromIndex > toIndex || toIndex > a.size())}
137     * @throws RuntimeException on worker thread error
138     */
139    public static OffHeapDisposableIterator<byte[]> sortedIteratorByLongKey(ExecutorService executor, int threadsCount, OffHeapStructCollection collection,
140                                                           int keyOffset, long fromIndex, long toIndex) {
141        if(fromIndex == toIndex) return emptyDisposableIterator(); // nothing to sort here
142        return OffHeapStructSorterLong.sortedIterator(executor, threadsCount, collection, fromIndex, toIndex, keyOffset);
143    }
144
145    /**
146     * Partially sorts collection and returns fully sorted iterator over it
147     *
148     * @param executor executor service for parallel sorting
149     * @param threadsCount number of worker threads to use
150     * @param collection the off-heap struct collection to be sorted
151     * @param keyOffset key offset
152     * @return sorted iterator over the collection
153     * @throws IllegalArgumentException {@code if (fromIndex < 0 || fromIndex > toIndex || toIndex > a.size())}
154     * @throws RuntimeException on worker thread error
155     */
156    public static OffHeapDisposableIterator<byte[]> sortedIteratorByIntKey(ExecutorService executor, int threadsCount, OffHeapStructCollection collection,
157                                                  int keyOffset) {
158        return OffHeapStructSorterInt.sortedIterator(executor, threadsCount, collection, keyOffset);
159    }
160
161    /**
162     * Partially sorts part of the collection and returns fully sorted iterator over it
163     *
164     * @param executor executor service for parallel sorting
165     * @param threadsCount number of worker threads to use
166     * @param collection the off-heap struct collection to be sorted
167     * @param fromIndex the index of the first element, inclusive, to be sorted
168     * @param toIndex the index of the last element, exclusive, to be sorted
169     * @param keyOffset key offset
170     * @return sorted iterator over the collection part
171     * @throws IllegalArgumentException {@code if (fromIndex < 0 || fromIndex > toIndex || toIndex > a.size())}
172     * @throws RuntimeException on worker thread error
173     */
174    public static OffHeapDisposableIterator<byte[]> sortedIteratorByIntKey(ExecutorService executor, int threadsCount, OffHeapStructCollection collection,
175                                                           int keyOffset, long fromIndex, long toIndex) {
176        if(fromIndex == toIndex) return emptyDisposableIterator(); // nothing to sort here
177        return OffHeapStructSorterInt.sortedIterator(executor, threadsCount, collection, fromIndex, toIndex, keyOffset);
178    }
179
180    /**
181     * Sorts the specified off-heap struct collection into ascending order using long struct key.
182     *
183     * @param a the off-heap struct collection to be sorted
184     * @param keyOffset long key field offset within stuct bounds
185     */
186    public static void sortByLongKey(OffHeapStructCollection a, int keyOffset) {
187        OffHeapStructSorterLong.sort(a, keyOffset);
188    }
189
190    /**
191     * Sorts the specified range of the off-heap struct collection into ascending order using long struct key.
192     * The range to be sorted extends from the index {@code fromIndex}, inclusive, to
193     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
194     * the range to be sorted is empty (and the call is a no-op).
195     *
196     * @param a the off-heap struct collection to be sorted
197     * @param fromIndex the index of the first element, inclusive, to be sorted
198     * @param toIndex the index of the last element, exclusive, to be sorted
199     * @param keyOffset long sort key field offset within stuct bounds
200     * @throws IllegalArgumentException {@code if (fromIndex < 0 || fromIndex > toIndex || toIndex > a.size())}
201     */
202    public static void sortByLongKey(OffHeapStructCollection a, long fromIndex, long toIndex, int keyOffset) {
203        OffHeapStructSorterLong.sort(a, fromIndex, toIndex, keyOffset);
204    }
205
206    /**
207     * Sorts collection by two long keys. Second key sorting is done in parallel.
208     *
209     * @param executor   executor for parallel sorting
210     * @param threads    number of worker threads to use
211     * @param a          the off-heap struct collection to be sorted
212     * @param key1Offset first key offset
213     * @param key2Offset second key offset
214     */
215    public static void sortByLongKeysParallel(Executor executor, int threads, OffHeapStructCollection a, int key1Offset, int key2Offset) {
216        OffHeapStructSorterLong.sortTwoKeysParallel(executor, threads, a, key1Offset, key2Offset);
217    }
218
219    /**
220     * Sorts the specified off-heap struct collection into ascending order using unsigned long struct key.
221     *
222     * @param a the off-heap struct collection to be sorted
223     * @param keyOffset long key field offset within stuct bounds
224     */
225    public static void sortByUnsignedLongKey(OffHeapStructCollection a, int keyOffset) {
226        OffHeapStructSorterUnsignedLong.sort(a, keyOffset);
227    }
228
229    /**
230     * Sorts the specified range of the off-heap struct collection into ascending order using unsigned long struct key.
231     * The range to be sorted extends from the index {@code fromIndex}, inclusive, to
232     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
233     * the range to be sorted is empty (and the call is a no-op).
234     *
235     * @param a the off-heap struct collection to be sorted
236     * @param fromIndex the index of the first element, inclusive, to be sorted
237     * @param toIndex the index of the last element, exclusive, to be sorted
238     * @param keyOffset long sort key field offset within stuct bounds
239     * @throws IllegalArgumentException {@code if (fromIndex < 0 || fromIndex > toIndex || toIndex > a.size())}
240     */
241    public static void sortByUnsignedLongKey(OffHeapStructCollection a, long fromIndex, long toIndex, int keyOffset) {
242        OffHeapStructSorterUnsignedLong.sort(a, fromIndex, toIndex, keyOffset);
243    }
244
245    /**
246     * Sorts the specified off-heap struct collection into ascending order using int struct key.
247     *
248     * @param a the off-heap struct collection to be sorted
249     * @param keyOffset int key field offset within stuct bounds
250     */
251    public static void sortByIntKey(OffHeapStructCollection a, int keyOffset) {
252        OffHeapStructSorterInt.sort(a, keyOffset);
253    }
254
255    /**
256     * Sorts the specified range of the off-heap struct collection into ascending order using int struct key. The range
257     * to be sorted extends from the index {@code fromIndex}, inclusive, to
258     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
259     * the range to be sorted is empty (and the call is a no-op).
260     *
261     * @param a the off-heap struct collection to be sorted
262     * @param fromIndex the index of the first element, inclusive, to be sorted
263     * @param toIndex the index of the last element, exclusive, to be sorted
264     * @param keyOffset int sort key field offset within stuct bounds
265     * @throws IllegalArgumentException {@code if (fromIndex < 0 || fromIndex > toIndex || toIndex > a.size())}
266     */
267    public static void sortByIntKey(OffHeapStructCollection a, long fromIndex, long toIndex, int keyOffset) {
268        OffHeapStructSorterInt.sort(a, fromIndex, toIndex, keyOffset);
269    }
270
271    /**
272     * Sorts the specified off-heap struct collection into ascending order using unsigned int struct key.
273     *
274     * @param a the off-heap struct collection to be sorted
275     * @param keyOffset int key field offset within stuct bounds
276     */
277    public static void sortByUnsignedIntKey(OffHeapStructCollection a, int keyOffset) {
278        OffHeapStructSorterUnsignedInt.sort(a, keyOffset);
279    }
280
281    /**
282     * Sorts the specified range of the off-heap struct collection into ascending order using unsigned int struct key. The range
283     * to be sorted extends from the index {@code fromIndex}, inclusive, to
284     * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
285     * the range to be sorted is empty (and the call is a no-op).
286     *
287     * @param a the off-heap struct collection to be sorted
288     * @param fromIndex the index of the first element, inclusive, to be sorted
289     * @param toIndex the index of the last element, exclusive, to be sorted
290     * @param keyOffset int sort key field offset within stuct bounds
291     * @throws IllegalArgumentException {@code if (fromIndex < 0 || fromIndex > toIndex || toIndex > a.size())}
292     */
293    public static void sortByUnsignedIntKey(OffHeapStructCollection a, long fromIndex, long toIndex, int keyOffset) {
294        OffHeapStructSorterUnsignedInt.sort(a, fromIndex, toIndex, keyOffset);
295    }
296
297    /**
298     * Sorts collection using additional {@link com.alexkasko.unsafe.offheaplong.OffHeapLongArray} with the same size
299     * as collection itself as an array of references (indices) of the collection
300     *
301     * @param a the off-heap struct collection to be sorted
302     * @param comparator structs comparator
303     * @return sorted iterable over the collection
304     * @throws IllegalArgumentException {@code if (fromIndex < 0 || fromIndex > toIndex || toIndex > a.size())}
305     */
306    public static OffHeapDisposableIterable<byte[]> sortedByRefIterable(OffHeapStructCollection a,
307                                                                        Comparator<OffHeapStructAccessor> comparator) {
308        return OffHeapStructSorterByReference.sortedIterable(a, comparator);
309    }
310
311    /**
312     * Sorts collection using additional {@link com.alexkasko.unsafe.offheaplong.OffHeapLongArray} with the same size
313     * as collection itself as an array of references (indices) of the collection
314     *
315     * @param a the off-heap struct collection to be sorted
316     * @param fromIndex the index of the first element, inclusive, to be sorted
317     * @param toIndex the index of the last element, exclusive, to be sorted
318     * @param comparator structs comparator
319     * @return sorted iterable over the collection
320     * @throws IllegalArgumentException {@code if (fromIndex < 0 || fromIndex > toIndex || toIndex > a.size())}
321     */
322    public static OffHeapDisposableIterable<byte[]> sortedByRefIterable(OffHeapStructCollection a, long fromIndex,
323                                                                        long toIndex, Comparator<OffHeapStructAccessor> comparator) {
324        return OffHeapStructSorterByReference.sortedIterable(a, fromIndex, toIndex, comparator);
325    }
326}