package at.hannibal2.skyhanni.utils import java.util.Collections import java.util.WeakHashMap import java.util.concurrent.ConcurrentLinkedQueue object CollectionUtils { fun ConcurrentLinkedQueue.drainTo(list: MutableCollection) { while (true) list.add(this.poll() ?: break) } // Let garbage collector handle the removal of entries in this list fun weakReferenceList(): MutableSet = Collections.newSetFromMap(WeakHashMap()) fun MutableCollection.filterToMutable(predicate: (T) -> Boolean) = filterTo(mutableListOf(), predicate) fun List.indexOfFirst(vararg args: T) = args.map { indexOf(it) }.firstOrNull { it != -1 } infix fun MutableMap.put(pairs: Pair) { this[pairs.first] = pairs.second } // Taken and modified from Skytils @JvmStatic fun T.equalsOneOf(vararg other: T): Boolean { for (obj in other) { if (this == obj) return true } return false } fun List.getOrNull(index: Int): E? { return if (index in indices) { get(index) } else null } fun T?.toSingletonListOrEmpty(): List { if (this == null) return emptyList() return listOf(this) } fun MutableMap.addOrPut(key: K, number: Int): Int = this.merge(key, number, Int::plus)!! // Never returns null since "plus" can't return null fun MutableMap.addOrPut(key: K, number: Long): Long = this.merge(key, number, Long::plus)!! // Never returns null since "plus" can't return null fun MutableMap.addOrPut(key: K, number: Double): Double = this.merge(key, number, Double::plus)!! // Never returns null since "plus" can't return null fun MutableMap.addOrPut(key: K, number: Float): Float = this.merge(key, number, Float::plus)!! // Never returns null since "plus" can't return null fun Map.sumAllValues(): Double { if (values.isEmpty()) return 0.0 return when (values.first()) { is Double -> values.sumOf { it.toDouble() } is Float -> values.sumOf { it.toDouble() } is Long -> values.sumOf { it.toLong() }.toDouble() else -> values.sumOf { it.toInt() }.toDouble() } } fun List.nextAfter(after: String, skip: Int = 1) = nextAfter({ it == after }, skip) fun List.nextAfter(after: (String) -> Boolean, skip: Int = 1): String? { var missing = -1 for (line in this) { if (after(line)) { missing = skip - 1 continue } if (missing == 0) { return line } if (missing != -1) { missing-- } } return null } fun List.removeNextAfter(after: String, skip: Int = 1) = removeNextAfter({ it == after }, skip) fun List.removeNextAfter(after: (String) -> Boolean, skip: Int = 1): List { val newList = mutableListOf() var missing = -1 for (line in this) { if (after(line)) { missing = skip - 1 continue } if (missing == 0) { missing-- continue } if (missing != -1) { missing-- } newList.add(line) } return newList } fun List.addIfNotNull(element: String?) = element?.let { plus(it) } ?: this fun Map.editCopy(function: MutableMap.() -> Unit) = toMutableMap().also { function(it) }.toMap() fun List.editCopy(function: MutableList.() -> Unit) = toMutableList().also { function(it) }.toList() fun Map.moveEntryToTop(matcher: (Map.Entry) -> Boolean): Map { val entry = entries.find(matcher) if (entry != null) { val newMap = linkedMapOf(entry.key to entry.value) newMap.putAll(this) return newMap } return this } fun MutableList>.addAsSingletonList(text: E) { add(Collections.singletonList(text)) } fun > List>.sorted(): List> { return sortedBy { (_, value) -> value } } fun > Map.sorted(): Map { return toList().sorted().toMap() } fun > Map.sortedDesc(): Map { return toList().sorted().reversed().toMap() } inline fun ConcurrentLinkedQueue.drainForEach(action: (T) -> Unit) { while (true) { val value = this.poll() ?: break action(value) } } fun Sequence.takeWhileInclusive(predicate: (T) -> Boolean) = sequence { with(iterator()) { while (hasNext()) { val next = next() yield(next) if (!predicate(next)) break } } } /** Updates a value if it is present in the set (equals), useful if the newValue is not reference equal with the value in the set */ inline fun MutableSet.refreshReference(newValue: T) = if (this.contains(newValue)) { this.remove(newValue) this.add(newValue) true } else false }