├── .gitignore ├── .gitmodules ├── .idea └── copyright │ ├── apache_2_0.xml │ └── profiles_settings.xml ├── .teamcity ├── Benchmarks.kt ├── additionalConfiguration.kt ├── pom.xml ├── settings.kts └── utils.kt ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE.txt ├── README.md ├── benchmarks ├── build.gradle.kts ├── commonMain │ └── src │ │ └── benchmarks │ │ ├── ObjectWrapper.kt │ │ ├── benchmarkSize.kt │ │ ├── hashCodeTypes.kt │ │ ├── immutableList │ │ ├── Add.kt │ │ ├── AddAll.kt │ │ ├── Get.kt │ │ ├── Iterate.kt │ │ ├── Remove.kt │ │ ├── RemoveAll.kt │ │ ├── RemoveAllPredicate.kt │ │ ├── Set.kt │ │ ├── builder │ │ │ ├── Add.kt │ │ │ ├── AddAll.kt │ │ │ ├── Get.kt │ │ │ ├── Iterate.kt │ │ │ ├── Remove.kt │ │ │ ├── RemoveAll.kt │ │ │ ├── Set.kt │ │ │ └── utils.kt │ │ └── utils.kt │ │ ├── immutableMap │ │ ├── Canonicalization.kt │ │ ├── Equals.kt │ │ ├── Get.kt │ │ ├── Iterate.kt │ │ ├── Put.kt │ │ ├── PutAll.kt │ │ ├── Remove.kt │ │ ├── builder │ │ │ ├── Equals.kt │ │ │ ├── Get.kt │ │ │ ├── Iterate.kt │ │ │ ├── Put.kt │ │ │ ├── Remove.kt │ │ │ └── utils.kt │ │ └── utils.kt │ │ ├── immutablePercentage.kt │ │ └── immutableSet │ │ ├── Add.kt │ │ ├── Canonicalization.kt │ │ ├── Contains.kt │ │ ├── Equals.kt │ │ ├── Iterate.kt │ │ ├── Remove.kt │ │ ├── builder │ │ ├── Add.kt │ │ ├── Contains.kt │ │ ├── Equals.kt │ │ ├── Iterate.kt │ │ ├── Remove.kt │ │ └── utils.kt │ │ └── utils.kt └── runner │ ├── build.gradle.kts │ └── src │ ├── contants.kt │ ├── csvPrinter.kt │ ├── customRunResult.kt │ ├── regressionCalculator.kt │ ├── reportPrinter.kt │ ├── runUtils.kt │ └── runners │ ├── hashMapBuilderRunner.kt │ ├── hashMapRunner.kt │ ├── hashSetBuilderRunner.kt │ ├── hashSetRunner.kt │ ├── listBuilderRunner.kt │ ├── listRunner.kt │ ├── orderedMapBuilderRunner.kt │ ├── orderedMapRunner.kt │ ├── orderedSetBuilderRunner.kt │ └── orderedSetRunner.kt ├── build.gradle.kts ├── core ├── api │ ├── kotlinx-collections-immutable.api │ └── kotlinx-collections-immutable.klib.api ├── build.gradle.kts ├── commonMain │ └── src │ │ ├── ImmutableCollection.kt │ │ ├── ImmutableList.kt │ │ ├── ImmutableMap.kt │ │ ├── ImmutableSet.kt │ │ ├── adapters │ │ └── ReadOnlyCollectionAdapters.kt │ │ ├── extensions.kt │ │ ├── implementations │ │ ├── immutableList │ │ │ ├── AbstractListIterator.kt │ │ │ ├── AbstractPersistentList.kt │ │ │ ├── BufferIterator.kt │ │ │ ├── PersistentVector.kt │ │ │ ├── PersistentVectorBuilder.kt │ │ │ ├── PersistentVectorIterator.kt │ │ │ ├── PersistentVectorMutableIterator.kt │ │ │ ├── SmallPersistentVector.kt │ │ │ ├── TrieIterator.kt │ │ │ └── Utils.kt │ │ ├── immutableMap │ │ │ ├── PersistentHashMap.kt │ │ │ ├── PersistentHashMapBuilder.kt │ │ │ ├── PersistentHashMapBuilderContentIterators.kt │ │ │ ├── PersistentHashMapBuilderContentViews.kt │ │ │ ├── PersistentHashMapContentIterators.kt │ │ │ ├── PersistentHashMapContentViews.kt │ │ │ └── TrieNode.kt │ │ ├── immutableSet │ │ │ ├── PersistentHashSet.kt │ │ │ ├── PersistentHashSetBuilder.kt │ │ │ ├── PersistentHashSetIterator.kt │ │ │ ├── PersistentHashSetMutableIterator.kt │ │ │ └── TrieNode.kt │ │ ├── persistentOrderedMap │ │ │ ├── PersistentOrderedMap.kt │ │ │ ├── PersistentOrderedMapBuilder.kt │ │ │ ├── PersistentOrderedMapBuilderContentIterators.kt │ │ │ ├── PersistentOrderedMapBuilderContentViews.kt │ │ │ ├── PersistentOrderedMapContentIterators.kt │ │ │ └── PersistentOrderedMapContentViews.kt │ │ └── persistentOrderedSet │ │ │ ├── PersistentOrderedSet.kt │ │ │ ├── PersistentOrderedSetBuilder.kt │ │ │ ├── PersistentOrderedSetIterator.kt │ │ │ └── PersistentOrderedSetMutableIterator.kt │ │ └── internal │ │ ├── EndOfChain.kt │ │ ├── ForEachOneBit.kt │ │ ├── ListImplementation.kt │ │ ├── MapImplementation.kt │ │ ├── MutabilityOwnership.kt │ │ ├── MutableCounter.kt │ │ └── commonFunctions.kt ├── commonTest │ └── src │ │ ├── ObjectWrapper.kt │ │ ├── contract │ │ ├── CollectionBehaviors.kt │ │ ├── ComparisonDSL.kt │ │ ├── list │ │ │ └── ImmutableListTest.kt │ │ ├── map │ │ │ ├── ImmutableMapTest.kt │ │ │ ├── KT41278Test.kt │ │ │ ├── PersistentHashMapBuilderTest.kt │ │ │ ├── PersistentHashMapTest.kt │ │ │ └── PersistentOrderedMapTest.kt │ │ └── set │ │ │ ├── ImmutableSetTest.kt │ │ │ ├── PersistentHashSetBuilderTest.kt │ │ │ ├── PersistentHashSetTest.kt │ │ │ └── PersistentOrderedSetTest.kt │ │ ├── implementations │ │ ├── list │ │ │ ├── BufferIteratorTest.kt │ │ │ └── TrieIteratorTest.kt │ │ └── map │ │ │ └── HashMapTrieNodeTest.kt │ │ ├── stress │ │ ├── ExecutionTimeMeasuringTest.kt │ │ ├── WrapperGenerator.kt │ │ ├── list │ │ │ ├── PersistentListBuilderTest.kt │ │ │ └── PersistentListTest.kt │ │ ├── map │ │ │ ├── PersistentHashMapBuilderTest.kt │ │ │ └── PersistentHashMapTest.kt │ │ └── set │ │ │ ├── PersistentHashSetBuilderTest.kt │ │ │ └── PersistentHashSetTest.kt │ │ └── testUtils.kt ├── dokka-templates │ └── README.md ├── jsMain │ └── src │ │ └── internal │ │ └── commonFunctions.kt ├── jsTest │ └── src │ │ └── testUtilsJs.kt ├── jvmMain │ └── src │ │ └── internal │ │ └── commonFunctions.kt ├── jvmTest │ └── src │ │ ├── contract │ │ ├── GuavaImmutableCollectionBaseTest.kt │ │ ├── list │ │ │ ├── GuavaImmutableListTest.kt │ │ │ └── PersistentListGenerator.kt │ │ ├── map │ │ │ ├── GuavaImmutableMapTest.kt │ │ │ └── PersistentMapGenerator.kt │ │ └── set │ │ │ ├── GuavaImmutableSetTest.kt │ │ │ └── PersistentSetGenerator.kt │ │ └── testUtilsJvm.kt ├── nativeMain │ └── src │ │ └── internal │ │ └── commonFunctions.kt ├── nativeTest │ └── src │ │ └── testUtilsNative.kt ├── wasmMain │ └── src │ │ └── internal │ │ └── commonFunctions.kt └── wasmTest │ └── src │ └── testUtilsJs.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── proposal.md └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/* 2 | !/.idea/copyright 3 | .gradle 4 | *.iml 5 | target 6 | build 7 | /kotlinx-collections-immutable/dependency-reduced-pom.xml 8 | /benchmarks-runner/benchmarkResults 9 | /benchmarks-runner/localReferenceBenchmarkResults -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kotlin/kotlinx.collections.immutable/c7f155af4bdadb955d15534f71ed7d7167cd5e6b/.gitmodules -------------------------------------------------------------------------------- /.idea/copyright/apache_2_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.teamcity/Benchmarks.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | import jetbrains.buildServer.configs.kotlin.* 7 | import jetbrains.buildServer.configs.kotlin.buildSteps.gradle 8 | import java.lang.IllegalArgumentException 9 | 10 | fun benchmarksProject(buildVersion: BuildType) = Project { 11 | this.id("Benchmarks") 12 | this.name = "Benchmarks" 13 | 14 | params { 15 | param("teamcity.ui.settings.readOnly", "true") 16 | } 17 | 18 | val benchmarkAll = benchmarkAll(buildVersion) 19 | val benchmarks = listOf( 20 | benchmark("js", Platform.Linux, buildVersion), 21 | benchmark("jvm", Platform.Linux, buildVersion), 22 | *platforms.map { benchmark("native", it, buildVersion) }.toTypedArray() 23 | ) 24 | 25 | benchmarks.forEach { benchmark -> 26 | benchmarkAll.dependsOnSnapshot(benchmark, onFailure = FailureAction.ADD_PROBLEM) 27 | benchmarkAll.dependsOn(benchmark) { 28 | artifacts { 29 | artifactRules = "+:reports=>reports" 30 | } 31 | } 32 | } 33 | 34 | buildTypesOrder = listOf(benchmarkAll, *benchmarks.toTypedArray()) 35 | } 36 | 37 | fun Project.benchmarkAll(buildVersion: BuildType) = BuildType { 38 | id("Benchmark_All") 39 | this.name = "Benchmark (All)" 40 | type = BuildTypeSettings.Type.COMPOSITE 41 | 42 | dependsOnSnapshot(buildVersion) 43 | buildNumberPattern = buildVersion.depParamRefs.buildNumber.ref 44 | 45 | commonConfigure() 46 | 47 | failureConditions { 48 | executionTimeoutMin = 1440 49 | } 50 | }.also { buildType(it) } 51 | 52 | fun Project.benchmark(target: String, platform: Platform, buildVersion: BuildType) = buildType("${target}Benchmark", platform) { 53 | 54 | dependsOnSnapshot(buildVersion) 55 | 56 | params { 57 | param(versionSuffixParameter, buildVersion.depParamRefs[versionSuffixParameter].ref) 58 | param(teamcitySuffixParameter, buildVersion.depParamRefs[teamcitySuffixParameter].ref) 59 | } 60 | 61 | steps { 62 | gradle { 63 | name = "Benchmark" 64 | tasks = benchmarkTask(target, platform) 65 | jdkHome = "%env.$jdk%" 66 | gradleParams = "--info --stacktrace -P$versionSuffixParameter=%$versionSuffixParameter% -P$teamcitySuffixParameter=%$teamcitySuffixParameter%" 67 | buildFile = "" 68 | gradleWrapperPath = "" 69 | } 70 | } 71 | 72 | artifactRules = "benchmarks/build/reports/**=> reports" 73 | 74 | requirements { 75 | benchmarkAgentInstanceTypeRequirement(platform) 76 | } 77 | 78 | failureConditions { 79 | executionTimeoutMin = 1440 80 | } 81 | } 82 | 83 | fun benchmarkTask(target: String, platform: Platform): String = when(target) { 84 | "js", "jvm" -> "${target}Benchmark" 85 | "native" -> "${platform.nativeTaskPrefix()}Benchmark" 86 | else -> throw IllegalArgumentException("Unknown target: $target") 87 | } 88 | 89 | fun Requirements.benchmarkAgentInstanceTypeRequirement(platform: Platform) { 90 | if (platform == Platform.Linux || platform == Platform.Windows) { 91 | matches("system.ec2.instance-type", "m5d?.xlarge") 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /.teamcity/additionalConfiguration.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | import jetbrains.buildServer.configs.kotlin.Project 7 | import jetbrains.buildServer.configs.kotlin.DslContext 8 | import jetbrains.buildServer.configs.kotlin.buildFeatures.commitStatusPublisher 9 | 10 | fun Project.additionalConfiguration() { 11 | subProject(benchmarksProject(knownBuilds.buildVersion)) 12 | 13 | knownBuilds.buildAll.features { 14 | commitStatusPublisher { 15 | vcsRootExtId = "${DslContext.settingsRoot.id}" 16 | publisher = github { 17 | githubUrl = "https://api.github.com" 18 | authType = storedToken { 19 | tokenId = "tc_token_id:CID_7db3007c46f7e30124f81ef54591b223:-1:f604c3ec-6391-4e29-a6e4-e59397b4622d" 20 | } 21 | } 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /.teamcity/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | TeamCity Config DSL Script 5 | kotlinx.team.infra 6 | teamcity 7 | 1.0-SNAPSHOT 8 | 9 | 10 | org.jetbrains.teamcity 11 | configs-dsl-kotlin-parent 12 | 1.0-SNAPSHOT 13 | 14 | 15 | 16 | 17 | jetbrains-all 18 | https://download.jetbrains.com/teamcity-repository 19 | 20 | true 21 | 22 | 23 | 24 | teamcity-server 25 | https://teamcity.jetbrains.com/app/dsl-plugins-repository 26 | 27 | true 28 | 29 | 30 | 31 | 32 | 33 | 34 | JetBrains 35 | https://download.jetbrains.com/teamcity-repository 36 | 37 | 38 | 39 | 40 | . 41 | 42 | 43 | kotlin-maven-plugin 44 | org.jetbrains.kotlin 45 | ${kotlin.version} 46 | 47 | 48 | 49 | 50 | compile 51 | process-sources 52 | 53 | compile 54 | 55 | 56 | 57 | test-compile 58 | process-test-sources 59 | 60 | test-compile 61 | 62 | 63 | 64 | 65 | 66 | org.jetbrains.teamcity 67 | teamcity-configs-maven-plugin 68 | ${teamcity.dsl.version} 69 | 70 | kotlin 71 | target/generated-configs 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | org.jetbrains.teamcity 80 | configs-dsl-kotlin-latest 81 | ${teamcity.dsl.version} 82 | compile 83 | 84 | 85 | org.jetbrains.teamcity 86 | configs-dsl-kotlin-plugins-latest 87 | 1.0-SNAPSHOT 88 | pom 89 | compile 90 | 91 | 92 | org.jetbrains.kotlin 93 | kotlin-stdlib-jdk8 94 | ${kotlin.version} 95 | compile 96 | 97 | 98 | org.jetbrains.kotlin 99 | kotlin-script-runtime 100 | ${kotlin.version} 101 | compile 102 | 103 | 104 | -------------------------------------------------------------------------------- /.teamcity/utils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | import jetbrains.buildServer.configs.kotlin.* 7 | 8 | const val versionSuffixParameter = "versionSuffix" 9 | const val teamcitySuffixParameter = "teamcitySuffix" 10 | const val releaseVersionParameter = "releaseVersion" 11 | 12 | const val libraryStagingRepoDescription = "Kotlin-Immutable-Collections" 13 | 14 | val platforms = Platform.values() 15 | const val jdk = "JDK_18_x64" 16 | 17 | enum class Platform { 18 | Windows, Linux, MacOS; 19 | } 20 | 21 | fun Platform.nativeTaskPrefix(): String = when(this) { 22 | Platform.Windows -> "mingwX64" 23 | Platform.Linux -> "linuxX64" 24 | Platform.MacOS -> "macosX64" 25 | } 26 | fun Platform.buildTypeName(): String = when (this) { 27 | Platform.Windows, Platform.Linux -> name 28 | Platform.MacOS -> "Mac OS X" 29 | } 30 | fun Platform.buildTypeId(): String = buildTypeName().substringBefore(" ") 31 | fun Platform.teamcityAgentName(): String = buildTypeName() 32 | 33 | 34 | const val BUILD_CONFIGURE_VERSION_ID = "Build_Version" 35 | const val BUILD_ALL_ID = "Build_All" 36 | const val DEPLOY_CONFIGURE_VERSION_ID = "Deploy_Configure" 37 | const val DEPLOY_PUBLISH_ID = "Deploy_Publish" 38 | 39 | val BUILD_CREATE_STAGING_REPO_ABSOLUTE_ID = AbsoluteId("KotlinTools_CreateSonatypeStagingRepository") 40 | 41 | class KnownBuilds(private val project: Project) { 42 | private fun buildWithId(id: String): BuildType { 43 | return project.buildTypes.single { it.id.toString().endsWith(id) } 44 | } 45 | 46 | val buildVersion: BuildType get() = buildWithId(BUILD_CONFIGURE_VERSION_ID) 47 | val buildAll: BuildType get() = buildWithId(BUILD_ALL_ID) 48 | fun buildOn(platform: Platform): BuildType = buildWithId("Build_${platform.buildTypeId()}") 49 | val deployVersion: BuildType get() = buildWithId(DEPLOY_CONFIGURE_VERSION_ID) 50 | val deployPublish: BuildType get() = buildWithId(DEPLOY_PUBLISH_ID) 51 | fun deployOn(platform: Platform): BuildType = buildWithId("Deploy_${platform.buildTypeId()}") 52 | } 53 | 54 | val Project.knownBuilds: KnownBuilds get() = KnownBuilds(this) 55 | 56 | 57 | fun Project.buildType(name: String, platform: Platform, configure: BuildType.() -> Unit) = BuildType { 58 | // ID is prepended with Project ID, so don't repeat it here 59 | // ID should conform to identifier rules, so just letters, numbers and underscore 60 | id("${name}_${platform.buildTypeId()}") 61 | // Display name of the build configuration 62 | this.name = "$name (${platform.buildTypeName()})" 63 | 64 | requirements { 65 | contains("teamcity.agent.jvm.os.name", platform.teamcityAgentName()) 66 | } 67 | 68 | params { 69 | // This parameter is needed for macOS agent to be compatible 70 | if (platform == Platform.MacOS) param("env.JDK_17", "") 71 | } 72 | 73 | commonConfigure() 74 | configure() 75 | }.also { buildType(it) } 76 | 77 | 78 | fun BuildType.commonConfigure() { 79 | requirements { 80 | noLessThan("teamcity.agent.hardware.memorySizeMb", "6144") 81 | } 82 | 83 | // Allow to fetch build status through API for badges 84 | allowExternalStatus = true 85 | 86 | // Configure VCS, by default use the same and only VCS root from which this configuration is fetched 87 | vcs { 88 | root(DslContext.settingsRoot) 89 | showDependenciesChanges = true 90 | checkoutMode = CheckoutMode.ON_AGENT 91 | } 92 | 93 | failureConditions { 94 | errorMessage = true 95 | nonZeroExitCode = true 96 | executionTimeoutMin = 120 97 | } 98 | 99 | features { 100 | feature { 101 | id = "perfmon" 102 | type = "perfmon" 103 | } 104 | } 105 | } 106 | 107 | fun BuildType.dependsOn(build: IdOwner, configure: Dependency.() -> Unit) = 108 | apply { 109 | dependencies.dependency(build, configure) 110 | } 111 | 112 | fun BuildType.dependsOnSnapshot(build: IdOwner, onFailure: FailureAction = FailureAction.FAIL_TO_START, configure: SnapshotDependency.() -> Unit = {}) = apply { 113 | dependencies.dependency(build) { 114 | snapshot { 115 | configure() 116 | onDependencyFailure = onFailure 117 | onDependencyCancel = FailureAction.CANCEL 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | 3 | This project and the corresponding community is governed by the [JetBrains Open Source and Community Code of Conduct](https://confluence.jetbrains.com/display/ALL/JetBrains+Open+Source+and+Community+Code+of+Conduct). Please make sure you read it. 4 | 5 | -------------------------------------------------------------------------------- /benchmarks/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import kotlinx.benchmark.gradle.JvmBenchmarkTarget 2 | import org.gradle.jvm.tasks.Jar 3 | import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi 4 | import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl 5 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 6 | 7 | plugins { 8 | id("kotlin-multiplatform") 9 | id("org.jetbrains.kotlinx.benchmark") version "0.4.13" 10 | } 11 | 12 | 13 | evaluationDependsOn(":kotlinx-collections-immutable") 14 | 15 | @OptIn(ExperimentalKotlinGradlePluginApi::class) 16 | kotlin { 17 | macosX64() 18 | macosArm64() 19 | linuxX64() 20 | mingwX64() 21 | 22 | jvm { 23 | compilerOptions { 24 | jvmTarget.set(JvmTarget.JVM_1_8) 25 | } 26 | } 27 | 28 | js { 29 | nodejs { 30 | 31 | } 32 | } 33 | 34 | @OptIn(ExperimentalWasmDsl::class) 35 | wasmJs { 36 | nodejs() 37 | } 38 | 39 | //TODO: Add wasmWasi benchmarks as soon as kx-benchmark supports the target 40 | 41 | sourceSets.all { 42 | kotlin.setSrcDirs(listOf("$name/src")) 43 | resources.setSrcDirs(listOf("$name/resources")) 44 | } 45 | 46 | sourceSets { 47 | commonMain { 48 | dependencies { 49 | implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.4.13") 50 | implementation(project(":kotlinx-collections-immutable")) 51 | } 52 | } 53 | } 54 | } 55 | 56 | 57 | // Configure benchmark 58 | benchmark { 59 | configurations { 60 | named("main") { 61 | warmups = 7 62 | iterations = 7 63 | iterationTime = 500 64 | iterationTimeUnit = "ms" 65 | param("size", "1", "10", "100", "1000", "10000") 66 | param("immutablePercentage", /*"95", "30", */"0") 67 | param("hashCodeType", "random", "collision") 68 | } 69 | 70 | register("fast") { 71 | warmups = 7 72 | iterations = 7 73 | iterationTime = 500 74 | iterationTimeUnit = "ms" 75 | param("size", "1000") 76 | param("immutablePercentage", "0") 77 | param("hashCodeType", "random") 78 | 79 | include("immutableList.Add.addLast$") 80 | include("immutableList.Get.getByIndex$") 81 | include("immutableList.Iterate.firstToLast$") 82 | include("immutableList.Remove.removeLast$") 83 | include("immutableList.Set.setByIndex$") 84 | 85 | include("immutableMap.Get.get$") 86 | include("immutableMap.Iterate.iterateKeys$") 87 | include("immutableMap.Put.put$") 88 | include("immutableMap.Remove.remove$") 89 | 90 | include("immutableSet.Add.add$") 91 | include("immutableSet.Contains.contains$") 92 | include("immutableSet.Iterate.iterate$") 93 | include("immutableSet.Remove.remove$") 94 | } 95 | } 96 | 97 | targets { 98 | register("jvm") { 99 | this as JvmBenchmarkTarget 100 | jmhVersion = "1.37" 101 | } 102 | register("js") 103 | register("wasmJs") 104 | register("macosX64") 105 | register("macosArm64") 106 | register("linuxX64") 107 | register("mingwX64") 108 | } 109 | } 110 | 111 | val benchmarksJar: Configuration by configurations.creating 112 | 113 | afterEvaluate { 114 | val jvmBenchmarkJar by tasks.getting(Jar::class) 115 | artifacts.add("benchmarksJar", jvmBenchmarkJar) 116 | } 117 | -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/ObjectWrapper.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks 7 | import kotlin.js.JsName 8 | 9 | class ObjectWrapper>( 10 | val obj: K, 11 | @JsName("_hashCode") val hashCode: Int 12 | ) : Comparable> { 13 | override fun hashCode(): Int { 14 | return hashCode 15 | } 16 | 17 | override fun equals(other: Any?): Boolean { 18 | if (other !is ObjectWrapper<*>) { 19 | return false 20 | } 21 | return obj == other.obj 22 | } 23 | 24 | override fun compareTo(other: ObjectWrapper): Int { 25 | return obj.compareTo(other.obj) 26 | } 27 | } 28 | 29 | 30 | typealias IntWrapper = ObjectWrapper -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/benchmarkSize.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks 7 | 8 | const val BM_1 = "1" 9 | const val BM_10 = "10" 10 | const val BM_100 = "100" 11 | const val BM_1000 = "1000" 12 | const val BM_10000 = "10000" 13 | const val BM_100000 = "100000" 14 | const val BM_1000000 = "1000000" 15 | const val BM_10000000 = "10000000" 16 | -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/hashCodeTypes.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks 7 | 8 | const val ASCENDING_HASH_CODE = "ascending" 9 | const val RANDOM_HASH_CODE = "random" 10 | const val COLLISION_HASH_CODE = "collision" 11 | const val NON_EXISTING_HASH_CODE = "nonExisting" 12 | 13 | private inline fun intWrappers(size: Int, hashCodeGenerator: (index: Int) -> Int): List { 14 | val keys = mutableListOf() 15 | repeat(size) { 16 | keys.add(IntWrapper(it, hashCodeGenerator(it))) 17 | } 18 | return keys 19 | } 20 | 21 | private fun generateIntWrappers(hashCodeType: String, size: Int): List { 22 | val random = kotlin.random.Random(40) 23 | return when(hashCodeType) { 24 | ASCENDING_HASH_CODE -> intWrappers(size) { it } 25 | RANDOM_HASH_CODE, 26 | NON_EXISTING_HASH_CODE -> intWrappers(size) { random.nextInt() } 27 | COLLISION_HASH_CODE -> intWrappers(size) { random.nextInt((size + 1) / 2) } 28 | else -> throw AssertionError("Unknown hashCodeType: $hashCodeType") 29 | } 30 | } 31 | 32 | fun generateKeys(hashCodeType: String, size: Int) = generateIntWrappers(hashCodeType, size) 33 | fun generateElements(hashCodeType: String, size: Int) = generateIntWrappers(hashCodeType, size) 34 | 35 | 36 | const val HASH_IMPL = "hash" 37 | const val ORDERED_IMPL = "ordered" -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/Add.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.ImmutableList 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Add { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 15 | var size: Int = 0 16 | 17 | @Benchmark 18 | fun addLast(): ImmutableList { 19 | return persistentListAdd(size) 20 | } 21 | 22 | @Benchmark 23 | fun addLastAndIterate(bh: Blackhole) { 24 | val list = persistentListAdd(size) 25 | for (e in list) { 26 | bh.consume(e) 27 | } 28 | } 29 | 30 | @Benchmark 31 | fun addLastAndGet(bh: Blackhole) { 32 | val list = persistentListAdd(size) 33 | for (i in 0 until list.size) { 34 | bh.consume(list[i]) 35 | } 36 | } 37 | 38 | /** 39 | * Adds [size] - 1 elements to an empty persistent list 40 | * and then inserts one element at the beginning. 41 | * 42 | * Measures mean time and memory spent per `add` operation. 43 | * 44 | * Expected time: nearly constant. 45 | * Expected memory: nearly constant. 46 | */ 47 | @Benchmark 48 | fun addFirst(): ImmutableList { 49 | return persistentListAdd(size - 1).add(0, "another element") 50 | } 51 | 52 | /** 53 | * Adds [size] - 1 elements to an empty persistent list 54 | * and then inserts one element at the middle. 55 | * 56 | * Measures mean time and memory spent per `add` operation. 57 | * 58 | * Expected time: nearly constant. 59 | * Expected memory: nearly constant. 60 | */ 61 | @Benchmark 62 | fun addMiddle(): ImmutableList { 63 | return persistentListAdd(size - 1).add(size / 2, "another element") 64 | } 65 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/AddAll.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.ImmutableList 10 | import kotlinx.collections.immutable.persistentListOf 11 | import kotlinx.benchmark.* 12 | 13 | @State(Scope.Benchmark) 14 | open class AddAll { 15 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 16 | var size: Int = 0 17 | 18 | private var listToAdd = emptyList() 19 | 20 | @Setup 21 | fun prepare() { 22 | listToAdd = List(size) { "another element" } 23 | } 24 | 25 | // Results of the following benchmarks do not indicate memory or time spent per operation, 26 | // however regressions there do indicate changes. 27 | // 28 | // the benchmarks measure mean time and memory spent per added element. 29 | // 30 | // Expected time: nearly constant. 31 | // Expected memory: nearly constant. 32 | 33 | /** 34 | * Adds [size] elements to an empty persistent list using `addAll` operation. 35 | */ 36 | @Benchmark 37 | fun addAllLast(): ImmutableList { 38 | return persistentListOf().addAll(listToAdd) 39 | } 40 | 41 | /** 42 | * Adds `size / 2` elements to an empty persistent list 43 | * and then adds `size - size / 2` elements using `addAll` operation. 44 | */ 45 | @Benchmark 46 | fun addAllLast_Half(): ImmutableList { 47 | val initialSize = size / 2 48 | val subListToAdd = listToAdd.subList(0, size - initialSize) // assuming subList creation is neglectable 49 | return persistentListAdd(initialSize).addAll(subListToAdd) 50 | } 51 | 52 | /** 53 | * Adds `size - size / 3` elements to an empty persistent list 54 | * and then adds `size / 3` elements using `addAll` operation. 55 | */ 56 | @Benchmark 57 | fun addAllLast_OneThird(): ImmutableList { 58 | val initialSize = size - size / 3 59 | val subListToAdd = listToAdd.subList(0, size - initialSize) 60 | return persistentListAdd(initialSize).addAll(subListToAdd) 61 | } 62 | 63 | /** 64 | * Adds `size / 2` elements to an empty persistent list 65 | * and then inserts `size - size / 2` elements at the beginning using `addAll` operation. 66 | */ 67 | @Benchmark 68 | fun addAllFirst_Half(): ImmutableList { 69 | val initialSize = size / 2 70 | val subListToAdd = listToAdd.subList(0, size - initialSize) 71 | return persistentListAdd(initialSize).addAll(0, subListToAdd) 72 | } 73 | 74 | /** 75 | * Adds `size - size / 3` elements to an empty persistent list 76 | * and then inserts `size / 3` elements at the beginning using `addAll` operation. 77 | */ 78 | @Benchmark 79 | fun addAllFirst_OneThird(): ImmutableList { 80 | val initialSize = size - size / 3 81 | val subListToAdd = listToAdd.subList(0, size - initialSize) 82 | return persistentListAdd(initialSize).addAll(0, subListToAdd) 83 | } 84 | 85 | /** 86 | * Adds `size / 2` elements to an empty persistent list 87 | * and then inserts `size - size / 2` elements at the middle using `addAll` operation. 88 | */ 89 | @Benchmark 90 | fun addAllMiddle_Half(): ImmutableList { 91 | val initialSize = size / 2 92 | val index = initialSize / 2 93 | val subListToAdd = listToAdd.subList(0, size - initialSize) 94 | return persistentListAdd(initialSize).addAll(index, subListToAdd) 95 | } 96 | 97 | /** 98 | * Adds `size - size / 3` elements to an empty persistent list builder 99 | * and then inserts `size / 3` elements at the middle using `addAll` operation. 100 | */ 101 | @Benchmark 102 | fun addAllMiddle_OneThird(): ImmutableList { 103 | val initialSize = size - size / 3 104 | val index = initialSize / 2 105 | val subListToAdd = listToAdd.subList(0, size - initialSize) 106 | return persistentListAdd(initialSize).addAll(index, subListToAdd) 107 | } 108 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/Get.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentList 10 | import kotlinx.collections.immutable.persistentListOf 11 | import kotlinx.benchmark.* 12 | 13 | @State(Scope.Benchmark) 14 | open class Get { 15 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 16 | var size: Int = 0 17 | 18 | private var persistentList: PersistentList = persistentListOf() 19 | 20 | @Setup 21 | fun prepare() { 22 | persistentList = persistentListAdd(size) 23 | } 24 | 25 | @Benchmark 26 | fun getByIndex(bh: Blackhole) { 27 | for (i in 0 until persistentList.size) { 28 | bh.consume(persistentList[i]) 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/Iterate.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentList 10 | import kotlinx.collections.immutable.persistentListOf 11 | import kotlinx.benchmark.* 12 | 13 | @State(Scope.Benchmark) 14 | open class Iterate { 15 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 16 | var size: Int = 0 17 | 18 | private var persistentList: PersistentList = persistentListOf() 19 | 20 | @Setup 21 | fun prepare() { 22 | persistentList = persistentListAdd(size) 23 | } 24 | 25 | @Benchmark 26 | fun firstToLast(bh: Blackhole) { 27 | for (e in persistentList) { 28 | bh.consume(e) 29 | } 30 | } 31 | 32 | @Benchmark 33 | fun lastToFirst(bh: Blackhole) { 34 | val iterator = persistentList.listIterator(size) 35 | 36 | while (iterator.hasPrevious()) { 37 | bh.consume(iterator.previous()) 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/Remove.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.ImmutableList 10 | import kotlinx.collections.immutable.PersistentList 11 | import kotlinx.collections.immutable.persistentListOf 12 | import kotlinx.benchmark.* 13 | 14 | @State(Scope.Benchmark) 15 | open class Remove { 16 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 17 | var size: Int = 0 18 | 19 | private var persistentList: PersistentList = persistentListOf() 20 | 21 | @Setup 22 | fun prepare() { 23 | persistentList = persistentListAdd(size) 24 | } 25 | 26 | @Benchmark 27 | fun removeLast(): ImmutableList { 28 | var list = persistentList 29 | repeat(times = size) { 30 | list = list.removeAt(list.size - 1) 31 | } 32 | return list 33 | } 34 | 35 | /** 36 | * Removes one element from the beginning. 37 | * 38 | * Measures (time and memory spent on `removeAt` operation) / size. 39 | * 40 | * Expected time: nearly constant. 41 | * Expected memory: nearly constant. 42 | */ 43 | @Benchmark 44 | fun removeFirst(): ImmutableList { 45 | val list = persistentList 46 | return list.removeAt(0) 47 | } 48 | 49 | /** 50 | * Removes one element from the middle. 51 | * 52 | * Measures (time and memory spent on `removeAt` operation) / size. 53 | * 54 | * Expected time: nearly constant. 55 | * Expected memory: nearly constant. 56 | */ 57 | @Benchmark 58 | fun removeMiddle(): ImmutableList { 59 | val list = persistentList 60 | return list.removeAt(size / 2) 61 | } 62 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/RemoveAll.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentList 10 | import kotlinx.collections.immutable.persistentListOf 11 | import kotlinx.benchmark.* 12 | import kotlin.random.Random 13 | 14 | @State(Scope.Benchmark) 15 | open class RemoveAll { 16 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 17 | var size: Int = 0 18 | 19 | private var persistentList: PersistentList = persistentListOf() 20 | 21 | @Setup 22 | fun prepare() { 23 | persistentList = persistentListOf().addAll(List(size) { it }) 24 | } 25 | 26 | // Results of the following benchmarks do not indicate memory or time spent per operation, 27 | // however regressions there do indicate changes. 28 | // 29 | // The benchmarks measure (time and memory spent on `removeAll` operation) / size 30 | // 31 | // Expected time: nearly constant 32 | // Expected memory: nearly constant 33 | 34 | /** 35 | * Removes all elements using `removeAll(elements)` operation. 36 | */ 37 | @Benchmark 38 | fun removeAll_All(): PersistentList { 39 | val list = persistentList 40 | val elementsToRemove = List(size) { it } 41 | return list.removeAll(elementsToRemove) 42 | } 43 | 44 | /** 45 | * Removes half of the elements using `removeAll(elements)` operation. 46 | */ 47 | @Benchmark 48 | fun removeAll_RandomHalf(): PersistentList { 49 | val list = persistentList 50 | val elementsToRemove = randomIndexes(size / 2) 51 | return list.removeAll(elementsToRemove) 52 | } 53 | 54 | /** 55 | * Removes 10 random elements using `removeAll(elements)` operation. 56 | */ 57 | @Benchmark 58 | fun removeAll_RandomTen(): PersistentList { 59 | val list = persistentList 60 | val elementsToRemove = randomIndexes(10) 61 | return list.removeAll(elementsToRemove) 62 | } 63 | 64 | /** 65 | * Removes last [tailSize] elements using `removeAll(elements)` operation. 66 | */ 67 | @Benchmark 68 | fun removeAll_Tail(): PersistentList { 69 | val list = persistentList 70 | val elementsToRemove = List(tailSize()) { size - 1 - it } 71 | return list.removeAll(elementsToRemove) 72 | } 73 | 74 | /** 75 | * Removes 10 non-existing elements using `removeAll(elements)` operation. 76 | */ 77 | @Benchmark 78 | fun removeAll_NonExisting(): PersistentList { 79 | val list = persistentList 80 | val elementsToRemove = randomIndexes(10).map { size + it } 81 | return list.removeAll(elementsToRemove) 82 | } 83 | 84 | private fun randomIndexes(count: Int): List { 85 | return List(count) { Random.nextInt(size) } 86 | } 87 | 88 | private fun tailSize(): Int { 89 | val bufferSize = 32 90 | return (size and (bufferSize - 1)).let { if (it == 0) bufferSize else it } 91 | } 92 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/RemoveAllPredicate.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2023 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentList 10 | import kotlinx.benchmark.* 11 | import kotlinx.collections.immutable.persistentListOf 12 | import kotlin.random.Random 13 | 14 | @State(Scope.Benchmark) 15 | open class RemoveAllPredicate { 16 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 17 | var size: Int = 0 18 | 19 | private var persistentList = persistentListOf() 20 | private val truePredicate: (String) -> Boolean = { true } 21 | private val falsePredicate: (String) -> Boolean = { false } 22 | private var randomHalfElementsPredicate: (String) -> Boolean = truePredicate 23 | private var randomTenElementsPredicate: (String) -> Boolean = truePredicate 24 | private var randomOneElementPredicate: (String) -> Boolean = truePredicate 25 | private var tailElementsPredicate: (String) -> Boolean = truePredicate 26 | 27 | @Setup 28 | fun prepare() { 29 | val randomHalfElements = randomIndexes(size / 2).map { it.toString() }.toHashSet() 30 | randomHalfElementsPredicate = { it in randomHalfElements } 31 | 32 | val randomTenElements = randomIndexes(10).map { it.toString() }.toHashSet() 33 | randomTenElementsPredicate = { it in randomTenElements } 34 | 35 | val randomOneElement = Random.nextInt(size).toString() 36 | randomOneElementPredicate = { it == randomOneElement } 37 | 38 | val tailElements = List(tailSize()) { (size - 1 - it).toString() }.toHashSet() 39 | tailElementsPredicate = { it in tailElements } 40 | 41 | val allElements = List(size) { it.toString() } 42 | persistentList = persistentListOf().addAll(allElements) 43 | } 44 | 45 | // The benchmarks measure (time and memory spent in `removeAll` operation) / size 46 | // 47 | // Expected time: nearly constant 48 | // Expected memory: nearly constant 49 | 50 | /** Removes all elements. */ 51 | @Benchmark 52 | fun removeAll_All(): PersistentList { 53 | return persistentList.removeAll(truePredicate) 54 | } 55 | 56 | /** Removes no elements. */ 57 | @Benchmark 58 | fun removeAll_Non(): PersistentList { 59 | return persistentList.removeAll(falsePredicate) 60 | } 61 | 62 | /** Removes half of the elements randomly selected. */ 63 | @Benchmark 64 | fun removeAll_RandomHalf(): PersistentList { 65 | return persistentList.removeAll(randomHalfElementsPredicate) 66 | } 67 | 68 | /** Removes 10 random elements. */ 69 | @Benchmark 70 | fun removeAll_RandomTen(): PersistentList { 71 | return persistentList.removeAll(randomTenElementsPredicate) 72 | } 73 | 74 | /** Removes a random element. */ 75 | @Benchmark 76 | fun removeAll_RandomOne(): PersistentList { 77 | return persistentList.removeAll(randomOneElementPredicate) 78 | } 79 | 80 | /** Removes last [tailSize] elements. */ 81 | @Benchmark 82 | fun removeAll_Tail(): PersistentList { 83 | return persistentList.removeAll(tailElementsPredicate) 84 | } 85 | 86 | private fun randomIndexes(count: Int): List { 87 | return List(count) { Random.nextInt(size) } 88 | } 89 | 90 | private fun tailSize(): Int { 91 | val bufferSize = 32 92 | return (size and (bufferSize - 1)).let { if (it == 0) bufferSize else it } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/Set.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.ImmutableList 10 | import kotlinx.collections.immutable.PersistentList 11 | import kotlinx.collections.immutable.persistentListOf 12 | import kotlinx.benchmark.* 13 | 14 | @State(Scope.Benchmark) 15 | open class Set { 16 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 17 | var size: Int = 0 18 | 19 | private var persistentList: PersistentList = persistentListOf() 20 | private var randomIndices = listOf() 21 | 22 | @Setup 23 | fun prepare() { 24 | persistentList = persistentListAdd(size) 25 | randomIndices = List(size) { it }.shuffled() 26 | } 27 | 28 | @Benchmark 29 | fun setByIndex(): ImmutableList { 30 | repeat(times = size) { index -> 31 | persistentList = persistentList.set(index, "another element") 32 | } 33 | return persistentList 34 | } 35 | 36 | @Benchmark 37 | fun setByRandomIndex(): ImmutableList { 38 | repeat(times = size) { index -> 39 | persistentList = persistentList.set(randomIndices[index], "another element") 40 | } 41 | return persistentList 42 | } 43 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/builder/Add.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentList 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Add { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 15 | var size: Int = 0 16 | 17 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 18 | var immutablePercentage: Double = 0.0 19 | 20 | @Benchmark 21 | fun addLast(): PersistentList.Builder { 22 | return persistentListBuilderAdd(size, immutablePercentage) 23 | } 24 | 25 | @Benchmark 26 | fun addLastAndIterate(bh: Blackhole) { 27 | val builder = persistentListBuilderAdd(size, immutablePercentage) 28 | for (e in builder) { 29 | bh.consume(e) 30 | } 31 | } 32 | 33 | @Benchmark 34 | fun addLastAndGet(bh: Blackhole) { 35 | val builder = persistentListBuilderAdd(size, immutablePercentage) 36 | for (i in 0 until builder.size) { 37 | bh.consume(builder[i]) 38 | } 39 | } 40 | 41 | /** 42 | * Adds [size] - 1 elements to an empty persistent list builder 43 | * and then inserts one element at the beginning. 44 | * 45 | * Measures mean time and memory spent per `add` operation. 46 | * 47 | * Expected time: nearly constant. 48 | * Expected memory: nearly constant. 49 | */ 50 | @Benchmark 51 | fun addFirst(): PersistentList.Builder { 52 | val builder = persistentListBuilderAdd(size - 1, immutablePercentage) 53 | builder.add(0, "another element") 54 | return builder 55 | } 56 | 57 | /** 58 | * Adds [size] - 1 elements to an empty persistent list builder 59 | * and then inserts one element at the middle. 60 | * 61 | * Measures mean time and memory spent per `add` operation. 62 | * 63 | * Expected time: nearly constant. 64 | * Expected memory: nearly constant. 65 | */ 66 | @Benchmark 67 | fun addMiddle(): PersistentList.Builder { 68 | val builder = persistentListBuilderAdd(size - 1, immutablePercentage) 69 | builder.add(size / 2, "another element") 70 | return builder 71 | } 72 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/builder/Get.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.persistentListOf 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Get { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 15 | var size: Int = 0 16 | 17 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 18 | var immutablePercentage: Double = 0.0 19 | 20 | private var builder = persistentListOf().builder() 21 | 22 | @Setup 23 | fun prepare() { 24 | builder = persistentListBuilderAdd(size, immutablePercentage) 25 | } 26 | 27 | @Benchmark 28 | fun getByIndex(bh: Blackhole) { 29 | for (i in 0 until builder.size) { 30 | bh.consume(builder[i]) 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/builder/Iterate.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.persistentListOf 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Iterate { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 15 | var size: Int = 0 16 | 17 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 18 | var immutablePercentage: Double = 0.0 19 | 20 | private var builder = persistentListOf().builder() 21 | 22 | @Setup 23 | fun prepare() { 24 | builder = persistentListBuilderAdd(size, immutablePercentage) 25 | } 26 | 27 | @Benchmark 28 | fun firstToLast(bh: Blackhole) { 29 | for (e in builder) { 30 | bh.consume(e) 31 | } 32 | } 33 | 34 | @Benchmark 35 | fun lastToFirst(bh: Blackhole) { 36 | val iterator = builder.listIterator(size) 37 | 38 | while (iterator.hasPrevious()) { 39 | bh.consume(iterator.previous()) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/builder/Remove.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentList 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Remove { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 15 | var size: Int = 0 16 | 17 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 18 | var immutablePercentage: Double = 0.0 19 | 20 | @Benchmark 21 | fun addAndRemoveLast(): PersistentList.Builder { 22 | val builder = persistentListBuilderAdd(size, immutablePercentage) 23 | for (i in 0 until size) { 24 | builder.removeAt(builder.size - 1) 25 | } 26 | return builder 27 | } 28 | 29 | /** 30 | * Adds [size] elements to an empty persistent list builder 31 | * and then removes one element from the beginning. 32 | * 33 | * Measures (mean time and memory spent per `add` operation) + (time and memory spent on `removeAt` operation) / size. 34 | * 35 | * Expected time: [Add.addLast] + nearly constant. 36 | * Expected memory: [Add.addLast] + nearly constant. 37 | */ 38 | @Benchmark 39 | fun addAndRemoveFirst(): String { 40 | val builder = persistentListBuilderAdd(size, immutablePercentage) 41 | return builder.removeAt(0) 42 | } 43 | 44 | /** 45 | * Adds [size] elements to an empty persistent list builder 46 | * and then removes one element from the middle. 47 | * 48 | * Measures (mean time and memory spent per `add` operation) + (time and memory spent on `removeAt` operation) / size. 49 | * 50 | * Expected time: [Add.addLast] + nearly constant. 51 | * Expected memory: [Add.addLast] + nearly constant. 52 | */ 53 | @Benchmark 54 | fun addAndRemoveMiddle(): String { 55 | val builder = persistentListBuilderAdd(size, immutablePercentage) 56 | return builder.removeAt(size / 2) 57 | } 58 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/builder/RemoveAll.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentList 10 | import kotlinx.collections.immutable.persistentListOf 11 | import kotlinx.benchmark.* 12 | import kotlin.random.Random 13 | 14 | @State(Scope.Benchmark) 15 | open class RemoveAll { 16 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 17 | var size: Int = 0 18 | 19 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 20 | var immutablePercentage: Double = 0.0 21 | 22 | // Results of the following benchmarks do not indicate memory or time spent per operation, 23 | // however regressions there do indicate changes. 24 | // 25 | // The benchmarks measure (mean time and memory spent per `add` operation) + (time and memory spent on `removeAll` operation) / size. 26 | // 27 | // Expected time: [Add.addLast] + nearly constant. 28 | // Expected memory: [Add.addLast] + nearly constant. 29 | 30 | /** 31 | * Adds [size] elements to an empty persistent list builder 32 | * and then removes all of them using `removeAll(elements)` operation. 33 | */ 34 | @Benchmark 35 | fun addAndRemoveAll_All(): Boolean { 36 | val builder = persistentListBuilderAddIndexes() 37 | val elementsToRemove = List(size) { it } 38 | return builder.removeAll(elementsToRemove) 39 | } 40 | 41 | /** 42 | * Adds [size] elements to an empty persistent list builder 43 | * and then removes half of them using `removeAll(elements)` operation. 44 | */ 45 | @Benchmark 46 | fun addAndRemoveAll_RandomHalf(): Boolean { 47 | val builder = persistentListBuilderAddIndexes() 48 | val elementsToRemove = randomIndexes(size / 2) 49 | return builder.removeAll(elementsToRemove) 50 | } 51 | 52 | /** 53 | * Adds [size] elements to an empty persistent list builder 54 | * and then removes 10 of them using `removeAll(elements)` operation. 55 | */ 56 | @Benchmark 57 | fun addAndRemoveAll_RandomTen(): Boolean { 58 | val builder = persistentListBuilderAddIndexes() 59 | val elementsToRemove = randomIndexes(10) 60 | return builder.removeAll(elementsToRemove) 61 | } 62 | 63 | /** 64 | * Adds [size] elements to an empty persistent list builder 65 | * and then removes last [tailSize] of them using `removeAll(elements)` operation. 66 | */ 67 | @Benchmark 68 | fun addAndRemoveAll_Tail(): Boolean { 69 | val builder = persistentListBuilderAddIndexes() 70 | val elementsToRemove = List(tailSize()) { size - 1 - it } 71 | return builder.removeAll(elementsToRemove) 72 | } 73 | 74 | /** 75 | * Adds [size] elements to an empty persistent list builder 76 | * and then removes 10 non-existing elements using `removeAll(elements)` operation. 77 | */ 78 | @Benchmark 79 | fun addAndRemoveAll_NonExisting(): Boolean { 80 | val builder = persistentListBuilderAddIndexes() 81 | val elementsToRemove = randomIndexes(10).map { size + it } 82 | return builder.removeAll(elementsToRemove) 83 | } 84 | 85 | private fun persistentListBuilderAddIndexes(): PersistentList.Builder { 86 | val immutableSize = immutableSize(size, immutablePercentage) 87 | var list = persistentListOf() 88 | for (i in 0 until immutableSize) { 89 | list = list.add(i) 90 | } 91 | val builder = list.builder() 92 | for (i in immutableSize until size) { 93 | builder.add(i) 94 | } 95 | return builder 96 | } 97 | 98 | private fun randomIndexes(count: Int): List { 99 | return List(count) { Random.nextInt(size) } 100 | } 101 | 102 | private fun tailSize(): Int { 103 | val bufferSize = 32 104 | return (size and (bufferSize - 1)).let { if (it == 0) bufferSize else it } 105 | } 106 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/builder/Set.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentList 10 | import kotlinx.collections.immutable.persistentListOf 11 | import kotlinx.benchmark.* 12 | 13 | @State(Scope.Benchmark) 14 | open class Set { 15 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000, BM_10000000) 16 | var size: Int = 0 17 | 18 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 19 | var immutablePercentage: Double = 0.0 20 | 21 | private var builder = persistentListOf().builder() 22 | private var randomIndices = listOf() 23 | 24 | @Setup 25 | fun prepare() { 26 | builder = persistentListBuilderAdd(size, immutablePercentage) 27 | randomIndices = List(size) { it }.shuffled() 28 | } 29 | 30 | @Benchmark 31 | fun setByIndex(): PersistentList.Builder { 32 | for (i in 0 until size) { 33 | builder[i] = "another element" 34 | } 35 | return builder 36 | } 37 | 38 | @Benchmark 39 | fun setByRandomIndex(): PersistentList.Builder { 40 | for (i in 0 until size) { 41 | builder[randomIndices[i]] = "another element" 42 | } 43 | return builder 44 | } 45 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/builder/utils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList.builder 7 | 8 | import kotlinx.collections.immutable.PersistentList 9 | import benchmarks.immutableList.persistentListAdd 10 | import benchmarks.immutableSize 11 | 12 | fun persistentListBuilderAdd(size: Int, immutablePercentage: Double): PersistentList.Builder { 13 | val immutableSize = immutableSize(size, immutablePercentage) 14 | val builder = persistentListAdd(immutableSize).builder() 15 | repeat(times = size - immutableSize) { 16 | builder.add("some element") 17 | } 18 | return builder 19 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableList/utils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableList 7 | 8 | import kotlinx.collections.immutable.PersistentList 9 | import kotlinx.collections.immutable.persistentListOf 10 | 11 | fun persistentListAdd(size: Int): PersistentList { 12 | var list = persistentListOf() 13 | repeat(times = size) { 14 | list = list.add("some element") 15 | } 16 | return list 17 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableMap/Equals.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2021 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableMap 7 | 8 | import benchmarks.* 9 | import kotlinx.benchmark.* 10 | import kotlinx.collections.immutable.persistentMapOf 11 | 12 | @State(Scope.Benchmark) 13 | open class Equals { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE, NON_EXISTING_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | private var persistentMap = persistentMapOf() 24 | private var sameMap = persistentMapOf() 25 | private var slightlyDifferentMap = persistentMapOf() 26 | private var veryDifferentMap = persistentMapOf() 27 | 28 | @Setup 29 | fun prepare() { 30 | val keys = generateKeys(hashCodeType, size * 2) 31 | persistentMap = persistentMapPut(implementation, keys.take(size)) 32 | sameMap = persistentMapPut(implementation, keys.take(size)) 33 | slightlyDifferentMap = sameMap.put(keys[size], "different value").remove(keys[0]) 34 | veryDifferentMap = persistentMapPut(implementation, keys.drop(size)) 35 | } 36 | 37 | @Benchmark 38 | fun equalsTrue() = persistentMap == sameMap 39 | @Benchmark 40 | fun nearlyEquals() = persistentMap == slightlyDifferentMap 41 | @Benchmark 42 | fun notEquals() = persistentMap == veryDifferentMap 43 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableMap/Get.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableMap 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.persistentMapOf 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Get { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE, NON_EXISTING_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | private var keys = listOf() 24 | private var persistentMap = persistentMapOf() 25 | 26 | @Setup 27 | fun prepare() { 28 | keys = generateKeys(hashCodeType, size) 29 | persistentMap = persistentMapPut(implementation, keys) 30 | 31 | if (hashCodeType == NON_EXISTING_HASH_CODE) 32 | keys = generateKeys(hashCodeType, size) 33 | } 34 | 35 | @Benchmark 36 | fun get(bh: Blackhole) { 37 | repeat(times = size) { index -> 38 | bh.consume(persistentMap[keys[index]]) 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableMap/Iterate.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableMap 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.persistentMapOf 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Iterate { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | private var persistentMap = persistentMapOf() 24 | 25 | @Setup 26 | fun prepare() { 27 | persistentMap = persistentMapPut(implementation, generateKeys(hashCodeType, size)) 28 | } 29 | 30 | @Benchmark 31 | fun iterateKeys(bh: Blackhole) { 32 | for (k in persistentMap.keys) { 33 | bh.consume(k) 34 | } 35 | } 36 | 37 | @Benchmark 38 | fun iterateValues(bh: Blackhole) { 39 | for (v in persistentMap.values) { 40 | bh.consume(v) 41 | } 42 | } 43 | 44 | @Benchmark 45 | fun iterateEntries(bh: Blackhole) { 46 | for (e in persistentMap) { 47 | bh.consume(e) 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableMap/Put.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableMap 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentMap 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Put { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | private var keys = listOf() 24 | 25 | @Setup 26 | fun prepare() { 27 | keys = generateKeys(hashCodeType, size) 28 | } 29 | 30 | @Benchmark 31 | fun put(): PersistentMap { 32 | return persistentMapPut(implementation, keys) 33 | } 34 | 35 | @Benchmark 36 | fun putAndGet(bh: Blackhole) { 37 | val map = persistentMapPut(implementation, keys) 38 | repeat(times = size) { index -> 39 | bh.consume(map[keys[index]]) 40 | } 41 | } 42 | 43 | @Benchmark 44 | fun putAndIterateKeys(bh: Blackhole) { 45 | val map = persistentMapPut(implementation, keys) 46 | for (key in map.keys) { 47 | bh.consume(key) 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableMap/PutAll.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2021 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableMap 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentMap 10 | import kotlinx.benchmark.* 11 | import kotlinx.collections.immutable.persistentMapOf 12 | 13 | @State(Scope.Benchmark) 14 | open class PutAll { 15 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 16 | var size: Int = 0 17 | 18 | @Param(HASH_IMPL, ORDERED_IMPL) 19 | var implementation = "" 20 | 21 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE) 22 | var hashCodeType = "" 23 | 24 | private var lhs = persistentMapOf() 25 | private var lhsSmall = persistentMapOf() 26 | private var rhs = persistentMapOf() 27 | private var rhsSmall = persistentMapOf() 28 | 29 | @Setup 30 | fun prepare() { 31 | val keys = generateKeys(hashCodeType, 2 * size) 32 | lhs = persistentMapPut(implementation, keys.take(size)) 33 | lhsSmall = persistentMapPut(implementation, keys.take((size / 1000) + 1)) 34 | rhs = persistentMapPut(implementation, keys.takeLast(size)) 35 | rhsSmall = persistentMapPut(implementation, keys.takeLast((size / 1000) + 1)) 36 | } 37 | 38 | @Benchmark 39 | fun putAllEqualSize(): PersistentMap { 40 | return lhs.putAll(rhs) 41 | } 42 | 43 | @Benchmark 44 | fun putAllSmallIntoLarge(): PersistentMap { 45 | return lhs.putAll(rhsSmall) 46 | } 47 | 48 | @Benchmark 49 | fun putAllLargeIntoSmall(): PersistentMap { 50 | return lhsSmall.putAll(rhs) 51 | } 52 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableMap/Remove.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableMap 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentMap 10 | import kotlinx.collections.immutable.persistentMapOf 11 | import kotlinx.benchmark.* 12 | 13 | @State(Scope.Benchmark) 14 | open class Remove { 15 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 16 | var size: Int = 0 17 | 18 | @Param(HASH_IMPL, ORDERED_IMPL) 19 | var implementation = "" 20 | 21 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE, NON_EXISTING_HASH_CODE) 22 | var hashCodeType = "" 23 | 24 | private var keys = listOf() 25 | private var persistentMap = persistentMapOf() 26 | 27 | @Setup 28 | fun prepare() { 29 | keys = generateKeys(hashCodeType, size) 30 | persistentMap = persistentMapPut(implementation, keys) 31 | 32 | if (hashCodeType == NON_EXISTING_HASH_CODE) 33 | keys = generateKeys(hashCodeType, size) 34 | } 35 | 36 | @Benchmark 37 | fun remove(): PersistentMap { 38 | var map = persistentMap 39 | repeat(times = size) { index -> 40 | map = map.remove(keys[index]) 41 | } 42 | return map 43 | } 44 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableMap/builder/Equals.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2021 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableMap.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.benchmark.* 10 | import kotlinx.collections.immutable.persistentMapOf 11 | 12 | @State(Scope.Benchmark) 13 | open class Equals { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE, NON_EXISTING_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | private var persistentMap = persistentMapOf().builder() 24 | private var sameMap = persistentMapOf().builder() 25 | private var slightlyDifferentMap = persistentMapOf().builder() 26 | private var veryDifferentMap = persistentMapOf().builder() 27 | 28 | @Setup 29 | fun prepare() { 30 | val keys = generateKeys(hashCodeType, size * 2) 31 | persistentMap = persistentMapBuilderPut(implementation, keys.take(size), 0.0) 32 | sameMap = persistentMapBuilderPut(implementation, keys.take(size), 0.0) 33 | slightlyDifferentMap = sameMap.build().builder() 34 | slightlyDifferentMap.put(keys[size], "different value") 35 | slightlyDifferentMap.remove(keys[0]) 36 | veryDifferentMap = persistentMapBuilderPut(implementation, keys.drop(size), 0.0) 37 | } 38 | 39 | @Benchmark 40 | fun equalsTrue() = persistentMap == sameMap 41 | @Benchmark 42 | fun nearlyEquals() = persistentMap == slightlyDifferentMap 43 | @Benchmark 44 | fun notEquals() = persistentMap == veryDifferentMap 45 | 46 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableMap/builder/Get.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableMap.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.persistentMapOf 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Get { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE, NON_EXISTING_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 24 | var immutablePercentage: Double = 0.0 25 | 26 | private var keys = listOf() 27 | private var builder = persistentMapOf().builder() 28 | 29 | @Setup 30 | fun prepare() { 31 | keys = generateKeys(hashCodeType, size) 32 | builder = persistentMapBuilderPut(implementation, keys, immutablePercentage) 33 | 34 | if (hashCodeType == NON_EXISTING_HASH_CODE) 35 | keys = generateKeys(hashCodeType, size) 36 | } 37 | 38 | @Benchmark 39 | fun get(bh: Blackhole) { 40 | repeat(times = size) { index -> 41 | bh.consume(builder[keys[index]]) 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableMap/builder/Iterate.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableMap.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.persistentMapOf 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Iterate { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 24 | var immutablePercentage: Double = 0.0 25 | 26 | private var builder = persistentMapOf().builder() 27 | 28 | @Setup 29 | fun prepare() { 30 | val keys = generateKeys(hashCodeType, size) 31 | builder = persistentMapBuilderPut(implementation, keys, immutablePercentage) 32 | } 33 | 34 | @Benchmark 35 | fun iterateKeys(bh: Blackhole) { 36 | for (k in builder.keys) { 37 | bh.consume(k) 38 | } 39 | } 40 | 41 | @Benchmark 42 | fun iterateValues(bh: Blackhole) { 43 | for (v in builder.values) { 44 | bh.consume(v) 45 | } 46 | } 47 | 48 | @Benchmark 49 | fun iterateEntries(bh: Blackhole) { 50 | for (e in builder) { 51 | bh.consume(e) 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableMap/builder/Put.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableMap.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentMap 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Put { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 24 | var immutablePercentage: Double = 0.0 25 | 26 | private var keys = listOf() 27 | 28 | @Setup 29 | fun prepare() { 30 | keys = generateKeys(hashCodeType, size) 31 | } 32 | 33 | @Benchmark 34 | fun put(): PersistentMap.Builder { 35 | return persistentMapBuilderPut(implementation, keys, immutablePercentage) 36 | } 37 | 38 | @Benchmark 39 | fun putAndGet(bh: Blackhole) { 40 | val builder = persistentMapBuilderPut(implementation, keys, immutablePercentage) 41 | repeat(times = size) { index -> 42 | bh.consume(builder[keys[index]]) 43 | } 44 | } 45 | 46 | @Benchmark 47 | fun putAndIterateKeys(bh: Blackhole) { 48 | val builder = persistentMapBuilderPut(implementation, keys, immutablePercentage) 49 | for (key in builder.keys) { 50 | bh.consume(key) 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableMap/builder/Remove.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableMap.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentMap 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Remove { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE, NON_EXISTING_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 24 | var immutablePercentage: Double = 0.0 25 | 26 | private var keys = listOf() 27 | private var keysToRemove = listOf() 28 | 29 | @Setup 30 | fun prepare() { 31 | keys = generateKeys(hashCodeType, size) 32 | 33 | keysToRemove = if (hashCodeType == NON_EXISTING_HASH_CODE) { 34 | generateKeys(hashCodeType, size) 35 | } else { 36 | keys 37 | } 38 | } 39 | 40 | // Q: Why not to benchmark pure remove method? 41 | // A: Each invocation of remove benchmark method would clear the builder and creating new one would be needed each time. 42 | // Setting `@Setup(Level.Invocation)` may cause bad benchmark accuracy amid frequent `prepare` calls, especially for small `size`. 43 | @Benchmark 44 | fun putAndRemove(): PersistentMap.Builder { 45 | val builder = persistentMapBuilderPut(implementation, keys, immutablePercentage) 46 | repeat(times = size) { index -> 47 | builder.remove(keysToRemove[index]) 48 | } 49 | return builder 50 | } 51 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableMap/builder/utils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableMap.builder 7 | 8 | import benchmarks.* 9 | import benchmarks.immutableMap.emptyPersistentMap 10 | import kotlinx.collections.immutable.PersistentMap 11 | 12 | 13 | fun persistentMapBuilderPut( 14 | implementation: String, 15 | keys: List, 16 | immutablePercentage: Double 17 | ): PersistentMap.Builder { 18 | val immutableSize = immutableSize(keys.size, immutablePercentage) 19 | 20 | var map = emptyPersistentMap(implementation) 21 | for (index in 0 until immutableSize) { 22 | map = map.put(keys[index], "some value") 23 | } 24 | 25 | val builder = map.builder() 26 | for (index in immutableSize until keys.size) { 27 | builder[keys[index]] = "some value" 28 | } 29 | 30 | return builder 31 | } 32 | -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableMap/utils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableMap 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentMap 10 | import kotlinx.collections.immutable.persistentHashMapOf 11 | import kotlinx.collections.immutable.persistentMapOf 12 | import kotlin.math.ceil 13 | import kotlin.math.log 14 | 15 | 16 | fun emptyPersistentMap(implementation: String): PersistentMap = when (implementation) { 17 | HASH_IMPL -> persistentHashMapOf() 18 | ORDERED_IMPL -> persistentMapOf() 19 | else -> throw AssertionError("Unknown PersistentMap implementation: $implementation") 20 | } 21 | 22 | fun persistentMapPut(implementation: String, keys: List): PersistentMap { 23 | var map = emptyPersistentMap(implementation) 24 | for (key in keys) { 25 | map = map.put(key, "some value") 26 | } 27 | return map 28 | } 29 | 30 | fun persistentMapRemove(persistentMap: PersistentMap, keys: List): PersistentMap { 31 | var map = persistentMap 32 | for (key in keys) { 33 | map = map.remove(key) 34 | } 35 | return map 36 | } 37 | 38 | 39 | private const val branchingFactor = 32 40 | private const val logBranchingFactor = 5 41 | 42 | private fun expectedHeightOfPersistentMapWithSize(size: Int): Int { 43 | return ceil(log(size.toDouble(), branchingFactor.toDouble())).toInt() 44 | } 45 | 46 | /** 47 | * Returns the size of a persistent map whose expected height is 48 | * half of the specified [persistentMap]'s expected height. 49 | */ 50 | fun sizeForHalfHeight(persistentMap: PersistentMap<*, *>): Int { 51 | val expectedHeight = expectedHeightOfPersistentMapWithSize(persistentMap.size) 52 | return 1 shl ((expectedHeight / 2) * logBranchingFactor) 53 | } 54 | -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutablePercentage.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks 7 | 8 | import kotlin.math.floor 9 | 10 | const val IP_100 = "100.0" 11 | const val IP_99_09 = "99.09" 12 | const val IP_95 = "95.0" 13 | const val IP_70 = "70.0" 14 | const val IP_50 = "50.0" 15 | const val IP_30 = "30.0" 16 | const val IP_0 = "0.0" 17 | 18 | 19 | fun immutableSize(size: Int, immutablePercentage: Double): Int { 20 | return floor(size * immutablePercentage / 100.0).toInt() 21 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableSet/Add.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableSet 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.ImmutableSet 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Add { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | private var elements = listOf() 24 | 25 | @Setup 26 | fun prepare() { 27 | elements = generateElements(hashCodeType, size) 28 | } 29 | 30 | @Benchmark 31 | fun add(): ImmutableSet { 32 | return persistentSetAdd(implementation, elements) 33 | } 34 | 35 | @Benchmark 36 | fun addAndContains(bh: Blackhole) { 37 | val set = persistentSetAdd(implementation, elements) 38 | repeat(times = size) { index -> 39 | bh.consume(set.contains(elements[index])) 40 | } 41 | } 42 | 43 | @Benchmark 44 | fun addAndIterate(bh: Blackhole) { 45 | val set = persistentSetAdd(implementation, elements) 46 | for (element in set) { 47 | bh.consume(element) 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableSet/Contains.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableSet 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.persistentSetOf 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Contains { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE, NON_EXISTING_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | private var elements = listOf() 24 | private var persistentSet = persistentSetOf() 25 | 26 | @Setup 27 | fun prepare() { 28 | elements = generateElements(hashCodeType, size) 29 | persistentSet = persistentSetAdd(implementation, elements) 30 | 31 | if (hashCodeType == NON_EXISTING_HASH_CODE) 32 | elements = generateElements(hashCodeType, size) 33 | } 34 | 35 | @Benchmark 36 | fun contains(bh: Blackhole) { 37 | repeat(times = size) { index -> 38 | bh.consume(persistentSet.contains(elements[index])) 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableSet/Equals.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2021 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableSet 7 | 8 | import benchmarks.* 9 | import kotlinx.benchmark.* 10 | import kotlinx.collections.immutable.persistentSetOf 11 | 12 | @State(Scope.Benchmark) 13 | open class Equals { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE, NON_EXISTING_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | private var persistentSet = persistentSetOf() 24 | private var sameSet = persistentSetOf() 25 | private var slightlyDifferentSet = persistentSetOf() 26 | private var veryDifferentSet = persistentSetOf() 27 | 28 | @Setup 29 | fun prepare() { 30 | val keys = generateKeys(hashCodeType, size * 2) 31 | persistentSet = persistentSetAdd(implementation, keys.take(size)) 32 | sameSet = persistentSetAdd(implementation, keys.take(size)) 33 | slightlyDifferentSet = sameSet.add(keys[size]).remove(keys[0]) 34 | veryDifferentSet = persistentSetAdd(implementation, keys.drop(size)) 35 | } 36 | 37 | @Benchmark 38 | fun equalsTrue() = persistentSet == sameSet 39 | @Benchmark 40 | fun nearlyEquals() = persistentSet == slightlyDifferentSet 41 | @Benchmark 42 | fun notEquals() = persistentSet == veryDifferentSet 43 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableSet/Iterate.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableSet 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.persistentSetOf 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Iterate { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | private var persistentSet = persistentSetOf() 24 | 25 | @Setup 26 | fun prepare() { 27 | persistentSet = persistentSetAdd(implementation, generateElements(hashCodeType, size)) 28 | } 29 | 30 | @Benchmark 31 | fun iterate(bh: Blackhole) { 32 | for (e in persistentSet) { 33 | bh.consume(e) 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableSet/Remove.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableSet 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.ImmutableSet 10 | import kotlinx.collections.immutable.persistentSetOf 11 | import kotlinx.benchmark.* 12 | 13 | @State(Scope.Benchmark) 14 | open class Remove { 15 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 16 | var size: Int = 0 17 | 18 | @Param(HASH_IMPL, ORDERED_IMPL) 19 | var implementation = "" 20 | 21 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE, NON_EXISTING_HASH_CODE) 22 | var hashCodeType = "" 23 | 24 | private var elements = listOf() 25 | private var persistentSet = persistentSetOf() 26 | 27 | @Setup 28 | fun prepare() { 29 | elements = generateElements(hashCodeType, size) 30 | persistentSet = persistentSetAdd(implementation, elements) 31 | 32 | if (hashCodeType == NON_EXISTING_HASH_CODE) 33 | elements = generateElements(hashCodeType, size) 34 | } 35 | 36 | @Benchmark 37 | fun remove(): ImmutableSet { 38 | var set = persistentSet 39 | repeat(times = size) { index -> 40 | set = set.remove(elements[index]) 41 | } 42 | return set 43 | } 44 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableSet/builder/Add.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableSet.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentSet 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Add { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 24 | var immutablePercentage: Double = 0.0 25 | 26 | private var elements = listOf() 27 | 28 | @Setup 29 | fun prepare() { 30 | elements = generateElements(hashCodeType, size) 31 | } 32 | 33 | @Benchmark 34 | fun add(): PersistentSet.Builder { 35 | return persistentSetBuilderAdd(implementation, elements, immutablePercentage) 36 | } 37 | 38 | @Benchmark 39 | fun addAndContains(bh: Blackhole) { 40 | val builder = persistentSetBuilderAdd(implementation, elements, immutablePercentage) 41 | repeat(times = size) { index -> 42 | bh.consume(builder.contains(elements[index])) 43 | } 44 | } 45 | 46 | @Benchmark 47 | fun addAndIterate(bh: Blackhole) { 48 | val set = persistentSetBuilderAdd(implementation, elements, immutablePercentage) 49 | for (element in set) { 50 | bh.consume(element) 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableSet/builder/Contains.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableSet.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.persistentSetOf 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Contains { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE, NON_EXISTING_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 24 | var immutablePercentage: Double = 0.0 25 | 26 | private var elements = listOf() 27 | private var builder = persistentSetOf().builder() 28 | 29 | @Setup 30 | fun prepare() { 31 | elements = generateElements(hashCodeType, size) 32 | builder = persistentSetBuilderAdd(implementation, elements, immutablePercentage) 33 | 34 | if (hashCodeType == NON_EXISTING_HASH_CODE) 35 | elements = generateElements(hashCodeType, size) 36 | } 37 | 38 | @Benchmark 39 | fun contains(bh: Blackhole) { 40 | repeat(times = size) { index -> 41 | bh.consume(builder.contains(elements[index])) 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableSet/builder/Equals.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2021 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableSet.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.benchmark.* 10 | import kotlinx.collections.immutable.persistentSetOf 11 | 12 | @State(Scope.Benchmark) 13 | open class Equals { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE, NON_EXISTING_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | private var persistentSet = persistentSetOf().builder() 24 | private var sameSet = persistentSetOf().builder() 25 | private var slightlyDifferentSet = persistentSetOf().builder() 26 | private var veryDifferentSet = persistentSetOf().builder() 27 | 28 | @Setup 29 | fun prepare() { 30 | val keys = generateKeys(hashCodeType, size * 2) 31 | persistentSet = persistentSetBuilderAdd(implementation, keys.take(size), 0.0) 32 | sameSet = persistentSetBuilderAdd(implementation, keys.take(size), 0.0) 33 | slightlyDifferentSet = sameSet.build().builder() 34 | slightlyDifferentSet.add(keys[size]) 35 | slightlyDifferentSet.remove(keys[0]) 36 | veryDifferentSet = persistentSetBuilderAdd(implementation, keys.drop(size), 0.0) 37 | } 38 | 39 | @Benchmark 40 | fun equalsTrue() = persistentSet == sameSet 41 | @Benchmark 42 | fun nearlyEquals() = persistentSet == slightlyDifferentSet 43 | @Benchmark 44 | fun notEquals() = persistentSet == veryDifferentSet 45 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableSet/builder/Iterate.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableSet.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.persistentSetOf 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Iterate { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 24 | var immutablePercentage: Double = 0.0 25 | 26 | private var builder = persistentSetOf().builder() 27 | 28 | @Setup 29 | fun prepare() { 30 | val elements = generateElements(hashCodeType, size) 31 | builder = persistentSetBuilderAdd(implementation, elements, immutablePercentage) 32 | } 33 | 34 | @Benchmark 35 | fun iterate(bh: Blackhole) { 36 | for (e in builder) { 37 | bh.consume(e) 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableSet/builder/Remove.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableSet.builder 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentSet 10 | import kotlinx.benchmark.* 11 | 12 | @State(Scope.Benchmark) 13 | open class Remove { 14 | @Param(BM_1, BM_10, BM_100, BM_1000, BM_10000, BM_100000, BM_1000000) 15 | var size: Int = 0 16 | 17 | @Param(HASH_IMPL, ORDERED_IMPL) 18 | var implementation = "" 19 | 20 | @Param(ASCENDING_HASH_CODE, RANDOM_HASH_CODE, COLLISION_HASH_CODE, NON_EXISTING_HASH_CODE) 21 | var hashCodeType = "" 22 | 23 | @Param(IP_100, IP_99_09, IP_95, IP_70, IP_50, IP_30, IP_0) 24 | var immutablePercentage: Double = 0.0 25 | 26 | private var elements = listOf() 27 | private var elementsToRemove = listOf() 28 | 29 | @Setup 30 | fun prepare() { 31 | elements = generateElements(hashCodeType, size) 32 | 33 | elementsToRemove = if (hashCodeType == NON_EXISTING_HASH_CODE) { 34 | generateElements(hashCodeType, size) 35 | } else { 36 | elements 37 | } 38 | } 39 | 40 | @Benchmark 41 | fun addAndRemove(): PersistentSet.Builder { 42 | val builder = persistentSetBuilderAdd(implementation, elements, immutablePercentage) 43 | repeat(times = size) { index -> 44 | builder.remove(elementsToRemove[index]) 45 | } 46 | return builder 47 | } 48 | } -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableSet/builder/utils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableSet.builder 7 | 8 | import benchmarks.* 9 | import benchmarks.immutableSet.emptyPersistentSet 10 | import kotlinx.collections.immutable.PersistentSet 11 | 12 | fun persistentSetBuilderAdd( 13 | implementation: String, 14 | elements: List, 15 | immutablePercentage: Double 16 | ): PersistentSet.Builder { 17 | val immutableSize = immutableSize(elements.size, immutablePercentage) 18 | 19 | var set = emptyPersistentSet(implementation) 20 | for (index in 0 until immutableSize) { 21 | set = set.add(elements[index]) 22 | } 23 | 24 | val builder = set.builder() 25 | for (index in immutableSize until elements.size) { 26 | builder.add(elements[index]) 27 | } 28 | 29 | return builder 30 | } 31 | -------------------------------------------------------------------------------- /benchmarks/commonMain/src/benchmarks/immutableSet/utils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package benchmarks.immutableSet 7 | 8 | import benchmarks.* 9 | import kotlinx.collections.immutable.PersistentSet 10 | import kotlinx.collections.immutable.persistentHashSetOf 11 | import kotlinx.collections.immutable.persistentSetOf 12 | import kotlin.math.ceil 13 | import kotlin.math.log 14 | 15 | 16 | fun emptyPersistentSet(implementation: String): PersistentSet = when (implementation) { 17 | HASH_IMPL -> persistentHashSetOf() 18 | ORDERED_IMPL -> persistentSetOf() 19 | else -> throw AssertionError("Unknown PersistentSet implementation: $implementation") 20 | } 21 | 22 | fun persistentSetAdd(implementation: String, elements: List): PersistentSet { 23 | var set = emptyPersistentSet(implementation) 24 | for (element in elements) { 25 | set = set.add(element) 26 | } 27 | return set 28 | } 29 | 30 | fun persistentSetRemove(persistentSet: PersistentSet, elements: List): PersistentSet { 31 | var set = persistentSet 32 | for (element in elements) { 33 | set = set.remove(element) 34 | } 35 | return set 36 | } 37 | 38 | private const val branchingFactor = 32 39 | private const val logBranchingFactor = 5 40 | 41 | private fun expectedHeightOfPersistentSetWithSize(size: Int): Int { 42 | return ceil(log(size.toDouble(), branchingFactor.toDouble())).toInt() 43 | } 44 | 45 | /** 46 | * Returns the size of a persistent set whose expected height is 47 | * half of the specified [persistentSet]'s expected height. 48 | */ 49 | fun sizeForHalfHeight(persistentSet: PersistentSet<*>): Int { 50 | val expectedHeight = expectedHeightOfPersistentSetWithSize(persistentSet.size) 51 | return 1 shl ((expectedHeight / 2) * logBranchingFactor) 52 | } 53 | -------------------------------------------------------------------------------- /benchmarks/runner/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("org.jetbrains.kotlin.jvm") 3 | } 4 | 5 | dependencies { 6 | implementation("org.jetbrains.kotlin:kotlin-stdlib") 7 | implementation("org.openjdk.jmh:jmh-core:1.21") 8 | 9 | runtimeOnly(project(path = ":benchmarks", configuration = "benchmarksJar")) 10 | runtimeOnly(project(":kotlinx-collections-immutable")) 11 | } 12 | 13 | sourceSets.main { 14 | kotlin.srcDirs("src") 15 | } 16 | 17 | // map 18 | val benchmarkHashMap by tasks.registering(JavaExec::class) { 19 | group = "Benchmark" 20 | mainClass = "runners.HashMapRunnerKt" 21 | } 22 | 23 | val benchmarkHashMapBuilder by tasks.registering(JavaExec::class) { 24 | group = "Benchmark" 25 | mainClass = "runners.HashMapBuilderRunnerKt" 26 | } 27 | 28 | val benchmarkOrderedMap by tasks.registering(JavaExec::class) { 29 | group = "Benchmark" 30 | mainClass = "runners.OrderedMapRunnerKt" 31 | } 32 | 33 | val benchmarkOrderedMapBuilder by tasks.registering(JavaExec::class) { 34 | group = "Benchmark" 35 | mainClass = "runners.OrderedMapBuilderRunnerKt" 36 | } 37 | 38 | val benchmarkAllMaps by tasks.registering { 39 | group = "Benchmark" 40 | dependsOn(benchmarkHashMap) 41 | dependsOn(benchmarkHashMapBuilder) 42 | dependsOn(benchmarkOrderedMap) 43 | dependsOn(benchmarkOrderedMapBuilder) 44 | } 45 | 46 | // set 47 | val benchmarkHashSet by tasks.registering(JavaExec::class) { 48 | group = "Benchmark" 49 | mainClass = "runners.HashSetRunnerKt" 50 | } 51 | 52 | val benchmarkHashSetBuilder by tasks.registering(JavaExec::class) { 53 | group = "Benchmark" 54 | mainClass = "runners.HashSetBuilderRunnerKt" 55 | } 56 | 57 | val benchmarkOrderedSet by tasks.registering(JavaExec::class) { 58 | group = "Benchmark" 59 | mainClass = "runners.OrderedSetRunnerKt" 60 | } 61 | 62 | val benchmarkOrderedSetBuilder by tasks.registering(JavaExec::class) { 63 | group = "Benchmark" 64 | mainClass = "runners.OrderedSetBuilderRunnerKt" 65 | } 66 | 67 | val benchmarkAllSets by tasks.registering { 68 | group = "Benchmark" 69 | dependsOn(benchmarkHashSet) 70 | dependsOn(benchmarkHashSetBuilder) 71 | dependsOn(benchmarkOrderedSet) 72 | dependsOn(benchmarkOrderedSetBuilder) 73 | } 74 | 75 | // list 76 | val benchmarkList by tasks.registering(JavaExec::class) { 77 | group = "Benchmark" 78 | mainClass = "runners.ListRunnerKt" 79 | } 80 | 81 | val benchmarkListBuilder by tasks.registering(JavaExec::class) { 82 | group = "Benchmark" 83 | mainClass = "runners.ListBuilderRunnerKt" 84 | } 85 | 86 | val benchmarkAllLists by tasks.registering { 87 | group = "Benchmark" 88 | dependsOn(benchmarkList) 89 | dependsOn(benchmarkListBuilder) 90 | } 91 | 92 | // all 93 | val benchmarkAll by tasks.registering { 94 | group = "Benchmark" 95 | dependsOn(benchmarkAllMaps) 96 | dependsOn(benchmarkAllSets) 97 | dependsOn(benchmarkAllLists) 98 | } 99 | 100 | // configure runner tasks 101 | 102 | val benchmarkParams = listOf( 103 | "remote", 104 | "forks", 105 | "measurementIterations", 106 | "measurementTime", 107 | "warmupIterations", 108 | "warmupTime", 109 | // "exclude", 110 | // "include", 111 | "size", 112 | "hashCodeType", 113 | "immutablePercentage" 114 | ) 115 | 116 | tasks.withType().configureEach { 117 | if (group == "Benchmark") { 118 | classpath = sourceSets.main.get().runtimeClasspath 119 | 120 | benchmarkParams.forEach { param -> 121 | if (project.hasProperty(param)) { 122 | systemProperty(param, requireNotNull(project.property(param))) 123 | } 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /benchmarks/runner/src/contants.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | import org.openjdk.jmh.runner.options.TimeValue 7 | 8 | 9 | const val localReferenceBenchmarkResultsDirectory = "localReferenceBenchmarkResults" 10 | const val remoteReferenceBenchmarkResultsDirectory = "remoteReferenceBenchmarkResults" 11 | const val benchmarkResultsDirectory = "benchmarkResults" 12 | 13 | const val hashMapOutputFileName = "hashMap" 14 | const val hashMapBuilderOutputFileName = "hashMapBuilder" 15 | const val orderedMapOutputFileName = "orderedMap" 16 | const val orderedMapBuilderOutputFileName = "orderedMapBuilder" 17 | 18 | const val hashSetOutputFileName = "hashSet" 19 | const val hashSetBuilderOutputFileName = "hashSetBuilder" 20 | const val orderedSetOutputFileName = "orderedSet" 21 | const val orderedSetBuilderOutputFileName = "orderedSetBuilder" 22 | 23 | const val listOutputFileName = "list" 24 | const val listBuilderOutputFileName = "listBuilder" 25 | 26 | 27 | const val benchmarkMethod = "Benchmark" 28 | const val benchmarkScore = "Score(ns/op)" 29 | const val benchmarkScoreError = "ScoreError(ns/op)" 30 | const val benchmarkAllocRate = "AllocRate(B/op)" 31 | 32 | const val benchmarkScoreRegressPercent = "Score(%)" 33 | const val benchmarkAllocRateRegressPercent = "AllocRate(%)" 34 | 35 | 36 | const val sizeParam = "size" 37 | const val hashCodeTypeParam = "hashCodeType" 38 | const val implementationParam = "implementation" 39 | const val immutablePercentageParam = "immutablePercentage" 40 | 41 | 42 | val jvmArgs = arrayOf("-Xms2048m", "-Xmx2048m") 43 | 44 | const val forks = 1 45 | const val warmupIterations = 10 46 | const val measurementIterations = 20 47 | val warmupTime = TimeValue.milliseconds(500)!! 48 | val measurementTime = TimeValue.milliseconds(1000)!! 49 | 50 | val sizeParamValues = arrayOf("1", "10", "100", "1000", "10000", "100000", "1000000") 51 | val hashCodeTypeParamValues = arrayOf("ascending", "random", "collision", "nonExisting") 52 | val immutablePercentageParamValues = arrayOf("0.0", "20.0", "50.0", "90.0") 53 | -------------------------------------------------------------------------------- /benchmarks/runner/src/csvPrinter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | import java.io.File 7 | import java.io.FileReader 8 | import java.io.FileWriter 9 | 10 | 11 | fun printCsvResults(benchmarkResults: BenchmarkResults, outputPath: String) { 12 | val paramsNamesString = benchmarkResults.paramsNames.joinToString(",") 13 | val csvHeader = "$benchmarkMethod,$paramsNamesString,$benchmarkScore,$benchmarkScoreError,$benchmarkAllocRate" 14 | 15 | File(outputPath).parentFile?.mkdirs() 16 | val fileWriter = FileWriter(outputPath) 17 | 18 | fileWriter.appendLine(csvHeader) 19 | benchmarkResults.runResults.forEach { res -> 20 | val paramsValuesString = benchmarkResults.paramsNames.joinToString(",") { res.paramValue(it) } 21 | val csvRow = "${res.benchmark},$paramsValuesString,${res.score.formatted()},${res.scoreError.formatted()},${res.allocRate.formatted()}" 22 | fileWriter.appendLine(csvRow) 23 | } 24 | 25 | fileWriter.flush() 26 | fileWriter.close() 27 | } 28 | 29 | 30 | fun readCsvResults(file: File): BenchmarkResults { 31 | val fileReader = FileReader(file) 32 | val lines = fileReader.readLines().map { it.split(',') } 33 | fileReader.close() 34 | 35 | check(lines.isNotEmpty()) 36 | check(lines.all { it.size == lines.first().size }) 37 | 38 | val header = lines.first() 39 | 40 | val benchmarkColumn = header.indexOf(benchmarkMethod) 41 | val scoreColumn = header.indexOf(benchmarkScore) 42 | val scoreErrorColumn = header.indexOf(benchmarkScoreError) 43 | val allocRateColumn = header.indexOf(benchmarkAllocRate) 44 | 45 | val paramsColumns = header.indices.filter { 46 | it !in listOf(benchmarkColumn, scoreColumn, scoreErrorColumn, allocRateColumn) 47 | } 48 | 49 | val runResults = lines.drop(1).map { line -> 50 | BenchmarkRunResult( 51 | benchmark = line[benchmarkColumn], 52 | params = paramsColumns.associate { header[it] to line[it] }, 53 | score = line[scoreColumn].toDouble(), 54 | scoreError = line[scoreErrorColumn].toDouble(), 55 | allocRate = line[allocRateColumn].toDouble() 56 | ) 57 | } 58 | 59 | return BenchmarkResults(paramsColumns.map { header[it] }, runResults) 60 | } 61 | 62 | 63 | fun Double.formatted(): String = "%.3f".format(this) -------------------------------------------------------------------------------- /benchmarks/runner/src/customRunResult.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | import org.openjdk.jmh.results.RunResult 7 | 8 | 9 | class BenchmarkResults( 10 | val paramsNames: List, 11 | val runResults: List 12 | ) 13 | 14 | fun Collection.toBenchmarkResults(): BenchmarkResults { 15 | val paramsNames = first().params.paramsKeys 16 | 17 | check(all { it.params.paramsKeys == paramsNames }) 18 | 19 | return BenchmarkResults(paramsNames.toList(), map(RunResult::toBenchmarkRunResult)) 20 | } 21 | 22 | 23 | class BenchmarkRunResult( 24 | val benchmark: String, 25 | val params: Map, 26 | val score: Double, 27 | val scoreError: Double, 28 | val allocRate: Double 29 | ) { 30 | fun paramValue(paramName: String): String = params.getValue(paramName) 31 | } 32 | 33 | private fun RunResult.toBenchmarkRunResult(): BenchmarkRunResult { 34 | val allocRateLabel = "·gc.alloc.rate.norm" 35 | val allocRate = secondaryResults[allocRateLabel]!! 36 | 37 | check(primaryResult.getScoreUnit() == "us/op") 38 | check(allocRate.getScoreUnit() == "B/op") 39 | 40 | val nanosInMicros = 1000 41 | val size = params.getParam(sizeParam).toInt() 42 | 43 | return BenchmarkRunResult( 44 | benchmark = params.benchmark, 45 | params = params.paramsKeys.associateWith { params.getParam(it) }, 46 | score = primaryResult.getScore() * nanosInMicros / size, 47 | scoreError = primaryResult.getScoreError() * nanosInMicros / size, 48 | allocRate = allocRate.getScore() / size 49 | ) 50 | } -------------------------------------------------------------------------------- /benchmarks/runner/src/regressionCalculator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | import java.io.* 7 | import kotlin.math.pow 8 | import kotlin.math.sqrt 9 | 10 | 11 | fun calculateRegression(benchmarkResults: BenchmarkResults, referencePath: String): BenchmarkResults? { 12 | val referenceFile = File(referencePath) 13 | 14 | if (!referenceFile.exists()) { 15 | println("No reference file exists to calculate regression against") 16 | println("Writing the target benchmark results to the reference file: $referencePath") 17 | printCsvResults(benchmarkResults, referencePath) 18 | return null 19 | } 20 | 21 | val referenceResults = readCsvResults(referenceFile) 22 | 23 | println("Calculating regression...\n") 24 | return calculateRegression(referenceResults, benchmarkResults) 25 | } 26 | 27 | private fun calculateRegression(referenceResults: BenchmarkResults, targetResults: BenchmarkResults): BenchmarkResults { 28 | val paramsNames = targetResults.paramsNames 29 | 30 | check(referenceResults.paramsNames == paramsNames) 31 | 32 | val regression = targetResults.runResults.map { target -> 33 | val reference = referenceResults.runResults.firstOrNull { ref -> 34 | target.benchmark == ref.benchmark 35 | && paramsNames.all { target.paramValue(it) == ref.paramValue(it) } 36 | } 37 | 38 | 39 | var regressScore = Double.NaN 40 | var regressScorePercent = Double.NaN 41 | var regressScoreError = Double.NaN 42 | var regressAllocRate = Double.NaN 43 | var regressAllocRatePercent = Double.NaN 44 | if (reference != null) { 45 | regressScore = target.score - reference.score 46 | regressScorePercent = 100 * regressScore / reference.score 47 | regressScoreError = sqrt(target.scoreError.pow(2) + reference.scoreError.pow(2)) 48 | regressAllocRate = target.allocRate - reference.allocRate 49 | regressAllocRatePercent = if (regressAllocRate > 0.1) 100 * regressAllocRate / reference.allocRate else 0.0 50 | } 51 | return@map BenchmarkRunResult( 52 | benchmark = target.benchmark, 53 | params = target.params + mapOf( 54 | benchmarkScoreRegressPercent to regressScorePercent.formatted(), 55 | benchmarkAllocRateRegressPercent to regressAllocRatePercent.formatted() 56 | ), 57 | score = regressScore, 58 | scoreError = regressScoreError, 59 | allocRate = regressAllocRate 60 | ) 61 | } 62 | 63 | return BenchmarkResults( 64 | paramsNames = paramsNames + listOf(benchmarkScoreRegressPercent, benchmarkAllocRateRegressPercent), 65 | runResults = regression 66 | ) 67 | } 68 | -------------------------------------------------------------------------------- /benchmarks/runner/src/reportPrinter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | import java.io.PrintStream 7 | 8 | 9 | private const val COLUMN_PAD = 2 10 | 11 | fun printReport(regression: BenchmarkResults, out: PrintStream, descendingScoreRegress: Boolean) { 12 | val runResults = if (descendingScoreRegress) { 13 | regression.runResults.sortedByDescending { it.paramValue(benchmarkScoreRegressPercent).toDouble() } 14 | } else { 15 | regression.runResults 16 | } 17 | 18 | // determine columns lengths 19 | var nameLen = benchmarkMethod.length 20 | var scoreLen = benchmarkScore.length 21 | var scoreErrLen = benchmarkScoreError.length 22 | var allocRateLen = benchmarkAllocRate.length 23 | 24 | val paramsNames = regression.paramsNames 25 | val paramsLengths = paramsNames.associate { it to it.length + COLUMN_PAD }.toMutableMap() 26 | 27 | for (res in runResults) { 28 | nameLen = Math.max(nameLen, res.benchmark.length) 29 | scoreLen = Math.max(scoreLen, res.score.formatted().length) 30 | scoreErrLen = Math.max(scoreErrLen, res.scoreError.formatted().length) 31 | allocRateLen = Math.max(allocRateLen, res.allocRate.formatted().length) 32 | 33 | for (p in paramsNames) { 34 | paramsLengths[p] = Math.max(paramsLengths[p]!!, res.paramValue(p).length + COLUMN_PAD) 35 | } 36 | } 37 | scoreLen += COLUMN_PAD 38 | scoreErrLen += COLUMN_PAD - 1 // digest a single character for +- separator 39 | allocRateLen += COLUMN_PAD 40 | 41 | // print header 42 | out.printf("%-" + nameLen + "s", benchmarkMethod) 43 | for (p in paramsNames) { 44 | out.printf("%" + paramsLengths[p] + "s", p) 45 | } 46 | 47 | out.printf("%" + scoreLen + "s", benchmarkScore) 48 | out.print(" ") 49 | out.printf("%" + scoreErrLen + "s", benchmarkScoreError) 50 | out.printf("%" + allocRateLen + "s", benchmarkAllocRate) 51 | out.println() 52 | 53 | // print benchmark results 54 | for (res in runResults) { 55 | out.printf("%-" + nameLen + "s", res.benchmark) 56 | 57 | for (p in res.params) { 58 | out.printf("%" + paramsLengths[p.key] + "s", p.value) 59 | } 60 | 61 | out.printf("%" + scoreLen + "s", res.score.formatted()) 62 | 63 | out.print(" \u00B1") 64 | out.printf("%" + scoreErrLen + "s", res.scoreError.formatted()) 65 | 66 | out.printf("%" + allocRateLen + "s", res.allocRate.formatted()) 67 | out.println() 68 | } 69 | } -------------------------------------------------------------------------------- /benchmarks/runner/src/runUtils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | import org.openjdk.jmh.annotations.Mode 7 | import org.openjdk.jmh.runner.Runner 8 | import org.openjdk.jmh.runner.options.ChainedOptionsBuilder 9 | import org.openjdk.jmh.runner.options.OptionsBuilder 10 | import org.openjdk.jmh.runner.options.TimeValue 11 | import java.util.concurrent.TimeUnit 12 | 13 | 14 | private fun systemProperty(name: String, transform: String.() -> T): T? 15 | = System.getProperty(name)?.transform() 16 | 17 | private fun timeSystemProperty(name: String): TimeValue? 18 | = systemProperty(name) { toLong().let { TimeValue.milliseconds(it) } } 19 | 20 | private fun intSystemProperty(name: String): Int? 21 | = systemProperty(name) { toInt() } 22 | 23 | private fun arraySystemProperty(name: String): Array? 24 | = systemProperty(name) { split(",").toTypedArray() } 25 | 26 | private val isRemoteSystemProperty: Boolean 27 | = systemProperty("remote") { toBoolean() } ?: false 28 | 29 | val referenceBenchmarkResultsDirectory: String = if (isRemoteSystemProperty) 30 | remoteReferenceBenchmarkResultsDirectory 31 | else 32 | localReferenceBenchmarkResultsDirectory 33 | 34 | fun ChainedOptionsBuilder.defaultOptions(): ChainedOptionsBuilder = this 35 | .jvmArgs(*jvmArgs) 36 | .addProfiler("gc") 37 | .param(sizeParam, *(arraySystemProperty(sizeParam) ?: sizeParamValues)) 38 | .param(hashCodeTypeParam, *(arraySystemProperty(hashCodeTypeParam) ?: hashCodeTypeParamValues)) 39 | .param(immutablePercentageParam, *(arraySystemProperty(immutablePercentageParam) ?: immutablePercentageParamValues)) 40 | .forks(intSystemProperty("forks") ?: forks) 41 | .warmupIterations(intSystemProperty("warmupIterations") ?: warmupIterations) 42 | .measurementIterations(intSystemProperty("measurementIterations") ?: measurementIterations) 43 | .warmupTime(timeSystemProperty("warmupTime") ?: warmupTime) 44 | .measurementTime(timeSystemProperty("measurementTime") ?: measurementTime) 45 | .mode(Mode.AverageTime) 46 | .timeUnit(TimeUnit.MICROSECONDS) 47 | 48 | inline fun runBenchmarks(outputFileName: String, configure: ChainedOptionsBuilder.() -> ChainedOptionsBuilder) { 49 | val options = OptionsBuilder() 50 | .defaultOptions() 51 | .configure() 52 | .build() 53 | 54 | val outputPath = "$benchmarkResultsDirectory/$outputFileName" 55 | val regressionReferencePath = "$referenceBenchmarkResultsDirectory/$outputFileName" 56 | 57 | Runner(options).run().toBenchmarkResults() 58 | .also { printCsvResults(it, "$outputPath.csv") } 59 | .let { calculateRegression(it, "$regressionReferencePath.csv") } 60 | ?.also { printReport(it, System.out, descendingScoreRegress = true) } 61 | ?.also { printCsvResults(it, "$outputPath-regression.csv") } 62 | } 63 | -------------------------------------------------------------------------------- /benchmarks/runner/src/runners/hashMapBuilderRunner.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package runners 7 | 8 | import hashMapBuilderOutputFileName 9 | import implementationParam 10 | import runBenchmarks 11 | 12 | 13 | fun main() { 14 | runBenchmarks(hashMapBuilderOutputFileName) { this 15 | .include("immutableMap.builder") 16 | .param(implementationParam, "hash") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /benchmarks/runner/src/runners/hashMapRunner.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package runners 7 | 8 | import hashMapOutputFileName 9 | import implementationParam 10 | import runBenchmarks 11 | 12 | 13 | fun main() { 14 | runBenchmarks(hashMapOutputFileName) { this 15 | .include("immutableMap") 16 | .exclude("builder") 17 | .param(implementationParam, "hash") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /benchmarks/runner/src/runners/hashSetBuilderRunner.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package runners 7 | 8 | import hashSetBuilderOutputFileName 9 | import implementationParam 10 | import runBenchmarks 11 | 12 | 13 | fun main() { 14 | runBenchmarks(hashSetBuilderOutputFileName) { this 15 | .include("immutableSet.builder") 16 | .param(implementationParam, "hash") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /benchmarks/runner/src/runners/hashSetRunner.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package runners 7 | 8 | import hashSetOutputFileName 9 | import implementationParam 10 | import runBenchmarks 11 | 12 | 13 | fun main() { 14 | runBenchmarks(hashSetOutputFileName) { this 15 | .include("immutableSet") 16 | .exclude("builder") 17 | .param(implementationParam, "hash") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /benchmarks/runner/src/runners/listBuilderRunner.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package runners 7 | 8 | import listBuilderOutputFileName 9 | import runBenchmarks 10 | 11 | 12 | fun main() { 13 | runBenchmarks(listBuilderOutputFileName) { this 14 | .include("immutableList.builder") 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /benchmarks/runner/src/runners/listRunner.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package runners 7 | 8 | import listOutputFileName 9 | import runBenchmarks 10 | 11 | 12 | fun main() { 13 | runBenchmarks(listOutputFileName) { this 14 | .include("immutableList") 15 | .exclude("builder") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /benchmarks/runner/src/runners/orderedMapBuilderRunner.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package runners 7 | 8 | import implementationParam 9 | import orderedMapBuilderOutputFileName 10 | import runBenchmarks 11 | 12 | 13 | fun main() { 14 | runBenchmarks(orderedMapBuilderOutputFileName) { this 15 | .include("immutableMap.builder") 16 | .param(implementationParam, "ordered") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /benchmarks/runner/src/runners/orderedMapRunner.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package runners 7 | 8 | import implementationParam 9 | import orderedMapOutputFileName 10 | import runBenchmarks 11 | 12 | 13 | fun main() { 14 | runBenchmarks(orderedMapOutputFileName) { this 15 | .include("immutableMap") 16 | .exclude("builder") 17 | .param(implementationParam, "ordered") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /benchmarks/runner/src/runners/orderedSetBuilderRunner.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package runners 7 | 8 | import implementationParam 9 | import orderedSetBuilderOutputFileName 10 | import runBenchmarks 11 | 12 | 13 | fun main() { 14 | runBenchmarks(orderedSetBuilderOutputFileName) { this 15 | .include("immutableSet.builder") 16 | .param(implementationParam, "ordered") 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /benchmarks/runner/src/runners/orderedSetRunner.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package runners 7 | 8 | import implementationParam 9 | import orderedSetOutputFileName 10 | import runBenchmarks 11 | 12 | 13 | fun main() { 14 | runBenchmarks(orderedSetOutputFileName) { this 15 | .include("immutableSet") 16 | .exclude("builder") 17 | .param(implementationParam, "ordered") 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile 2 | import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile 3 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask 4 | 5 | buildscript { 6 | dependencies { 7 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.properties["kotlin_version"]}") 8 | } 9 | } 10 | 11 | plugins { 12 | id("kotlinx.team.infra") version "0.4.0-dev-85" 13 | id("org.jetbrains.kotlinx.binary-compatibility-validator") version "0.17.0" 14 | } 15 | 16 | infra { 17 | publishing { 18 | include(":kotlinx-collections-immutable") 19 | 20 | libraryRepoUrl = "https://github.com/Kotlin/kotlinx.collections.immutable" 21 | sonatype { 22 | libraryStagingRepoDescription = project.name 23 | } 24 | } 25 | } 26 | 27 | apiValidation { 28 | ignoredProjects += listOf( 29 | "benchmarks", 30 | "runner", 31 | ) 32 | 33 | @OptIn(kotlinx.validation.ExperimentalBCVApi::class) 34 | klib { 35 | enabled = true 36 | } 37 | } 38 | 39 | allprojects { 40 | repositories { 41 | mavenCentral() 42 | 43 | val kotlinRepoUrl = providers.gradleProperty("kotlin_repo_url").orNull 44 | if (kotlinRepoUrl != null) { 45 | maven(kotlinRepoUrl) 46 | } 47 | } 48 | 49 | val setAllWarningsAsError = providers.gradleProperty("kotlin_Werror_override").map { 50 | when (it) { 51 | "enable" -> true 52 | "disable" -> false 53 | else -> error("Unexpected value for 'kotlin_Werror_override' property: $it") 54 | } 55 | } 56 | 57 | tasks.withType(KotlinCompilationTask::class).configureEach { 58 | compilerOptions { 59 | if (setAllWarningsAsError.orNull != false) { 60 | allWarningsAsErrors = true 61 | } else { 62 | freeCompilerArgs.addAll( 63 | "-Wextra", 64 | "-Xuse-fir-experimental-checkers" 65 | ) 66 | } 67 | freeCompilerArgs.addAll( 68 | "-Xexpect-actual-classes", 69 | "-Xreport-all-warnings", 70 | "-Xrender-internal-diagnostic-names" 71 | ) 72 | } 73 | if (this is KotlinJsCompile) { 74 | compilerOptions { 75 | freeCompilerArgs.add("-Xwasm-enable-array-range-checks") 76 | } 77 | } else if (this is KotlinJvmCompile) { 78 | compilerOptions { 79 | freeCompilerArgs.add("-Xjvm-default=disable") 80 | } 81 | } 82 | 83 | val extraOpts = providers.gradleProperty("kotlin_additional_cli_options").orNull 84 | extraOpts?.split(' ')?.map(String::trim)?.filter(String::isNotBlank)?.let { opts -> 85 | if (opts.isNotEmpty()) { 86 | compilerOptions.freeCompilerArgs.addAll(opts) 87 | } 88 | } 89 | 90 | doFirst { 91 | logger.info("Added Kotlin compiler flags: ${compilerOptions.freeCompilerArgs.get().joinToString(", ")}") 92 | logger.info("allWarningsAsErrors=${compilerOptions.allWarningsAsErrors.get()}") 93 | } 94 | } 95 | } 96 | 97 | tasks.withType().configureEach { 98 | args.add("--ignore-engines") 99 | } 100 | -------------------------------------------------------------------------------- /core/commonMain/src/adapters/ReadOnlyCollectionAdapters.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.adapters 7 | 8 | import kotlinx.collections.immutable.* 9 | 10 | 11 | /* 12 | These classes allow to expose read-only collection as immutable, if it's actually immutable one 13 | Use with caution: wrapping mutable collection as immutable is a contract violation of the latter. 14 | */ 15 | 16 | public open class ImmutableCollectionAdapter(private val impl: Collection) : ImmutableCollection, Collection by impl { 17 | override fun equals(other: Any?): Boolean = impl.equals(other) 18 | override fun hashCode(): Int = impl.hashCode() 19 | override fun toString(): String = impl.toString() 20 | } 21 | 22 | 23 | public class ImmutableListAdapter(private val impl: List) : ImmutableList, List by impl { 24 | 25 | override fun subList(fromIndex: Int, toIndex: Int): ImmutableList = ImmutableListAdapter(impl.subList(fromIndex, toIndex)) 26 | 27 | override fun equals(other: Any?): Boolean = impl.equals(other) 28 | override fun hashCode(): Int = impl.hashCode() 29 | override fun toString(): String = impl.toString() 30 | } 31 | 32 | 33 | public class ImmutableSetAdapter(impl: Set) : ImmutableSet, ImmutableCollectionAdapter(impl) 34 | 35 | 36 | public class ImmutableMapAdapter(private val impl: Map) : ImmutableMap, Map by impl { 37 | // TODO: Lazy initialize these properties? 38 | override val keys: ImmutableSet = ImmutableSetAdapter(impl.keys) 39 | override val values: ImmutableCollection = ImmutableCollectionAdapter(impl.values) 40 | override val entries: ImmutableSet> = ImmutableSetAdapter(impl.entries) 41 | 42 | override fun equals(other: Any?): Boolean = impl.equals(other) 43 | override fun hashCode(): Int = impl.hashCode() 44 | override fun toString(): String = impl.toString() 45 | } -------------------------------------------------------------------------------- /core/commonMain/src/implementations/immutableList/AbstractListIterator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.immutableList 7 | 8 | internal abstract class AbstractListIterator(var index: Int, var size: Int) : ListIterator { 9 | override fun hasNext(): Boolean { 10 | return index < size 11 | } 12 | 13 | override fun hasPrevious(): Boolean { 14 | return index > 0 15 | } 16 | 17 | override fun nextIndex(): Int { 18 | return index 19 | } 20 | 21 | override fun previousIndex(): Int { 22 | return index - 1 23 | } 24 | 25 | internal fun checkHasNext() { 26 | if (!hasNext()) 27 | throw NoSuchElementException() 28 | } 29 | 30 | internal fun checkHasPrevious() { 31 | if (!hasPrevious()) 32 | throw NoSuchElementException() 33 | } 34 | } 35 | 36 | 37 | internal class SingleElementListIterator(private val element: E, index: Int): AbstractListIterator(index, 1) { 38 | override fun next(): E { 39 | checkHasNext() 40 | index++ 41 | return element 42 | } 43 | 44 | override fun previous(): E { 45 | checkHasPrevious() 46 | index-- 47 | return element 48 | } 49 | } -------------------------------------------------------------------------------- /core/commonMain/src/implementations/immutableList/AbstractPersistentList.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.immutableList 7 | 8 | import kotlinx.collections.immutable.ImmutableList 9 | import kotlinx.collections.immutable.PersistentList 10 | import kotlinx.collections.immutable.mutate 11 | import kotlinx.collections.immutable.internal.ListImplementation.checkPositionIndex 12 | 13 | public abstract class AbstractPersistentList : PersistentList, AbstractList() { 14 | override fun subList(fromIndex: Int, toIndex: Int): ImmutableList { 15 | return super.subList(fromIndex, toIndex) 16 | } 17 | 18 | override fun addAll(elements: Collection): PersistentList { 19 | if (elements.isEmpty()) return this 20 | return mutate { it.addAll(elements) } 21 | } 22 | 23 | override fun addAll(index: Int, c: Collection): PersistentList { 24 | checkPositionIndex(index, size) 25 | if (c.isEmpty()) return this 26 | return mutate { it.addAll(index, c) } 27 | } 28 | 29 | override fun remove(element: E): PersistentList { 30 | val index = this.indexOf(element) 31 | if (index != -1) { 32 | return this.removeAt(index) 33 | } 34 | return this 35 | } 36 | 37 | override fun removeAll(elements: Collection): PersistentList { 38 | if (elements.isEmpty()) return this 39 | return removeAll { elements.contains(it) } 40 | } 41 | 42 | override fun retainAll(elements: Collection): PersistentList { 43 | if (elements.isEmpty()) return persistentVectorOf() 44 | return removeAll { !elements.contains(it) } 45 | } 46 | 47 | override fun clear(): PersistentList { 48 | return persistentVectorOf() 49 | } 50 | 51 | override fun contains(element: E): Boolean { 52 | return this.indexOf(element) != -1 53 | } 54 | 55 | override fun containsAll(elements: Collection): Boolean { 56 | return elements.all { this.contains(it) } 57 | } 58 | 59 | override fun iterator(): Iterator { 60 | return this.listIterator() 61 | } 62 | 63 | override fun listIterator(): ListIterator { 64 | return this.listIterator(0) 65 | } 66 | } -------------------------------------------------------------------------------- /core/commonMain/src/implementations/immutableList/BufferIterator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.immutableList 7 | 8 | internal class BufferIterator( 9 | private val buffer: Array, 10 | index: Int, 11 | size: Int 12 | ) : AbstractListIterator(index, size) { 13 | override fun next(): T { 14 | if (!hasNext()) { 15 | throw NoSuchElementException() 16 | } 17 | return buffer[index++] 18 | } 19 | 20 | override fun previous(): T { 21 | if (!hasPrevious()) { 22 | throw NoSuchElementException() 23 | } 24 | return buffer[--index] 25 | } 26 | } -------------------------------------------------------------------------------- /core/commonMain/src/implementations/immutableList/PersistentVectorIterator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.immutableList 7 | 8 | internal class PersistentVectorIterator(root: Array, 9 | private val tail: Array, 10 | index: Int, 11 | size: Int, 12 | trieHeight: Int) : AbstractListIterator(index, size) { 13 | private val trieIterator: TrieIterator 14 | 15 | init { 16 | val trieSize = rootSize(size) 17 | val trieIndex = index.coerceAtMost(trieSize) 18 | trieIterator = TrieIterator(root, trieIndex, trieSize, trieHeight) 19 | } 20 | 21 | override fun next(): T { 22 | checkHasNext() 23 | if (trieIterator.hasNext()) { 24 | index++ 25 | return trieIterator.next() 26 | } 27 | return tail[index++ - trieIterator.size] 28 | } 29 | 30 | override fun previous(): T { 31 | checkHasPrevious() 32 | if (index > trieIterator.size) { 33 | return tail[--index - trieIterator.size] 34 | } 35 | index-- 36 | return trieIterator.previous() 37 | } 38 | } -------------------------------------------------------------------------------- /core/commonMain/src/implementations/immutableList/TrieIterator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.immutableList 7 | 8 | internal class TrieIterator(root: Array, 9 | index: Int, 10 | size: Int, 11 | private var height: Int) : AbstractListIterator(index, size) { 12 | private var path: Array = arrayOfNulls(height) 13 | private var isInRightEdge = index == size 14 | 15 | init { 16 | path[0] = root 17 | fillPath(index - if (isInRightEdge) 1 else 0, 1) 18 | } 19 | 20 | internal fun reset(root: Array, index: Int, size: Int, height: Int) { 21 | this.index = index 22 | this.size = size 23 | this.height = height 24 | if (path.size < height) path = arrayOfNulls(height) 25 | path[0] = root 26 | isInRightEdge = index == size 27 | 28 | fillPath(index - if (isInRightEdge) 1 else 0, 1) 29 | } 30 | 31 | private fun fillPath(index: Int, startLevel: Int) { 32 | var shift = (height - startLevel) * LOG_MAX_BUFFER_SIZE 33 | var i = startLevel 34 | while (i < height) { 35 | @Suppress("UNCHECKED_CAST") 36 | path[i] = (path[i - 1] as Array)[indexSegment(index, shift)] 37 | shift -= LOG_MAX_BUFFER_SIZE 38 | i += 1 39 | } 40 | } 41 | 42 | // TODO: Document that it positions path to the first or the last element 43 | private fun fillPathIfNeeded(indexPredicate: Int) { 44 | var shift = 0 45 | while (indexSegment(index, shift) == indexPredicate) { 46 | shift += LOG_MAX_BUFFER_SIZE 47 | } 48 | 49 | if (shift > 0) { 50 | val level = height - 1 - shift / LOG_MAX_BUFFER_SIZE 51 | fillPath(index, level + 1) 52 | } 53 | } 54 | 55 | private fun elementAtCurrentIndex(): E { 56 | val leafBufferIndex = index and MAX_BUFFER_SIZE_MINUS_ONE 57 | @Suppress("UNCHECKED_CAST") 58 | return (path[height - 1] as Array)[leafBufferIndex] 59 | } 60 | 61 | override fun next(): E { 62 | if (!hasNext()) { 63 | throw NoSuchElementException() 64 | } 65 | 66 | val result = elementAtCurrentIndex() 67 | index += 1 68 | 69 | if (index == size) { 70 | isInRightEdge = true 71 | return result 72 | } 73 | 74 | fillPathIfNeeded(0) 75 | 76 | return result 77 | } 78 | 79 | override fun previous(): E { 80 | if (!hasPrevious()) { 81 | throw NoSuchElementException() 82 | } 83 | 84 | index -= 1 85 | 86 | if (isInRightEdge) { 87 | isInRightEdge = false 88 | return elementAtCurrentIndex() 89 | } 90 | 91 | fillPathIfNeeded(MAX_BUFFER_SIZE_MINUS_ONE) 92 | 93 | return elementAtCurrentIndex() 94 | } 95 | } -------------------------------------------------------------------------------- /core/commonMain/src/implementations/immutableList/Utils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.immutableList 7 | 8 | import kotlinx.collections.immutable.PersistentList 9 | 10 | internal const val MAX_BUFFER_SIZE = 32 11 | internal const val LOG_MAX_BUFFER_SIZE = 5 12 | internal const val MAX_BUFFER_SIZE_MINUS_ONE = MAX_BUFFER_SIZE - 1 13 | internal const val MUTABLE_BUFFER_SIZE = MAX_BUFFER_SIZE + 1 14 | 15 | internal class ObjectRef(var value: Any?) 16 | 17 | internal fun persistentVectorOf(): PersistentList { 18 | return SmallPersistentVector.EMPTY 19 | } 20 | 21 | 22 | /** Creates new buffer of [MAX_BUFFER_SIZE] capacity having first element initialized with the specified [element]. */ 23 | internal fun presizedBufferWith(element: Any?): Array { 24 | val buffer = arrayOfNulls(MAX_BUFFER_SIZE) 25 | buffer[0] = element 26 | return buffer 27 | } 28 | 29 | /** 30 | * Gets trie index segment of the specified [index] at the level specified by [shift]. 31 | * 32 | * `shift` equal to zero corresponds to the bottommost (leaf) level. 33 | * For each upper level `shift` increments by [LOG_MAX_BUFFER_SIZE]. 34 | */ 35 | internal fun indexSegment(index: Int, shift: Int): Int = 36 | (index shr shift) and MAX_BUFFER_SIZE_MINUS_ONE 37 | 38 | /** 39 | * Returns the size of trie part of a persistent vector of the specified [vectorSize]. 40 | */ 41 | internal fun rootSize(vectorSize: Int) = 42 | (vectorSize - 1) and MAX_BUFFER_SIZE_MINUS_ONE.inv() 43 | -------------------------------------------------------------------------------- /core/commonMain/src/implementations/immutableMap/PersistentHashMapBuilderContentViews.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.immutableMap 7 | 8 | import kotlinx.collections.immutable.internal.MapImplementation 9 | 10 | // intermediate abstract class to workaround KT-43321 11 | internal abstract class AbstractMapBuilderEntries, K, V> : AbstractMutableSet() { 12 | final override fun contains(element: E): Boolean { 13 | // TODO: Eliminate this check after KT-30016 gets fixed. 14 | @Suppress("USELESS_CAST") 15 | if ((element as? Any?) !is Map.Entry<*, *>) return false 16 | return containsEntry(element) 17 | } 18 | abstract fun containsEntry(element: Map.Entry): Boolean 19 | 20 | final override fun remove(element: E): Boolean { 21 | // TODO: Eliminate this check after KT-30016 gets fixed. 22 | @Suppress("USELESS_CAST") 23 | if ((element as? Any?) !is Map.Entry<*, *>) return false 24 | return removeEntry(element) 25 | } 26 | abstract fun removeEntry(element: Map.Entry): Boolean 27 | } 28 | 29 | internal class PersistentHashMapBuilderEntries(private val builder: PersistentHashMapBuilder) 30 | : AbstractMapBuilderEntries, K, V>() { 31 | override fun add(element: MutableMap.MutableEntry): Boolean { 32 | throw UnsupportedOperationException() 33 | } 34 | 35 | override fun clear() { 36 | builder.clear() 37 | } 38 | 39 | override fun iterator(): MutableIterator> { 40 | return PersistentHashMapBuilderEntriesIterator(builder) 41 | } 42 | 43 | override fun removeEntry(element: Map.Entry): Boolean { 44 | return builder.remove(element.key, element.value) 45 | } 46 | 47 | override val size: Int 48 | get() = builder.size 49 | 50 | override fun containsEntry(element: Map.Entry): Boolean { 51 | return MapImplementation.containsEntry(builder, element) 52 | } 53 | } 54 | 55 | internal class PersistentHashMapBuilderKeys(private val builder: PersistentHashMapBuilder) : MutableSet, AbstractMutableSet() { 56 | override fun add(element: K): Boolean { 57 | throw UnsupportedOperationException() 58 | } 59 | 60 | override fun clear() { 61 | builder.clear() 62 | } 63 | 64 | override fun iterator(): MutableIterator { 65 | return PersistentHashMapBuilderKeysIterator(builder) 66 | } 67 | 68 | override fun remove(element: K): Boolean { 69 | if (builder.containsKey(element)) { 70 | builder.remove(element) 71 | return true 72 | } 73 | return false 74 | } 75 | 76 | override val size: Int 77 | get() = builder.size 78 | 79 | override fun contains(element: K): Boolean { 80 | return builder.containsKey(element) 81 | } 82 | } 83 | 84 | internal class PersistentHashMapBuilderValues(private val builder: PersistentHashMapBuilder) : MutableCollection, AbstractMutableCollection() { 85 | override val size: Int 86 | get() = builder.size 87 | 88 | override fun contains(element: V): Boolean { 89 | return builder.containsValue(element) 90 | } 91 | 92 | override fun add(element: V): Boolean { 93 | throw UnsupportedOperationException() 94 | } 95 | 96 | override fun clear() { 97 | builder.clear() 98 | } 99 | 100 | override fun iterator(): MutableIterator { 101 | return PersistentHashMapBuilderValuesIterator(builder) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /core/commonMain/src/implementations/immutableMap/PersistentHashMapContentViews.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.immutableMap 7 | 8 | import kotlinx.collections.immutable.ImmutableCollection 9 | import kotlinx.collections.immutable.ImmutableSet 10 | import kotlinx.collections.immutable.internal.MapImplementation 11 | 12 | internal class PersistentHashMapEntries(private val map: PersistentHashMap) : ImmutableSet>, AbstractSet>() { 13 | override val size: Int get() = map.size 14 | 15 | override fun contains(element: Map.Entry): Boolean { 16 | return MapImplementation.containsEntry(map, element) 17 | } 18 | 19 | override fun iterator(): Iterator> { 20 | return PersistentHashMapEntriesIterator(map.node) 21 | } 22 | } 23 | 24 | internal class PersistentHashMapKeys(private val map: PersistentHashMap) : ImmutableSet, AbstractSet() { 25 | override val size: Int 26 | get() = map.size 27 | 28 | override fun contains(element: K): Boolean { 29 | return map.containsKey(element) 30 | } 31 | 32 | override fun iterator(): Iterator { 33 | return PersistentHashMapKeysIterator(map.node) 34 | } 35 | } 36 | 37 | internal class PersistentHashMapValues(private val map: PersistentHashMap) : ImmutableCollection, AbstractCollection() { 38 | override val size: Int 39 | get() = map.size 40 | 41 | override fun contains(element: V): Boolean { 42 | return map.containsValue(element) 43 | } 44 | 45 | override fun iterator(): Iterator { 46 | return PersistentHashMapValuesIterator(map.node) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/commonMain/src/implementations/immutableSet/PersistentHashSet.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.immutableSet 7 | 8 | import kotlinx.collections.immutable.PersistentSet 9 | import kotlinx.collections.immutable.mutate 10 | 11 | internal class PersistentHashSet(internal val node: TrieNode, 12 | override val size: Int): AbstractSet(), PersistentSet { 13 | override fun contains(element: E): Boolean { 14 | return node.contains(element.hashCode(), element, 0) 15 | } 16 | 17 | override fun add(element: E): PersistentSet { 18 | val newNode = node.add(element.hashCode(), element, 0) 19 | if (node === newNode) { return this } 20 | return PersistentHashSet(newNode, size + 1) 21 | } 22 | 23 | override fun addAll(elements: Collection): PersistentSet { 24 | if (elements.isEmpty()) return this 25 | return this.mutate { it.addAll(elements) } 26 | } 27 | 28 | override fun remove(element: E): PersistentSet { 29 | val newNode = node.remove(element.hashCode(), element, 0) 30 | if (node === newNode) { return this } 31 | return PersistentHashSet(newNode, size - 1) 32 | } 33 | 34 | override fun removeAll(elements: Collection): PersistentSet { 35 | if (elements.isEmpty()) return this 36 | return mutate { it.removeAll(elements) } 37 | } 38 | 39 | override fun removeAll(predicate: (E) -> Boolean): PersistentSet { 40 | return mutate { it.removeAll(predicate) } 41 | } 42 | 43 | override fun retainAll(elements: Collection): PersistentSet { 44 | if (elements.isEmpty()) return PersistentHashSet.emptyOf() 45 | return mutate { it.retainAll(elements) } 46 | } 47 | 48 | override fun containsAll(elements: Collection): Boolean { 49 | if (elements is PersistentHashSet) { 50 | return node.containsAll(elements.node, 0) 51 | } 52 | if (elements is PersistentHashSetBuilder) { 53 | return node.containsAll(elements.node, 0) 54 | } 55 | return super.containsAll(elements) 56 | } 57 | 58 | override fun clear(): PersistentSet { 59 | return PersistentHashSet.emptyOf() 60 | } 61 | 62 | override fun iterator(): Iterator { 63 | return PersistentHashSetIterator(node) 64 | } 65 | 66 | override fun builder(): PersistentSet.Builder { 67 | return PersistentHashSetBuilder(this) 68 | } 69 | 70 | internal companion object { 71 | private val EMPTY = PersistentHashSet(TrieNode.EMPTY, 0) 72 | internal fun emptyOf(): PersistentSet = PersistentHashSet.EMPTY 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /core/commonMain/src/implementations/immutableSet/PersistentHashSetIterator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.immutableSet 7 | 8 | import kotlinx.collections.immutable.internal.assert 9 | import kotlin.js.JsName 10 | 11 | internal open class PersistentHashSetIterator(node: TrieNode) : Iterator { 12 | protected val path = mutableListOf(TrieNodeIterator()) 13 | protected var pathLastIndex = 0 14 | @JsName("_hasNext") 15 | private var hasNext = true 16 | 17 | init { 18 | path[0].reset(node.buffer) 19 | pathLastIndex = 0 20 | ensureNextElementIsReady() 21 | } 22 | 23 | private fun moveToNextNodeWithData(pathIndex: Int): Int { 24 | if (path[pathIndex].hasNextElement()) { 25 | return pathIndex 26 | } 27 | if (path[pathIndex].hasNextNode()) { 28 | val node = path[pathIndex].currentNode() 29 | 30 | if (pathIndex + 1 == path.size) { 31 | path.add(TrieNodeIterator()) 32 | } 33 | path[pathIndex + 1].reset(node.buffer) 34 | return moveToNextNodeWithData(pathIndex + 1) 35 | } 36 | return -1 37 | } 38 | 39 | private fun ensureNextElementIsReady() { 40 | if (path[pathLastIndex].hasNextElement()) { 41 | return 42 | } 43 | for(i in pathLastIndex downTo 0) { 44 | var result = moveToNextNodeWithData(i) 45 | 46 | if (result == -1 && path[i].hasNextCell()) { 47 | path[i].moveToNextCell() 48 | result = moveToNextNodeWithData(i) 49 | } 50 | if (result != -1) { 51 | pathLastIndex = result 52 | return 53 | } 54 | if (i > 0) { 55 | path[i - 1].moveToNextCell() 56 | } 57 | path[i].reset(TrieNode.EMPTY.buffer, 0) 58 | } 59 | hasNext = false 60 | } 61 | 62 | override fun hasNext(): Boolean { 63 | return hasNext 64 | } 65 | 66 | override fun next(): E { 67 | if (!hasNext) 68 | throw NoSuchElementException() 69 | 70 | val result = path[pathLastIndex].nextElement() 71 | ensureNextElementIsReady() 72 | return result 73 | } 74 | 75 | protected fun currentElement(): E { 76 | assert(hasNext()) 77 | return path[pathLastIndex].currentElement() 78 | } 79 | } 80 | 81 | internal class TrieNodeIterator { 82 | private var buffer = TrieNode.EMPTY.buffer 83 | private var index = 0 84 | 85 | fun reset(buffer: Array, index: Int = 0) { 86 | this.buffer = buffer 87 | this.index = index 88 | } 89 | 90 | fun hasNextCell(): Boolean { 91 | return index < buffer.size 92 | } 93 | 94 | fun moveToNextCell() { 95 | assert(hasNextCell()) 96 | index++ 97 | } 98 | 99 | fun hasNextElement(): Boolean { 100 | return hasNextCell() && buffer[index] !is TrieNode<*> 101 | } 102 | 103 | fun currentElement(): E { 104 | assert(hasNextElement()) 105 | @Suppress("UNCHECKED_CAST") 106 | return buffer[index] as E 107 | } 108 | 109 | fun nextElement(): E { 110 | assert(hasNextElement()) 111 | @Suppress("UNCHECKED_CAST") 112 | return buffer[index++] as E 113 | } 114 | 115 | fun hasNextNode(): Boolean { 116 | return hasNextCell() && buffer[index] is TrieNode<*> 117 | } 118 | 119 | fun currentNode(): TrieNode { 120 | assert(hasNextNode()) 121 | @Suppress("UNCHECKED_CAST") 122 | return buffer[index] as TrieNode 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /core/commonMain/src/implementations/immutableSet/PersistentHashSetMutableIterator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.immutableSet 7 | 8 | import kotlinx.collections.immutable.internal.assert 9 | 10 | internal class PersistentHashSetMutableIterator(private val builder: PersistentHashSetBuilder) 11 | : PersistentHashSetIterator(builder.node), MutableIterator { 12 | private var lastIteratedElement: E? = null 13 | private var nextWasInvoked = false 14 | private var expectedModCount = builder.modCount 15 | 16 | override fun next(): E { 17 | checkForComodification() 18 | val next = super.next() 19 | lastIteratedElement = next 20 | nextWasInvoked = true 21 | return next 22 | } 23 | 24 | override fun remove() { 25 | checkNextWasInvoked() 26 | if (hasNext()) { 27 | val currentElement = currentElement() 28 | 29 | builder.remove(lastIteratedElement) 30 | resetPath(currentElement.hashCode(), builder.node, currentElement, 0) 31 | } else { 32 | builder.remove(lastIteratedElement) 33 | } 34 | 35 | lastIteratedElement = null 36 | nextWasInvoked = false 37 | expectedModCount = builder.modCount 38 | } 39 | 40 | private fun resetPath(hashCode: Int, node: TrieNode<*>, element: E, pathIndex: Int) { 41 | if (isCollision(node)) { 42 | val index = node.buffer.indexOf(element) 43 | assert(index != -1) 44 | path[pathIndex].reset(node.buffer, index) 45 | pathLastIndex = pathIndex 46 | return 47 | } 48 | 49 | val position = 1 shl indexSegment(hashCode, pathIndex * LOG_MAX_BRANCHING_FACTOR) 50 | val index = node.indexOfCellAt(position) 51 | 52 | path[pathIndex].reset(node.buffer, index) 53 | 54 | val cell = node.buffer[index] 55 | if (cell is TrieNode<*>) { 56 | resetPath(hashCode, cell, element, pathIndex + 1) 57 | } else { 58 | // assert(cell == element) 59 | pathLastIndex = pathIndex 60 | } 61 | } 62 | 63 | private fun isCollision(node: TrieNode<*>): Boolean { 64 | return node.bitmap == 0 65 | } 66 | 67 | private fun checkNextWasInvoked() { 68 | if (!nextWasInvoked) 69 | throw IllegalStateException() 70 | } 71 | 72 | private fun checkForComodification() { 73 | if (builder.modCount != expectedModCount) 74 | throw ConcurrentModificationException() 75 | } 76 | } -------------------------------------------------------------------------------- /core/commonMain/src/implementations/persistentOrderedMap/PersistentOrderedMapBuilderContentViews.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.persistentOrderedMap 7 | 8 | import kotlinx.collections.immutable.implementations.immutableMap.AbstractMapBuilderEntries 9 | import kotlinx.collections.immutable.internal.MapImplementation 10 | 11 | internal class PersistentOrderedMapBuilderEntries(private val builder: PersistentOrderedMapBuilder) 12 | : AbstractMapBuilderEntries, K, V>() { 13 | override fun add(element: MutableMap.MutableEntry): Boolean { 14 | throw UnsupportedOperationException() 15 | } 16 | 17 | override fun clear() { 18 | builder.clear() 19 | } 20 | 21 | override fun iterator(): MutableIterator> { 22 | return PersistentOrderedMapBuilderEntriesIterator(builder) 23 | } 24 | 25 | override fun removeEntry(element: Map.Entry): Boolean { 26 | return builder.remove(element.key, element.value) 27 | } 28 | 29 | override val size: Int 30 | get() = builder.size 31 | 32 | override fun containsEntry(element: Map.Entry): Boolean { 33 | return MapImplementation.containsEntry(builder, element) 34 | } 35 | } 36 | 37 | internal class PersistentOrderedMapBuilderKeys(private val builder: PersistentOrderedMapBuilder) : MutableSet, AbstractMutableSet() { 38 | override fun add(element: K): Boolean { 39 | throw UnsupportedOperationException() 40 | } 41 | 42 | override fun clear() { 43 | builder.clear() 44 | } 45 | 46 | override fun iterator(): MutableIterator { 47 | return PersistentOrderedMapBuilderKeysIterator(builder) 48 | } 49 | 50 | override fun remove(element: K): Boolean { 51 | if (builder.containsKey(element)) { 52 | builder.remove(element) 53 | return true 54 | } 55 | return false 56 | } 57 | 58 | override val size: Int 59 | get() = builder.size 60 | 61 | override fun contains(element: K): Boolean { 62 | return builder.containsKey(element) 63 | } 64 | } 65 | 66 | internal class PersistentOrderedMapBuilderValues(private val builder: PersistentOrderedMapBuilder) : MutableCollection, AbstractMutableCollection() { 67 | override val size: Int 68 | get() = builder.size 69 | 70 | override fun contains(element: V): Boolean { 71 | return builder.containsValue(element) 72 | } 73 | 74 | override fun add(element: V): Boolean { 75 | throw UnsupportedOperationException() 76 | } 77 | 78 | override fun clear() { 79 | builder.clear() 80 | } 81 | 82 | override fun iterator(): MutableIterator { 83 | return PersistentOrderedMapBuilderValuesIterator(builder) 84 | } 85 | } -------------------------------------------------------------------------------- /core/commonMain/src/implementations/persistentOrderedMap/PersistentOrderedMapContentIterators.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.persistentOrderedMap 7 | 8 | import kotlinx.collections.immutable.implementations.immutableMap.MapEntry 9 | 10 | internal open class PersistentOrderedMapLinksIterator( 11 | internal var nextKey: Any?, 12 | private val hashMap: Map> 13 | ) : Iterator> { 14 | internal var index = 0 15 | 16 | override fun hasNext(): Boolean { 17 | return index < hashMap.size 18 | } 19 | 20 | override fun next(): LinkedValue { 21 | if (!hasNext()) { 22 | throw NoSuchElementException() 23 | } 24 | @Suppress("UNCHECKED_CAST") 25 | val result = hashMap.getOrElse(nextKey as K) { 26 | throw ConcurrentModificationException("Hash code of a key ($nextKey) has changed after it was added to the persistent map.") 27 | } 28 | index++ 29 | nextKey = result.next 30 | return result 31 | } 32 | 33 | } 34 | 35 | internal class PersistentOrderedMapEntriesIterator(map: PersistentOrderedMap) : Iterator> { 36 | private val internal = PersistentOrderedMapLinksIterator(map.firstKey, map.hashMap) 37 | 38 | override fun hasNext(): Boolean { 39 | return internal.hasNext() 40 | } 41 | 42 | override fun next(): Map.Entry { 43 | @Suppress("UNCHECKED_CAST") 44 | val nextKey = internal.nextKey as K 45 | val nextValue = internal.next().value 46 | return MapEntry(nextKey, nextValue) 47 | } 48 | } 49 | 50 | internal class PersistentOrderedMapKeysIterator(map: PersistentOrderedMap) : Iterator { 51 | private val internal = PersistentOrderedMapLinksIterator(map.firstKey, map.hashMap) 52 | 53 | override fun hasNext(): Boolean { 54 | return internal.hasNext() 55 | } 56 | 57 | override fun next(): K { 58 | @Suppress("UNCHECKED_CAST") 59 | val nextKey = internal.nextKey as K 60 | internal.next() 61 | return nextKey 62 | } 63 | } 64 | 65 | internal class PersistentOrderedMapValuesIterator(map: PersistentOrderedMap) : Iterator { 66 | private val internal = PersistentOrderedMapLinksIterator(map.firstKey, map.hashMap) 67 | 68 | override fun hasNext(): Boolean { 69 | return internal.hasNext() 70 | } 71 | 72 | override fun next(): V { 73 | return internal.next().value 74 | } 75 | } -------------------------------------------------------------------------------- /core/commonMain/src/implementations/persistentOrderedMap/PersistentOrderedMapContentViews.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.persistentOrderedMap 7 | 8 | import kotlinx.collections.immutable.ImmutableCollection 9 | import kotlinx.collections.immutable.ImmutableSet 10 | import kotlinx.collections.immutable.internal.MapImplementation 11 | 12 | internal class PersistentOrderedMapEntries(private val map: PersistentOrderedMap) : ImmutableSet>, AbstractSet>() { 13 | override val size: Int get() = map.size 14 | 15 | override fun contains(element: Map.Entry): Boolean { 16 | return MapImplementation.containsEntry(map, element) 17 | } 18 | 19 | override fun iterator(): Iterator> { 20 | return PersistentOrderedMapEntriesIterator(map) 21 | } 22 | } 23 | 24 | internal class PersistentOrderedMapKeys(private val map: PersistentOrderedMap) : ImmutableSet, AbstractSet() { 25 | override val size: Int 26 | get() = map.size 27 | 28 | override fun contains(element: K): Boolean { 29 | return map.containsKey(element) 30 | } 31 | 32 | override fun iterator(): Iterator { 33 | return PersistentOrderedMapKeysIterator(map) 34 | } 35 | } 36 | 37 | internal class PersistentOrderedMapValues(private val map: PersistentOrderedMap) : ImmutableCollection, AbstractCollection() { 38 | override val size: Int 39 | get() = map.size 40 | 41 | override fun contains(element: V): Boolean { 42 | return map.containsValue(element) 43 | } 44 | 45 | override fun iterator(): Iterator { 46 | return PersistentOrderedMapValuesIterator(map) 47 | } 48 | } -------------------------------------------------------------------------------- /core/commonMain/src/implementations/persistentOrderedSet/PersistentOrderedSetIterator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.persistentOrderedSet 7 | 8 | internal open class PersistentOrderedSetIterator(private var nextElement: Any?, 9 | internal val map: Map) : Iterator { 10 | internal var index = 0 11 | 12 | override fun hasNext(): Boolean { 13 | return index < map.size 14 | } 15 | 16 | override fun next(): E { 17 | checkHasNext() 18 | 19 | @Suppress("UNCHECKED_CAST") 20 | val result = nextElement as E 21 | index++ 22 | nextElement = map.getOrElse(result) { 23 | throw ConcurrentModificationException("Hash code of an element ($result) has changed after it was added to the persistent set.") 24 | }.next 25 | return result 26 | } 27 | 28 | private fun checkHasNext() { 29 | if (!hasNext()) 30 | throw NoSuchElementException() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /core/commonMain/src/implementations/persistentOrderedSet/PersistentOrderedSetMutableIterator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.implementations.persistentOrderedSet 7 | 8 | internal class PersistentOrderedSetMutableIterator(private val builder: PersistentOrderedSetBuilder) 9 | : PersistentOrderedSetIterator(builder.firstElement, builder.hashMapBuilder), MutableIterator { 10 | 11 | private var lastIteratedElement: E? = null 12 | private var nextWasInvoked = false 13 | private var expectedModCount = builder.hashMapBuilder.modCount 14 | 15 | override fun next(): E { 16 | checkForComodification() 17 | val next = super.next() 18 | lastIteratedElement = next 19 | nextWasInvoked = true 20 | return next 21 | } 22 | 23 | override fun remove() { 24 | checkNextWasInvoked() 25 | builder.remove(lastIteratedElement) 26 | lastIteratedElement = null 27 | nextWasInvoked = false 28 | expectedModCount = builder.hashMapBuilder.modCount 29 | index-- 30 | } 31 | 32 | private fun checkNextWasInvoked() { 33 | if (!nextWasInvoked) 34 | throw IllegalStateException() 35 | } 36 | 37 | private fun checkForComodification() { 38 | if (builder.hashMapBuilder.modCount != expectedModCount) 39 | throw ConcurrentModificationException() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /core/commonMain/src/internal/EndOfChain.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.internal 7 | 8 | internal object EndOfChain -------------------------------------------------------------------------------- /core/commonMain/src/internal/ForEachOneBit.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.internal 7 | 8 | // 'iterate' all the bits set to one in a given integer, in the form of one-bit masks 9 | internal inline fun Int.forEachOneBit(body: (mask: Int, index: Int) -> Unit) { 10 | var mask = this 11 | var index = 0 12 | while (mask != 0) { 13 | val bit = mask.takeLowestOneBit() 14 | body(bit, index) 15 | index++ 16 | mask = mask xor bit 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/commonMain/src/internal/ListImplementation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.internal 7 | 8 | import kotlin.jvm.JvmStatic 9 | 10 | internal object ListImplementation { 11 | 12 | @JvmStatic 13 | internal fun checkElementIndex(index: Int, size: Int) { 14 | if (index < 0 || index >= size) { 15 | throw IndexOutOfBoundsException("index: $index, size: $size") 16 | } 17 | } 18 | 19 | @JvmStatic 20 | internal fun checkPositionIndex(index: Int, size: Int) { 21 | if (index < 0 || index > size) { 22 | throw IndexOutOfBoundsException("index: $index, size: $size") 23 | } 24 | } 25 | 26 | @JvmStatic 27 | internal fun checkRangeIndexes(fromIndex: Int, toIndex: Int, size: Int) { 28 | if (fromIndex < 0 || toIndex > size) { 29 | throw IndexOutOfBoundsException("fromIndex: $fromIndex, toIndex: $toIndex, size: $size") 30 | } 31 | if (fromIndex > toIndex) { 32 | throw IllegalArgumentException("fromIndex: $fromIndex > toIndex: $toIndex") 33 | } 34 | } 35 | 36 | @JvmStatic 37 | internal fun orderedHashCode(c: Collection<*>): Int { 38 | var hashCode = 1 39 | for (e in c) { 40 | hashCode = 31 * hashCode + (e?.hashCode() ?: 0) 41 | } 42 | return hashCode 43 | } 44 | 45 | @JvmStatic 46 | internal fun orderedEquals(c: Collection<*>, other: Collection<*>): Boolean { 47 | if (c.size != other.size) return false 48 | 49 | val otherIterator = other.iterator() 50 | for (elem in c) { 51 | val elemOther = otherIterator.next() 52 | if (elem != elemOther) { 53 | return false 54 | } 55 | } 56 | return true 57 | } 58 | } -------------------------------------------------------------------------------- /core/commonMain/src/internal/MapImplementation.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2021 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.internal 7 | 8 | /** 9 | * This should not be needed after KT-30016 and KT-45673 are fixed 10 | */ 11 | internal object MapImplementation { 12 | internal fun containsEntry(map: Map, element: Map.Entry): Boolean { 13 | @Suppress("USELESS_CAST") 14 | if ((element as Any?) !is Map.Entry<*, *>) return false 15 | return map[element.key]?.let { candidate -> candidate == element.value } 16 | ?: (element.value == null && map.containsKey(element.key)) 17 | } 18 | 19 | internal fun equals(thisMap: Map, otherMap: Map<*, *>): Boolean { 20 | require(thisMap.size == otherMap.size) 21 | @Suppress("UNCHECKED_CAST") 22 | return (otherMap as Map).all { entry -> containsEntry(thisMap, entry) } 23 | } 24 | 25 | internal fun hashCode(map: Map): Int = map.entries.hashCode() 26 | } 27 | -------------------------------------------------------------------------------- /core/commonMain/src/internal/MutabilityOwnership.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.internal 7 | 8 | /** 9 | * The mutability ownership token of a persistent collection builder. 10 | * 11 | * Used to mark persistent data structures, that are owned by a collection builder and can be mutated by it. 12 | */ 13 | internal class MutabilityOwnership -------------------------------------------------------------------------------- /core/commonMain/src/internal/MutableCounter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2020 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.internal 7 | 8 | internal data class DeltaCounter(var count: Int = 0) { 9 | operator fun plusAssign(that: Int) { count += that } 10 | } -------------------------------------------------------------------------------- /core/commonMain/src/internal/commonFunctions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.internal 7 | 8 | internal expect fun assert(condition: Boolean) 9 | -------------------------------------------------------------------------------- /core/commonTest/src/ObjectWrapper.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests 7 | 8 | import kotlinx.collections.immutable.internal.assert 9 | import kotlin.js.JsName 10 | 11 | class ObjectWrapper>( 12 | val obj: K, 13 | @JsName("_hashCode") val hashCode: Int 14 | ) : Comparable> { 15 | override fun hashCode(): Int { 16 | return hashCode 17 | } 18 | 19 | override fun equals(other: Any?): Boolean { 20 | if (other !is ObjectWrapper<*>) { 21 | return false 22 | } 23 | assert(obj != other.obj || hashCode == other.hashCode) // if elements are equal hashCodes must be equal 24 | return obj == other.obj 25 | } 26 | 27 | override fun compareTo(other: ObjectWrapper): Int { 28 | return obj.compareTo(other.obj) 29 | } 30 | 31 | override fun toString(): String { 32 | return "ObjectWrapper($obj, hashCode = $hashCode)" 33 | } 34 | } 35 | 36 | typealias IntWrapper = ObjectWrapper -------------------------------------------------------------------------------- /core/commonTest/src/contract/CollectionBehaviors.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.contract 7 | 8 | fun CompareContext>.listBehavior() { 9 | equalityBehavior() 10 | collectionBehavior() 11 | compareProperty( { listIterator() }, { listIteratorBehavior() }) 12 | compareProperty( { listIterator(0) }, { listIteratorBehavior() }) 13 | compareProperty( { listIterator(size / 2) }, { listIteratorBehavior() }) 14 | 15 | propertyFails { listIterator(-1) } 16 | propertyFails { listIterator(size + 1) } 17 | 18 | for (index in expected.indices) 19 | propertyEquals { this[index] } 20 | 21 | propertyFailsWith { this[size] } 22 | 23 | propertyEquals { indexOf(elementAtOrNull(0)) } 24 | propertyEquals { lastIndexOf(elementAtOrNull(0)) } 25 | 26 | propertyFails { subList(0, size + 1)} 27 | propertyFails { subList(-1, 0)} 28 | propertyEquals { subList(0, size) } 29 | } 30 | 31 | fun CompareContext>.listIteratorBehavior() { 32 | listIteratorProperties() 33 | 34 | while (expected.hasNext()) { 35 | propertyEquals { next() } 36 | listIteratorProperties() 37 | } 38 | propertyFails { next() } 39 | 40 | while (expected.hasPrevious()) { 41 | propertyEquals { previous() } 42 | listIteratorProperties() 43 | } 44 | propertyFails { previous() } 45 | } 46 | 47 | fun CompareContext>.listIteratorProperties() { 48 | propertyEquals { hasNext() } 49 | propertyEquals { hasPrevious() } 50 | propertyEquals { nextIndex() } 51 | propertyEquals { previousIndex() } 52 | } 53 | 54 | fun CompareContext>.iteratorBehavior() { 55 | propertyEquals { hasNext() } 56 | 57 | while (expected.hasNext()) { 58 | propertyEquals { next() } 59 | propertyEquals { hasNext() } 60 | } 61 | propertyFails { next() } 62 | } 63 | 64 | fun CompareContext>.setBehavior(objectName: String = "", ordered: Boolean) { 65 | equalityBehavior(objectName, ordered) 66 | collectionBehavior(objectName, ordered) 67 | 68 | propertyEquals { containsAll(actual) } 69 | propertyEquals { containsAll(expected) } 70 | } 71 | 72 | 73 | 74 | 75 | fun CompareContext>.mapBehavior(ordered: Boolean) { 76 | propertyEquals { size } 77 | propertyEquals { isEmpty() } 78 | equalityBehavior(ordered = ordered) 79 | 80 | (object {}).let { propertyEquals { containsKey(it as Any?) } } 81 | 82 | if (expected.isEmpty().not()) 83 | propertyEquals { contains(keys.first()) } 84 | 85 | propertyEquals { containsKey(keys.firstOrNull()) } 86 | propertyEquals { containsValue(values.firstOrNull()) } 87 | propertyEquals { get(null as Any?) } 88 | 89 | compareProperty( { keys }, { setBehavior("keySet", ordered) } ) 90 | compareProperty( { entries }, { setBehavior("entrySet", ordered) } ) 91 | compareProperty( { values }, { collectionBehavior("values", ordered) }) 92 | } 93 | 94 | 95 | fun CompareContext.equalityBehavior(objectName: String = "", ordered: Boolean = true) { 96 | val prefix = objectName + if (objectName.isNotEmpty()) "." else "" 97 | equals(objectName) 98 | propertyEquals(prefix + "hashCode") { hashCode() } 99 | if (ordered) 100 | propertyEquals(prefix + "toString") { toString() } 101 | } 102 | 103 | 104 | fun CompareContext>.collectionBehavior(objectName: String = "", ordered: Boolean = true) { 105 | val prefix = objectName + if (objectName.isNotEmpty()) "." else "" 106 | propertyEquals (prefix + "size") { size } 107 | propertyEquals (prefix + "isEmpty") { isEmpty() } 108 | 109 | (object {}).let { propertyEquals { contains(it as Any?) } } 110 | propertyEquals { contains(firstOrNull()) } 111 | propertyEquals { containsAll(this) } 112 | if (ordered) { 113 | compareProperty({iterator()}, { iteratorBehavior() }) 114 | } 115 | } 116 | 117 | 118 | -------------------------------------------------------------------------------- /core/commonTest/src/contract/ComparisonDSL.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.contract 7 | 8 | import tests.assertTypeEquals 9 | import kotlin.test.* 10 | 11 | fun compare(expected: T, actual: T, block: CompareContext.() -> Unit) { 12 | CompareContext(expected, actual).block() 13 | } 14 | 15 | class CompareContext(val expected: T, val actual: T) { 16 | 17 | fun equals(message: String = "") { 18 | assertEquals(expected, actual, message) 19 | } 20 | fun

propertyEquals(message: String = "", getter: T.() -> P) { 21 | assertEquals(expected.getter(), actual.getter(), message) 22 | } 23 | fun propertyFails(getter: T.() -> Unit) { assertFailEquals({expected.getter()}, {actual.getter()}) } 24 | inline fun propertyFailsWith(noinline getter: T.() -> Unit) = propertyFailsWith({ it is E }, getter) 25 | fun propertyFailsWith(exceptionPredicate: (Throwable) -> Boolean, getter: T.() -> Unit) { assertFailEquals({expected.getter()}, {actual.getter()}, exceptionPredicate) } 26 | fun

compareProperty(getter: T.() -> P, block: CompareContext

.() -> Unit) { 27 | compare(expected.getter(), actual.getter(), block) 28 | } 29 | 30 | private fun assertFailEquals(expected: () -> Unit, actual: () -> Unit, exceptionPredicate: ((Throwable) -> Boolean)? = null) { 31 | val expectedFail = assertFails(expected) 32 | val actualFail = assertFails(actual) 33 | 34 | if (exceptionPredicate != null) { 35 | assertTrue(exceptionPredicate(expectedFail), "expected fail") 36 | assertTrue(exceptionPredicate(actualFail), "actual fail") 37 | } else { 38 | //assertEquals(expectedFail != null, actualFail != null) 39 | assertTypeEquals(expectedFail, actualFail) 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /core/commonTest/src/contract/map/PersistentHashMapTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2025 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.contract.map 7 | 8 | import kotlinx.collections.immutable.implementations.immutableMap.PersistentHashMap 9 | import kotlinx.collections.immutable.persistentHashMapOf 10 | import tests.IntWrapper 11 | import kotlin.test.Test 12 | import kotlin.test.assertEquals 13 | import kotlin.test.assertTrue 14 | 15 | class PersistentHashMapTest { 16 | 17 | @Test 18 | fun `if the collision is of size 2 and one of the keys is removed the remaining key must be promoted`() { 19 | val map1: PersistentHashMap = 20 | persistentHashMapOf(-1 to "a", 0 to "b", 32 to "c") as PersistentHashMap 21 | val builder = map1.builder() 22 | val map2 = builder.build() 23 | 24 | assertTrue(map1.equals(builder)) 25 | assertEquals(map1, map2.toMap()) 26 | assertEquals(map1, map2) 27 | 28 | val map3 = map1.remove(0) 29 | builder.remove(0) 30 | val map4 = builder.build() 31 | 32 | assertTrue(map3.equals(builder)) 33 | assertEquals(map3, map4.toMap()) 34 | assertEquals(map3, map4) 35 | } 36 | 37 | @Test 38 | fun `builder should correctly handle multiple element removals in case of full collision`() { 39 | val a = IntWrapper(0, 0) 40 | val b = IntWrapper(1, 0) 41 | val c = IntWrapper(2, 0) 42 | 43 | val original: PersistentHashMap = 44 | persistentHashMapOf(a to "a", b to "b", c to "c") as PersistentHashMap 45 | 46 | val onlyA: PersistentHashMap = 47 | persistentHashMapOf(a to "a") as PersistentHashMap 48 | 49 | val builder = original.builder() 50 | builder.remove(b) 51 | builder.remove(c) 52 | val removedBC = builder.build() 53 | 54 | assertEquals(onlyA, removedBC) 55 | } 56 | 57 | @Test 58 | fun `builder should correctly handle multiple element removals in case of partial collision`() { 59 | val a = IntWrapper(0, 0) 60 | val b = IntWrapper(1, 0) 61 | val c = IntWrapper(2, 0) 62 | val d = IntWrapper(3, 11) 63 | 64 | val original: PersistentHashMap = 65 | persistentHashMapOf(a to "a", b to "b", c to "c", d to "d") as PersistentHashMap 66 | 67 | val afterImmutableRemoving = original.remove(b).remove(c) 68 | 69 | val builder = original.builder() 70 | builder.remove(b) 71 | builder.remove(c) 72 | val afterMutableRemoving = builder.build() 73 | 74 | assertEquals(afterImmutableRemoving, afterMutableRemoving) 75 | } 76 | } -------------------------------------------------------------------------------- /core/commonTest/src/contract/map/PersistentOrderedMapTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2025 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.contract.map 7 | 8 | import kotlinx.collections.immutable.minus 9 | import kotlinx.collections.immutable.persistentMapOf 10 | import kotlin.test.Test 11 | import kotlin.test.assertEquals 12 | 13 | class PersistentOrderedMapTest { 14 | 15 | /** 16 | * Test from issue: https://github.com/Kotlin/kotlinx.collections.immutable/issues/198 17 | */ 18 | @Test 19 | fun `when removing multiple keys with identical hashcodes the remaining key should be correctly promoted`() { 20 | class ChosenHashCode( 21 | private val hashCode: Int, 22 | private val name: String, 23 | ) { 24 | override fun equals(other: Any?): Boolean { 25 | return other is ChosenHashCode && (other.name == name) 26 | } 27 | 28 | override fun hashCode(): Int { 29 | return hashCode 30 | } 31 | 32 | override fun toString(): String { 33 | return name 34 | } 35 | } 36 | 37 | val a = ChosenHashCode(123, "A") 38 | val b = ChosenHashCode(123, "B") 39 | val c = ChosenHashCode(123, "C") 40 | 41 | val abc = persistentMapOf( 42 | a to "x", 43 | b to "y", 44 | c to "z", 45 | ) 46 | 47 | val minusAb = abc.minus(arrayOf(a, b)) 48 | val cOnly = persistentMapOf(c to "z") 49 | 50 | assertEquals(minusAb.entries, cOnly.entries) 51 | assertEquals(minusAb, cOnly) 52 | } 53 | } -------------------------------------------------------------------------------- /core/commonTest/src/contract/set/PersistentHashSetBuilderTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2025 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.contract.set 7 | 8 | import kotlinx.collections.immutable.implementations.immutableSet.PersistentHashSet 9 | import kotlinx.collections.immutable.persistentHashSetOf 10 | import tests.IntWrapper 11 | import kotlin.test.Test 12 | import kotlin.test.assertEquals 13 | import kotlin.test.assertFailsWith 14 | import kotlin.test.assertFalse 15 | import kotlin.test.assertTrue 16 | 17 | class PersistentHashSetBuilderTest { 18 | 19 | @Test 20 | fun `should correctly iterate after removing integer element`() { 21 | val removedElement = 0 22 | val set: PersistentHashSet = 23 | persistentHashSetOf(1, 2, 3, removedElement, 32) 24 | as PersistentHashSet 25 | 26 | validate(set, removedElement) 27 | } 28 | 29 | @Test 30 | fun `should correctly iterate after removing IntWrapper element`() { 31 | val removedElement = IntWrapper(0, 0) 32 | val set: PersistentHashSet = persistentHashSetOf( 33 | removedElement, 34 | IntWrapper(1, 0), 35 | IntWrapper(2, 32), 36 | IntWrapper(3, 32) 37 | ) as PersistentHashSet 38 | 39 | validate(set, removedElement) 40 | } 41 | 42 | private fun validate(set: PersistentHashSet, removedElement: E) { 43 | val builder = set.builder() 44 | val iterator = builder.iterator() 45 | 46 | val expectedCount = set.size 47 | var actualCount = 0 48 | 49 | while (iterator.hasNext()) { 50 | val element = iterator.next() 51 | if (element == removedElement) { 52 | iterator.remove() 53 | } 54 | actualCount++ 55 | } 56 | 57 | val resultSet = builder.build() 58 | for (element in set) { 59 | if (element != removedElement) { 60 | assertTrue(element in resultSet) 61 | } else { 62 | assertFalse(element in resultSet) 63 | } 64 | } 65 | 66 | assertEquals(expectedCount, actualCount) 67 | } 68 | 69 | @Test 70 | fun `removing twice on iterators throws IllegalStateException`() { 71 | val set: PersistentHashSet = 72 | persistentHashSetOf(1, 2, 3, 0, 32) as PersistentHashSet 73 | val builder = set.builder() 74 | val iterator = builder.iterator() 75 | 76 | assertFailsWith { 77 | while (iterator.hasNext()) { 78 | val element = iterator.next() 79 | if (element == 0) iterator.remove() 80 | if (element == 0) { 81 | iterator.remove() 82 | iterator.remove() 83 | } 84 | } 85 | } 86 | } 87 | 88 | @Test 89 | fun `removing elements from different iterators throws ConcurrentModificationException`() { 90 | val set: PersistentHashSet = 91 | persistentHashSetOf(1, 2, 3, 0, 32) as PersistentHashSet 92 | val builder = set.builder() 93 | val iterator1 = builder.iterator() 94 | val iterator2 = builder.iterator() 95 | 96 | assertFailsWith { 97 | while (iterator1.hasNext()) { 98 | val element1 = iterator1.next() 99 | iterator2.next() 100 | if (element1 == 0) iterator1.remove() 101 | if (element1 == 2) iterator2.remove() 102 | } 103 | } 104 | } 105 | 106 | @Test 107 | fun `removing element from one iterator and accessing another throws ConcurrentModificationException`() { 108 | val set = persistentHashSetOf(1, 2, 3) 109 | val builder = set.builder() 110 | val iterator1 = builder.iterator() 111 | val iterator2 = builder.iterator() 112 | 113 | assertFailsWith { 114 | iterator1.next() 115 | iterator1.remove() 116 | iterator2.next() 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /core/commonTest/src/contract/set/PersistentHashSetTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2025 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.contract.set 7 | 8 | import kotlinx.collections.immutable.implementations.immutableSet.PersistentHashSet 9 | import kotlinx.collections.immutable.persistentHashSetOf 10 | import kotlinx.collections.immutable.minus 11 | import kotlinx.collections.immutable.toPersistentHashSet 12 | import kotlin.test.Test 13 | import kotlin.test.assertEquals 14 | import kotlin.test.assertTrue 15 | 16 | class PersistentHashSetTest { 17 | 18 | @Test 19 | fun `persistentHashSet and their builder should be equal before and after modification`() { 20 | val set1 = persistentHashSetOf(-1, 0, 32) 21 | val builder = set1.builder() 22 | 23 | assertTrue(set1.equals(builder)) 24 | assertEquals(set1, builder.build()) 25 | assertEquals(set1, builder.build().toSet()) 26 | 27 | val set2 = set1.remove(0) 28 | builder.remove(0) 29 | 30 | assertEquals(set2, builder.build().toSet()) 31 | assertEquals(set2, builder.build()) 32 | } 33 | 34 | /** 35 | * Test from issue: https://github.com/Kotlin/kotlinx.collections.immutable/issues/144 36 | */ 37 | @Test 38 | fun `removing multiple batches should leave only remaining elements`() { 39 | val firstBatch = listOf(4554, 9380, 4260, 6602) 40 | val secondBatch = listOf(1188, 14794) 41 | val extraElement = 7450 42 | 43 | val set = firstBatch.plus(secondBatch).plus(extraElement).toPersistentHashSet() 44 | val result = set.minus(firstBatch.toPersistentHashSet()).minus(secondBatch) 45 | assertEquals(1, result.size) 46 | assertEquals(extraElement, result.first()) 47 | } 48 | 49 | @Test 50 | fun `after removing elements from one collision the remaining one element must be promoted to the root`() { 51 | val set1: PersistentHashSet = persistentHashSetOf(0, 32768, 65536) as PersistentHashSet 52 | val set2: PersistentHashSet = persistentHashSetOf(0, 32768) as PersistentHashSet 53 | 54 | val expected = persistentHashSetOf(65536) 55 | val actual = set1 - set2 56 | 57 | assertEquals(expected, actual) 58 | } 59 | } -------------------------------------------------------------------------------- /core/commonTest/src/contract/set/PersistentOrderedSetTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2025 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.contract.set 7 | 8 | import kotlinx.collections.immutable.persistentSetOf 9 | import kotlin.test.Test 10 | import kotlin.test.assertEquals 11 | import kotlin.test.assertTrue 12 | 13 | class PersistentOrderedSetTest { 14 | 15 | /** 16 | * Test from issue: https://github.com/Kotlin/kotlinx.collections.immutable/issues/204 17 | */ 18 | @Test 19 | fun `persistentOrderedSet and their builder should be equal before and after modification`() { 20 | val set1 = persistentSetOf(-486539264, 16777216, 0, 67108864) 21 | val builder = set1.builder() 22 | 23 | assertTrue(set1.equals(builder)) 24 | assertEquals(set1, builder.build()) 25 | assertEquals(set1, builder.build().toSet()) 26 | 27 | val set2 = set1.remove(0) 28 | builder.remove(0) 29 | 30 | assertEquals(set2, builder.build().toSet()) 31 | assertEquals(set2, builder.build()) 32 | } 33 | } -------------------------------------------------------------------------------- /core/commonTest/src/implementations/list/BufferIteratorTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.implementations.list 7 | 8 | import kotlinx.collections.immutable.implementations.immutableList.* 9 | import kotlin.test.* 10 | 11 | class BufferIteratorTest { 12 | @Test 13 | fun emptyBufferIteratorTest() { 14 | val emptyIterator = BufferIterator(emptyArray(), 0, 0) 15 | 16 | assertFalse(emptyIterator.hasNext()) 17 | assertFailsWith { emptyIterator.next() } 18 | } 19 | 20 | @Test 21 | fun simpleTest() { 22 | val bufferIterator = BufferIterator(arrayOf(1, 2, 3, 4, 5), 0, 5) 23 | 24 | repeat(times = 5) { it -> 25 | assertTrue(bufferIterator.hasNext()) 26 | assertEquals(it + 1, bufferIterator.next()) 27 | } 28 | 29 | assertFalse(bufferIterator.hasNext()) 30 | assertFailsWith { bufferIterator.next() } 31 | } 32 | 33 | @Test 34 | fun biggerThanSizeBufferTest() { 35 | val bufferIterator = BufferIterator(arrayOf(1, 2, 3, 4, 5), 0, 3) 36 | 37 | repeat(times = 3) { it -> 38 | assertTrue(bufferIterator.hasNext()) 39 | assertEquals(it + 1, bufferIterator.next()) 40 | } 41 | 42 | assertFalse(bufferIterator.hasNext()) 43 | assertFailsWith { bufferIterator.next() } 44 | } 45 | } -------------------------------------------------------------------------------- /core/commonTest/src/implementations/list/TrieIteratorTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.implementations.list 7 | 8 | import kotlinx.collections.immutable.implementations.immutableList.* 9 | import kotlinx.collections.immutable.internal.assert 10 | import kotlin.math.pow 11 | import kotlin.random.* 12 | import kotlin.test.* 13 | 14 | class TrieIteratorTest { 15 | @Test 16 | fun emptyIteratorTest() { 17 | val emptyIterator = TrieIterator(emptyArray(), 0, 0, 1) 18 | 19 | assertFalse(emptyIterator.hasNext()) 20 | assertFailsWith { 21 | emptyIterator.next() 22 | } 23 | } 24 | 25 | private fun makeRoot(height: Int, leafCount: Int): Array { 26 | var leaves = arrayListOf() 27 | repeat(leafCount * MAX_BUFFER_SIZE) { it -> 28 | leaves.add(it) 29 | } 30 | 31 | repeat(height) { 32 | val newLeaves = arrayListOf() 33 | for (i in 0 until leaves.size step MAX_BUFFER_SIZE) { 34 | val buffer = arrayOfNulls(MAX_BUFFER_SIZE) 35 | for (j in i until minOf(leaves.size, i + MAX_BUFFER_SIZE)) { 36 | buffer[j - i] = leaves[j] 37 | } 38 | newLeaves.add(buffer) 39 | } 40 | leaves = newLeaves 41 | } 42 | 43 | check(leaves.size == 1) 44 | 45 | @Suppress("UNCHECKED_CAST") 46 | return leaves.single() as Array 47 | } 48 | 49 | @Test 50 | fun simpleTest() { 51 | for (height in 1..4) { 52 | val maxCount = MAX_BUFFER_SIZE.toDouble().pow(height - 1).toInt() 53 | val minCount = maxCount / 32 + 1 54 | val leafCountRange = minCount..maxCount 55 | val leafCounts = (listOf(minCount, maxCount) + List(10) { Random.nextInt(leafCountRange) }).distinct().sorted() 56 | 57 | for (leafCount in leafCounts) { 58 | val root = makeRoot(height, leafCount) 59 | val size = leafCount * MAX_BUFFER_SIZE 60 | 61 | val iterator = TrieIterator(root, 0, size, height) 62 | for (index in 0 until size) { 63 | assertTrue(iterator.hasNext()) 64 | assertEquals(index, iterator.next()) 65 | } 66 | 67 | assertFalse(iterator.hasNext()) 68 | assertFailsWith { 69 | iterator.next() 70 | } 71 | } 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /core/commonTest/src/stress/ExecutionTimeMeasuringTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.stress 7 | 8 | import kotlin.test.AfterTest 9 | import kotlin.test.BeforeTest 10 | import kotlin.time.* 11 | import kotlin.time.Duration.Companion.seconds 12 | 13 | abstract class ExecutionTimeMeasuringTest { 14 | private var clockMark: TimeMark? = null 15 | 16 | private fun markExecutionStart() { 17 | clockMark = TimeSource.Monotonic.markNow() 18 | } 19 | 20 | private fun printExecutionTime() { 21 | val nonNullClockMark = clockMark ?: throw IllegalStateException("markExecutionStart() must be called first") 22 | val elapsed = nonNullClockMark.elapsedNow() 23 | 24 | if (elapsed > 3.seconds) { 25 | print("#".repeat(20) + " ") 26 | } 27 | println("Execution time: ${elapsed.toString(DurationUnit.MILLISECONDS)}") 28 | 29 | clockMark = null 30 | } 31 | 32 | @BeforeTest 33 | fun before() { 34 | markExecutionStart() 35 | } 36 | 37 | @AfterTest 38 | fun after() { 39 | printExecutionTime() 40 | } 41 | } -------------------------------------------------------------------------------- /core/commonTest/src/stress/WrapperGenerator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.stress 7 | 8 | import tests.ObjectWrapper 9 | import kotlin.random.Random 10 | 11 | 12 | class WrapperGenerator>(private val hashCodeUpperBound: Int) { 13 | private val elementMap = hashMapOf>() 14 | private val hashCodeMap = hashMapOf>>() 15 | 16 | fun wrapper(element: K): ObjectWrapper { 17 | val existing = elementMap[element] 18 | if (existing != null) { 19 | return existing 20 | } 21 | val hashCode = Random.nextInt(hashCodeUpperBound) 22 | val wrapper = ObjectWrapper(element, hashCode) 23 | elementMap[element] = wrapper 24 | 25 | val wrappers = hashCodeMap[hashCode] ?: mutableListOf() 26 | wrappers.add(wrapper) 27 | hashCodeMap[hashCode] = wrappers 28 | 29 | return wrapper 30 | } 31 | 32 | fun wrappersByHashCode(hashCode: Int): List> { 33 | return hashCodeMap[hashCode] ?: mutableListOf() 34 | } 35 | } -------------------------------------------------------------------------------- /core/commonTest/src/testUtils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests 7 | 8 | import kotlin.native.concurrent.ThreadLocal 9 | 10 | 11 | internal fun Char.isUpperCase(): Boolean = this in 'A'..'Z' 12 | internal fun Char.isDigit(): Boolean = this in '0'..'9' 13 | 14 | @Suppress("EXTENSION_SHADOWED_BY_MEMBER") 15 | internal fun MutableMap.remove(key: K, value: V): Boolean = 16 | if (key in this && this[key] == value) { 17 | remove(key) 18 | true 19 | } else { 20 | false 21 | } 22 | 23 | expect fun assertTypeEquals(expected: Any?, actual: Any?) 24 | 25 | enum class TestPlatform { 26 | JVM, 27 | JS, 28 | Native, 29 | Wasm, 30 | } 31 | expect val currentPlatform: TestPlatform 32 | 33 | inline fun testOn(platform: TestPlatform, action: () -> Unit) { 34 | if (platform == currentPlatform) action() 35 | } 36 | 37 | @ThreadLocal 38 | private var stringValues = mutableListOf() 39 | 40 | internal fun distinctStringValues(size: Int): List { 41 | if (size <= stringValues.size) { 42 | return stringValues.subList(0, size) 43 | } 44 | for (index in stringValues.size until size) { 45 | stringValues.add(index.toString()) 46 | } 47 | return stringValues 48 | } 49 | 50 | expect object NForAlgorithmComplexity { 51 | val O_N: Int 52 | val O_NlogN: Int 53 | val O_NN: Int 54 | val O_NNlogN: Int 55 | } -------------------------------------------------------------------------------- /core/dokka-templates/README.md: -------------------------------------------------------------------------------- 1 | # Dokka's template customization 2 | To provide unified navigation for all parts of [kotlinlang.org](https://kotlinlang.org/), 3 | the Kotlin Website Team uses this directory to place custom templates in this folder 4 | during the website build time on TeamCity. 5 | 6 | It is not practical to place these templates in the kotlinx.collections.immutable repository because they change from time to time 7 | and aren't related to the library's release cycle. 8 | 9 | The folder is defined as a source for custom templates by the templatesDir property through Dokka's plugin configuration. 10 | 11 | [Here](https://kotlinlang.org/docs/dokka-html.html#templates), you can 12 | find more about the customization of Dokka's HTML output. -------------------------------------------------------------------------------- /core/jsMain/src/internal/commonFunctions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.internal 7 | 8 | internal actual fun assert(condition: Boolean) { 9 | if (!condition) { 10 | throw AssertionError("Assertion failed") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/jsTest/src/testUtilsJs.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests 7 | 8 | import kotlin.test.assertEquals 9 | 10 | actual fun assertTypeEquals(expected: Any?, actual: Any?) { 11 | assertEquals(expected?.let { it::class.js }, actual?.let { it::class.js }) 12 | } 13 | 14 | actual val currentPlatform: TestPlatform get() = TestPlatform.JS 15 | 16 | actual object NForAlgorithmComplexity { 17 | actual val O_N: Int = 500_000 18 | actual val O_NlogN: Int = 100_000 19 | actual val O_NN: Int = 5_000 20 | actual val O_NNlogN: Int = 1_000 21 | } -------------------------------------------------------------------------------- /core/jvmMain/src/internal/commonFunctions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.internal 7 | 8 | internal actual fun assert(condition: Boolean) = kotlin.assert(condition) -------------------------------------------------------------------------------- /core/jvmTest/src/contract/GuavaImmutableCollectionBaseTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.contract 7 | 8 | import com.google.common.collect.testing.testers.* 9 | import junit.framework.* 10 | import java.lang.IllegalArgumentException 11 | 12 | open class GuavaImmutableCollectionBaseTest: TestListener { 13 | override fun addFailure(test: Test, e: AssertionFailedError) = throw e 14 | override fun addError(test: Test, e: Throwable) { 15 | if (e is ConcurrentModificationException 16 | && test is ListSubListTester<*> 17 | && test.testMethodName in listOf("testSubList_originalListSetAffectsSubList", "testSubList_originalListSetAffectsSubListLargeList")) { 18 | // These test cases check that changes in sublist are reflected in backed list, and vice-versa. 19 | // Backed list is structurally modified due to `set` function invocation, 20 | // leading to CME when `sublist.listIterator()` gets invoked to iterate elements of sublist to make sure changes are reflected. 21 | // The `sublist.listIterator()` method has the comodification check. 22 | // 23 | // The guava-testlib doesn't expect any exceptions to be thrown, 24 | // despite `List.subList` javadoc statement "The semantics of the list returned by this method become undefined" is such case. 25 | return 26 | } 27 | if (e is NoSuchElementException 28 | // Removing the only element from the sublist and calling `next()` on it's earlier created iterator throws NSEE. 29 | && (test is ListRemoveAtIndexTester<*> && test.testMethodName == "testRemoveAtIndexConcurrentWithIteration" 30 | // Removing all elements from the sublist and calling `next()` on it's earlier created iterator throws NSEE. 31 | || test is CollectionClearTester<*> && test.testMethodName == "testClearConcurrentWithIteration")) { 32 | // These test cases check that sublist iterator is fail-fast. 33 | // 34 | // `AbstractList` implementation of sublist iterator is not fail-fast. 35 | // Seems we need to override the `subList()` method in `PersistentVectorBuilder` 36 | // to return custom sublist implementation with fail-fast iterator. 37 | return 38 | } 39 | if (e is IllegalArgumentException 40 | && (test is CollectionAddAllTester<*> && test.testMethodName == "testAddAll_nullCollectionReference" 41 | || test is CollectionRemoveAllTester<*> && test.testMethodName == "testRemoveAll_nullCollectionReferenceEmptySubject" 42 | || test is CollectionRemoveAllTester<*> && test.testMethodName == "testRemoveAll_nullCollectionReferenceNonEmptySubject" 43 | || test is ListAddAllAtIndexTester<*> && test.testMethodName == "testAddAllAtIndex_nullCollectionReference")) { 44 | // These test cases check that `addAll(elements)`, `addAll(index, elements)` and `removeAll(elements)` 45 | // throw `NullPointerException` when null collection is passed. 46 | // 47 | // Kotlin throws IllegalArgumentException as those methods has Non-Null collection type parameter. 48 | return 49 | } 50 | throw e 51 | } 52 | override fun startTest(test: Test) { } 53 | override fun endTest(test: Test) { } 54 | 55 | fun runTestSuite(suite: TestSuite) { 56 | for (t in suite.tests()) { 57 | val r = TestResult() 58 | r.addListener(this) 59 | t.run(r) 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /core/jvmTest/src/contract/list/GuavaImmutableListTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.contract.list 7 | 8 | import com.google.common.collect.testing.ListTestSuiteBuilder 9 | import com.google.common.collect.testing.TestListGenerator 10 | import com.google.common.collect.testing.features.CollectionFeature 11 | import com.google.common.collect.testing.features.CollectionSize 12 | import com.google.common.collect.testing.features.ListFeature 13 | import tests.contract.GuavaImmutableCollectionBaseTest 14 | import tests.contract.list.PersistentListGenerator.PList 15 | import kotlin.test.Test 16 | 17 | class GuavaImmutableListTest: GuavaImmutableCollectionBaseTest() { 18 | private fun runImmutableListTestsUsing(generator: TestListGenerator) { 19 | ListTestSuiteBuilder 20 | .using(generator) 21 | .named(generator.javaClass.simpleName) 22 | .withFeatures( 23 | CollectionSize.ANY, 24 | CollectionFeature.ALLOWS_NULL_VALUES 25 | ) 26 | .createTestSuite() 27 | .run { runTestSuite(this) } 28 | 29 | } 30 | 31 | private fun runMutableListTestsUsing(generator: TestListGenerator) { 32 | ListTestSuiteBuilder 33 | .using(generator) 34 | .named(generator.javaClass.simpleName) 35 | .withFeatures( 36 | CollectionSize.ANY, 37 | CollectionFeature.ALLOWS_NULL_VALUES, 38 | CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 39 | ListFeature.GENERAL_PURPOSE 40 | ) 41 | .createTestSuite() 42 | .run { runTestSuite(this) } 43 | 44 | } 45 | 46 | @Test 47 | fun list() { 48 | listOf( 49 | PList.Of, 50 | PList.AddAll, 51 | PList.AddEach, 52 | PList.MutateAddAll, 53 | PList.MutateAddEach, 54 | PList.HeadSubList, 55 | PList.TailSubList, 56 | PList.MiddleSubList 57 | ).forEach { 58 | runImmutableListTestsUsing(it) 59 | } 60 | } 61 | 62 | @Test 63 | fun listBuilder() { 64 | listOf( 65 | PList.Builder.Of, 66 | PList.Builder.AddAll, 67 | PList.Builder.AddEach, 68 | PList.Builder.AddAt, 69 | PList.Builder.HeadSubList, 70 | PList.Builder.TailSubList, 71 | PList.Builder.MiddleSubList 72 | ).forEach { 73 | runMutableListTestsUsing(it) 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /core/jvmTest/src/contract/map/GuavaImmutableMapTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.contract.map 7 | 8 | import com.google.common.collect.testing.MapTestSuiteBuilder 9 | import com.google.common.collect.testing.TestMapGenerator 10 | import com.google.common.collect.testing.features.CollectionFeature 11 | import com.google.common.collect.testing.features.CollectionSize 12 | import com.google.common.collect.testing.features.Feature 13 | import com.google.common.collect.testing.features.MapFeature 14 | import tests.contract.GuavaImmutableCollectionBaseTest 15 | import tests.contract.map.PersistentMapGenerator.HashMap 16 | import tests.contract.map.PersistentMapGenerator.OrderedMap 17 | import kotlin.test.Test 18 | 19 | class GuavaImmutableMapTest: GuavaImmutableCollectionBaseTest() { 20 | private fun runImmutableMapTestsUsing(generator: TestMapGenerator, knownOrder: Boolean) { 21 | val features = mutableListOf>( 22 | CollectionSize.ANY, 23 | MapFeature.ALLOWS_NULL_KEYS, 24 | MapFeature.ALLOWS_NULL_VALUES, 25 | MapFeature.ALLOWS_NULL_ENTRY_QUERIES/*, 26 | MapFeature.REJECTS_DUPLICATES_AT_CREATION*/ 27 | ) 28 | if (knownOrder) 29 | features.add(CollectionFeature.KNOWN_ORDER) 30 | 31 | MapTestSuiteBuilder 32 | .using(generator) 33 | .named(generator.javaClass.simpleName) 34 | .withFeatures(features) 35 | .createTestSuite() 36 | .run { runTestSuite(this) } 37 | } 38 | 39 | private fun runMutableMapTestsUsing(generator: TestMapGenerator, knownOrder: Boolean) { 40 | val features = mutableListOf>( 41 | CollectionSize.ANY, 42 | MapFeature.ALLOWS_NULL_KEYS, 43 | MapFeature.ALLOWS_NULL_VALUES, 44 | MapFeature.ALLOWS_NULL_ENTRY_QUERIES, 45 | MapFeature.GENERAL_PURPOSE, 46 | MapFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 47 | CollectionFeature.SUPPORTS_ITERATOR_REMOVE, // iteration over entries/keys/values 48 | CollectionFeature.SUPPORTS_REMOVE/*, 49 | MapFeature.REJECTS_DUPLICATES_AT_CREATION*/ 50 | ) 51 | if (knownOrder) 52 | features.add(CollectionFeature.KNOWN_ORDER) 53 | 54 | MapTestSuiteBuilder 55 | .using(generator) 56 | .named(generator.javaClass.simpleName) 57 | .withFeatures(features) 58 | .createTestSuite() 59 | .run { runTestSuite(this) } 60 | } 61 | 62 | @Test 63 | fun hashMap() { 64 | listOf( 65 | HashMap.Of, 66 | HashMap.PutAll, 67 | HashMap.PutEach, 68 | HashMap.MutatePutAll, 69 | HashMap.MutatePutEach 70 | ).forEach { 71 | runImmutableMapTestsUsing(it, knownOrder = false) 72 | } 73 | } 74 | 75 | @Test 76 | fun hashMapBuilder() { 77 | listOf( 78 | HashMap.Builder.Of, 79 | HashMap.Builder.PutAll, 80 | HashMap.Builder.PutEach 81 | ).forEach { 82 | runMutableMapTestsUsing(it, knownOrder = false) 83 | } 84 | } 85 | 86 | 87 | @Test 88 | fun orderedMap() { 89 | listOf( 90 | OrderedMap.Of, 91 | OrderedMap.PutAll, 92 | OrderedMap.PutEach, 93 | OrderedMap.MutatePutAll, 94 | OrderedMap.MutatePutEach 95 | ).forEach { 96 | runImmutableMapTestsUsing(it, knownOrder = true) 97 | } 98 | } 99 | 100 | @Test 101 | fun orderedMapBuilder() { 102 | listOf( 103 | OrderedMap.Builder.Of, 104 | OrderedMap.Builder.PutAll, 105 | OrderedMap.Builder.PutEach 106 | ).forEach { 107 | runMutableMapTestsUsing(it, knownOrder = true) 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /core/jvmTest/src/contract/set/GuavaImmutableSetTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests.contract.set 7 | 8 | import com.google.common.collect.testing.SetTestSuiteBuilder 9 | import com.google.common.collect.testing.TestSetGenerator 10 | import com.google.common.collect.testing.features.CollectionFeature 11 | import com.google.common.collect.testing.features.CollectionSize 12 | import com.google.common.collect.testing.features.Feature 13 | import tests.contract.GuavaImmutableCollectionBaseTest 14 | import tests.contract.set.PersistentSetGenerator.HashSet 15 | import tests.contract.set.PersistentSetGenerator.OrderedSet 16 | import kotlin.test.Test 17 | 18 | class GuavaImmutableSetTest: GuavaImmutableCollectionBaseTest() { 19 | private fun runImmutableSetTestsUsing(generator: TestSetGenerator, knownOrder: Boolean) { 20 | val features = mutableListOf>( 21 | CollectionSize.ANY, 22 | CollectionFeature.ALLOWS_NULL_VALUES, 23 | CollectionFeature.SUBSET_VIEW, 24 | CollectionFeature.DESCENDING_VIEW/*, 25 | CollectionFeature.REJECTS_DUPLICATES_AT_CREATION*/ 26 | ) 27 | if (knownOrder) 28 | features.add(CollectionFeature.KNOWN_ORDER) 29 | 30 | SetTestSuiteBuilder 31 | .using(generator) 32 | .named(generator.javaClass.simpleName) 33 | .withFeatures(features) 34 | .createTestSuite() 35 | .run { runTestSuite(this) } 36 | 37 | } 38 | 39 | private fun runMutableSetTestsUsing(generator: TestSetGenerator, knownOrder: Boolean) { 40 | val features = mutableListOf>( 41 | CollectionSize.ANY, 42 | CollectionFeature.ALLOWS_NULL_VALUES, 43 | CollectionFeature.GENERAL_PURPOSE, 44 | CollectionFeature.FAILS_FAST_ON_CONCURRENT_MODIFICATION, 45 | CollectionFeature.SUBSET_VIEW, 46 | CollectionFeature.DESCENDING_VIEW/*, 47 | CollectionFeature.REJECTS_DUPLICATES_AT_CREATION*/ 48 | ) 49 | if (knownOrder) 50 | features.add(CollectionFeature.KNOWN_ORDER) 51 | 52 | SetTestSuiteBuilder 53 | .using(generator) 54 | .named(generator.javaClass.simpleName) 55 | .withFeatures(features) 56 | .createTestSuite() 57 | .run { runTestSuite(this) } 58 | 59 | } 60 | 61 | @Test 62 | fun hashSet() { 63 | listOf( 64 | HashSet.Of, 65 | HashSet.AddAll, 66 | HashSet.AddEach, 67 | HashSet.MutateAddAll, 68 | HashSet.MutateAddEach 69 | ).forEach { 70 | runImmutableSetTestsUsing(it, knownOrder = false) 71 | } 72 | } 73 | 74 | @Test 75 | fun hashSetBuilder() { 76 | listOf( 77 | HashSet.Builder.Of, 78 | HashSet.Builder.AddAll, 79 | HashSet.Builder.AddEach 80 | ).forEach { 81 | runMutableSetTestsUsing(it, knownOrder = false) 82 | } 83 | } 84 | 85 | 86 | @Test 87 | fun orderedSet() { 88 | listOf( 89 | OrderedSet.Of, 90 | OrderedSet.AddAll, 91 | OrderedSet.AddEach, 92 | OrderedSet.MutateAddAll, 93 | OrderedSet.MutateAddEach 94 | ).forEach { 95 | runImmutableSetTestsUsing(it, knownOrder = true) 96 | } 97 | } 98 | 99 | @Test 100 | fun orderedSetBuilder() { 101 | listOf( 102 | OrderedSet.Builder.Of, 103 | OrderedSet.Builder.AddAll, 104 | OrderedSet.Builder.AddEach 105 | ).forEach { 106 | runMutableSetTestsUsing(it, knownOrder = true) 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /core/jvmTest/src/testUtilsJvm.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests 7 | 8 | import kotlin.test.assertEquals 9 | 10 | actual fun assertTypeEquals(expected: Any?, actual: Any?) { 11 | assertEquals(expected?.javaClass, actual?.javaClass) 12 | } 13 | 14 | actual val currentPlatform: TestPlatform get() = TestPlatform.JVM 15 | 16 | actual object NForAlgorithmComplexity { 17 | actual val O_N: Int = 1_000_000 18 | actual val O_NlogN: Int = 200_000 19 | actual val O_NN: Int = 10_000 20 | actual val O_NNlogN: Int = 5_000 21 | } -------------------------------------------------------------------------------- /core/nativeMain/src/internal/commonFunctions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.internal 7 | 8 | @OptIn(kotlin.experimental.ExperimentalNativeApi::class) 9 | internal actual fun assert(condition: Boolean) = kotlin.assert(condition) 10 | -------------------------------------------------------------------------------- /core/nativeTest/src/testUtilsNative.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2019 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests 7 | 8 | import kotlin.test.assertTrue 9 | 10 | actual fun assertTypeEquals(expected: Any?, actual: Any?) { 11 | if (expected != null && actual != null) { 12 | assertTrue(expected::class.isInstance(actual) || actual::class.isInstance(expected), 13 | "Expected: $expected, Actual: $actual") 14 | } else { 15 | assertTrue(expected == null && actual == null) 16 | } 17 | } 18 | 19 | actual val currentPlatform: TestPlatform get() = TestPlatform.Native 20 | 21 | actual object NForAlgorithmComplexity { 22 | actual val O_N: Int = 100_000 23 | actual val O_NlogN: Int = 20_000 24 | actual val O_NN: Int = 1_000 25 | actual val O_NNlogN: Int = 500 26 | } -------------------------------------------------------------------------------- /core/wasmMain/src/internal/commonFunctions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2023 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package kotlinx.collections.immutable.internal 7 | 8 | internal actual fun assert(condition: Boolean) { 9 | if (!condition) { 10 | throw AssertionError("Assertion failed") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /core/wasmTest/src/testUtilsJs.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016-2023 JetBrains s.r.o. 3 | * Use of this source code is governed by the Apache 2.0 License that can be found in the LICENSE.txt file. 4 | */ 5 | 6 | package tests 7 | 8 | import kotlin.test.assertTrue 9 | 10 | actual fun assertTypeEquals(expected: Any?, actual: Any?) { 11 | if (expected != null && actual != null) { 12 | assertTrue(expected::class.isInstance(actual) || actual::class.isInstance(expected), 13 | "Expected: $expected, Actual: $actual") 14 | } else { 15 | assertTrue(expected == null && actual == null) 16 | } 17 | } 18 | 19 | actual val currentPlatform: TestPlatform get() = TestPlatform.Wasm 20 | 21 | actual object NForAlgorithmComplexity { 22 | actual val O_N: Int = 500_000 23 | actual val O_NlogN: Int = 100_000 24 | actual val O_NN: Int = 5_000 25 | actual val O_NNlogN: Int = 1_000 26 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group=org.jetbrains.kotlinx 2 | version=0.4 3 | versionSuffix=SNAPSHOT 4 | 5 | kotlin_version=2.1.20 6 | dokkaVersion=2.0.0 7 | 8 | org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=2048m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 9 | 10 | org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled 11 | org.jetbrains.dokka.experimental.gradle.pluginMode.nowarn=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kotlin/kotlinx.collections.immutable/c7f155af4bdadb955d15534f71ed7d7167cd5e6b/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlinx/maven") 4 | gradlePluginPortal() 5 | 6 | val kotlinRepoUrl = providers.gradleProperty("kotlin_repo_url").orNull 7 | if (kotlinRepoUrl != null) { 8 | maven(kotlinRepoUrl) 9 | } 10 | } 11 | val dokkaVersion: String by settings 12 | plugins { 13 | id("org.jetbrains.dokka") version dokkaVersion 14 | } 15 | } 16 | 17 | rootProject.name = "Kotlin-Immutable-Collections" // TODO: Make readable name when it's not used in js module names 18 | 19 | include(":core") 20 | project(":core").name="kotlinx-collections-immutable" 21 | 22 | include( 23 | ":benchmarks", 24 | ":benchmarks:runner" 25 | ) 26 | --------------------------------------------------------------------------------