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}