diff --git a/iter/iter.go b/iter/iter.go new file mode 100644 index 0000000..e206bb8 --- /dev/null +++ b/iter/iter.go @@ -0,0 +1,52 @@ +package iter + +import "constraints" + +// Able is anything that is iter.Able +type Able[T any] interface { + Iter() Ator[T] +} + +// Ator is an iter.Ator +type Ator[T any] interface { + // Next assigns the value pointed at by *T to the next value in the + // iteration. Next should return true if a value was set. An Ator that + // returns false should continue to return false; once iteration is + // complete it should be complete forever. + Next(*T) bool +} + +func Ate[T any](a Able[T]) (T, Ator[T]) { + var v T + return v, a.Iter() +} + +func Min[T constraints.Ordered](it Ator[T]) T { + var v T + if !it.Next(&v) { + var zero T + return zero + } + min := v + for it.Next(&v) { + if v < min { + min = v + } + } + return min +} + +func Max[T constraints.Ordered](it Ator[T]) T { + var v T + if !it.Next(&v) { + var zero T + return zero + } + max := v + for it.Next(&v) { + if v > max { + max = v + } + } + return max +} diff --git a/iter/span.go b/iter/span.go new file mode 100644 index 0000000..6f42e7c --- /dev/null +++ b/iter/span.go @@ -0,0 +1,30 @@ +package iter + +import ( + "constraints" +) + +type span[T constraints.Integer] struct { + next T + final T + step T +} + +func (s *span[T]) Next(n *T) bool { + if s.next >= s.final { + return false + } + *n = s.next + s.next += s.step + return true +} + +// Span creates a span of integers between start and end +func Span[T constraints.Integer](start, end T) Ator[T] { + return &span[T]{next: start, final: end, step: 1} +} + +// Step is the same as span, but allows for step sizes greater than 1 +func Step[T constraints.Integer](start, end, step T) Ator[T] { + return &span[T]{next: start, final: end, step: step} +} diff --git a/iter/span_test.go b/iter/span_test.go new file mode 100644 index 0000000..3f22b45 --- /dev/null +++ b/iter/span_test.go @@ -0,0 +1,37 @@ +package iter + +import ( + "testing" +) + +func TestSpan(t *testing.T) { + var n int + s := Span(1, 10) + + s.Next(&n) + if n != 1 { + t.Errorf("expected n to be 1 but is %d instead", n) + } + for s.Next(&n) { + } + if n != 9 { + t.Errorf("expected n to be 9 but is %d instead", n) + } + + beer := Max(Span(1, 100)) + if beer != 99 { + t.Errorf("expected 99 beers but saw %d instead", beer) + } + + old := Min(Span(30, 40)) + if old != 30 { + t.Errorf("expected 30 to be old but saw %d instead", old) + } +} + +func TestStep(t *testing.T) { + s := Step(1, 10, 3) + for n := 0; s.Next(&n); { + t.Log(n) + } +} diff --git a/list/iter.go b/list/iter.go index f03ff82..e1749c2 100644 --- a/list/iter.go +++ b/list/iter.go @@ -8,6 +8,10 @@ type Iter[T any] interface { Next(*T) bool } +// for v, it := iter.Ate(foods); it.Next(&v); { +// +// } + // This actually works, but for some reason I don't yet understand, defining // Max with a constraint of constrains.Ordered that takes Iterable[T] cannot // have its type parameter infered, but defining it with the same constraint of diff --git a/list/list.go b/list/list.go index 2118d73..4f01bd5 100644 --- a/list/list.go +++ b/list/list.go @@ -41,6 +41,9 @@ func Make[T any](vals ...T) List[T] { return l } +// func From[T any](it iter.Able) List[T] { +// } + // Empty is true for empty lists func (l List[T]) Empty() bool { return l.head == nil diff --git a/list/list_test.go b/list/list_test.go index b0686f6..09ad424 100644 --- a/list/list_test.go +++ b/list/list_test.go @@ -41,6 +41,18 @@ func TestOne(t *testing.T) { if l.Len() != 1 { t.Errorf("expected a list of size 1 but saw %d instead", l.Len()) } + + if n := l.Pop(); n != 3 { + t.Errorf("popping first element from the list should be 3 but is %d instead", n) + } + + if !l.Empty() { + t.Errorf("new list is not empty, but should be") + } + + if l.Len() != 0 { + t.Errorf("expected a list of size 0 but saw %d instead", l.Len()) + } } func TestMake(t *testing.T) {