github.com/primecitizens/pcz/std@v0.2.1/core/iter/iter.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 4 // Package iter. 5 package iter 6 7 // Core is the minimal interface of an iterator. 8 // 9 // Rationales choosing interface over function for iterator definition: 10 // 11 // - Implicit allocations: interface values can use mark.Noescape to avoid 12 // allocation but functions cannot, closures always allocate unless 13 // properly inlined by the compiler, which is not something controlled 14 // by application developers (at the time of go1.21). 15 // 16 // Drawbacks of interface: 17 // 18 // - One concrete type can only implement one iterator interface, some types 19 // may need multiple iterator implementations. 20 // A workaround is to define `type OtherTree Tree` and use pointer type 21 // cast for iterator implementation. 22 type Core[Elem any] interface { 23 // Nth returns the n-th element, the returned bool value indicates whether 24 // the element exists. 25 // 26 // It is required to support the 1-step [0, end) range as input sequence, 27 // in which case Nth(int) MUST function exactly the same way as Next() would. 28 // 29 // Caller SHOULD assume the implementation only supports the iteration 30 // style implied by the above requirement: 31 // 32 // for i := 0; ; i++ { 33 // elem, ok := iter.Nth(i) 34 // if !ok { 35 // break 36 // } 37 // 38 // _ = elem 39 // } 40 // 41 // Following features are optional: 42 // 43 // - Negative n (index from end) 44 // - Step more than 1 (calling with non-consecutive n) 45 // - Backward iteration (calling with n from high to low) 46 // - Arbitrary iteration (calling with unordered n) 47 // 48 // Rationales choosing Nth(int) instead of Next() as core iterator function: 49 // 50 // - Passing an integer argument is cheap (a register in ABIInternal). 51 // - Nth(int) is Next() when called with a sequence of ascending numbers. 52 // (per implementation requirement) 53 // - Nth(int) may skip unwanted elements without extraneous call. 54 // - Nth(int) may step-backward with no external caching. 55 // - Nth(int) is more friendly to slices. 56 // - Nth(int) may be used with binary search to get the total length 57 // of the iterator (when unknown). 58 // - Stateless values can use the integer passed in to decide when to 59 // stop iteration, otherwise an additional Next() style iterator 60 // should be implemented. 61 Nth(int) (Elem, bool) 62 } 63 64 // Func implements Core for function. 65 type Func[Elem any] func(int) (Elem, bool) 66 67 func (fn Func[Elem]) Nth(i int) (Elem, bool) { 68 return fn(i) 69 } 70 71 // Finite is implemented by iterators with a finite number of elements. 72 type Finite interface { 73 // Len returns the count of elements a iterator may produce. 74 Len() int 75 } 76 77 // Divisible is implemented by iterators can be divided into multiple 78 // sub-iterators. 79 type Divisible[Self any] interface { 80 // SliceFrom returns a sub-iterator by slicing at the `start` of current 81 // itertor, it resembles the native `x[start:]` operation. 82 SliceFrom(start int) Self 83 } 84 85 // Interface is the most complete iterator interface covers most use cases 86 // of an iterator. 87 type Interface[T, Self any] interface { 88 Core[T] 89 Divisible[Self] 90 Finite 91 } 92 93 // CanSkip should be implemented by iterators support skipping elements 94 // during a single iteration. 95 // 96 // Hint: embed iter.MarkCanSkip. 97 type CanSkip interface { 98 IterCanSkip() 99 } 100 101 // CanBackward should be implemented by iterators support backward iteration 102 // (from higher to lower). 103 // 104 // Hint: embed iter.MarkCanBackward. 105 type CanBackward interface { 106 IterCanBackward() 107 } 108 109 // CanIndexFromEnd should be implemented by iterators support negative 110 // argument to Nth(int) method. 111 // 112 // Hint: embed iter.MarkCanIndexFromEnd. 113 type CanIndexFromEnd interface { 114 IterCanIndexFromEnd() 115 } 116 117 // MarkCanSkip is a zero size implementation of CanSkip. 118 type MarkCanSkip struct{} 119 120 func (MarkCanSkip) IterCanSkip() {} 121 122 // MarkCanBackward is a zero size implementation of CanBackward. 123 type MarkCanBackward struct{} 124 125 func (MarkCanBackward) IterCanBackward() {} 126 127 // MarkCanIndexFromEnd is a zero size implementation of CanIndexFromEnd. 128 type MarkCanIndexFromEnd struct{} 129 130 func (MarkCanIndexFromEnd) IterCanIndexFromEnd() {}