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