Skip to content

Commit f4b5f15

Browse files
committed
Add persistent Collection builder functions
1 parent fe7b163 commit f4b5f15

File tree

6 files changed

+149
-0
lines changed

6 files changed

+149
-0
lines changed

core/api/kotlinx-collections-immutable.api

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
public final class kotlinx/collections/immutable/ExtensionsKt {
2+
public static final fun buildPersistentHashMap (Lkotlin/jvm/functions/Function1;)Lkotlinx/collections/immutable/PersistentMap;
3+
public static final fun buildPersistentHashSet (Lkotlin/jvm/functions/Function1;)Lkotlinx/collections/immutable/PersistentSet;
4+
public static final fun buildPersistentList (Lkotlin/jvm/functions/Function1;)Lkotlinx/collections/immutable/PersistentList;
5+
public static final fun buildPersistentMap (Lkotlin/jvm/functions/Function1;)Lkotlinx/collections/immutable/PersistentMap;
6+
public static final fun buildPersistentSet (Lkotlin/jvm/functions/Function1;)Lkotlinx/collections/immutable/PersistentSet;
27
public static final fun immutableHashMapOf ([Lkotlin/Pair;)Lkotlinx/collections/immutable/PersistentMap;
38
public static final fun immutableHashSetOf ([Ljava/lang/Object;)Lkotlinx/collections/immutable/PersistentSet;
49
public static final fun immutableListOf ()Lkotlinx/collections/immutable/PersistentList;

core/api/kotlinx-collections-immutable.klib.api

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ final inline fun <#A: kotlin/Any?, #B: kotlin/Any?> (kotlinx.collections.immutab
236236
final inline fun <#A: kotlin/Any?, #B: kotlin/Any?> (kotlinx.collections.immutable/PersistentMap<out #A, #B>).kotlinx.collections.immutable/plus(kotlin.sequences/Sequence<kotlin/Pair<#A, #B>>): kotlinx.collections.immutable/PersistentMap<#A, #B> // kotlinx.collections.immutable/plus|[email protected]<out|0:0,0:1>(kotlin.sequences.Sequence<kotlin.Pair<0:0,0:1>>){0§<kotlin.Any?>;1§<kotlin.Any?>}[0]
237237
final inline fun <#A: kotlin/Any?, #B: kotlin/Any?> (kotlinx.collections.immutable/PersistentMap<out #A, #B>).kotlinx.collections.immutable/plus(kotlin/Array<out kotlin/Pair<#A, #B>>): kotlinx.collections.immutable/PersistentMap<#A, #B> // kotlinx.collections.immutable/plus|[email protected]<out|0:0,0:1>(kotlin.Array<out|kotlin.Pair<0:0,0:1>>){0§<kotlin.Any?>;1§<kotlin.Any?>}[0]
238238
final inline fun <#A: kotlin/Any?, #B: kotlin/Any?> (kotlinx.collections.immutable/PersistentMap<out #A, #B>).kotlinx.collections.immutable/plus(kotlin/Pair<#A, #B>): kotlinx.collections.immutable/PersistentMap<#A, #B> // kotlinx.collections.immutable/plus|[email protected]<out|0:0,0:1>(kotlin.Pair<0:0,0:1>){0§<kotlin.Any?>;1§<kotlin.Any?>}[0]
239+
final inline fun <#A: kotlin/Any?, #B: kotlin/Any?> kotlinx.collections.immutable/buildPersistentHashMap(kotlin/Function1<kotlinx.collections.immutable/PersistentMap.Builder<#A, #B>, kotlin/Unit>): kotlinx.collections.immutable/PersistentMap<#A, #B> // kotlinx.collections.immutable/buildPersistentHashMap|buildPersistentHashMap(kotlin.Function1<kotlinx.collections.immutable.PersistentMap.Builder<0:0,0:1>,kotlin.Unit>){0§<kotlin.Any?>;1§<kotlin.Any?>}[0]
240+
final inline fun <#A: kotlin/Any?, #B: kotlin/Any?> kotlinx.collections.immutable/buildPersistentMap(kotlin/Function1<kotlinx.collections.immutable/PersistentMap.Builder<#A, #B>, kotlin/Unit>): kotlinx.collections.immutable/PersistentMap<#A, #B> // kotlinx.collections.immutable/buildPersistentMap|buildPersistentMap(kotlin.Function1<kotlinx.collections.immutable.PersistentMap.Builder<0:0,0:1>,kotlin.Unit>){0§<kotlin.Any?>;1§<kotlin.Any?>}[0]
239241
final inline fun <#A: kotlin/Any?> (kotlinx.collections.immutable/PersistentCollection<#A>).kotlinx.collections.immutable/minus(#A): kotlinx.collections.immutable/PersistentCollection<#A> // kotlinx.collections.immutable/minus|[email protected]<0:0>(0:0){0§<kotlin.Any?>}[0]
240242
final inline fun <#A: kotlin/Any?> (kotlinx.collections.immutable/PersistentCollection<#A>).kotlinx.collections.immutable/plus(#A): kotlinx.collections.immutable/PersistentCollection<#A> // kotlinx.collections.immutable/plus|[email protected]<0:0>(0:0){0§<kotlin.Any?>}[0]
241243
final inline fun <#A: kotlin/Any?> (kotlinx.collections.immutable/PersistentList<#A>).kotlinx.collections.immutable/minus(#A): kotlinx.collections.immutable/PersistentList<#A> // kotlinx.collections.immutable/minus|[email protected]<0:0>(0:0){0§<kotlin.Any?>}[0]
@@ -244,3 +246,6 @@ final inline fun <#A: kotlin/Any?> (kotlinx.collections.immutable/PersistentList
244246
final inline fun <#A: kotlin/Any?> (kotlinx.collections.immutable/PersistentSet<#A>).kotlinx.collections.immutable/minus(#A): kotlinx.collections.immutable/PersistentSet<#A> // kotlinx.collections.immutable/minus|[email protected]<0:0>(0:0){0§<kotlin.Any?>}[0]
245247
final inline fun <#A: kotlin/Any?> (kotlinx.collections.immutable/PersistentSet<#A>).kotlinx.collections.immutable/mutate(kotlin/Function1<kotlin.collections/MutableSet<#A>, kotlin/Unit>): kotlinx.collections.immutable/PersistentSet<#A> // kotlinx.collections.immutable/mutate|[email protected]<0:0>(kotlin.Function1<kotlin.collections.MutableSet<0:0>,kotlin.Unit>){0§<kotlin.Any?>}[0]
246248
final inline fun <#A: kotlin/Any?> (kotlinx.collections.immutable/PersistentSet<#A>).kotlinx.collections.immutable/plus(#A): kotlinx.collections.immutable/PersistentSet<#A> // kotlinx.collections.immutable/plus|[email protected]<0:0>(0:0){0§<kotlin.Any?>}[0]
249+
final inline fun <#A: kotlin/Any?> kotlinx.collections.immutable/buildPersistentHashSet(kotlin/Function1<kotlinx.collections.immutable/PersistentSet.Builder<#A>, kotlin/Unit>): kotlinx.collections.immutable/PersistentSet<#A> // kotlinx.collections.immutable/buildPersistentHashSet|buildPersistentHashSet(kotlin.Function1<kotlinx.collections.immutable.PersistentSet.Builder<0:0>,kotlin.Unit>){0§<kotlin.Any?>}[0]
250+
final inline fun <#A: kotlin/Any?> kotlinx.collections.immutable/buildPersistentList(kotlin/Function1<kotlinx.collections.immutable/PersistentList.Builder<#A>, kotlin/Unit>): kotlinx.collections.immutable/PersistentList<#A> // kotlinx.collections.immutable/buildPersistentList|buildPersistentList(kotlin.Function1<kotlinx.collections.immutable.PersistentList.Builder<0:0>,kotlin.Unit>){0§<kotlin.Any?>}[0]
251+
final inline fun <#A: kotlin/Any?> kotlinx.collections.immutable/buildPersistentSet(kotlin/Function1<kotlinx.collections.immutable/PersistentSet.Builder<#A>, kotlin/Unit>): kotlinx.collections.immutable/PersistentSet<#A> // kotlinx.collections.immutable/buildPersistentSet|buildPersistentSet(kotlin.Function1<kotlinx.collections.immutable.PersistentSet.Builder<0:0>,kotlin.Unit>){0§<kotlin.Any?>}[0]

core/commonMain/src/extensions.kt

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ import kotlinx.collections.immutable.implementations.persistentOrderedMap.Persis
1616
import kotlinx.collections.immutable.implementations.persistentOrderedMap.PersistentOrderedMapBuilder
1717
import kotlinx.collections.immutable.implementations.persistentOrderedSet.PersistentOrderedSet
1818
import kotlinx.collections.immutable.implementations.persistentOrderedSet.PersistentOrderedSetBuilder
19+
import kotlin.contracts.ExperimentalContracts
20+
import kotlin.contracts.InvocationKind
21+
import kotlin.contracts.contract
22+
import kotlin.experimental.ExperimentalTypeInference
1923

2024
//@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
2125
//inline fun <T> @kotlin.internal.Exact ImmutableCollection<T>.mutate(mutator: (MutableCollection<T>) -> Unit): ImmutableCollection<T> = builder().apply(mutator).build()
@@ -766,3 +770,76 @@ public fun <K, V> Map<K, V>.toPersistentHashMap(): PersistentMap<K, V>
766770
= this as? PersistentHashMap
767771
?: (this as? PersistentHashMapBuilder<K, V>)?.build()
768772
?: PersistentHashMap.emptyOf<K, V>().putAll(this)
773+
774+
/**
775+
* Builds a new [PersistentList] by populating a [PersistentList.Builder] using the given [builderAction]
776+
* and returning an immutable list with the same elements.
777+
*
778+
* The list passed as a receiver to the [builderAction] is valid only inside that function.
779+
* Using it outside the function produces an unspecified behavior.
780+
*/
781+
@OptIn(ExperimentalTypeInference::class, ExperimentalContracts::class)
782+
public inline fun <T> buildPersistentList(@BuilderInference builderAction: PersistentList.Builder<T>.() -> Unit): PersistentList<T> {
783+
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
784+
return persistentListOf<T>().builder().apply(builderAction).build()
785+
}
786+
787+
/**
788+
* Builds a new [PersistentSet] by populating a [PersistentSet.Builder] using the given [builderAction]
789+
* and returning an immutable set with the same elements.
790+
*
791+
* The set passed as a receiver to the [builderAction] is valid only inside that function.
792+
* Using it outside the function produces an unspecified behavior.
793+
*
794+
* Elements of the set are iterated in the order they were added by the [builderAction].
795+
*/
796+
@OptIn(ExperimentalTypeInference::class, ExperimentalContracts::class)
797+
public inline fun <T> buildPersistentSet(@BuilderInference builderAction: PersistentSet.Builder<T>.() -> Unit): PersistentSet<T> {
798+
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
799+
return persistentSetOf<T>().builder().apply(builderAction).build()
800+
}
801+
802+
/**
803+
* Builds a new [PersistentSet] by populating a [PersistentSet.Builder] using the given [builderAction]
804+
* and returning an immutable set with the same elements.
805+
*
806+
* The set passed as a receiver to the [builderAction] is valid only inside that function.
807+
* Using it outside the function produces an unspecified behavior.
808+
*
809+
* Order of the elements in the returned set is unspecified.
810+
*/
811+
@OptIn(ExperimentalTypeInference::class, ExperimentalContracts::class)
812+
public inline fun <T> buildPersistentHashSet(@BuilderInference builderAction: PersistentSet.Builder<T>.() -> Unit): PersistentSet<T> {
813+
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
814+
return persistentHashSetOf<T>().builder().apply(builderAction).build()
815+
}
816+
817+
/**
818+
* Builds a new [PersistentMap] by populating a [PersistentMap.Builder] using the given [builderAction]
819+
* and returning an immutable map with the same key-value pairs.
820+
*
821+
* The map passed as a receiver to the [builderAction] is valid only inside that function.
822+
* Using it outside the function produces an unspecified behavior.
823+
*
824+
* Entries of the map are iterated in the order they were added by the [builderAction].
825+
*/
826+
@OptIn(ExperimentalTypeInference::class, ExperimentalContracts::class)
827+
public inline fun <K, V> buildPersistentMap(@BuilderInference builderAction: PersistentMap.Builder<K, V>.() -> Unit): PersistentMap<K, V> {
828+
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
829+
return persistentMapOf<K, V>().builder().apply(builderAction).build()
830+
}
831+
832+
/**
833+
* Builds a new [PersistentMap] by populating a [PersistentMap.Builder] using the given [builderAction]
834+
* and returning an immutable map with the same key-value pairs.
835+
*
836+
* The map passed as a receiver to the [builderAction] is valid only inside that function.
837+
* Using it outside the function produces an unspecified behavior.
838+
*
839+
* Order of the entries in the returned map is unspecified.
840+
*/
841+
@OptIn(ExperimentalTypeInference::class, ExperimentalContracts::class)
842+
public inline fun <K, V> buildPersistentHashMap(@BuilderInference builderAction: PersistentMap.Builder<K, V>.() -> Unit): PersistentMap<K, V> {
843+
contract { callsInPlace(builderAction, InvocationKind.EXACTLY_ONCE) }
844+
return persistentHashMapOf<K, V>().builder().apply(builderAction).build()
845+
}

core/commonTest/src/contract/list/ImmutableListTest.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,16 @@ class ImmutableListTest {
159159
}
160160
}
161161

162+
@Test fun buildPersistentList() {
163+
val expected = persistentListOf(1, 2, 3, 4, 5, 6)
164+
val actual = buildPersistentList {
165+
for (i in 1..6) {
166+
add(i)
167+
}
168+
}
169+
assertEquals(expected, actual)
170+
}
171+
162172
@Test fun subListOfBuilder() {
163173
val list = "abcxaxyz12".toImmutableList().toPersistentList()
164174
val builder = list.builder()

core/commonTest/src/contract/map/ImmutableMapTest.kt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,21 @@ class ImmutableHashMapTest : ImmutableMapTest() {
7878
compareMaps(expected, builder1.build())
7979
}
8080

81+
@Test fun buildPersistentHashMap() {
82+
val expected = mutableMapOf<String, Int>()
83+
val actual = buildPersistentHashMap {
84+
for (i in 300..400) {
85+
put("$i", i)
86+
expected["$i"] = i
87+
}
88+
for (i in 0..200) {
89+
put("$i", i)
90+
expected["$i"] = i
91+
}
92+
}
93+
compareMapsUnordered(expected, actual)
94+
}
95+
8196
@Test fun regressionGithubIssue109() {
8297
// https://github.com/Kotlin/kotlinx.collections.immutable/issues/109
8398
val map0 = immutableMapOf<Int, Int>().put(0, 0).put(1, 1).put(32, 32)
@@ -139,6 +154,21 @@ class ImmutableOrderedMapTest : ImmutableMapTest() {
139154
changing.add("break iteration")
140155
assertFailsWith<ConcurrentModificationException> { builder.filter { it.key === changing } }
141156
}
157+
158+
@Test fun buildPersistentMap() {
159+
val expected = mutableMapOf<String, Int>()
160+
val actual = buildPersistentMap {
161+
for (i in 300..400) {
162+
put("$i", i)
163+
expected["$i"] = i
164+
}
165+
for (i in 0..200) {
166+
put("$i", i)
167+
expected["$i"] = i
168+
}
169+
}
170+
compareMaps(expected, actual)
171+
}
142172
}
143173

144174
abstract class ImmutableMapTest {

core/commonTest/src/contract/set/ImmutableSetTest.kt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,17 @@ class ImmutableHashSetTest : ImmutableSetTestBase() {
195195
compareSets(immutableSetOf<Int>(), left - right)
196196
}
197197
}
198+
199+
@Test fun buildPersistentHashSet() {
200+
val expected = mutableSetOf<Int>()
201+
val actual = buildPersistentHashSet {
202+
for (i in 0..2000) {
203+
add(i)
204+
expected.add(i)
205+
}
206+
}
207+
compareSetsUnordered(expected, actual)
208+
}
198209
}
199210

200211
class ImmutableOrderedSetTest : ImmutableSetTestBase() {
@@ -221,6 +232,17 @@ class ImmutableOrderedSetTest : ImmutableSetTestBase() {
221232
changing.add("break iteration")
222233
assertFailsWith<ConcurrentModificationException> { builder.filter { it === changing } }
223234
}
235+
236+
@Test fun buildPersistentSet() {
237+
val expected = mutableSetOf<Int>()
238+
val actual = buildPersistentSet {
239+
for (i in 0..2000) {
240+
add(i)
241+
expected.add(i)
242+
}
243+
}
244+
compareSets(expected, actual)
245+
}
224246
}
225247

226248
abstract class ImmutableSetTestBase {

0 commit comments

Comments
 (0)