Skip to content

Commit

Permalink
Merge pull request #109 from touchlab/MohamadJaara-feat/implement-com…
Browse files Browse the repository at this point in the history
…puteIfAbsent

Mohamad jaara feat/implement compute if absent
  • Loading branch information
kpgalligan authored Dec 3, 2023
2 parents 806daf6 + 6a3c7e8 commit f77b367
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 0 deletions.
49 changes: 49 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: deploy
on:
pull_request:
push:
branches:
- main
workflow_dispatch:

jobs:
deploy:
runs-on: macos-latest
steps:
- name: Checkout the repo
uses: actions/checkout@v3

- uses: actions/setup-java@v2
with:
distribution: "adopt"
java-version: "17"
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v1
- name: Cache gradle
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Cache konan
uses: actions/cache@v2
with:
path: ~/.konan
key: ${{ runner.os }}-gradle-${{ hashFiles('*.gradle.kts') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Publish Mac/Windows Artifacts
run: ./gradlew build --no-daemon --stacktrace --no-build-cache
env:
ORG_GRADLE_PROJECT_SONATYPE_NEXUS_USERNAME: ${{ secrets.SONATYPE_NEXUS_USERNAME }}
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_NEXUS_USERNAME }}
ORG_GRADLE_PROJECT_SONATYPE_NEXUS_PASSWORD: ${{ secrets.SONATYPE_NEXUS_PASSWORD }}
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_NEXUS_PASSWORD }}
ORG_GRADLE_PROJECT_SIGNING_KEY: ${{ secrets.SIGNING_KEY }}
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_KEY }}

env:
GRADLE_OPTS: -Dkotlin.incremental=false -Dorg.gradle.jvmargs="-Xmx3g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 -XX:MaxMetaspaceSize=512m"
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public final class co/touchlab/stately/collections/ConcurrentMutableMap : java/u
public fun put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
public fun putAll (Ljava/util/Map;)V
public fun remove (Ljava/lang/Object;)Ljava/lang/Object;
public final fun safeComputeIfAbsent (Ljava/lang/Object;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public final fun size ()I
public final fun values ()Ljava/util/Collection;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package co.touchlab.stately.collections

import co.touchlab.stately.concurrency.Synchronizable
import co.touchlab.stately.concurrency.synchronize
import kotlin.jvm.JvmName

class ConcurrentMutableMap<K, V> internal constructor(
rootArg: Synchronizable? = null,
private val del: MutableMap<K, V>
) : Synchronizable(), MutableMap<K, V> {

constructor() : this(null, mutableMapOf())

private val syncTarget: Synchronizable = rootArg ?: this
Expand All @@ -28,6 +30,24 @@ class ConcurrentMutableMap<K, V> internal constructor(
syncTarget.synchronize { del.clear() }
}

/**
* If the specified key is not already associated with a value
* attempts to compute its value using the given mapping function and enters it into this map
*/
@JvmName("safeComputeIfAbsent")
fun computeIfAbsent(key: K, defaultValue: (K) -> V): V {
return syncTarget.synchronize {
val value = del[key]
if (value == null) {
val newValue = defaultValue(key)
del[key] = newValue
newValue
} else {
value
}
}
}

override fun put(key: K, value: V): V? = syncTarget.synchronize { del.put(key, value) }
override fun putAll(from: Map<out K, V>) {
syncTarget.synchronize { del.putAll(from) }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package co.touchlab.stately.collections

import co.touchlab.stately.concurrency.AtomicInt
import co.touchlab.testhelp.concurrency.sleep
import kotlinx.coroutines.delay
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
Expand Down Expand Up @@ -68,4 +71,21 @@ class ConcurrentMutableMapTest {

assertEquals(map.size, DEFAULT_RUNS * 2)
}

@Test
@NoJsTest
fun computeIfAbsent() {
val map = ConcurrentMutableMap<String, SomeData>()
val count = AtomicInt(0)

runAlot(1) { run ->
map.computeIfAbsent("key") {
sleep(1000)
count.incrementAndGet()
SomeData("value $run")
}
}

assertEquals(count.get(), 1)
}
}

0 comments on commit f77b367

Please sign in to comment.