refactor Stack to "store an interface" i.e. items []Keyer -> interface Keyer { Key() string }
if storing []Keyer instead, i can store a struct that can contain any number of other fields.
65 lines
1.4 KiB
Go
65 lines
1.4 KiB
Go
package stack
|
|
|
|
type Stack struct {
|
|
items []Keyer
|
|
}
|
|
|
|
type Keyer interface {
|
|
Key() string
|
|
}
|
|
|
|
func NewStack(size int) *Stack {
|
|
s := Stack{items: make([]Keyer, 0, size)}
|
|
return &s
|
|
}
|
|
|
|
type EmptyKey struct{}
|
|
func (ek EmptyKey) Key() string {
|
|
return ""
|
|
}
|
|
var Empty EmptyKey
|
|
|
|
// 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)
|
|
}
|
|
|
|
|
|
// get evicted item
|
|
func (s *Stack) Push (newItem Keyer) Keyer {
|
|
if len(s.items) > 0 && s.items[0].Key() == newItem.Key() {
|
|
return Empty
|
|
}
|
|
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 in stack previously, perform in place swap and exit early
|
|
} else if elem.Key() == newItem.Key() {
|
|
s.items[i] = prev
|
|
return Empty
|
|
} else {
|
|
// propagate change outwards in stack, moving all items one step further
|
|
temp := s.items[i]
|
|
s.items[i] = prev
|
|
prev = temp
|
|
}
|
|
}
|
|
// if we have capacity still, append the last item back onto the end of the staack
|
|
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
|
|
}
|
|
return Empty
|
|
}
|
|
|