Skip to content

Commit

Permalink
Rename to Stamped.
Browse files Browse the repository at this point in the history
  • Loading branch information
kennethshackleton committed Jun 21, 2024
1 parent 67f9198 commit 025afc7
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

package com.bloomberg.selekt.collections.map.benchmarks

import com.bloomberg.selekt.collections.map.FastAccessOrderedStringMap
import com.bloomberg.selekt.collections.map.FastStampedStringMap
import org.openjdk.jmh.annotations.Benchmark
import org.openjdk.jmh.annotations.BenchmarkMode
import org.openjdk.jmh.annotations.Level
Expand All @@ -26,32 +26,32 @@ import org.openjdk.jmh.annotations.Setup
import org.openjdk.jmh.annotations.State

@State(Scope.Thread)
open class LruMapInput {
internal lateinit var map: FastAccessOrderedStringMap<Any>
open class StampedMapInput {
internal lateinit var map: FastStampedStringMap<Any>

@Setup(Level.Iteration)
fun setUp() {
map = FastAccessOrderedStringMap(1)
map = FastStampedStringMap(1)
}
}

open class FastLruStringMapBenchmark {
@Benchmark
@BenchmarkMode(Mode.Throughput)
fun getEntry(input: LruMapInput) = input.map.run {
fun getEntry(input: StampedMapInput) = input.map.run {
getEntryElsePut("1") { "" }
}

@Benchmark
@BenchmarkMode(Mode.Throughput)
fun getEntryWithCollision(input: LruMapInput) = input.map.run {
fun getEntryWithCollision(input: StampedMapInput) = input.map.run {
getEntryElsePut("1") { "" }
getEntryElsePut("2") { "" }
}

@Benchmark
@BenchmarkMode(Mode.Throughput)
fun getThenRemoveEntry(input: LruMapInput) = input.map.run {
fun getThenRemoveEntry(input: StampedMapInput) = input.map.run {
getEntryElsePut("1") { "" }
removeEntry("1")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,14 @@ class FastLinkedStringMap<T>(
spare = null
head = null
var entry = tail
tail = null
while (entry != null) {
val previous = entry.previous
disposal(entry.unlink().value!!)
entry.key = ""
entry.value = null
entry = previous
}
tail = null
}

private fun LinkedEntry<T>.unlink(): Entry<T> = apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ package com.bloomberg.selekt.collections.map
import javax.annotation.concurrent.NotThreadSafe

@NotThreadSafe
class FastAccessOrderedStringMap<T>(
class FastStampedStringMap<T>(
capacity: Int
) : FastStringMap<T>(capacity) {
private var accessNumber = Int.MIN_VALUE
private var spare: AOEntry<T>? = null
private var currentStamp = Int.MIN_VALUE
private var spare: StampedEntry<T>? = null

inline fun getElsePut(
key: String,
Expand All @@ -32,7 +32,7 @@ class FastAccessOrderedStringMap<T>(
val hashCode = hash(key)
val index = hashIndex(hashCode)
entryMatching(index, hashCode, key)?.let {
(it as AOEntry<T>).accessNumber = nextAccessCount()
(it as StampedEntry<T>).stamp = nextStamp()
return it.value!!
}
return addAssociation(index, hashCode, key, supplier()).value!!
Expand All @@ -46,33 +46,23 @@ class FastAccessOrderedStringMap<T>(
): Entry<T> {
spare?.let {
spare = null
return it.update(index, hashCode, key, value, nextAccessCount(), store[index])
return it.update(index, hashCode, key, value, nextStamp(), store[index])
}
return AOEntry(index, hashCode, key, value, nextAccessCount(), store[index])
return StampedEntry(index, hashCode, key, value, nextStamp(), store[index])
}

override fun clear() {
super.clear()
spare = null
}

internal fun asLinkedMap(
capacity: Int = size
) = FastLinkedStringMap<T>(capacity = capacity).apply {
entries().sortedBy {
(it as AOEntry<T>).accessNumber
}.forEach {
addAssociation(it.index, it.hashCode, it.key, it.value!!)
}
}

@PublishedApi
internal fun nextAccessCount(): Int {
accessNumber += 1
if (accessNumber == Int.MIN_VALUE) {
resetAllAccessCounts()
internal fun nextStamp(): Int {
if (Int.MAX_VALUE == currentStamp) {
resetAllStamps()
}
return accessNumber
currentStamp += 1
return currentStamp
}

private fun entries(): Iterable<Entry<T>> = store.flatMap {
Expand All @@ -85,21 +75,24 @@ class FastAccessOrderedStringMap<T>(
}
}.asIterable()

private fun resetAllAccessCounts() {
private fun resetAllStamps() {
entries().sortedBy {
(it as AOEntry<T>).accessNumber
}.forEachIndexed { index, it ->
(it as AOEntry<T>).accessNumber = Int.MIN_VALUE + index
(it as StampedEntry<T>).stamp
}.run {
currentStamp = Int.MIN_VALUE + maxOf(0, size - 1)
forEachIndexed { index, it ->
(it as StampedEntry<T>).stamp = Int.MIN_VALUE + index
}
}
}

@PublishedApi
internal class AOEntry<T>(
internal class StampedEntry<T>(
index: Int,
hashCode: Int,
key: String,
value: T,
var accessNumber: Int,
var stamp: Int,
after: Entry<T>?
) : Entry<T>(index, hashCode, key, value, after) {
@Suppress("NOTHING_TO_INLINE")
Expand All @@ -108,14 +101,14 @@ class FastAccessOrderedStringMap<T>(
hashCode: Int,
key: String,
value: T,
accessCount: Int,
stamp: Int,
after: Entry<T>?
) = apply {
this.index = index
this.hashCode = hashCode
this.key = key
this.value = value
this.accessNumber = accessCount
this.stamp = stamp
this.after = after
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,26 @@ import kotlin.test.assertSame
import kotlin.test.assertTrue
import kotlin.test.fail

internal class FastAccessOrderedStringMapTest {
internal class FastStampedStringMapTest {
@Test
fun get() {
val first = Any()
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
assertSame(first, map.getElsePut("1") { first })
}

@Test
fun sizeOne() {
val first = Any()
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
map.getElsePut("1") { first }
assertEquals(1, map.size)
}

@Test
fun getTwice() {
val first = Any()
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
map.getElsePut("1") { first }
assertSame(first, map.getElsePut("1") { fail() })
}
Expand All @@ -58,7 +58,7 @@ internal class FastAccessOrderedStringMapTest {
fun getWhenAbsent() {
val supplier = mock<() -> Any>()
whenever(supplier.invoke()) doReturn Any()
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
val item = map.getElsePut("1", supplier)
verify(supplier, times(1)).invoke()
assertSame(item, map.getElsePut("1", supplier))
Expand All @@ -69,7 +69,7 @@ internal class FastAccessOrderedStringMapTest {
fun getTwo() {
val first = Any()
val second = Any()
val map = FastAccessOrderedStringMap<Any>(64)
val map = FastStampedStringMap<Any>(64)
map.getElsePut("1") { first }
map.getElsePut("2") { second }
assertEquals(2, map.size)
Expand All @@ -79,7 +79,7 @@ internal class FastAccessOrderedStringMapTest {
fun getTwoWithCollisions() {
val first = Any()
val second = Any()
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
map.getElsePut("1") { first }
map.getElsePut("2") { second }
assertSame(first, map.getElsePut("1") { fail() })
Expand All @@ -90,7 +90,7 @@ internal class FastAccessOrderedStringMapTest {
fun sizeTwo() {
val first = Any()
val second = Any()
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
map.getElsePut("1") { first }
map.getElsePut("2") { second }
assertSame(first, map.getElsePut("1") { fail() })
Expand All @@ -100,7 +100,7 @@ internal class FastAccessOrderedStringMapTest {
@Test
fun removeOne() {
val first = Any()
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
map.getElsePut("1") { first }
assertSame(first, map.removeEntry("1").value)
}
Expand All @@ -109,7 +109,7 @@ internal class FastAccessOrderedStringMapTest {
fun removeTwo() {
val first = Any()
val second = Any()
val map = FastAccessOrderedStringMap<Any>(2)
val map = FastStampedStringMap<Any>(2)
map.getElsePut("1") { first }
map.getElsePut("2") { second }
assertSame(first, map.removeEntry("1").value)
Expand All @@ -120,7 +120,7 @@ internal class FastAccessOrderedStringMapTest {
fun removeTwoWithCollisions() {
val first = Any()
val second = Any()
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
map.getElsePut("1") { first }
map.getElsePut("2") { second }
assertSame(first, map.removeEntry("1").value)
Expand All @@ -130,15 +130,15 @@ internal class FastAccessOrderedStringMapTest {
@Test
fun removeThenSize() {
val first = Any()
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
map.getElsePut("1") { first }
map.removeEntry("1")
assertEquals(0, map.size)
}

@Test
fun removeWhenEmpty() {
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
assertThrows<NoSuchElementException> {
map.removeEntry("1")
}
Expand All @@ -147,7 +147,7 @@ internal class FastAccessOrderedStringMapTest {

@Test
fun clear() {
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
map.getElsePut("1") { Any() }
assertEquals(1, map.size)
map.clear()
Expand All @@ -156,7 +156,7 @@ internal class FastAccessOrderedStringMapTest {

@Test
fun clearWhenEmpty() {
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
map.clear()
assertTrue(map.isEmpty())
}
Expand All @@ -165,7 +165,7 @@ internal class FastAccessOrderedStringMapTest {
fun containsFalse() {
val supplier = mock<() -> Any>()
whenever(supplier.invoke()) doReturn Any()
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
map.getElsePut("1", supplier)
assertFalse(map.containsKey("2"))
}
Expand All @@ -174,7 +174,7 @@ internal class FastAccessOrderedStringMapTest {
fun containsTrue() {
val supplier = mock<() -> Any>()
whenever(supplier.invoke()) doReturn Any()
val map = FastAccessOrderedStringMap<Any>(1)
val map = FastStampedStringMap<Any>(1)
map.getElsePut("1", supplier)
assertTrue(map.containsKey("1"))
}
Expand Down

0 comments on commit 025afc7

Please sign in to comment.