diff --git a/src/commonMain/kotlin/ru/spbstu/wheels/Breakable.kt b/src/commonMain/kotlin/ru/spbstu/wheels/Breakable.kt index dee3e47..5f3798d 100644 --- a/src/commonMain/kotlin/ru/spbstu/wheels/Breakable.kt +++ b/src/commonMain/kotlin/ru/spbstu/wheels/Breakable.kt @@ -1,5 +1,10 @@ +@file:OptIn(ExperimentalContracts::class) package ru.spbstu.wheels +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract + object Break : NoStackThrowable("break") object Continue : NoStackThrowable("continue") @@ -7,22 +12,27 @@ object BreakableContext { inline val break_: Nothing get() = throw Break inline val continue_: Nothing get() = throw Continue - inline fun iteration(body: BreakableContext.() -> T): T? = - try { - this.body() - } catch (_: Continue) { - null - } - - inline fun loop(body: BreakableContext.() -> T): T? = - try { - this.body() - } catch (_: Break) { - null - } + inline fun iteration(body: BreakableContext.() -> T): T? { + contract { callsInPlace(body, InvocationKind.EXACTLY_ONCE) } + return try { + this.body() + } catch (_: Continue) { + null + } + } + + inline fun loop(body: BreakableContext.() -> T): T? { + contract { callsInPlace(body, InvocationKind.EXACTLY_ONCE) } + return try { + this.body() + } catch (_: Break) { + null + } + } } inline fun Iterable.forEachB(body: BreakableContext.(T) -> Unit) { + contract { callsInPlace(body) } BreakableContext.loop { forEach { iteration { body(it) } @@ -31,6 +41,7 @@ inline fun Iterable.forEachB(body: BreakableContext.(T) -> Unit) { } inline fun Sequence.forEachB(body: BreakableContext.(T) -> Unit) { + contract { callsInPlace(body) } BreakableContext.loop { forEach { iteration { body(it) } @@ -39,6 +50,7 @@ inline fun Sequence.forEachB(body: BreakableContext.(T) -> Unit) { } inline fun Iterable.forEachIndexedB(body: BreakableContext.(Int, T) -> Unit) { + contract { callsInPlace(body) } BreakableContext.loop { forEachIndexed { i, e -> iteration { body(i, e) } @@ -47,6 +59,7 @@ inline fun Iterable.forEachIndexedB(body: BreakableContext.(Int, T) -> Un } inline fun Sequence.forEachIndexedB(body: BreakableContext.(Int, T) -> Unit) { + contract { callsInPlace(body) } BreakableContext.loop { forEachIndexed { i, e -> iteration { body(i, e) } @@ -54,7 +67,9 @@ inline fun Sequence.forEachIndexedB(body: BreakableContext.(Int, T) -> Un } } + inline fun repeatB(times: Int, body: BreakableContext.(Int) -> Unit) { + contract { callsInPlace(body) } BreakableContext.loop { repeat(times) { iteration { body(it) } @@ -63,6 +78,7 @@ inline fun repeatB(times: Int, body: BreakableContext.(Int) -> Unit) { } inline fun > Iterable.mapOrBreakTo(to: C, body: BreakableContext.(T) -> U): C { + contract { callsInPlace(body) } BreakableContext.loop { forEach { iteration { to.add(body(it)) } @@ -75,6 +91,7 @@ inline fun Iterable.mapOrBreak(body: BreakableContext.(T) -> U): List< mapOrBreakTo(mutableListOf(), body) inline fun > Sequence.mapOrBreakTo(to: C, body: BreakableContext.(T) -> U): C { + contract { callsInPlace(body) } BreakableContext.loop { forEach { iteration { to.add(body(it)) } @@ -92,6 +109,7 @@ inline fun Sequence.mapOrBreak(crossinline body: BreakableContext.(T) } inline fun > Iterable.mapIndexedOrBreakTo(to: C, body: BreakableContext.(Int, T) -> U): C { + contract { callsInPlace(body) } BreakableContext.loop { forEachIndexed { i, it -> iteration { to.add(body(i, it)) } diff --git a/src/commonMain/kotlin/ru/spbstu/wheels/Collections.kt b/src/commonMain/kotlin/ru/spbstu/wheels/Collections.kt index b3eca38..0dd7de3 100644 --- a/src/commonMain/kotlin/ru/spbstu/wheels/Collections.kt +++ b/src/commonMain/kotlin/ru/spbstu/wheels/Collections.kt @@ -119,3 +119,16 @@ inline fun Iterable.anyIndexed(body: (Int, T) -> Boolean): Boolean { } return false } + +inline fun , C2: MutableCollection> Iterable.partitionTo( + c1: C1, c2: C2, body: (T) -> Boolean +): Pair { + for (e in this) { + if (body(e)) { + c1.add(e) + } else { + c2.add(e) + } + } + return Pair(c1, c2) +} diff --git a/src/commonMain/kotlin/ru/spbstu/wheels/Maps.kt b/src/commonMain/kotlin/ru/spbstu/wheels/Maps.kt index 0695180..efe948a 100644 --- a/src/commonMain/kotlin/ru/spbstu/wheels/Maps.kt +++ b/src/commonMain/kotlin/ru/spbstu/wheels/Maps.kt @@ -118,3 +118,20 @@ fun > Iterable.zipTo(that: Iterable, to: M): M { @Suppress(Warnings.NOTHING_TO_INLINE) inline fun Map.asMap(): Map = this + + +inline fun , C2: MutableMap> Map.partitionTo( + c1: C1, c2: C2, body: (K, V) -> Boolean +): Pair { + for ((k, v) in this) { + if (body(k, v)) { + c1.put(k, v) + } else { + c2.put(k, v) + } + } + return Pair(c1, c2) +} + +inline fun Map.partition(body: (K, V) -> Boolean): Pair, Map> = + partitionTo(mutableMapOf(), mutableMapOf(), body) diff --git a/src/commonMain/kotlin/ru/spbstu/wheels/Misc.kt b/src/commonMain/kotlin/ru/spbstu/wheels/Misc.kt new file mode 100644 index 0000000..184bda4 --- /dev/null +++ b/src/commonMain/kotlin/ru/spbstu/wheels/Misc.kt @@ -0,0 +1,10 @@ +@file:OptIn(ExperimentalContracts::class) +package ru.spbstu.wheels + +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +inline infix fun Int.times(body: (Int) -> Unit) { + contract { callsInPlace(body) } + repeat(this, body) +}