mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-10-04 20:32:30 +02:00
Merge pull request #1411 from davotoula/reduce-duplications-large-cache
Reduce duplications: large cache
This commit is contained in:
@@ -0,0 +1,367 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.quartz.utils
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.utils.CacheCollectors.BiFilter
|
||||||
|
import com.vitorpamplona.quartz.utils.CacheCollectors.BiMapper
|
||||||
|
import com.vitorpamplona.quartz.utils.CacheCollectors.BiMapperNotNull
|
||||||
|
import com.vitorpamplona.quartz.utils.CacheCollectors.BiNotNullMapper
|
||||||
|
import com.vitorpamplona.quartz.utils.CacheCollectors.BiSumOfLong
|
||||||
|
import java.util.function.BiConsumer
|
||||||
|
|
||||||
|
class BiFilterCollector<K, V>(
|
||||||
|
private val filter: BiFilter<K, V>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results: ArrayList<V> = ArrayList()
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
if (filter.filter(k, v)) {
|
||||||
|
results.add(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiFilterUniqueCollector<K, V>(
|
||||||
|
private val filter: BiFilter<K, V>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results: HashSet<V> = HashSet()
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
if (filter.filter(k, v)) {
|
||||||
|
results.add(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiMapCollector<K, V, R>(
|
||||||
|
private val mapper: BiMapper<K, V, R?>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results: ArrayList<R> = ArrayList()
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
val result = mapper.map(k, v)
|
||||||
|
if (result != null) {
|
||||||
|
results.add(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiMapUniqueCollector<K, V, R>(
|
||||||
|
private val mapper: BiMapper<K, V, R?>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results: HashSet<R> = HashSet()
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
val result = mapper.map(k, v)
|
||||||
|
if (result != null) {
|
||||||
|
results.add(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiMapFlattenCollector<K, V, R>(
|
||||||
|
private val mapper: BiMapper<K, V, Collection<R>?>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results: ArrayList<R> = ArrayList()
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
val result = mapper.map(k, v)
|
||||||
|
if (result != null) {
|
||||||
|
results.addAll(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiMapFlattenUniqueCollector<K, V, R>(
|
||||||
|
private val mapper: BiMapper<K, V, Collection<R>?>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results: HashSet<R> = HashSet()
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
val result = mapper.map(k, v)
|
||||||
|
if (result != null) {
|
||||||
|
results.addAll(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiNotNullMapCollector<K, V, R>(
|
||||||
|
private val mapper: BiNotNullMapper<K, V, R>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results: ArrayList<R> = ArrayList()
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
results.add(mapper.map(k, v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiMaxOfCollector<K, V>(
|
||||||
|
private val filter: BiFilter<K, V>,
|
||||||
|
private val comparator: Comparator<V>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
private var _maxK: K? = null
|
||||||
|
private var _maxV: V? = null
|
||||||
|
|
||||||
|
val maxK: K? get() = _maxK
|
||||||
|
val maxV: V? get() = _maxV
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
if (filter.filter(k, v)) {
|
||||||
|
if (_maxK == null || comparator.compare(v, _maxV) > 0) {
|
||||||
|
_maxK = k
|
||||||
|
_maxV = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiSumOfCollector<K, V>(
|
||||||
|
private val mapper: CacheCollectors.BiSumOf<K, V>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
private var _sum = 0
|
||||||
|
val sum: Int get() = _sum
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
_sum += mapper.map(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiSumOfLongCollector<K, V>(
|
||||||
|
private val mapper: BiSumOfLong<K, V>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
private var _sum = 0L
|
||||||
|
val sum: Long get() = _sum
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
_sum += mapper.map(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiGroupByCollector<K, V, R>(
|
||||||
|
private val mapper: BiNotNullMapper<K, V, R>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results = HashMap<R, ArrayList<V>>()
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
val group = mapper.map(k, v)
|
||||||
|
val list = results[group]
|
||||||
|
if (list == null) {
|
||||||
|
val answer = ArrayList<V>()
|
||||||
|
answer.add(v)
|
||||||
|
results[group] = answer
|
||||||
|
} else {
|
||||||
|
list.add(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiCountByGroupCollector<K, V, R>(
|
||||||
|
private val mapper: BiNotNullMapper<K, V, R>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results = HashMap<R, Int>()
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
val group = mapper.map(k, v)
|
||||||
|
val count = results[group]
|
||||||
|
if (count == null) {
|
||||||
|
results[group] = 1
|
||||||
|
} else {
|
||||||
|
results[group] = count + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiSumByGroupCollector<K, V, R>(
|
||||||
|
private val mapper: BiNotNullMapper<K, V, R>,
|
||||||
|
private val sumOf: BiNotNullMapper<K, V, Long>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results = HashMap<R, Long>()
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
val group = mapper.map(k, v)
|
||||||
|
val sum = results[group]
|
||||||
|
if (sum == null) {
|
||||||
|
results[group] = sumOf.map(k, v)
|
||||||
|
} else {
|
||||||
|
results[group] = sum + sumOf.map(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiCountIfCollector<K, V>(
|
||||||
|
private val filter: BiFilter<K, V>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
private var _count = 0
|
||||||
|
val count: Int get() = _count
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
if (filter.filter(k, v)) _count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiAssociateCollector<K, V, T, U>(
|
||||||
|
size: Int,
|
||||||
|
private val mapper: BiMapperNotNull<K, V, Pair<T, U>>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results: LinkedHashMap<T, U> = LinkedHashMap(size)
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
val pair = mapper.map(k, v)
|
||||||
|
results[pair.first] = pair.second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiAssociateNotNullCollector<K, V, T, U>(
|
||||||
|
size: Int,
|
||||||
|
private val mapper: BiMapper<K, V, Pair<T, U>?>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results: LinkedHashMap<T, U> = LinkedHashMap(size)
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
val pair = mapper.map(k, v)
|
||||||
|
if (pair != null) {
|
||||||
|
results[pair.first] = pair.second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiAssociateWithCollector<K, V, U>(
|
||||||
|
size: Int,
|
||||||
|
private val mapper: BiMapper<K, V, U?>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results: LinkedHashMap<K, U?> = LinkedHashMap(size)
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
results[k] = mapper.map(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BiAssociateNotNullWithCollector<K, V, U>(
|
||||||
|
size: Int,
|
||||||
|
private val mapper: BiMapper<K, V, U>,
|
||||||
|
) : BiConsumer<K, V> {
|
||||||
|
val results: LinkedHashMap<K, U> = LinkedHashMap(size)
|
||||||
|
|
||||||
|
override fun accept(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
) {
|
||||||
|
val newValue = mapper.map(k, v)
|
||||||
|
if (newValue != null) {
|
||||||
|
results[k] = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object CacheCollectors {
|
||||||
|
fun interface BiFilter<K, V> {
|
||||||
|
fun filter(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface BiMapper<K, V, R> {
|
||||||
|
fun map(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
): R?
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface BiMapperNotNull<K, V, R> {
|
||||||
|
fun map(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
): R
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface BiNotNullMapper<K, V, R> {
|
||||||
|
fun map(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
): R
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface BiSumOf<K, V> {
|
||||||
|
fun map(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface BiSumOfLong<K, V> {
|
||||||
|
fun map(
|
||||||
|
k: K,
|
||||||
|
v: V,
|
||||||
|
): Long
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,161 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.quartz.utils
|
||||||
|
|
||||||
|
import java.util.function.BiConsumer
|
||||||
|
|
||||||
|
interface CacheOperations<K, V> {
|
||||||
|
fun forEach(consumer: BiConsumer<K, V>)
|
||||||
|
|
||||||
|
fun size(): Int
|
||||||
|
|
||||||
|
fun filter(consumer: CacheCollectors.BiFilter<K, V>): List<V> {
|
||||||
|
val runner = BiFilterCollector(consumer)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.results
|
||||||
|
}
|
||||||
|
|
||||||
|
fun filterIntoSet(consumer: CacheCollectors.BiFilter<K, V>): Set<V> {
|
||||||
|
val runner = BiFilterUniqueCollector(consumer)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.results
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R> map(consumer: CacheCollectors.BiNotNullMapper<K, V, R>): List<R> {
|
||||||
|
val runner = BiNotNullMapCollector(consumer)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.results
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R> mapNotNull(consumer: CacheCollectors.BiMapper<K, V, R?>): List<R> {
|
||||||
|
val runner = BiMapCollector(consumer)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.results
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R> mapNotNullIntoSet(consumer: CacheCollectors.BiMapper<K, V, R?>): Set<R> {
|
||||||
|
val runner = BiMapUniqueCollector(consumer)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.results
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R> mapFlatten(consumer: CacheCollectors.BiMapper<K, V, Collection<R>?>): List<R> {
|
||||||
|
val runner = BiMapFlattenCollector(consumer)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.results
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R> mapFlattenIntoSet(consumer: CacheCollectors.BiMapper<K, V, Collection<R>?>): Set<R> {
|
||||||
|
val runner = BiMapFlattenUniqueCollector(consumer)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.results
|
||||||
|
}
|
||||||
|
|
||||||
|
fun maxOrNullOf(
|
||||||
|
filter: CacheCollectors.BiFilter<K, V>,
|
||||||
|
comparator: Comparator<V>,
|
||||||
|
): V? {
|
||||||
|
val runner = BiMaxOfCollector(filter, comparator)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.maxV
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sumOf(consumer: CacheCollectors.BiSumOf<K, V>): Int {
|
||||||
|
val runner = BiSumOfCollector(consumer)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.sum
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sumOfLong(consumer: CacheCollectors.BiSumOfLong<K, V>): Long {
|
||||||
|
val runner = BiSumOfLongCollector(consumer)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.sum
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R> groupBy(consumer: CacheCollectors.BiNotNullMapper<K, V, R>): Map<R, List<V>> {
|
||||||
|
val runner = BiGroupByCollector(consumer)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.results
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R> countByGroup(consumer: CacheCollectors.BiNotNullMapper<K, V, R>): Map<R, Int> {
|
||||||
|
val runner = BiCountByGroupCollector(consumer)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.results
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <R> sumByGroup(
|
||||||
|
groupMap: CacheCollectors.BiNotNullMapper<K, V, R>,
|
||||||
|
sumOf: CacheCollectors.BiNotNullMapper<K, V, Long>,
|
||||||
|
): Map<R, Long> {
|
||||||
|
val runner = BiSumByGroupCollector(groupMap, sumOf)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.results
|
||||||
|
}
|
||||||
|
|
||||||
|
fun count(consumer: CacheCollectors.BiFilter<K, V>): Int {
|
||||||
|
val runner = BiCountIfCollector(consumer)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.count
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T, U> associate(transform: (K, V) -> Pair<T, U>): Map<T, U> {
|
||||||
|
val runner = BiAssociateCollector(size(), transform)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.results
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <U> associateWith(transform: (K, V) -> U?): Map<K, U?> {
|
||||||
|
val runner = BiAssociateWithCollector(size(), transform)
|
||||||
|
forEach(runner)
|
||||||
|
return runner.results
|
||||||
|
}
|
||||||
|
|
||||||
|
fun joinToString(
|
||||||
|
separator: CharSequence = ", ",
|
||||||
|
prefix: CharSequence = "",
|
||||||
|
postfix: CharSequence = "",
|
||||||
|
limit: Int = -1,
|
||||||
|
truncated: CharSequence = "...",
|
||||||
|
transform: ((K, V) -> CharSequence)? = null,
|
||||||
|
): String {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
@@ -23,7 +23,7 @@ package com.vitorpamplona.quartz.utils
|
|||||||
import java.util.concurrent.ConcurrentSkipListMap
|
import java.util.concurrent.ConcurrentSkipListMap
|
||||||
import java.util.function.BiConsumer
|
import java.util.function.BiConsumer
|
||||||
|
|
||||||
class LargeCache<K, V> {
|
class LargeCache<K, V> : CacheOperations<K, V> {
|
||||||
private val cache = ConcurrentSkipListMap<K, V>()
|
private val cache = ConcurrentSkipListMap<K, V>()
|
||||||
|
|
||||||
fun keys() = cache.keys
|
fun keys() = cache.keys
|
||||||
@@ -34,7 +34,7 @@ class LargeCache<K, V> {
|
|||||||
|
|
||||||
fun remove(key: K) = cache.remove(key)
|
fun remove(key: K) = cache.remove(key)
|
||||||
|
|
||||||
fun size() = cache.size
|
override fun size() = cache.size
|
||||||
|
|
||||||
fun isEmpty() = cache.isEmpty()
|
fun isEmpty() = cache.isEmpty()
|
||||||
|
|
||||||
@@ -76,489 +76,7 @@ class LargeCache<K, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun forEach(consumer: BiConsumer<K, V>) {
|
override fun forEach(consumer: BiConsumer<K, V>) {
|
||||||
innerForEach(consumer)
|
cache.forEach(consumer)
|
||||||
}
|
|
||||||
|
|
||||||
fun filter(consumer: BiFilter<K, V>): List<V> {
|
|
||||||
val runner = BiFilterCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun filterIntoSet(consumer: BiFilter<K, V>): Set<V> {
|
|
||||||
val runner = BiFilterUniqueCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> map(consumer: BiNotNullMapper<K, V, R>): List<R> {
|
|
||||||
val runner = BiNotNullMapCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> mapNotNull(consumer: BiMapper<K, V, R?>): List<R> {
|
|
||||||
val runner = BiMapCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> mapNotNullIntoSet(consumer: BiMapper<K, V, R?>): Set<R> {
|
|
||||||
val runner = BiMapUniqueCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> mapFlatten(consumer: BiMapper<K, V, Collection<R>?>): List<R> {
|
|
||||||
val runner = BiMapFlattenCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> mapFlattenIntoSet(consumer: BiMapper<K, V, Collection<R>?>): Set<R> {
|
|
||||||
val runner = BiMapFlattenUniqueCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun maxOrNullOf(
|
|
||||||
filter: BiFilter<K, V>,
|
|
||||||
comparator: Comparator<V>,
|
|
||||||
): V? {
|
|
||||||
val runner = BiMaxOfCollector(filter, comparator)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.maxV
|
|
||||||
}
|
|
||||||
|
|
||||||
fun sumOf(consumer: BiSumOf<K, V>): Int {
|
|
||||||
val runner = BiSumOfCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.sum
|
|
||||||
}
|
|
||||||
|
|
||||||
fun sumOfLong(consumer: BiSumOfLong<K, V>): Long {
|
|
||||||
val runner = BiSumOfLongCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.sum
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> groupBy(consumer: BiNotNullMapper<K, V, R>): Map<R, List<V>> {
|
|
||||||
val runner = BiGroupByCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> countByGroup(consumer: BiNotNullMapper<K, V, R>): Map<R, Int> {
|
|
||||||
val runner = BiCountByGroupCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> sumByGroup(
|
|
||||||
groupMap: BiNotNullMapper<K, V, R>,
|
|
||||||
sumOf: BiNotNullMapper<K, V, Long>,
|
|
||||||
): Map<R, Long> {
|
|
||||||
val runner = BiSumByGroupCollector(groupMap, sumOf)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun count(consumer: BiFilter<K, V>): Int {
|
|
||||||
val runner = BiCountIfCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.count
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T, U> associate(transform: (K, V) -> Pair<T, U>): Map<T, U> {
|
|
||||||
val runner = BiAssociateCollector(size(), transform)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T, U> associateNotNull(transform: (K, V) -> Pair<T, U>?): Map<T, U> {
|
|
||||||
val runner = BiAssociateNotNullCollector(size(), transform)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <U> associateWith(transform: (K, V) -> U?): Map<K, U?> {
|
|
||||||
val runner = BiAssociateWithCollector(size(), transform)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <U> associateNotNullWith(transform: (K, V) -> U): Map<K, U> {
|
|
||||||
val runner = BiAssociateNotNullWithCollector(size(), transform)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun innerForEach(runner: BiConsumer<K, V>) {
|
|
||||||
cache.forEach(runner)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun joinToString(
|
|
||||||
separator: CharSequence = ", ",
|
|
||||||
prefix: CharSequence = "",
|
|
||||||
postfix: CharSequence = "",
|
|
||||||
limit: Int = -1,
|
|
||||||
truncated: CharSequence = "...",
|
|
||||||
transform: ((K, V) -> CharSequence)? = null,
|
|
||||||
): String {
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface BiFilter<K, V> {
|
|
||||||
fun filter(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
): Boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiFilterCollector<K, V>(
|
|
||||||
val filter: BiFilter<K, V>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: ArrayList<V> = ArrayList()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
if (filter.filter(k, v)) {
|
|
||||||
results.add(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiFilterUniqueCollector<K, V>(
|
|
||||||
val filter: BiFilter<K, V>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: HashSet<V> = HashSet()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
if (filter.filter(k, v)) {
|
|
||||||
results.add(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface BiMapper<K, V, R> {
|
|
||||||
fun map(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
): R?
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface BiMapperNotNull<K, V, R> {
|
|
||||||
fun map(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
): R
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiMapCollector<K, V, R>(
|
|
||||||
val mapper: BiMapper<K, V, R?>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: ArrayList<R> = ArrayList()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val result = mapper.map(k, v)
|
|
||||||
if (result != null) {
|
|
||||||
results.add(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiAssociateCollector<K, V, T, U>(
|
|
||||||
val size: Int,
|
|
||||||
val mapper: BiMapperNotNull<K, V, Pair<T, U>>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: LinkedHashMap<T, U> = LinkedHashMap(size)
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val pair = mapper.map(k, v)
|
|
||||||
results.put(pair.first, pair.second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiAssociateNotNullCollector<K, V, T, U>(
|
|
||||||
val size: Int,
|
|
||||||
val mapper: BiMapper<K, V, Pair<T, U>?>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: LinkedHashMap<T, U> = LinkedHashMap(size)
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val pair = mapper.map(k, v)
|
|
||||||
if (pair != null) {
|
|
||||||
results.put(pair.first, pair.second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiAssociateWithCollector<K, V, U>(
|
|
||||||
val size: Int,
|
|
||||||
val mapper: BiMapper<K, V, U?>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: LinkedHashMap<K, U?> = LinkedHashMap(size)
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
results.put(k, mapper.map(k, v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiAssociateNotNullWithCollector<K, V, U>(
|
|
||||||
val size: Int,
|
|
||||||
val mapper: BiMapper<K, V, U>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: LinkedHashMap<K, U> = LinkedHashMap(size)
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val newValue = mapper.map(k, v)
|
|
||||||
if (newValue != null) {
|
|
||||||
results.put(k, newValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiMapUniqueCollector<K, V, R>(
|
|
||||||
val mapper: BiMapper<K, V, R?>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: HashSet<R> = HashSet()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val result = mapper.map(k, v)
|
|
||||||
if (result != null) {
|
|
||||||
results.add(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiMapFlattenCollector<K, V, R>(
|
|
||||||
val mapper: BiMapper<K, V, Collection<R>?>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: ArrayList<R> = ArrayList()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val result = mapper.map(k, v)
|
|
||||||
if (result != null) {
|
|
||||||
results.addAll(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiMapFlattenUniqueCollector<K, V, R>(
|
|
||||||
val mapper: BiMapper<K, V, Collection<R>?>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: HashSet<R> = HashSet()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val result = mapper.map(k, v)
|
|
||||||
if (result != null) {
|
|
||||||
results.addAll(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface BiNotNullMapper<K, V, R> {
|
|
||||||
fun map(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
): R
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiNotNullMapCollector<K, V, R>(
|
|
||||||
val mapper: BiNotNullMapper<K, V, R>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: ArrayList<R> = ArrayList()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
results.add(mapper.map(k, v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface BiSumOf<K, V> {
|
|
||||||
fun map(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
): Int
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiMaxOfCollector<K, V>(
|
|
||||||
val filter: BiFilter<K, V>,
|
|
||||||
val comparator: Comparator<V>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var maxK: K? = null
|
|
||||||
var maxV: V? = null
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
if (filter.filter(k, v)) {
|
|
||||||
if (maxK == null || comparator.compare(v, maxV) > 0) {
|
|
||||||
maxK = k
|
|
||||||
maxV = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiSumOfCollector<K, V>(
|
|
||||||
val mapper: BiSumOf<K, V>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var sum = 0
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
sum += mapper.map(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface BiSumOfLong<K, V> {
|
|
||||||
fun map(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
): Long
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiSumOfLongCollector<K, V>(
|
|
||||||
val mapper: BiSumOfLong<K, V>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var sum = 0L
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
sum += mapper.map(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiGroupByCollector<K, V, R>(
|
|
||||||
val mapper: BiNotNullMapper<K, V, R>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results = HashMap<R, ArrayList<V>>()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val group = mapper.map(k, v)
|
|
||||||
|
|
||||||
val list = results[group]
|
|
||||||
if (list == null) {
|
|
||||||
val answer = ArrayList<V>()
|
|
||||||
answer.add(v)
|
|
||||||
results[group] = answer
|
|
||||||
} else {
|
|
||||||
list.add(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiCountByGroupCollector<K, V, R>(
|
|
||||||
val mapper: BiNotNullMapper<K, V, R>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results = HashMap<R, Int>()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val group = mapper.map(k, v)
|
|
||||||
|
|
||||||
val count = results[group]
|
|
||||||
if (count == null) {
|
|
||||||
results[group] = 1
|
|
||||||
} else {
|
|
||||||
results[group] = count + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiSumByGroupCollector<K, V, R>(
|
|
||||||
val mapper: BiNotNullMapper<K, V, R>,
|
|
||||||
val sumOf: BiNotNullMapper<K, V, Long>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results = HashMap<R, Long>()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val group = mapper.map(k, v)
|
|
||||||
|
|
||||||
val sum = results[group]
|
|
||||||
if (sum == null) {
|
|
||||||
results[group] = sumOf.map(k, v)
|
|
||||||
} else {
|
|
||||||
results[group] = sum + sumOf.map(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiCountIfCollector<K, V>(
|
|
||||||
val filter: BiFilter<K, V>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var count = 0
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
if (filter.filter(k, v)) count++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -24,7 +24,7 @@ import java.lang.ref.WeakReference
|
|||||||
import java.util.concurrent.ConcurrentSkipListMap
|
import java.util.concurrent.ConcurrentSkipListMap
|
||||||
import java.util.function.BiConsumer
|
import java.util.function.BiConsumer
|
||||||
|
|
||||||
class LargeSoftCache<K, V> {
|
class LargeSoftCache<K, V> : CacheOperations<K, V> {
|
||||||
private val cache = ConcurrentSkipListMap<K, WeakReference<V>>()
|
private val cache = ConcurrentSkipListMap<K, WeakReference<V>>()
|
||||||
|
|
||||||
fun keys() = cache.keys
|
fun keys() = cache.keys
|
||||||
@@ -43,7 +43,7 @@ class LargeSoftCache<K, V> {
|
|||||||
|
|
||||||
fun remove(key: K) = cache.remove(key)
|
fun remove(key: K) = cache.remove(key)
|
||||||
|
|
||||||
fun size() = cache.size
|
override fun size() = cache.size
|
||||||
|
|
||||||
fun isEmpty() = cache.isEmpty()
|
fun isEmpty() = cache.isEmpty()
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ class LargeSoftCache<K, V> {
|
|||||||
key: K,
|
key: K,
|
||||||
builder: (key: K) -> V,
|
builder: (key: K) -> V,
|
||||||
): V {
|
): V {
|
||||||
val softRef = cache.get(key)
|
val softRef = cache[key]
|
||||||
val value = softRef?.get()
|
val value = softRef?.get()
|
||||||
|
|
||||||
return if (value != null) {
|
return if (value != null) {
|
||||||
@@ -89,20 +89,6 @@ class LargeSoftCache<K, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createIfAbsent(
|
|
||||||
key: K,
|
|
||||||
builder: (key: K) -> V,
|
|
||||||
): Boolean {
|
|
||||||
val softRef = cache.get(key)
|
|
||||||
val value = softRef?.get()
|
|
||||||
return if (value != null) {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
val newObject = builder(key)
|
|
||||||
cache.putIfAbsent(key, WeakReference(newObject)) == null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Proactively cleans up the cache by removing entries whose weakly referenced
|
* Proactively cleans up the cache by removing entries whose weakly referenced
|
||||||
* objects have been garbage collected. While `get` handles cleanup on access,
|
* objects have been garbage collected. While `get` handles cleanup on access,
|
||||||
@@ -122,156 +108,8 @@ class LargeSoftCache<K, V> {
|
|||||||
println("Cache cleanup completed. Remaining size: ${cache.size}")
|
println("Cache cleanup completed. Remaining size: ${cache.size}")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun forEach(consumer: BiConsumer<K, V>) {
|
override fun forEach(consumer: BiConsumer<K, V>) {
|
||||||
innerForEach(consumer)
|
cache.forEach(BiConsumerWrapper(this, consumer))
|
||||||
}
|
|
||||||
|
|
||||||
fun filter(consumer: BiFilter<K, V>): List<V> {
|
|
||||||
val runner = BiFilterCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun filterIntoSet(consumer: BiFilter<K, V>): Set<V> {
|
|
||||||
val runner = BiFilterUniqueCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> map(consumer: BiNotNullMapper<K, V, R>): List<R> {
|
|
||||||
val runner = BiNotNullMapCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> mapNotNull(consumer: BiMapper<K, V, R?>): List<R> {
|
|
||||||
val runner = BiMapCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> mapNotNullIntoSet(consumer: BiMapper<K, V, R?>): Set<R> {
|
|
||||||
val runner = BiMapUniqueCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> mapFlatten(consumer: BiMapper<K, V, Collection<R>?>): List<R> {
|
|
||||||
val runner = BiMapFlattenCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> mapFlattenIntoSet(consumer: BiMapper<K, V, Collection<R>?>): Set<R> {
|
|
||||||
val runner = BiMapFlattenUniqueCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun maxOrNullOf(
|
|
||||||
filter: BiFilter<K, V>,
|
|
||||||
comparator: Comparator<V>,
|
|
||||||
): V? {
|
|
||||||
val runner = BiMaxOfCollector(filter, comparator)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.maxV
|
|
||||||
}
|
|
||||||
|
|
||||||
fun sumOf(consumer: BiSumOf<K, V>): Int {
|
|
||||||
val runner = BiSumOfCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.sum
|
|
||||||
}
|
|
||||||
|
|
||||||
fun sumOfLong(consumer: BiSumOfLong<K, V>): Long {
|
|
||||||
val runner = BiSumOfLongCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.sum
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> groupBy(consumer: BiNotNullMapper<K, V, R>): Map<R, List<V>> {
|
|
||||||
val runner = BiGroupByCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> countByGroup(consumer: BiNotNullMapper<K, V, R>): Map<R, Int> {
|
|
||||||
val runner = BiCountByGroupCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <R> sumByGroup(
|
|
||||||
groupMap: BiNotNullMapper<K, V, R>,
|
|
||||||
sumOf: BiNotNullMapper<K, V, Long>,
|
|
||||||
): Map<R, Long> {
|
|
||||||
val runner = BiSumByGroupCollector(groupMap, sumOf)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun count(consumer: BiFilter<K, V>): Int {
|
|
||||||
val runner = BiCountIfCollector(consumer)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.count
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T, U> associate(transform: (K, V) -> Pair<T, U>): Map<T, U> {
|
|
||||||
val runner = BiAssociateCollector(size(), transform)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T, U> associateNotNull(transform: (K, V) -> Pair<T, U>?): Map<T, U> {
|
|
||||||
val runner = BiAssociateNotNullCollector(size(), transform)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <U> associateWith(transform: (K, V) -> U?): Map<K, U?> {
|
|
||||||
val runner = BiAssociateWithCollector(size(), transform)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <U> associateNotNullWith(transform: (K, V) -> U): Map<K, U> {
|
|
||||||
val runner = BiAssociateNotNullWithCollector(size(), transform)
|
|
||||||
innerForEach(runner)
|
|
||||||
return runner.results
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun innerForEach(runner: BiConsumer<K, V>) {
|
|
||||||
cache.forEach(BiConsumerWrapper(this, runner))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun joinToString(
|
|
||||||
separator: CharSequence = ", ",
|
|
||||||
prefix: CharSequence = "",
|
|
||||||
postfix: CharSequence = "",
|
|
||||||
limit: Int = -1,
|
|
||||||
truncated: CharSequence = "...",
|
|
||||||
transform: ((K, V) -> CharSequence)? = null,
|
|
||||||
): String {
|
|
||||||
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()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class BiConsumerWrapper<K, V>(
|
class BiConsumerWrapper<K, V>(
|
||||||
@@ -290,338 +128,4 @@ class LargeSoftCache<K, V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun interface BiFilter<K, V> {
|
|
||||||
fun filter(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
): Boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiFilterCollector<K, V>(
|
|
||||||
val filter: BiFilter<K, V>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: ArrayList<V> = ArrayList()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
if (filter.filter(k, v)) {
|
|
||||||
results.add(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiFilterUniqueCollector<K, V>(
|
|
||||||
val filter: BiFilter<K, V>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: HashSet<V> = HashSet()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
if (filter.filter(k, v)) {
|
|
||||||
results.add(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface BiMapper<K, V, R> {
|
|
||||||
fun map(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
): R?
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface BiMapperNotNull<K, V, R> {
|
|
||||||
fun map(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
): R
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiMapCollector<K, V, R>(
|
|
||||||
val mapper: BiMapper<K, V, R?>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: ArrayList<R> = ArrayList()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val result = mapper.map(k, v)
|
|
||||||
if (result != null) {
|
|
||||||
results.add(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiAssociateCollector<K, V, T, U>(
|
|
||||||
val size: Int,
|
|
||||||
val mapper: BiMapperNotNull<K, V, Pair<T, U>>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: LinkedHashMap<T, U> = LinkedHashMap(size)
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val pair = mapper.map(k, v)
|
|
||||||
results.put(pair.first, pair.second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiAssociateNotNullCollector<K, V, T, U>(
|
|
||||||
val size: Int,
|
|
||||||
val mapper: BiMapper<K, V, Pair<T, U>?>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: LinkedHashMap<T, U> = LinkedHashMap(size)
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val pair = mapper.map(k, v)
|
|
||||||
if (pair != null) {
|
|
||||||
results.put(pair.first, pair.second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiAssociateWithCollector<K, V, U>(
|
|
||||||
val size: Int,
|
|
||||||
val mapper: BiMapper<K, V, U?>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: LinkedHashMap<K, U?> = LinkedHashMap(size)
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
results.put(k, mapper.map(k, v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiAssociateNotNullWithCollector<K, V, U>(
|
|
||||||
val size: Int,
|
|
||||||
val mapper: BiMapper<K, V, U>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: LinkedHashMap<K, U> = LinkedHashMap(size)
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val newValue = mapper.map(k, v)
|
|
||||||
if (newValue != null) {
|
|
||||||
results.put(k, newValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiMapUniqueCollector<K, V, R>(
|
|
||||||
val mapper: BiMapper<K, V, R?>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: HashSet<R> = HashSet()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val result = mapper.map(k, v)
|
|
||||||
if (result != null) {
|
|
||||||
results.add(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiMapFlattenCollector<K, V, R>(
|
|
||||||
val mapper: BiMapper<K, V, Collection<R>?>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: ArrayList<R> = ArrayList()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val result = mapper.map(k, v)
|
|
||||||
if (result != null) {
|
|
||||||
results.addAll(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiMapFlattenUniqueCollector<K, V, R>(
|
|
||||||
val mapper: BiMapper<K, V, Collection<R>?>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: HashSet<R> = HashSet()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val result = mapper.map(k, v)
|
|
||||||
if (result != null) {
|
|
||||||
results.addAll(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface BiNotNullMapper<K, V, R> {
|
|
||||||
fun map(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
): R
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiNotNullMapCollector<K, V, R>(
|
|
||||||
val mapper: BiNotNullMapper<K, V, R>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results: ArrayList<R> = ArrayList()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
results.add(mapper.map(k, v))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface BiSumOf<K, V> {
|
|
||||||
fun map(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
): Int
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiMaxOfCollector<K, V>(
|
|
||||||
val filter: BiFilter<K, V>,
|
|
||||||
val comparator: Comparator<V>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var maxK: K? = null
|
|
||||||
var maxV: V? = null
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
if (filter.filter(k, v)) {
|
|
||||||
if (maxK == null || comparator.compare(v, maxV) > 0) {
|
|
||||||
maxK = k
|
|
||||||
maxV = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiSumOfCollector<K, V>(
|
|
||||||
val mapper: BiSumOf<K, V>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var sum = 0
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
sum += mapper.map(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface BiSumOfLong<K, V> {
|
|
||||||
fun map(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
): Long
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiSumOfLongCollector<K, V>(
|
|
||||||
val mapper: BiSumOfLong<K, V>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var sum = 0L
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
sum += mapper.map(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiGroupByCollector<K, V, R>(
|
|
||||||
val mapper: BiNotNullMapper<K, V, R>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results = HashMap<R, ArrayList<V>>()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val group = mapper.map(k, v)
|
|
||||||
|
|
||||||
val list = results[group]
|
|
||||||
if (list == null) {
|
|
||||||
val answer = ArrayList<V>()
|
|
||||||
answer.add(v)
|
|
||||||
results[group] = answer
|
|
||||||
} else {
|
|
||||||
list.add(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiCountByGroupCollector<K, V, R>(
|
|
||||||
val mapper: BiNotNullMapper<K, V, R>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results = HashMap<R, Int>()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val group = mapper.map(k, v)
|
|
||||||
|
|
||||||
val count = results[group]
|
|
||||||
if (count == null) {
|
|
||||||
results[group] = 1
|
|
||||||
} else {
|
|
||||||
results[group] = count + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiSumByGroupCollector<K, V, R>(
|
|
||||||
val mapper: BiNotNullMapper<K, V, R>,
|
|
||||||
val sumOf: BiNotNullMapper<K, V, Long>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var results = HashMap<R, Long>()
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
val group = mapper.map(k, v)
|
|
||||||
|
|
||||||
val sum = results[group]
|
|
||||||
if (sum == null) {
|
|
||||||
results[group] = sumOf.map(k, v)
|
|
||||||
} else {
|
|
||||||
results[group] = sum + sumOf.map(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BiCountIfCollector<K, V>(
|
|
||||||
val filter: BiFilter<K, V>,
|
|
||||||
) : BiConsumer<K, V> {
|
|
||||||
var count = 0
|
|
||||||
|
|
||||||
override fun accept(
|
|
||||||
k: K,
|
|
||||||
v: V,
|
|
||||||
) {
|
|
||||||
if (filter.filter(k, v)) count++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user