@@ -20,17 +20,33 @@ package com.lambda.util.collections
2020import java.time.Instant
2121import java.util.concurrent.ConcurrentLinkedQueue
2222
23+ /* *
24+ * A thread-safe collection that limits the number of elements it can hold and automatically removes elements
25+ * older than a specified time interval. The elements are stored with the timestamp of their addition to the collection.
26+ *
27+ * @param E The type of elements held in this collection.
28+ * @property sizeLimit The maximum number of elements the queue can hold at any given time.
29+ * @property maxAge The age (in milliseconds) after which elements are considered expired and are removed from the queue.
30+ */
2331class LimitedDecayQueue <E >(
2432 private var sizeLimit : Int ,
25- private var interval : Long ,
26- ) {
33+ private var maxAge : Long ,
34+ ) : AbstractMutableCollection<E>() {
2735 private val queue: ConcurrentLinkedQueue <Pair <E , Instant >> = ConcurrentLinkedQueue ()
2836
29- val size: Int
30- get() = queue.size
37+ override val size: Int
38+ get() {
39+ cleanUp()
40+ return queue.size
41+ }
42+
43+ override fun iterator (): MutableIterator <E > {
44+ cleanUp()
45+ return queue.map { it.first }.iterator() as MutableIterator <E >
46+ }
3147
3248 @Synchronized
33- fun add (element : E ): Boolean {
49+ override fun add (element : E ): Boolean {
3450 cleanUp()
3551 return if (queue.size < sizeLimit) {
3652 queue.add(element to Instant .now())
@@ -41,21 +57,63 @@ class LimitedDecayQueue<E>(
4157 }
4258
4359 @Synchronized
44- fun setMaxSize (newSize : Int ) {
45- sizeLimit = newSize
60+ override fun addAll (elements : Collection <E >): Boolean {
61+ cleanUp()
62+ val spaceAvailable = sizeLimit - queue.size
63+ val elementsToAdd = elements.take(spaceAvailable)
64+ val added = elementsToAdd.map { queue.add(it to Instant .now()) }
65+ return added.any { it }
66+ }
67+
68+ @Synchronized
69+ override fun remove (element : E ): Boolean {
70+ cleanUp()
71+ return queue.removeIf { it.first == element }
72+ }
73+
74+ @Synchronized
75+ override fun removeAll (elements : Collection <E >): Boolean {
4676 cleanUp()
77+ return queue.removeIf { it.first in elements }
4778 }
4879
4980 @Synchronized
50- fun setInterval (newInterval : Long ) {
51- interval = newInterval
81+ override fun retainAll (elements : Collection <E >): Boolean {
5282 cleanUp()
83+ return queue.removeIf { it.first !in elements }
5384 }
5485
5586 @Synchronized
87+ override fun clear () {
88+ queue.clear()
89+ }
90+
91+ /* *
92+ * Updates the maximum allowed size for the queue and triggers a cleanup operation
93+ * to remove elements exceeding the new size or falling outside the allowed time interval.
94+ *
95+ * @param newSize The new maximum size for the queue. Must be a non-negative integer.
96+ */
97+ fun setMaxSize (newSize : Int ) {
98+ sizeLimit = newSize
99+ cleanUp()
100+ }
101+
102+ /* *
103+ * Sets the decay time for the elements in the queue. The decay time determines the
104+ * maximum age that any element in the queue can have before being considered expired
105+ * and removed. Updates the internal state and triggers a cleanup of expired elements.
106+ *
107+ * @param decayTime The decay time in milliseconds. Must be a non-negative value.
108+ */
109+ fun setDecayTime (decayTime : Long ) {
110+ maxAge = decayTime
111+ cleanUp()
112+ }
113+
56114 private fun cleanUp () {
57115 val now = Instant .now()
58- while (queue.isNotEmpty() && now.minusMillis(interval ).isAfter(queue.peek().second)) {
116+ while (queue.isNotEmpty() && now.minusMillis(maxAge ).isAfter(queue.peek().second)) {
59117 queue.poll()
60118 }
61119 }
0 commit comments