github.com/gofiber/fiber/v2@v2.47.0/middleware/cache/heap.go (about)

     1  package cache
     2  
     3  import (
     4  	"container/heap"
     5  )
     6  
     7  type heapEntry struct {
     8  	key   string
     9  	exp   uint64
    10  	bytes uint
    11  	idx   int
    12  }
    13  
    14  // indexedHeap is a regular min-heap that allows finding
    15  // elements in constant time. It does so by handing out special indices
    16  // and tracking entry movement.
    17  //
    18  // indexdedHeap is used for quickly finding entries with the lowest
    19  // expiration timestamp and deleting arbitrary entries.
    20  type indexedHeap struct {
    21  	// Slice the heap is built on
    22  	entries []heapEntry
    23  	// Mapping "index" to position in heap slice
    24  	indices []int
    25  	// Max index handed out
    26  	maxidx int
    27  }
    28  
    29  func (h indexedHeap) Len() int {
    30  	return len(h.entries)
    31  }
    32  
    33  func (h indexedHeap) Less(i, j int) bool {
    34  	return h.entries[i].exp < h.entries[j].exp
    35  }
    36  
    37  func (h indexedHeap) Swap(i, j int) {
    38  	h.entries[i], h.entries[j] = h.entries[j], h.entries[i]
    39  	h.indices[h.entries[i].idx] = i
    40  	h.indices[h.entries[j].idx] = j
    41  }
    42  
    43  func (h *indexedHeap) Push(x interface{}) {
    44  	h.pushInternal(x.(heapEntry)) //nolint:forcetypeassert // Forced type assertion required to implement the heap.Interface interface
    45  }
    46  
    47  func (h *indexedHeap) Pop() interface{} {
    48  	n := len(h.entries)
    49  	h.entries = h.entries[0 : n-1]
    50  	return h.entries[0:n][n-1]
    51  }
    52  
    53  func (h *indexedHeap) pushInternal(entry heapEntry) {
    54  	h.indices[entry.idx] = len(h.entries)
    55  	h.entries = append(h.entries, entry)
    56  }
    57  
    58  // Returns index to track entry
    59  func (h *indexedHeap) put(key string, exp uint64, bytes uint) int {
    60  	idx := 0
    61  	if len(h.entries) < h.maxidx {
    62  		// Steal index from previously removed entry
    63  		// capacity > size is guaranteed
    64  		n := len(h.entries)
    65  		idx = h.entries[:n+1][n].idx
    66  	} else {
    67  		idx = h.maxidx
    68  		h.maxidx++
    69  		h.indices = append(h.indices, idx)
    70  	}
    71  	// Push manually to avoid allocation
    72  	h.pushInternal(heapEntry{
    73  		key: key, exp: exp, idx: idx, bytes: bytes,
    74  	})
    75  	heap.Fix(h, h.Len()-1)
    76  	return idx
    77  }
    78  
    79  func (h *indexedHeap) removeInternal(realIdx int) (string, uint) {
    80  	x := heap.Remove(h, realIdx).(heapEntry) //nolint:forcetypeassert,errcheck // Forced type assertion required to implement the heap.Interface interface
    81  	return x.key, x.bytes
    82  }
    83  
    84  // Remove entry by index
    85  func (h *indexedHeap) remove(idx int) (string, uint) {
    86  	return h.removeInternal(h.indices[idx])
    87  }
    88  
    89  // Remove entry with lowest expiration time
    90  func (h *indexedHeap) removeFirst() (string, uint) {
    91  	return h.removeInternal(0)
    92  }