Foundations(iOS Sourceset): Provide implementation for LargeCache, using a CacheMap.
This commit is contained in:
+252
-44
@@ -20,131 +20,172 @@
|
||||
*/
|
||||
package com.vitorpamplona.quartz.utils.cache
|
||||
|
||||
// Need of find a Concurrent/ThreadSafe HashMap in iOS
|
||||
import io.github.charlietap.cachemap.CacheMap
|
||||
import io.github.charlietap.cachemap.cacheMapOf
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlin.collections.plus
|
||||
import kotlin.collections.set
|
||||
|
||||
// An implementation of a Threadsafe map, using CacheMap.
|
||||
// Investigating a Swift-based alternative(for now)
|
||||
actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
private val concurrentMap = cacheMapOf<K, V>()
|
||||
|
||||
actual fun keys(): Set<K> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.keys
|
||||
}
|
||||
|
||||
actual fun values(): Iterable<V> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.values
|
||||
}
|
||||
|
||||
actual fun get(key: K): V? {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap[key]
|
||||
}
|
||||
|
||||
actual fun remove(key: K): V? {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.remove(key)
|
||||
}
|
||||
|
||||
actual fun isEmpty(): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.isEmpty()
|
||||
}
|
||||
|
||||
actual fun clear() {
|
||||
concurrentMap.clear()
|
||||
}
|
||||
|
||||
actual fun containsKey(key: K): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.containsKey(key)
|
||||
}
|
||||
|
||||
actual fun put(
|
||||
key: K,
|
||||
value: V,
|
||||
) {
|
||||
concurrentMap.put(key, value)
|
||||
}
|
||||
|
||||
actual fun getOrCreate(
|
||||
key: K,
|
||||
builder: (K) -> V,
|
||||
): V {
|
||||
TODO("Not yet implemented")
|
||||
val value = concurrentMap.get(key)
|
||||
|
||||
return if (value != null) {
|
||||
value
|
||||
} else {
|
||||
val newObject = builder(key)
|
||||
concurrentMap.put(key, newObject)
|
||||
concurrentMap[key] ?: newObject
|
||||
}
|
||||
}
|
||||
|
||||
actual fun createIfAbsent(
|
||||
key: K,
|
||||
builder: (K) -> V,
|
||||
): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
return runBlocking {
|
||||
val value = concurrentMap.get(key)
|
||||
if (value != null) {
|
||||
false
|
||||
} else {
|
||||
val newObject = builder(key)
|
||||
concurrentMap.put(key, newObject)
|
||||
concurrentMap[key] == null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
actual override fun size(): Int {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.size
|
||||
}
|
||||
|
||||
actual override fun forEach(consumer: ICacheBiConsumer<K, V>) {
|
||||
TODO("Not yet implemented")
|
||||
concurrentMap.forEach { consumer.accept(it.key, it.value) }
|
||||
}
|
||||
|
||||
actual override fun filter(consumer: CacheCollectors.BiFilter<K, V>): List<V> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap
|
||||
.filter { consumer.filter(it.key, it.value) }
|
||||
.values
|
||||
.toList()
|
||||
}
|
||||
|
||||
actual override fun filterIntoSet(consumer: CacheCollectors.BiFilter<K, V>): Set<V> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap
|
||||
.filter { consumer.filter(it.key, it.value) }
|
||||
.values
|
||||
.toSet()
|
||||
}
|
||||
|
||||
actual override fun <R> map(consumer: CacheCollectors.BiNotNullMapper<K, V, R>): List<R> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.map { consumer.map(it.key, it.value) }
|
||||
}
|
||||
|
||||
actual override fun <R> mapNotNull(consumer: CacheCollectors.BiMapper<K, V, R?>): List<R> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.mapNotNull { consumer.map(it.key, it.value) }
|
||||
}
|
||||
|
||||
actual override fun <R> mapNotNullIntoSet(consumer: CacheCollectors.BiMapper<K, V, R?>): Set<R> {
|
||||
TODO("Not yet implemented")
|
||||
return mapNotNull(consumer).toSet()
|
||||
}
|
||||
|
||||
actual override fun <R> mapFlatten(consumer: CacheCollectors.BiMapper<K, V, Collection<R>?>): List<R> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.flatMap { consumer.map(it.key, it.value) as Iterable<R> }
|
||||
}
|
||||
|
||||
actual override fun <R> mapFlattenIntoSet(consumer: CacheCollectors.BiMapper<K, V, Collection<R>?>): Set<R> {
|
||||
TODO("Not yet implemented")
|
||||
return mapFlatten(consumer).toSet()
|
||||
}
|
||||
|
||||
actual override fun maxOrNullOf(
|
||||
filter: CacheCollectors.BiFilter<K, V>,
|
||||
comparator: Comparator<V>,
|
||||
): V? {
|
||||
TODO("Not yet implemented")
|
||||
// return concurrentMap.maxOfWithOrNull(
|
||||
// comparator,
|
||||
// selector = {
|
||||
// if (filter.filter(it.key, it.value)) it.value else concurrentMap.getValue(it.key)
|
||||
// }
|
||||
// )
|
||||
return concurrentMap.maxOrNullOf(filter, comparator)
|
||||
}
|
||||
|
||||
actual override fun sumOf(consumer: CacheCollectors.BiSumOf<K, V>): Int {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.sumOf(consumer)
|
||||
// return concurrentMap.map { consumer.map(it.key, it.value) }.sum()
|
||||
}
|
||||
|
||||
actual override fun sumOfLong(consumer: CacheCollectors.BiSumOfLong<K, V>): Long {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.sumOfLong(consumer)
|
||||
}
|
||||
|
||||
actual override fun <R> groupBy(consumer: CacheCollectors.BiNotNullMapper<K, V, R>): Map<R, List<V>> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.groupBy(consumer)
|
||||
}
|
||||
|
||||
actual override fun <R> countByGroup(consumer: CacheCollectors.BiNotNullMapper<K, V, R>): Map<R, Int> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.countByGroup(consumer)
|
||||
}
|
||||
|
||||
actual override fun <R> sumByGroup(
|
||||
groupMap: CacheCollectors.BiNotNullMapper<K, V, R>,
|
||||
sumOf: CacheCollectors.BiNotNullMapper<K, V, Long>,
|
||||
): Map<R, Long> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.sumByGroup(groupMap, sumOf)
|
||||
}
|
||||
|
||||
actual override fun count(consumer: CacheCollectors.BiFilter<K, V>): Int {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.count { consumer.filter(it.key, it.value) }
|
||||
}
|
||||
|
||||
actual override fun <T, U> associate(transform: (K, V) -> Pair<T, U>): Map<T, U> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.associate(transform)
|
||||
}
|
||||
|
||||
actual override fun <U> associateWith(transform: (K, V) -> U?): Map<K, U?> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.associateWith(transform)
|
||||
}
|
||||
|
||||
actual override fun filter(
|
||||
@@ -152,7 +193,8 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
consumer: CacheCollectors.BiFilter<K, V>,
|
||||
): List<V> {
|
||||
TODO("Not yet implemented")
|
||||
val transientList = concurrentMap.subMapAlt(from, to)
|
||||
return transientList.filter { consumer.filter(it.key, it.value) }.values.toList()
|
||||
}
|
||||
|
||||
actual override fun filterIntoSet(
|
||||
@@ -160,7 +202,7 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
consumer: CacheCollectors.BiFilter<K, V>,
|
||||
): Set<V> {
|
||||
TODO("Not yet implemented")
|
||||
return filter(from, to, consumer).toSet()
|
||||
}
|
||||
|
||||
actual override fun <R> map(
|
||||
@@ -168,7 +210,8 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
consumer: CacheCollectors.BiNotNullMapper<K, V, R>,
|
||||
): List<R> {
|
||||
TODO("Not yet implemented")
|
||||
val transientList = concurrentMap.subMapAlt(from, to)
|
||||
return transientList.map { consumer.map(it.key, it.value) }
|
||||
}
|
||||
|
||||
actual override fun <R> mapNotNull(
|
||||
@@ -176,7 +219,7 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
consumer: CacheCollectors.BiMapper<K, V, R?>,
|
||||
): List<R> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.subMapAlt(from, to).mapNotNull { consumer.map(it.key, it.value) }
|
||||
}
|
||||
|
||||
actual override fun <R> mapNotNullIntoSet(
|
||||
@@ -184,7 +227,7 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
consumer: CacheCollectors.BiMapper<K, V, R?>,
|
||||
): Set<R> {
|
||||
TODO("Not yet implemented")
|
||||
return mapNotNull(from, to, consumer).toSet()
|
||||
}
|
||||
|
||||
actual override fun <R> mapFlatten(
|
||||
@@ -192,7 +235,7 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
consumer: CacheCollectors.BiMapper<K, V, Collection<R>?>,
|
||||
): List<R> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.subMapAlt(from, to).flatMap { consumer.map(it.key, it.value) as Iterable<R> }
|
||||
}
|
||||
|
||||
actual override fun <R> mapFlattenIntoSet(
|
||||
@@ -200,7 +243,7 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
consumer: CacheCollectors.BiMapper<K, V, Collection<R>?>,
|
||||
): Set<R> {
|
||||
TODO("Not yet implemented")
|
||||
return mapFlatten(from, to, consumer).toSet()
|
||||
}
|
||||
|
||||
actual override fun maxOrNullOf(
|
||||
@@ -209,7 +252,8 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
filter: CacheCollectors.BiFilter<K, V>,
|
||||
comparator: Comparator<V>,
|
||||
): V? {
|
||||
TODO("Not yet implemented")
|
||||
val transient = concurrentMap.subMapAlt(from, to)
|
||||
return transient.maxOrNullOf(filter, comparator)
|
||||
}
|
||||
|
||||
actual override fun sumOf(
|
||||
@@ -217,7 +261,7 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
consumer: CacheCollectors.BiSumOf<K, V>,
|
||||
): Int {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.subMapAlt(from, to).sumOf(consumer)
|
||||
}
|
||||
|
||||
actual override fun sumOfLong(
|
||||
@@ -225,7 +269,7 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
consumer: CacheCollectors.BiSumOfLong<K, V>,
|
||||
): Long {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.subMapAlt(from, to).sumOfLong(consumer)
|
||||
}
|
||||
|
||||
actual override fun <R> groupBy(
|
||||
@@ -233,7 +277,7 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
consumer: CacheCollectors.BiNotNullMapper<K, V, R>,
|
||||
): Map<R, List<V>> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.subMapAlt(from, to).groupBy(consumer)
|
||||
}
|
||||
|
||||
actual override fun <R> countByGroup(
|
||||
@@ -241,7 +285,7 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
consumer: CacheCollectors.BiNotNullMapper<K, V, R>,
|
||||
): Map<R, Int> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.subMapAlt(from, to).countByGroup(consumer)
|
||||
}
|
||||
|
||||
actual override fun <R> sumByGroup(
|
||||
@@ -250,7 +294,7 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
groupMap: CacheCollectors.BiNotNullMapper<K, V, R>,
|
||||
sumOf: CacheCollectors.BiNotNullMapper<K, V, Long>,
|
||||
): Map<R, Long> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.subMapAlt(from, to).sumByGroup(groupMap, sumOf)
|
||||
}
|
||||
|
||||
actual override fun count(
|
||||
@@ -258,7 +302,7 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
consumer: CacheCollectors.BiFilter<K, V>,
|
||||
): Int {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.subMapAlt(from, to).count { consumer.filter(it.key, it.value) }
|
||||
}
|
||||
|
||||
actual override fun <T, U> associate(
|
||||
@@ -266,7 +310,7 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
transform: (K, V) -> Pair<T, U>,
|
||||
): Map<T, U> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.subMapAlt(from, to).associate(transform)
|
||||
}
|
||||
|
||||
actual override fun <U> associateWith(
|
||||
@@ -274,7 +318,7 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
to: K,
|
||||
transform: (K, V) -> U?,
|
||||
): Map<K, U?> {
|
||||
TODO("Not yet implemented")
|
||||
return concurrentMap.subMapAlt(from, to).associateWith(transform)
|
||||
}
|
||||
|
||||
actual override fun joinToString(
|
||||
@@ -285,6 +329,170 @@ actual class LargeCache<K, V> : ICacheOperations<K, V> {
|
||||
truncated: CharSequence,
|
||||
transform: ((K, V) -> CharSequence)?,
|
||||
): String {
|
||||
TODO("Not yet implemented")
|
||||
val buffer = StringBuilder()
|
||||
buffer.append(prefix)
|
||||
var count = 0
|
||||
forEach { key, value ->
|
||||
val str = if (transform != null) transform(key, value) else ""
|
||||
if (str.isNotEmpty()) {
|
||||
if (++count > 1) buffer.append(separator)
|
||||
if (limit < 0 || count <= limit) {
|
||||
when {
|
||||
transform != null -> buffer.append(str)
|
||||
else -> buffer.append("$key $value")
|
||||
}
|
||||
} else {
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
}
|
||||
if (limit >= 0 && count > limit) buffer.append(truncated)
|
||||
buffer.append(postfix)
|
||||
return buffer.toString()
|
||||
}
|
||||
}
|
||||
|
||||
// Different subMap implementations below. Investigating their performance for now.
|
||||
|
||||
fun <K, V> CacheMap<K, V>.subMapSlow(from: K, to: K, toInclusive: Boolean = true): Map<K, V> {
|
||||
val transientList = toList()
|
||||
val transientSubList = transientList.subList(
|
||||
fromIndex = transientList.indexOf(Pair(from, getValue(from))),
|
||||
toIndex = transientList.indexOf(Pair(to, getValue(to))),
|
||||
)
|
||||
val completeSubList = transientSubList + Pair(to, getValue(to))
|
||||
|
||||
return if (toInclusive) completeSubList.toMap() else transientSubList.toMap()
|
||||
}
|
||||
|
||||
fun <K, V> CacheMap<K, V>.subMapAlt(from: K, to: K, toInclusive: Boolean = true): Map<K, V> {
|
||||
val resultMap = hashMapOf<K, V>()
|
||||
val keySet = keys
|
||||
val fromIndex = keySet.indexOf(from)
|
||||
val toIndex = keySet.indexOf(to)
|
||||
for (index in fromIndex..toIndex){
|
||||
val correspondingEntry = entries.elementAt(index)
|
||||
resultMap[correspondingEntry.key] = correspondingEntry.value
|
||||
}
|
||||
|
||||
return resultMap
|
||||
}
|
||||
|
||||
/**
|
||||
* The following functions below are (re)implementations for the ICacheOperations
|
||||
* interface. A lot of it is copying and pasting, with modifications to make it work
|
||||
* consistently.
|
||||
*/
|
||||
|
||||
fun <K, V> Map<K, V>.maxOrNullOf(
|
||||
filter: CacheCollectors.BiFilter<K, V>,
|
||||
comparator: Comparator<V>,
|
||||
): V? {
|
||||
var _maxK: K? = null
|
||||
var _maxV: V? = null
|
||||
|
||||
val maxK: K? = _maxK
|
||||
val maxV: V? = _maxV
|
||||
|
||||
forEach {
|
||||
if (filter.filter(it.key, it.value)) {
|
||||
if (_maxK == null || (_maxV != null && comparator.compare(it.value, _maxV) > 0)) {
|
||||
_maxK = it.key
|
||||
_maxV = it.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maxV
|
||||
}
|
||||
|
||||
fun <K,V> Map<K, V>.sumOf(
|
||||
consumer: CacheCollectors.BiSumOf<K, V>,
|
||||
): Int {
|
||||
var sum = 0
|
||||
val totalSum = sum
|
||||
forEach { sum += consumer.map(it.key, it.value) }
|
||||
return totalSum
|
||||
}
|
||||
|
||||
fun <K,V> Map<K, V>.sumOfLong(
|
||||
consumer: CacheCollectors.BiSumOfLong<K, V>,
|
||||
): Long {
|
||||
var sum = 0L
|
||||
val totalSum = sum
|
||||
forEach { sum += consumer.map(it.key, it.value) }
|
||||
return totalSum
|
||||
}
|
||||
|
||||
fun <K, V, R> Map<K, V>.groupBy(
|
||||
consumer: CacheCollectors.BiNotNullMapper<K, V, R>
|
||||
): Map<R, List<V>> {
|
||||
val results = HashMap<R, ArrayList<V>>()
|
||||
forEach {
|
||||
val group = consumer.map(it.key, it.value)
|
||||
val list = results[group]
|
||||
if (list == null) {
|
||||
val answer = ArrayList<V>()
|
||||
answer.add(it.value)
|
||||
results[group] = answer
|
||||
} else {
|
||||
list.add(it.value)
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
fun <K, V, R> Map<K, V>.countByGroup(
|
||||
consumer: CacheCollectors.BiNotNullMapper<K, V, R>
|
||||
): Map<R, Int> {
|
||||
val results = HashMap<R, Int>()
|
||||
forEach {
|
||||
val group = consumer.map(it.key, it.value)
|
||||
val count = results[group]
|
||||
if (count == null) {
|
||||
results[group] = 1
|
||||
} else {
|
||||
results[group] = count + 1
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
fun <K, V, R> Map<K, V>.sumByGroup(
|
||||
groupMap: CacheCollectors.BiNotNullMapper<K, V, R>,
|
||||
sumOf: CacheCollectors.BiNotNullMapper<K, V, Long>,
|
||||
): Map<R, Long> {
|
||||
val results = HashMap<R, Long>()
|
||||
forEach {
|
||||
val group = groupMap.map(it.key, it.value)
|
||||
val sum = results[group]
|
||||
if (sum == null) {
|
||||
results[group] = sumOf.map(it.key, it.value)
|
||||
} else {
|
||||
results[group] = sum + sumOf.map(it.key, it.value)
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
fun <K, V,T, U> Map<K, V>.associate(transform: (K, V) -> Pair<T, U>): Map<T, U> {
|
||||
val results: LinkedHashMap<T, U> = LinkedHashMap(size)
|
||||
forEach {
|
||||
val pair = transform(it.key, it.value)
|
||||
results[pair.first] = pair.second
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
fun <K, V, U> Map<K, V>.associateWith(transform: (K, V) -> U?): Map<K, U?> {
|
||||
val results: LinkedHashMap<K, U?> = LinkedHashMap(size)
|
||||
forEach {
|
||||
results[it.key] = transform(it.key, it.value)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user