/* Package "iterator" */ package iterator import "fmt" // An iterator over slices. type Iterator[T any] struct { data []T index int } // Create a new iterator, over a set of items. func New[T any](items []T) *Iterator[T] { return &Iterator[T]{data: items, index: 0} } // Returns the current position of the iterator. func (i Iterator[T]) Index() int { return i.index } // Returns true if the iterator has no more items to iterate over. func (i Iterator[T]) IsDone() bool { return i.index == len(i.data) } // Gets the next item in the slice, if one exists. Returns an error if there // isn't one. func (i Iterator[T]) Peek() (T, error) { var null T if i.IsDone() { return null, fmt.Errorf("iterator is exhausted") } return i.data[i.index], nil } // Moves the iterator pointer to the next item. Returns the current item. Fails // if there are no more items to iterate over. func (i *Iterator[T]) Pop() (T, error) { val, err := i.Peek() if err != nil { return val, err } i.index++ return val, nil } // Pop until the clause returns false. func (i *Iterator[T]) PopWhile(fn func(T) bool) []T { result := []T{} for { popped, err := i.Peek() if err != nil || !fn(popped) { break } result = append(result, popped) if _, err := i.Pop(); err != nil { break } } return result }