|
| 1 | +package com.mineinabyss.packy.helpers |
| 2 | + |
| 3 | +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap |
| 4 | +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap |
| 5 | +import it.unimi.dsi.fastutil.objects.ObjectArrayList |
| 6 | +import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet |
| 7 | +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet |
| 8 | +import java.util.* |
| 9 | +import kotlin.also |
| 10 | +import kotlin.apply |
| 11 | +import kotlin.collections.addAll |
| 12 | +import kotlin.collections.associateByTo |
| 13 | +import kotlin.collections.associateTo |
| 14 | +import kotlin.collections.associateWithTo |
| 15 | +import kotlin.collections.copyOf |
| 16 | +import kotlin.collections.count |
| 17 | +import kotlin.collections.filterIsInstanceTo |
| 18 | +import kotlin.collections.filterTo |
| 19 | +import kotlin.collections.flatMapTo |
| 20 | +import kotlin.collections.mapNotNullTo |
| 21 | +import kotlin.collections.mapTo |
| 22 | +import kotlin.collections.set |
| 23 | +import kotlin.collections.toMap |
| 24 | +import kotlin.let |
| 25 | +import kotlin.ranges.coerceAtLeast |
| 26 | +import kotlin.sequences.filterTo |
| 27 | +import kotlin.to |
| 28 | + |
| 29 | +inline fun <T, R> Iterable<T>.flatMapFast(transform: (T) -> Iterable<R>): ObjectArrayList<R> { |
| 30 | + return flatMapTo(ObjectArrayList<R>(), transform) |
| 31 | +} |
| 32 | + |
| 33 | +inline fun <T, R> Iterable<T>.flatMapFastNotNull(transform: (T) -> Iterable<R?>): ObjectArrayList<R> { |
| 34 | + val result = ObjectArrayList<R>() |
| 35 | + for (element in this) { |
| 36 | + for (item in transform(element)) { |
| 37 | + if (item != null) result.add(item) |
| 38 | + } |
| 39 | + } |
| 40 | + return result |
| 41 | +} |
| 42 | + |
| 43 | +inline fun <T, R> Iterable<T>.flatMapSetFast(transform: (T) -> Iterable<R>): ObjectLinkedOpenHashSet<R> { |
| 44 | + return flatMapTo(ObjectLinkedOpenHashSet<R>(), transform) |
| 45 | +} |
| 46 | + |
| 47 | +inline fun <T, R> Iterable<T>.mapFast(transform: (T) -> R): ObjectArrayList<R> { |
| 48 | + return mapTo(ObjectArrayList<R>((this as? Collection)?.size ?: 10), transform) |
| 49 | +} |
| 50 | + |
| 51 | +inline fun <T, R : Any> Iterable<T>.mapNotNullFast(transform: (T) -> R?): ObjectArrayList<R> { |
| 52 | + return mapNotNullTo(ObjectArrayList<R>(), transform) |
| 53 | +} |
| 54 | + |
| 55 | +inline fun <T, R> Iterable<T>.mapFastSet(transform: (T) -> R): ObjectOpenHashSet<R> { |
| 56 | + return mapTo(ObjectOpenHashSet<R>((this as? Collection)?.size ?: 10), transform) |
| 57 | +} |
| 58 | + |
| 59 | +inline fun <T, reified R> Iterable<T>.toTypedArrayIndexed(transform: (Int, T) -> R): Array<R> { |
| 60 | + val result = arrayOfNulls<R>(this.count()) |
| 61 | + var index = 0 |
| 62 | + for (item in this) result[index] = transform(index, item).also { index++ } |
| 63 | + return result as Array<R> |
| 64 | +} |
| 65 | + |
| 66 | +inline fun <T, reified R> Iterable<T>.toTypedArray(transform: (T) -> R): Array<R> { |
| 67 | + val result = arrayOfNulls<R>(this.count()) |
| 68 | + var index = 0 |
| 69 | + for (item in this) result[index++] = transform(item) |
| 70 | + return result as Array<R> |
| 71 | +} |
| 72 | + |
| 73 | +inline fun <T, reified R> Array<T>.toTypedArray(transform: (T) -> R): Array<R> { |
| 74 | + val result = arrayOfNulls<R>(this.count()) |
| 75 | + var index = 0 |
| 76 | + for (item in this) result[index++] = transform(item) |
| 77 | + return result as Array<R> |
| 78 | +} |
| 79 | + |
| 80 | +inline fun <T, reified R : Any> Iterable<T>.toTypedArrayNotNull(transform: (T) -> R?): Array<R> { |
| 81 | + var result = arrayOfNulls<R>(this.count()) |
| 82 | + var index = 0 |
| 83 | + |
| 84 | + for (item in this) { |
| 85 | + transform(item)?.let { |
| 86 | + if (index >= result.size) { |
| 87 | + result = result.copyOf(kotlin.comparisons.maxOf(result.size * 2, this.count())) |
| 88 | + } |
| 89 | + result[index++] = it |
| 90 | + } |
| 91 | + } |
| 92 | + |
| 93 | + // Trim to exact size |
| 94 | + return result.copyOf(index) as Array<R> |
| 95 | +} |
| 96 | + |
| 97 | + |
| 98 | +inline fun <T, K, V> Iterable<T>.associateFast(transform: (T) -> Pair<K, V>): Object2ObjectOpenHashMap<K, V> { |
| 99 | + val capacity = mapCapacity((this as? Collection)?.size ?: 10).coerceAtLeast(16) |
| 100 | + return associateTo(Object2ObjectOpenHashMap<K, V>(capacity), transform) |
| 101 | +} |
| 102 | + |
| 103 | +inline fun <T, K, V> Array<T>.associateFast(transform: (T) -> Pair<K, V>): Object2ObjectOpenHashMap<K, V> { |
| 104 | + val capacity = mapCapacity(size).coerceAtLeast(16) |
| 105 | + return associateTo(Object2ObjectOpenHashMap<K, V>(capacity), transform) |
| 106 | +} |
| 107 | + |
| 108 | +inline fun <T, K> Iterable<T>.associateFastBy(keySelector: (T) -> K): Object2ObjectOpenHashMap<K, T> { |
| 109 | + val result = Object2ObjectOpenHashMap<K, T>(mapCapacity((this as? Collection)?.size ?: 10).coerceAtLeast(16)) |
| 110 | + return associateByTo(result, keySelector) |
| 111 | +} |
| 112 | + |
| 113 | +inline fun <K, V> Iterable<K>.associateFastWith(valueSelector: (K) -> V): Object2ObjectOpenHashMap<K, V> { |
| 114 | + val result = Object2ObjectOpenHashMap<K, V>(mapCapacity((this as? Collection)?.size ?: 10).coerceAtLeast(16)) |
| 115 | + return associateWithTo(result, valueSelector) |
| 116 | +} |
| 117 | + |
| 118 | +inline fun <T, K, V> Iterable<T>.associateFastLinked(pairSelector: (T) -> Pair<K, V>): Object2ObjectLinkedOpenHashMap<K, V> { |
| 119 | + val result = Object2ObjectLinkedOpenHashMap<K, V>(mapCapacity((this as? Collection)?.size ?: 10).coerceAtLeast(16)) |
| 120 | + return associateTo(result, pairSelector) |
| 121 | +} |
| 122 | + |
| 123 | +inline fun <K, V> Iterable<K>.associateFastLinkedWith(valueSelector: (K) -> V): Object2ObjectLinkedOpenHashMap<K, V> { |
| 124 | + val result = Object2ObjectLinkedOpenHashMap<K, V>(mapCapacity((this as? Collection)?.size ?: 10).coerceAtLeast(16)) |
| 125 | + return associateWithTo(result, valueSelector) |
| 126 | +} |
| 127 | + |
| 128 | +inline fun <T, K, V> Iterable<T>.associateFastNotNull( |
| 129 | + pairSelector: (T) -> Pair<K?, V?>? |
| 130 | +): Object2ObjectOpenHashMap<K, V> { |
| 131 | + val result = Object2ObjectOpenHashMap<K, V>(mapCapacity((this as? Collection)?.size ?: 10).coerceAtLeast(16)) |
| 132 | + for (element in this) { |
| 133 | + val (key, value) = pairSelector(element)?.let { (it.first ?: continue) to (it.second ?: continue) } ?: continue |
| 134 | + result[key] = value |
| 135 | + } |
| 136 | + return result |
| 137 | +} |
| 138 | + |
| 139 | +inline fun <T, K, V> Iterable<T>.associateFastLinkedNotNull( |
| 140 | + pairSelector: (T) -> Pair<K?, V?>? |
| 141 | +): Object2ObjectLinkedOpenHashMap<K, V> { |
| 142 | + val result = Object2ObjectLinkedOpenHashMap<K, V>(mapCapacity((this as? Collection)?.size ?: 10).coerceAtLeast(16)) |
| 143 | + for (element in this) { |
| 144 | + val (key, value) = pairSelector(element)?.let { (it.first ?: continue) to (it.second ?: continue) } ?: continue |
| 145 | + result[key] = value |
| 146 | + } |
| 147 | + return result |
| 148 | +} |
| 149 | + |
| 150 | +inline fun <T, K, V> Iterable<T>.associateFastByNotNull( |
| 151 | + keySelector: (T) -> K?, |
| 152 | + valueSelector: (T) -> V? |
| 153 | +): Object2ObjectOpenHashMap<K, V> { |
| 154 | + val result = Object2ObjectOpenHashMap<K, V>(mapCapacity((this as? Collection)?.size ?: 10).coerceAtLeast(16)) |
| 155 | + for (element in this) { |
| 156 | + val key = keySelector(element) ?: continue |
| 157 | + val value = valueSelector(element) ?: continue |
| 158 | + result[key] = value |
| 159 | + } |
| 160 | + return result |
| 161 | +} |
| 162 | + |
| 163 | +inline fun <reified R> Iterable<*>.filterFastIsInstance(): ObjectArrayList<R> { |
| 164 | + return filterIsInstanceTo(ObjectArrayList<R>()) |
| 165 | +} |
| 166 | + |
| 167 | +inline fun <reified R> Iterable<*>.filterFastIsInstance(predicate: (R) -> Boolean): ObjectArrayList<R> { |
| 168 | + val result = ObjectArrayList<R>() |
| 169 | + for (element in this) if (element is R && predicate(element)) result.add(element) |
| 170 | + return result |
| 171 | +} |
| 172 | + |
| 173 | +inline fun <T> Iterable<T>.filterFast(predicate: (T) -> Boolean): ObjectArrayList<T> { |
| 174 | + return filterTo(ObjectArrayList<T>(), predicate) |
| 175 | +} |
| 176 | + |
| 177 | +inline fun <T> Iterable<T>.filterFastSet(predicate: (T) -> Boolean): ObjectOpenHashSet<T> { |
| 178 | + return filterTo(ObjectOpenHashSet<T>(), predicate) |
| 179 | +} |
| 180 | + |
| 181 | +inline fun <reified R> Sequence<*>.filterFastIsInstance(predicate: (R) -> Boolean): ObjectArrayList<R> { |
| 182 | + val result = ObjectArrayList<R>() |
| 183 | + for (element in this) if (element is R && predicate(element)) result.add(element) |
| 184 | + return result |
| 185 | +} |
| 186 | + |
| 187 | +inline fun <T> Sequence<T>.filterFast(predicate: (T) -> Boolean): ObjectArrayList<T> { |
| 188 | + return filterTo(ObjectArrayList<T>(), predicate) |
| 189 | +} |
| 190 | + |
| 191 | +inline fun <T> Sequence<T>.filterFastSet(predicate: (T) -> Boolean): ObjectOpenHashSet<T> { |
| 192 | + return filterTo(ObjectOpenHashSet<T>(), predicate) |
| 193 | +} |
| 194 | + |
| 195 | +inline fun <K, V> Map<out K, V>.filterFast(predicate: (Map.Entry<K, V>) -> Boolean): Object2ObjectOpenHashMap<K, V> { |
| 196 | + return filterTo(Object2ObjectOpenHashMap<K, V>(), predicate) |
| 197 | +} |
| 198 | + |
| 199 | +fun <K, V> Iterable<Pair<K, V>>.toFastMap(): Object2ObjectOpenHashMap<K, V> { |
| 200 | + if (this is Collection) { |
| 201 | + return when (size) { |
| 202 | + 0 -> Object2ObjectOpenHashMap() |
| 203 | + 1 -> fastMapOf(if (this is List) this[0] else iterator().next()) |
| 204 | + else -> toMap(Object2ObjectOpenHashMap<K, V>(mapCapacity(size))) |
| 205 | + } |
| 206 | + } |
| 207 | + return toMap(LinkedHashMap<K, V>()).optimizeReadOnlyMap() |
| 208 | +} |
| 209 | + |
| 210 | +fun <K, V> fastMapOf(pair: Pair<K, V>): Object2ObjectOpenHashMap<K, V> = Object2ObjectOpenHashMap<K, V>().apply { put(pair.first, pair.second) } |
| 211 | + |
| 212 | +fun mapCapacity(expectedSize: Int): Int = when { |
| 213 | + // We are not coercing the value to a valid one and not throwing an exception. It is up to the caller to |
| 214 | + // properly handle negative values. |
| 215 | + expectedSize < 0 -> expectedSize |
| 216 | + expectedSize < 3 -> expectedSize + 1 |
| 217 | + expectedSize < INT_MAX_POWER_OF_TWO -> ((expectedSize / 0.75F) + 1.0F).toInt() |
| 218 | + // any large value |
| 219 | + else -> Int.MAX_VALUE |
| 220 | +} |
| 221 | + |
| 222 | +internal fun <K, V> Map<K, V>.optimizeReadOnlyMap() = when (size) { |
| 223 | + 0 -> Object2ObjectOpenHashMap() |
| 224 | + 1 -> Object2ObjectOpenHashMap(with(entries.iterator().next()) { |
| 225 | + Collections.singletonMap(key, value) |
| 226 | + }) |
| 227 | + else -> Object2ObjectOpenHashMap(this) |
| 228 | +} |
| 229 | + |
| 230 | +private const val INT_MAX_POWER_OF_TWO: Int = 1 shl (Int.SIZE_BITS - 2) |
| 231 | + |
| 232 | +fun <T> List<T>.plusFast(elements: Iterable<T>): ObjectArrayList<T> { |
| 233 | + if (elements is Collection) { |
| 234 | + val result = ObjectArrayList<T>(this.size + elements.size) |
| 235 | + result.addAll(this) |
| 236 | + result.addAll(elements) |
| 237 | + return result |
| 238 | + } else { |
| 239 | + val result = ObjectArrayList<T>(this) |
| 240 | + result.addAll(elements) |
| 241 | + return result |
| 242 | + } |
| 243 | +} |
| 244 | + |
| 245 | +fun <T> Set<T>.plusFast(elements: Iterable<T>): ObjectOpenHashSet<T> { |
| 246 | + if (elements is Collection) { |
| 247 | + val result = ObjectOpenHashSet<T>(this.size + elements.size) |
| 248 | + result.addAll(this) |
| 249 | + result.addAll(elements) |
| 250 | + return result |
| 251 | + } else { |
| 252 | + val result = ObjectOpenHashSet<T>(this) |
| 253 | + result.addAll(elements) |
| 254 | + return result |
| 255 | + } |
| 256 | +} |
| 257 | + |
| 258 | +inline fun <T, K> Iterable<T>.groupByFast(keySelector: (T) -> K): Object2ObjectLinkedOpenHashMap<K, ObjectArrayList<T>> { |
| 259 | + val map = Object2ObjectLinkedOpenHashMap<K, ObjectArrayList<T>>() |
| 260 | + for (element in this) { |
| 261 | + val key = keySelector(element) |
| 262 | + map.computeIfAbsent(key) { ObjectArrayList() }.add(element) |
| 263 | + } |
| 264 | + return map |
| 265 | +} |
| 266 | + |
| 267 | +inline fun <T, K> Iterable<T>.groupByFastSet(keySelector: (T) -> K): Object2ObjectLinkedOpenHashMap<K, ObjectOpenHashSet<T>> { |
| 268 | + val map = Object2ObjectLinkedOpenHashMap<K, ObjectOpenHashSet<T>>() |
| 269 | + for (element in this) { |
| 270 | + val key = keySelector(element) |
| 271 | + map.computeIfAbsent(key) { ObjectOpenHashSet() }.add(element) |
| 272 | + } |
| 273 | + return map |
| 274 | +} |
0 commit comments