diff --git a/internal/util/util.go b/internal/util/util.go new file mode 100644 index 0000000..3f490dc --- /dev/null +++ b/internal/util/util.go @@ -0,0 +1,101 @@ +package util + +import "image/color" + +// IndexOf returns the index of needle within haystack. If needle does not exist +// within haystack, it returns -1. +func IndexOf[T comparable] (haystack []T, needle T) int { + for index, test := range haystack { + if test == needle { + return index + } + } + return -1 +} + +// Remove removes an element from slice at index. +func Remove[T any] (slice []T, index int) []T { + return append(slice[:index], slice[index + 1:]...) +} + +// Insert inserts an element into slice at index. +func Insert[T any] (slice []T, index int, element T) []T { + slice = append(slice[:index + 1], slice[index:]...) + slice[index] = element + return slice +} + +// Transparent returns whether or not a color has transparency. +func Transparent (c color.Color) bool { + _, _, _, a := c.RGBA() + return a != 0xFFFF +} + +// Set is a set of unique items, built on top of map. +type Set[T comparable] map[T] struct { } + +// Empty returns true if there are no items in the set. +func (set Set[T]) Empty () bool { + return set == nil || len(set) == 0 +} + +// Has returns true if the set contains item. +func (set Set[T]) Has (item T) bool { + if set == nil { + return false + } + _, ok := set[item] + return ok +} + +// Add adds an item to the set. +func (set Set[T]) Add (item T) { + set[item] = struct { } { } +} + +// Pop removes the first accessible item from the set and returns it. +func (set Set[T]) Pop () (item T) { + for item := range set { + delete(set, item) + return item + } + return +} + +// Memo holds a cached value. +type Memo[T any] struct { + cache T + valid bool + update func () T +} + +// NewMemo creates a new Memo which will take its value from the specified +// update callback. +func NewMemo[T any] (update func () T) Memo[T] { + return Memo[T] { + update: update, + } +} + +// Value returns the Memo's value, updating it if the current cached value is +// invalid. +func (this *Memo[T]) Value () T { + if !this.valid { + this.cache = this.update() + } + return this.cache +} + +// Invalidate marks the Memo's value as invalid, which will cause it to be +// updated the next time Value is called. +func (this *Memo[T]) Invalidate () { + this.valid = false +} + +// InvalidateTo invalidates the Memo and sets its value. The new value will be +// entirely inaccessible. This is only intended to be used for setting a +// reference to nil +func (this *Memo[T]) InvalidateTo (value T) { + this.Invalidate() + this.cache = value +}