src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

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 }