Files
iroh-tracker/stack/stack.go
T

76 lines
2.3 KiB
Go

package stack
type Stack struct {
items []Keyer
}
// things that are to be in the stack have to implement Key() string
type Keyer interface {
Key() string
}
func NewStack(size int) *Stack {
s := Stack{items: make([]Keyer, 0, size)}
return &s
}
// TODO (2026-10-16): look up how to make a proper enumerable / iterable array in golang
// it is apparently relatively recent (2024): https://go.dev/blog/range-functions
func (s* Stack) Items() []Keyer {
return s.items
}
func (s* Stack) Size() int {
return len(s.items)
}
// attempt to push newItem on stack. maintains the pointer of the first instance of item being pushed on stack
//
// if newItem WAS on the stack stack
// * bumps value that was already on stack to top of stack
// * return the value that was already in the stack and false (no eviction)
//
// if newItem WAS NOT on the stack:
// * put newItem at top of stack, and..
// * returns newItem and false (no eviction) if stack was below capacity
// * returns evicted item and true (eviction) if stack was above capacity
// NOTE (2026-10-29): bit complex tho init?
const ITEM_EVICTED = true
func (s *Stack) Push (newItem Keyer) (Keyer, bool) {
// stack below capacity, and newItem was at front of stack - exit early
if len(s.items) > 0 && s.items[0].Key() == newItem.Key() {
return newItem, !ITEM_EVICTED
}
prev := newItem
for i, elem := range s.items {
// insert newItem at front
if i == 0 {
prev = s.items[0]
s.items[0] = newItem
// newItem was already in stack, perform in place swap and exit early
} else if elem.Key() == newItem.Key() {
s.items[i] = prev
s.items[0] = elem // ignore value of newItem and re-use what was already in stack instead
// return the previously stored value / pointer
return elem, !ITEM_EVICTED
// propagate change outwards in stack, moving all items one step further
} else {
temp := s.items[i]
s.items[i] = prev
prev = temp
}
}
// newItem wasn't in stack, we might need to evict an item depending on current capacity
// if we still have capacity, append the last item back onto the end of the stack
if len(s.items) < cap(s.items) {
s.items = append(s.items, prev)
} else {
// we evict the list item, forgetting about it and return the evicted item
return prev, ITEM_EVICTED
}
return newItem, !ITEM_EVICTED
}