tagan.base.1.5.1.source-code.util.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of base Show documentation
Show all versions of base Show documentation
Yatagan is a Dependency Injection framework, specializing on runtime performance and build speed. Supports code generation (apt/kapt/ksp) or reflection.
The newest version!
/*
* Copyright 2022 Yandex LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.yandex.yatagan.base
import java.util.ServiceLoader
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.reflect.KProperty
inline fun ifOrElseNull(condition: Boolean, block: () -> R): R? {
contract { callsInPlace(block, InvocationKind.AT_MOST_ONCE) }
return if (condition) block() else null
}
inline fun loadServices(): List {
val serviceClass = S::class.java
return ServiceLoader.load(serviceClass, serviceClass.classLoader).toList()
}
inline fun Array.mapToArray(map: (T) -> R): Array {
contract { callsInPlace(map) }
return Array(size) { map(get(it)) }
}
inline fun List.mapToArray(map: (T) -> R): Array {
contract { callsInPlace(map) }
return Array(size) { map(get(it)) }
}
fun Sequence.zipOrNull(another: Sequence): Sequence> {
return Sequence {
object : Iterator> {
val iterator1 = [email protected]()
val iterator2 = another.iterator()
override fun hasNext() = iterator1.hasNext() || iterator2.hasNext()
override fun next(): Pair {
val v1 = ifOrElseNull(iterator1.hasNext()) { iterator1.next() }
val v2 = ifOrElseNull(iterator2.hasNext()) { iterator2.next() }
return v1 to v2
}
}
}
}
inline fun Iterable.zipWithNextOrNull(block: (T, T?) -> R): List {
contract { callsInPlace(block) }
val iterator = iterator()
if (!iterator.hasNext()) {
return emptyList()
}
val iteratorNext = iterator().also { it.next() }
val list: MutableList = when (this) {
is Collection<*> -> ArrayList(size - 1)
else -> ArrayList()
}
while (iterator.hasNext()) {
val first = iterator.next()
val second = ifOrElseNull(iterator.hasNext()) { iteratorNext.next() }
list.add(block(first, second))
}
return list
}
inline fun Iterable>.forEachBi(block: (K, V) -> Unit) {
contract { callsInPlace(block) }
forEach { (k, v) -> block(k, v) }
}
inline fun Array>.forEachBi(block: (K, V) -> Unit) {
contract { callsInPlace(block) }
forEach { (k, v) -> block(k, v) }
}
fun Iterable.sortedWithBy(comparator: Comparator, selector: (T) -> R): List {
return sortedWith(Comparator.comparing(selector, comparator))
}
inline fun traverseDepthFirstWithPath(
roots: Iterable,
childrenOf: (T) -> Iterable,
onLoop: ((loop: Sequence) -> Unit) = { /* nothing by default */ },
visit: (path: Sequence, node: T) -> Unit = { _, _ -> /* nothing by default */ },
) {
val markedGray = hashSetOf()
val markedBlack = hashSetOf()
val stack = arrayListOf>()
val currentPath = stack.asSequence().map { it.last() }
stack += roots.toMutableList()
while (stack.isNotEmpty()) {
// Substack is introduced to preserve node hierarchy
val subStack = stack.last()
if (subStack.isEmpty()) {
stack.removeLast()
continue
}
when (val node = subStack.last()) {
in markedBlack -> {
subStack.removeLast()
}
in markedGray -> {
subStack.removeLast()
markedBlack += node
markedGray -= node
}
else -> {
markedGray += node
visit(currentPath, node)
stack += childrenOf(node).mapNotNullTo(arrayListOf()) { child ->
if (child in markedGray) {
// Loop: report and skip
onLoop(currentPath.dropWhile { it != child })
null
} else child
}
}
}
}
}
class SingleInitPropertyWithFallbackDelegate(
private val fallbackValue: () -> T,
) {
@Volatile private var valueHolder: Lazy = lazy(fallbackValue)
operator fun getValue(thisRef: Any?, property: KProperty<*>): T = valueHolder.value
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
check(!valueHolder.isInitialized()) {
"$property was already initialized, can't initialize after usage or twice"
}
valueHolder = object : Lazy {
override val value: T get() = value
override fun isInitialized() = true
}
}
fun deinitialize() {
valueHolder = lazy(fallbackValue)
}
fun isInitialized(): Boolean {
return valueHolder.isInitialized()
}
}
fun singleInitWithFallback(fallback: () -> T) = SingleInitPropertyWithFallbackDelegate(fallback)