github.com/haraldrudell/parl@v0.4.176/iters/slice1.go (about)

     1  /*
     2  © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/)
     3  ISC License
     4  */
     5  
     6  package iters
     7  
     8  import (
     9  	"github.com/haraldrudell/parl/internal/cyclebreaker"
    10  )
    11  
    12  // Slice traverses a slice container. thread-safe
    13  type Slice1[T any] struct {
    14  	slice []T // the slice providing values
    15  	// index is next slice-index to return
    16  	//	- if index == len(slice) there are no more values
    17  	index int
    18  }
    19  
    20  // NewSliceIterator returns an iterator iterating over slice T values
    21  //   - thread-safe
    22  //   - uses non-pointer atomics
    23  func NewSlice1Iterator[T any](slice []T) (iterator Iterator[T]) { return &Slice[T]{slice: slice} }
    24  
    25  // Init implements the right-hand side of a short variable declaration in
    26  // the init statement for a Go “for” clause
    27  //
    28  // Usage:
    29  //
    30  //		for i, iterator := NewSlicePointerIterator(someSlice).Init(); iterator.Cond(&i); {
    31  //	   // i is pointer to slice element
    32  func (i *Slice1[T]) Init() (iterationVariable T, iterator Iterator[T]) {
    33  	iterator = i
    34  	return
    35  }
    36  
    37  // Cond implements the condition statement of a Go “for” clause
    38  //   - the iterationVariable is updated by being provided as a pointer.
    39  //     iterationVariable cannot be nil
    40  //   - errp is an optional error pointer receiving any errors during iterator execution
    41  //   - condition is true if iterationVariable was assigned a value and the iteration should continue
    42  //
    43  // Usage:
    44  //
    45  //		for i, iterator := NewSlicePointerIterator(someSlice).Init(); iterator.Cond(&i); {
    46  //	   // i is pointer to slice element
    47  func (i *Slice1[T]) Cond(iterationVariablep *T, errp ...*error) (condition bool) {
    48  	if iterationVariablep == nil {
    49  		cyclebreaker.NilError("iterationVariablep")
    50  	}
    51  
    52  	// check for next value
    53  	var value T
    54  	if value, condition = i.Next(); condition {
    55  		*iterationVariablep = value
    56  	}
    57  
    58  	return // condition and iterationVariablep updated, errp unchanged
    59  }
    60  
    61  // Next advances to next item and returns it
    62  //   - if hasValue true, value contains the next value
    63  //   - otherwise, no more items exist and value is the data type zero-value
    64  func (i *Slice1[T]) Next() (value T, hasValue bool) {
    65  	var index = i.index
    66  	if hasValue = index < len(i.slice); !hasValue {
    67  		return // no more values
    68  	}
    69  	value = i.slice[index]
    70  	i.index++
    71  
    72  	return
    73  }
    74  
    75  // Cancel release resources for this iterator. Thread-safe
    76  //   - not every iterator requires a Cancel invocation
    77  func (i *Slice1[T]) Cancel(errp ...*error) (err error) {
    78  	i.slice = nil
    79  	return
    80  }