86 lines
2.2 KiB
Go
86 lines
2.2 KiB
Go
|
package ttlcache
|
||
|
|
||
|
import (
|
||
|
"container/heap"
|
||
|
"container/list"
|
||
|
)
|
||
|
|
||
|
// expirationQueue stores items that are ordered by their expiration
|
||
|
// timestamps. The 0th item is closest to its expiration.
|
||
|
type expirationQueue[K comparable, V any] []*list.Element
|
||
|
|
||
|
// newExpirationQueue creates and initializes a new expiration queue.
|
||
|
func newExpirationQueue[K comparable, V any]() expirationQueue[K, V] {
|
||
|
q := make(expirationQueue[K, V], 0)
|
||
|
heap.Init(&q)
|
||
|
return q
|
||
|
}
|
||
|
|
||
|
// isEmpty checks if the queue is empty.
|
||
|
func (q expirationQueue[K, V]) isEmpty() bool {
|
||
|
return q.Len() == 0
|
||
|
}
|
||
|
|
||
|
// update updates an existing item's value and position in the queue.
|
||
|
func (q *expirationQueue[K, V]) update(elem *list.Element) {
|
||
|
heap.Fix(q, elem.Value.(*Item[K, V]).queueIndex)
|
||
|
}
|
||
|
|
||
|
// push pushes a new item into the queue and updates the order of its
|
||
|
// elements.
|
||
|
func (q *expirationQueue[K, V]) push(elem *list.Element) {
|
||
|
heap.Push(q, elem)
|
||
|
}
|
||
|
|
||
|
// remove removes an item from the queue and updates the order of its
|
||
|
// elements.
|
||
|
func (q *expirationQueue[K, V]) remove(elem *list.Element) {
|
||
|
heap.Remove(q, elem.Value.(*Item[K, V]).queueIndex)
|
||
|
}
|
||
|
|
||
|
// Len returns the total number of items in the queue.
|
||
|
func (q expirationQueue[K, V]) Len() int {
|
||
|
return len(q)
|
||
|
}
|
||
|
|
||
|
// Less checks if the item at the i position expires sooner than
|
||
|
// the one at the j position.
|
||
|
func (q expirationQueue[K, V]) Less(i, j int) bool {
|
||
|
item1, item2 := q[i].Value.(*Item[K, V]), q[j].Value.(*Item[K, V])
|
||
|
if item1.expiresAt.IsZero() {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
if item2.expiresAt.IsZero() {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
return item1.expiresAt.Before(item2.expiresAt)
|
||
|
}
|
||
|
|
||
|
// Swap switches the places of two queue items.
|
||
|
func (q expirationQueue[K, V]) Swap(i, j int) {
|
||
|
q[i], q[j] = q[j], q[i]
|
||
|
q[i].Value.(*Item[K, V]).queueIndex = i
|
||
|
q[j].Value.(*Item[K, V]).queueIndex = j
|
||
|
}
|
||
|
|
||
|
// Push appends a new item to the item slice.
|
||
|
func (q *expirationQueue[K, V]) Push(x interface{}) {
|
||
|
elem := x.(*list.Element)
|
||
|
elem.Value.(*Item[K, V]).queueIndex = len(*q)
|
||
|
*q = append(*q, elem)
|
||
|
}
|
||
|
|
||
|
// Pop removes and returns the last item.
|
||
|
func (q *expirationQueue[K, V]) Pop() interface{} {
|
||
|
old := *q
|
||
|
i := len(old) - 1
|
||
|
elem := old[i]
|
||
|
elem.Value.(*Item[K, V]).queueIndex = -1
|
||
|
old[i] = nil // avoid memory leak
|
||
|
*q = old[:i]
|
||
|
|
||
|
return elem
|
||
|
}
|