iterator.go (2387B)
1 package iterators 2 3 import "github.com/clipperhouse/stringish" 4 5 type SplitFunc[T stringish.Interface] func(T, bool) (int, T, error) 6 7 // Iterator is a generic iterator for words that are either []byte or string. 8 // Iterate while Next() is true, and access the word via Value(). 9 type Iterator[T stringish.Interface] struct { 10 split SplitFunc[T] 11 data T 12 start int 13 pos int 14 } 15 16 // New creates a new Iterator for the given data and SplitFunc. 17 func New[T stringish.Interface](split SplitFunc[T], data T) *Iterator[T] { 18 return &Iterator[T]{ 19 split: split, 20 data: data, 21 } 22 } 23 24 // SetText sets the text for the iterator to operate on, and resets all state. 25 func (iter *Iterator[T]) SetText(data T) { 26 iter.data = data 27 iter.start = 0 28 iter.pos = 0 29 } 30 31 // Split sets the SplitFunc for the Iterator. 32 func (iter *Iterator[T]) Split(split SplitFunc[T]) { 33 iter.split = split 34 } 35 36 // Next advances the iterator to the next token. It returns false when there 37 // are no remaining tokens or an error occurred. 38 func (iter *Iterator[T]) Next() bool { 39 if iter.pos == len(iter.data) { 40 return false 41 } 42 if iter.pos > len(iter.data) { 43 panic("SplitFunc advanced beyond the end of the data") 44 } 45 46 iter.start = iter.pos 47 48 advance, _, err := iter.split(iter.data[iter.pos:], true) 49 if err != nil { 50 panic(err) 51 } 52 if advance <= 0 { 53 panic("SplitFunc returned a zero or negative advance") 54 } 55 56 iter.pos += advance 57 if iter.pos > len(iter.data) { 58 panic("SplitFunc advanced beyond the end of the data") 59 } 60 61 return true 62 } 63 64 // Value returns the current token. 65 func (iter *Iterator[T]) Value() T { 66 return iter.data[iter.start:iter.pos] 67 } 68 69 // Start returns the byte position of the current token in the original data. 70 func (iter *Iterator[T]) Start() int { 71 return iter.start 72 } 73 74 // End returns the byte position after the current token in the original data. 75 func (iter *Iterator[T]) End() int { 76 return iter.pos 77 } 78 79 // Reset resets the iterator to the beginning of the data. 80 func (iter *Iterator[T]) Reset() { 81 iter.start = 0 82 iter.pos = 0 83 } 84 85 func (iter *Iterator[T]) First() T { 86 if len(iter.data) == 0 { 87 return iter.data 88 } 89 advance, _, err := iter.split(iter.data, true) 90 if err != nil { 91 panic(err) 92 } 93 if advance <= 0 { 94 panic("SplitFunc returned a zero or negative advance") 95 } 96 if advance > len(iter.data) { 97 panic("SplitFunc advanced beyond the end of the data") 98 } 99 return iter.data[:advance] 100 }