graphql.nadel.enginekt.util.CollectionUtil.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nadel-engine-nextgen Show documentation
Show all versions of nadel-engine-nextgen Show documentation
Nadel is a Java library that combines multiple GrahpQL services together into one API.
The newest version!
package graphql.nadel.enginekt.util
import java.util.Collections
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.set
/**
* Like [singleOrNull] but the single item must be of type [T].
*/
inline fun Collection<*>.singleOfTypeOrNull(predicate: (T) -> Boolean = { true }): T? {
return singleOrNull { it is T && predicate(it) } as T?
}
/**
* Like [singleOrNull] but the single item must be of type [T].
*/
inline fun Collection<*>.singleOfType(predicate: (T) -> Boolean = { true }): T {
return singleOfTypeOrNull(predicate)!!
}
inline fun Iterable.strictAssociateBy(crossinline keyExtractor: (E) -> K): Map {
return mapFrom(
map {
keyExtractor(it) to it
}
)
}
inline fun Sequence.strictAssociateBy(crossinline keyExtractor: (E) -> K): Map {
val map = mutableMapOf()
var count = 0
forEach {
map[keyExtractor(it)] = it
count++
}
require(map.size == count)
return Collections.unmodifiableMap(map)
}
/**
* Like [mapOf] but takes in a [Collection] instead of vararg. Useful if your input
* into the [Map] is [List.map]ped from another [Collection].
*/
@JvmName("mapFromPairs")
fun mapFrom(entries: Collection>): Map {
val map = HashMap(entries.size)
map.putAll(entries)
require(map.size == entries.size) {
@Suppress("SimpleRedundantLet") // For debugging purposes if you want to visit the values
"Duplicate keys: " + entries.groupBy { it.first }.filterValues { it.size > 1 }.let {
it.keys
}
}
return map
}
/**
* Like [mapOf] but takes in a [Collection] instead of vararg. Useful if your input
* into the [Map] is [List.map]ped from another [Collection].
*/
@JvmName("mapFromPairs")
fun mapFrom(entries: Sequence>): Map {
val map = HashMap()
var count = 0
entries.forEach {
map[it.first] = it.second
count++
}
require(map.size == count) {
@Suppress("SimpleRedundantLet") // For debugging purposes if you want to visit the values
"Duplicate keys: " + entries.groupBy { it.first }.filterValues { it.size > 1 }.let {
it.keys
}
}
return map
}
fun Sequence>.toMapStrictly(): Map {
return mapFrom(entries = this)
}
fun Collection>.toMapStrictly(): Map {
return mapFrom(entries = this)
}
/**
* Like [mapOf] but takes in a [Collection] instead of vararg. Useful if your input
* into the [Map] is [List.map]ped from another [Collection].
*/
@JvmName("mapFromEntries")
fun mapFrom(entries: Collection>): Map {
val map = HashMap(entries.size)
entries.forEach(map::put)
require(map.size == entries.size)
return map
}
/**
* Utility function to set the [Map.Entry.key] to [Map.Entry.value] in the given [MutableMap].
*/
fun MutableMap.put(entry: Map.Entry) {
put(entry.key, entry.value)
}
/**
* Utility function to set the [Map.Entry.key] to [Map.Entry.value] in the given [MutableMap].
*/
fun MutableMap.put(entry: Pair) {
put(entry.first, entry.second)
}
/**
* Inverts the [Map] such that the values are now the keys and the keys are now the values.
*/
fun Map.invert(): Map {
val map = HashMap(this.size)
forEach { (key, value) ->
map[value] = key
}
require(map.size == this.size)
return map
}
/**
* Try to replace the function body with just:
*
* ```kotlin
*putAll(map)
* ```
*
* If it works then yay we don't need this function anymore, but right now I'm getting:
*
* Type mismatch
*
* Required: Map
*
* Found: Map<*, *>
*/
fun AnyMutableMap.hackPutAll(map: AnyMap) {
@Suppress("UNCHECKED_CAST")
(this as MutableMap).putAll(map)
}
/**
* This function permits an empty collection or a [single] object in the collection.
*
* @return null if empty or [single] object
* @see single
*/
fun Iterable.emptyOrSingle(): T? {
return when (this) {
is List -> when (isEmpty()) {
true -> null
else -> single()
}
else -> iterator().emptyOrSingle()
}
}
/**
* See `Iterable`.[emptyOrSingle]
*/
fun Iterator.emptyOrSingle(): T? {
return when (hasNext()) {
true -> next().also {
if (hasNext()) {
// Copied from List.single
throw IllegalArgumentException("List has more than one element.")
}
}
else -> null
}
}
/**
* See `Iterable`.[emptyOrSingle]
*/
fun Sequence.emptyOrSingle(): T? {
return iterator().emptyOrSingle()
}
inline fun Map.filterValuesOfType(): Map {
@Suppress("UNCHECKED_CAST")
return filterValues {
it is T
} as Map
}
fun Sequence.flatten(recursively: Boolean): Sequence {
return flatMap { element ->
when (element) {
is AnyMap -> sequenceOf(element)
is AnyIterable -> element.asSequence().let {
if (recursively) {
it.flatten(recursively = true)
} else {
it
}
}
else -> sequenceOf(element)
}
}
}
/**
* See [List.subList], but if input is out of bounds then null is returned instead.
*/
fun List.subListOrNull(fromIndex: Int, toIndex: Int): List? {
if (fromIndex < 0 || /*toIndex is exclusive, hence minus 1*/ toIndex - 1 > lastIndex) {
return null
}
return subList(fromIndex = fromIndex, toIndex = toIndex)
}
fun Iterable.foldWhileNotNull(initial: R, operation: (acc: R, T) -> R): R? {
var accumulator = initial
for (element in this) {
accumulator = operation(accumulator, element) ?: return null
}
return accumulator
}
fun listOfNulls(size: Int): List {
return ArrayList(size).also {
for (i in 1..size) {
it.add(null)
}
}
}
fun sequenceOfNulls(size: Int): Sequence {
return sequence {
for (i in 1..size) {
yield(null)
}
}
}