Skip to content

Commit

Permalink
v0.4.118 iters optimized for Go “for” clause
Browse files Browse the repository at this point in the history
  • Loading branch information
haraldrudell committed Oct 30, 2023
1 parent ae0f641 commit 4bb102e
Show file tree
Hide file tree
Showing 21 changed files with 301 additions and 151 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ toolchain go1.21.3

require (
github.com/google/btree v1.1.2
github.com/haraldrudell/parl/yamler v0.4.116
github.com/haraldrudell/parl/yamler v0.4.117
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
golang.org/x/sys v0.13.0
golang.org/x/text v0.13.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/haraldrudell/parl/yamler v0.4.116 h1:bi45DW6izbhntjC93ZQyaNERPiu2SwpkAh4cCyQJDkw=
github.com/haraldrudell/parl/yamler v0.4.116/go.mod h1:2VF8uKY0EV6eTDWQXAowD7liuG/zt8szyoC3eS31NsI=
github.com/haraldrudell/parl/yamler v0.4.117 h1:GCjl9mEvTYaeymWDU+ZGjP8illDcFQJBEQsa1v19LnA=
github.com/haraldrudell/parl/yamler v0.4.117/go.mod h1:VeafJ+gpRUHRPdE4wa3rODro1XKCjL+6gVMo5xY8FVY=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
Expand Down
9 changes: 5 additions & 4 deletions if-enum.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package parl
import (
"fmt"

"github.com/haraldrudell/parl/iters"
"golang.org/x/exp/constraints"
)

Expand Down Expand Up @@ -36,16 +37,16 @@ type KeyEnum[K constraints.Ordered, T any] interface {

// K

IsKey(key K) (isKey bool) // IsKey checks whether key maps to an enumerated value
Value(key K) (enum T, err error) // Value looks up an enumerated value by key
KeyIterator() (iterator Iterator[K]) // KeyIterator returns an iterator that iterates over all keys in order of definition
IsKey(key K) (isKey bool) // IsKey checks whether key maps to an enumerated value
Value(key K) (enum T, err error) // Value looks up an enumerated value by key
KeyIterator() (iterator iters.Iterator[K]) // KeyIterator returns an iterator that iterates over all keys in order of definition

// T

IsValid(enum T) (isEnumValue bool) // IsValid checks whether value is among enumerated values
Key(value T) (key K, err error) // Key gets the key value for an enumerated T value
ValueAny(value any) (enum T, err error) // ValueAny attempts to convert any value to a T enumerated value
Iterator() (iterator Iterator[T]) // Iterator returns an iterator that iterates over all enumerated values in order of definition
Iterator() (iterator iters.Iterator[T]) // Iterator returns an iterator that iterates over all enumerated values in order of definition
Description(enum T) (desc string) // Description gets a descriptive sentence for an enum value
StringT(enum T) (s string) // StringT provides a string representation for an enumeration value
// Compare compares two T values.
Expand Down
48 changes: 0 additions & 48 deletions if-iterator.go

This file was deleted.

84 changes: 64 additions & 20 deletions iters/base-iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,70 @@ func NewBaseIterator[T any](
return &BaseIterator[T]{baseIterator: &i}
}

// Cond implements the condition statement of a Go “for” clause
// - the iterationVariable is updated by being provided as a pointer.
// iterationVariable cannot be nil
// - errp is an optional error pointer receiving any errors during iterator execution
// - condition is true if iterationVariable was assigned a value and the iteration should continue
func (i *baseIterator[T]) Cond(iterationVariablep *T, errp ...*error) (condition bool) {
if iterationVariablep == nil {
perrors.NewPF("iterationVariablep cannot bee nil")
}

// handle error
if ep := i.err.Load(); ep != nil {
if err := *ep; err != nil {
if len(errp) > 0 {
if errp0 := errp[0]; errp0 != nil {
*errp0 = err // update errp with error
}
}
return // error return: cond false, iterationVariablep unchanged, errp updated
}
}

// check for next value
var value T
if value, condition = i.delegateAction(IsNext); condition {
*iterationVariablep = value
}

return // condition and iterationVariablep updated, errp unchanged
}

// Cancel release resources for this iterator.
// Not every iterator requires a Cancel invocation.
func (i *baseIterator[T]) Cancel(errp ...*error) (err error) {

// ignore if cancel alread invoked
if !i.cancelState.CompareAndSwap(uint32(notCanceled), uint32(cancelRequested)) {
i.errWait.Wait()
if err = *i.err.Load(); err != nil {
if len(errp) > 0 {
if ep := errp[0]; ep != nil {
*ep = perrors.AppendError(*ep, err)
}
}
}
return // already beyond cancel
}

// wait for access to fn
i.publicsLock.Lock()
defer i.publicsLock.Unlock()

_, _, err = i.enqueueForFn(enqueueForFnCancel)
if err != nil {
if len(errp) > 0 {
if ep := errp[0]; ep != nil {
*ep = perrors.AppendError(*ep, err)
}
}
}

return
}

// delegateAction finds the next or the same value
// - isSame true means first or same value should be returned
// - value is the sought value or the T type’s zero-value if no value exists
Expand Down Expand Up @@ -162,26 +226,6 @@ func (i *baseIterator[T]) delegateAction(isSame NextAction) (value T, hasValue b
return // hasValue true, valid value return
}

// Cancel release resources for this iterator.
// Not every iterator requires a Cancel invocation.
func (i *baseIterator[T]) Cancel() (err error) {

// ignore if cancel alread invoked
if !i.cancelState.CompareAndSwap(uint32(notCanceled), uint32(cancelRequested)) {
i.errWait.Wait()
err = *i.err.Load()
return // already beyond cancel
}

// wait for access to fn
i.publicsLock.Lock()
defer i.publicsLock.Unlock()

_, _, err = i.enqueueForFn(enqueueForFnCancel)

return
}

// enqueueForFn invokes iter.fn
// - is hasValue true, value is valid, err nil, cancelState notCanceled
// - otherwise, i.err is updated, i.errWait released,
Expand Down
7 changes: 7 additions & 0 deletions iters/converter-iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ func NewConverterIterator[K constraints.Ordered, V any](
}
}

// Init implements the right-hand side of a short variable declaration in
// the init statement for a Go “for” clause
func (i *ConverterIterator[K, T]) Init() (iterationVariable T, iterator Iterator[T]) {
iterator = i
return
}

// invokeConverterFunction invokes converterFunction recovering a possible panic
// - if cancelState == notCanceled, a new value is requested.
// Otherwise, iteration cancel is requested
Expand Down
36 changes: 27 additions & 9 deletions iters/delegator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,42 @@ func TestDelegator(t *testing.T) {
slice := []int{5, 6, 7, 8}

var actualT int
var value int
var hasNext bool

iter := NewSliceIterator(slice)

// methods

if !iter.HasNext() {
value, hasNext = iter.Next()
if !hasNext {
t.Error("HasNext false")
}

if actualT = iter.NextValue(); actualT != slice[1] {
t.Errorf("NextValue: %d exp %d", actualT, slice[1])
if value != slice[0] {
t.Errorf("NextValue: %d exp %d", actualT, slice[0])
}

if !iter.Has() {
t.Error("Has false")
value, hasNext = iter.Same()
if !hasNext {
t.Error("HasNext false")
}

if actualT = iter.SameValue(); actualT != slice[1] {
t.Errorf("SameValue: %d exp %d", actualT, slice[1])
if value != slice[0] {
t.Errorf("NextValue: %d exp %d", actualT, slice[0])
}

// if !iter.HasNext() {
// t.Error("HasNext false")
// }

// if actualT = iter.NextValue(); actualT != slice[1] {
// t.Errorf("NextValue: %d exp %d", actualT, slice[1])
// }

// if !iter.Has() {
// t.Error("Has false")
// }

// if actualT = iter.SameValue(); actualT != slice[1] {
// t.Errorf("SameValue: %d exp %d", actualT, slice[1])
// }
}
21 changes: 13 additions & 8 deletions iters/empty-iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@ type EmptyIterator[T any] struct{}

// NewEmptyIterator returns an empty iterator of values type T.
// - EmptyIterator is thread-safe.
func NewEmptyIterator[T any]() (iterator Iterator[T]) { return &EmptyIterator[T]{} }
func (iter *EmptyIterator[T]) Next() (value T, hasValue bool) { return }
func (iter *EmptyIterator[T]) HasNext() (ok bool) { return }
func (iter *EmptyIterator[T]) NextValue() (value T) { return }
func (iter *EmptyIterator[T]) Same() (value T, hasValue bool) { return }
func (iter *EmptyIterator[T]) Has() (hasValue bool) { return }
func (iter *EmptyIterator[T]) SameValue() (value T) { return }
func (iter *EmptyIterator[T]) Cancel() (err error) { return }
func NewEmptyIterator[T any]() (iterator Iterator[T]) { return &EmptyIterator[T]{} }
func (i *EmptyIterator[T]) Init() (iterationVariable T, iterator Iterator[T]) {
iterator = i
return
}
func (i *EmptyIterator[T]) Cond(iterationVariablep *T, errp ...*error) (condition bool) { return }
func (i *EmptyIterator[T]) Next() (value T, hasValue bool) { return }
func (i *EmptyIterator[T]) HasNext() (ok bool) { return }
func (i *EmptyIterator[T]) NextValue() (value T) { return }
func (i *EmptyIterator[T]) Same() (value T, hasValue bool) { return }
func (i *EmptyIterator[T]) Has() (hasValue bool) { return }
func (i *EmptyIterator[T]) SameValue() (value T) { return }
func (i *EmptyIterator[T]) Cancel(errp ...*error) (err error) { return }
24 changes: 12 additions & 12 deletions iters/empty-iterator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,23 @@ func TestEmptyIterator(t *testing.T) {
} else if actual != zeroValue {
t.Error("Next returned other than zero-value")
}
if ok = iter.HasNext(); ok {
t.Error("GoNext returned true")
}
if actual = iter.NextValue(); actual != zeroValue {
t.Errorf("Next not zero value: %d exp %d", actual, zeroValue)
}
// if ok = iter.HasNext(); ok {
// t.Error("GoNext returned true")
// }
// if actual = iter.NextValue(); actual != zeroValue {
// t.Errorf("Next not zero value: %d exp %d", actual, zeroValue)
// }
if actual, ok = iter.Same(); ok {
t.Error("Next returned true")
} else if actual != zeroValue {
t.Error("Next returned other than zero-value")
}
if ok = iter.Has(); ok {
t.Error("Has returned true")
}
if actual = iter.SameValue(); actual != zeroValue {
t.Errorf("Same not zero value: %d exp %d", actual, zeroValue)
}
// if ok = iter.Has(); ok {
// t.Error("Has returned true")
// }
// if actual = iter.SameValue(); actual != zeroValue {
// t.Errorf("Same not zero value: %d exp %d", actual, zeroValue)
// }
if err = iter.Cancel(); err != nil {
t.Errorf("Cancel err: %v", err)
}
Expand Down
7 changes: 7 additions & 0 deletions iters/function-iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ func NewFunctionIterator[T any](
}
}

// Init implements the right-hand side of a short variable declaration in
// the init statement for a Go “for” clause
func (i *FunctionIterator[T]) Init() (iterationVariable T, iterator Iterator[T]) {
iterator = i
return
}

// invokeFn invokes fn recovering a possible panic
// - if cancelState == notCanceled, a new value is requested.
// Otherwise, iteration cancel is requested
Expand Down
Loading

0 comments on commit 4bb102e

Please sign in to comment.