├── .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 |
4 |
5 |
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