github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/niterator/ordone/iterator.go (about)

     1  package ordone
     2  
     3  import (
     4  	"io"
     5  
     6  	"github.com/egonelbre/exp/niterator/shape"
     7  )
     8  
     9  type Iterator struct {
    10  	*shape.AP
    11  
    12  	Track     []int
    13  	NextIndex int
    14  	Done      bool
    15  }
    16  
    17  func NewIterator(ap *shape.AP) *Iterator {
    18  	return &Iterator{
    19  		AP:    ap,
    20  		Track: make([]int, len(ap.Shape)),
    21  	}
    22  }
    23  
    24  func (it *Iterator) IsDone() bool {
    25  	return it.Done
    26  }
    27  
    28  func (it *Iterator) Next() (int, error) {
    29  	if it.Done {
    30  		return 0, io.EOF
    31  	}
    32  
    33  	last := len(it.Shape) - 1
    34  	next := it.NextIndex
    35  	result := next
    36  
    37  	// the following 3 lines causes the compiler to perform bounds check here,
    38  	// instead of being done in the loop
    39  	coord := it.Shape[:last+1]
    40  	track := it.Track[:last+1]
    41  	stride := it.Stride[:last+1]
    42  	for i := last; i >= 0; i-- {
    43  		track[i]++
    44  		shapeI := coord[i]
    45  		strideI := stride[i]
    46  
    47  		if track[i] == shapeI {
    48  			it.Done = i == 0
    49  			track[i] = 0
    50  			next -= (shapeI - 1) * strideI
    51  			continue
    52  		}
    53  		next += strideI
    54  		break
    55  	}
    56  	it.NextIndex = next
    57  	return result, nil
    58  }