mirror of
https://github.com/luxfi/utils.git
synced 2026-07-27 06:54:45 +00:00
133 lines
2.7 KiB
Go
133 lines
2.7 KiB
Go
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package heap
|
|
|
|
import (
|
|
"container/heap"
|
|
|
|
"github.com/luxfi/utils"
|
|
)
|
|
|
|
var _ heap.Interface = (*indexedQueue[int, int])(nil)
|
|
|
|
func MapValues[K comparable, V any](m Map[K, V]) []V {
|
|
result := make([]V, 0, m.Len())
|
|
for _, e := range m.queue.entries {
|
|
result = append(result, e.v)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// NewMap returns a heap without duplicates ordered by its values
|
|
func NewMap[K comparable, V any](less func(a, b V) bool) Map[K, V] {
|
|
return Map[K, V]{
|
|
queue: &indexedQueue[K, V]{
|
|
queue: queue[entry[K, V]]{
|
|
less: func(a, b entry[K, V]) bool {
|
|
return less(a.v, b.v)
|
|
},
|
|
},
|
|
index: make(map[K]int),
|
|
},
|
|
}
|
|
}
|
|
|
|
type Map[K comparable, V any] struct {
|
|
queue *indexedQueue[K, V]
|
|
}
|
|
|
|
// Push returns the evicted previous value if present
|
|
func (m *Map[K, V]) Push(k K, v V) (V, bool) {
|
|
if i, ok := m.queue.index[k]; ok {
|
|
prev := m.queue.entries[i]
|
|
m.queue.entries[i].v = v
|
|
heap.Fix(m.queue, i)
|
|
return prev.v, true
|
|
}
|
|
|
|
heap.Push(m.queue, entry[K, V]{k: k, v: v})
|
|
return utils.Zero[V](), false
|
|
}
|
|
|
|
func (m *Map[K, V]) Pop() (K, V, bool) {
|
|
if m.Len() == 0 {
|
|
return utils.Zero[K](), utils.Zero[V](), false
|
|
}
|
|
|
|
popped := heap.Pop(m.queue).(entry[K, V])
|
|
return popped.k, popped.v, true
|
|
}
|
|
|
|
func (m *Map[K, V]) Peek() (K, V, bool) {
|
|
if m.Len() == 0 {
|
|
return utils.Zero[K](), utils.Zero[V](), false
|
|
}
|
|
|
|
entry := m.queue.entries[0]
|
|
return entry.k, entry.v, true
|
|
}
|
|
|
|
func (m *Map[K, V]) Len() int {
|
|
return m.queue.Len()
|
|
}
|
|
|
|
func (m *Map[K, V]) Remove(k K) (V, bool) {
|
|
if i, ok := m.queue.index[k]; ok {
|
|
removed := heap.Remove(m.queue, i).(entry[K, V])
|
|
return removed.v, true
|
|
}
|
|
return utils.Zero[V](), false
|
|
}
|
|
|
|
func (m *Map[K, V]) Contains(k K) bool {
|
|
_, ok := m.queue.index[k]
|
|
return ok
|
|
}
|
|
|
|
func (m *Map[K, V]) Get(k K) (V, bool) {
|
|
if i, ok := m.queue.index[k]; ok {
|
|
got := m.queue.entries[i]
|
|
return got.v, true
|
|
}
|
|
return utils.Zero[V](), false
|
|
}
|
|
|
|
func (m *Map[K, V]) Fix(k K) {
|
|
if i, ok := m.queue.index[k]; ok {
|
|
heap.Fix(m.queue, i)
|
|
}
|
|
}
|
|
|
|
type indexedQueue[K comparable, V any] struct {
|
|
queue[entry[K, V]]
|
|
index map[K]int
|
|
}
|
|
|
|
func (h *indexedQueue[K, V]) Swap(i, j int) {
|
|
h.entries[i], h.entries[j] = h.entries[j], h.entries[i]
|
|
h.index[h.entries[i].k], h.index[h.entries[j].k] = i, j
|
|
}
|
|
|
|
func (h *indexedQueue[K, V]) Push(x any) {
|
|
entry := x.(entry[K, V])
|
|
h.entries = append(h.entries, entry)
|
|
h.index[entry.k] = len(h.index)
|
|
}
|
|
|
|
func (h *indexedQueue[K, V]) Pop() any {
|
|
end := len(h.entries) - 1
|
|
|
|
popped := h.entries[end]
|
|
h.entries[end] = entry[K, V]{}
|
|
h.entries = h.entries[:end]
|
|
|
|
delete(h.index, popped.k)
|
|
return popped
|
|
}
|
|
|
|
type entry[K any, V any] struct {
|
|
k K
|
|
v V
|
|
}
|