|
|
@@ -0,0 +1,89 @@
|
|
|
+/*
|
|
|
+ * Copyright 2020 Mamoe Technologies and contributors.
|
|
|
+ *
|
|
|
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
|
|
+ * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
|
|
+ *
|
|
|
+ * https://github.com/mamoe/mirai/blob/master/LICENSE
|
|
|
+ */
|
|
|
+
|
|
|
+package net.mamoe.mirai.qqandroid.utils
|
|
|
+
|
|
|
+import kotlinx.atomicfu.AtomicLong
|
|
|
+import kotlinx.atomicfu.atomic
|
|
|
+import kotlinx.atomicfu.locks.reentrantLock
|
|
|
+import kotlinx.atomicfu.locks.withLock
|
|
|
+import net.mamoe.mirai.utils.currentTimeMillis
|
|
|
+import kotlin.jvm.JvmField
|
|
|
+import kotlin.jvm.Volatile
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * Dynamically sized cache list with retention period.
|
|
|
+ * No concurrency guaranteed on same elements.
|
|
|
+ */
|
|
|
+internal class AtomicResizeCacheList<E>(private val retention: Long) {
|
|
|
+ private inner class Cache {
|
|
|
+ @Volatile
|
|
|
+ @JvmField
|
|
|
+ var element: E? = null
|
|
|
+
|
|
|
+ val time: AtomicLong = atomic(0L)
|
|
|
+ }
|
|
|
+
|
|
|
+ companion object {
|
|
|
+ const val initialCapacity: Int = 32
|
|
|
+ }
|
|
|
+
|
|
|
+ private val list: MutableList<Cache> = ArrayList(initialCapacity)
|
|
|
+ private val lock = reentrantLock()
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Adds an element, also cleanup outdated caches, but no duplication is removed.
|
|
|
+ * No concurrency guaranteed on same [element].
|
|
|
+ */
|
|
|
+ private fun add(element: E) {
|
|
|
+ val currentTime = currentTimeMillis
|
|
|
+ findAvailable@ while (true) {
|
|
|
+ for (cache in list) {
|
|
|
+ val instant = cache.time.value
|
|
|
+ when {
|
|
|
+ instant == currentTime -> {
|
|
|
+ if (cache.time.compareAndSet(instant, currentTime + retention)) {
|
|
|
+ cache.element = element
|
|
|
+ return
|
|
|
+ } else continue@findAvailable
|
|
|
+ }
|
|
|
+ // outdated
|
|
|
+ instant < currentTime -> cache.time.compareAndSet(instant, 0)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // no more Cache instance available
|
|
|
+ lock.withLock {
|
|
|
+ list.add(Cache().apply {
|
|
|
+ this.element = element
|
|
|
+ this.time.value = currentTime + retention
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * No concurrency guaranteed on same [element]
|
|
|
+ */
|
|
|
+ private fun removeDuplication(element: E): Boolean {
|
|
|
+ val duplicate = list.firstOrNull { it.element == element } ?: return false
|
|
|
+ duplicate.time.value = 0
|
|
|
+ return true
|
|
|
+ }
|
|
|
+
|
|
|
+ fun ensureNoDuplication(element: E): Boolean {
|
|
|
+ return if (removeDuplication(element)) {
|
|
|
+ false
|
|
|
+ } else {
|
|
|
+ add(element)
|
|
|
+ true
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|