From 4032920454acf5f4f7427ab07ea0d2ec9dd4fc79 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Wed, 24 Nov 2021 02:16:34 +0000 Subject: [PATCH] ahh --- iter/iter.go | 30 +++++++++++++++++++++++++++--- iter/span.go | 46 +++++++++++++++++++++++++++++++++++++--------- iter/span_test.go | 6 ++++-- 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/iter/iter.go b/iter/iter.go index e206bb8..4244b41 100644 --- a/iter/iter.go +++ b/iter/iter.go @@ -14,14 +14,37 @@ type Ator[T any] interface { // returns false should continue to return false; once iteration is // complete it should be complete forever. Next(*T) bool + + // An iterator must also be iterable. That is, a valid iterator must be + // able to create a new iterator beginning at the same position of that + // iterator, such that calling Iter() on an Iterator returns a new + // Iterator, and that both can be iterated without affecting one another. + Able[T] } -func Ate[T any](a Able[T]) (T, Ator[T]) { +// Start starts the iteration for an Iterable. This is a convenience function +// to facilitate iterating in a for loop. E.g., given an Iterable value l, such +// as a list, the following would iterate over the entire iterable: +// +// for v, it := iter.Start(l); it.Next(&v); { +// // utilize v here +// } +// +// Without such a construct, a developer would have to do something similar instead: +// +// for v, it := 0, l.Iter(); it.Next(&v); { +// +// } +// +// Doing that would require that the developer type out the zero-value for that +// type, when that value could just as easily be inferred. +func Start[T any](a Able[T]) (T, Ator[T]) { var v T return v, a.Iter() } -func Min[T constraints.Ordered](it Ator[T]) T { +func Min[T constraints.Ordered](src Able[T]) T { + it := src.Iter() var v T if !it.Next(&v) { var zero T @@ -36,7 +59,8 @@ func Min[T constraints.Ordered](it Ator[T]) T { return min } -func Max[T constraints.Ordered](it Ator[T]) T { +func Max[T constraints.Ordered](src Able[T]) T { + it := src.Iter() var v T if !it.Next(&v) { var zero T diff --git a/iter/span.go b/iter/span.go index 6f42e7c..554e1ad 100644 --- a/iter/span.go +++ b/iter/span.go @@ -5,13 +5,29 @@ import ( ) type span[T constraints.Integer] struct { - next T - final T + start T + end T + step T +} + +type spanIter[T constraints.Integer] struct { + start T + end T step T + next T } -func (s *span[T]) Next(n *T) bool { - if s.next >= s.final { +func (s span[T]) Iter() Ator[T] { + return &spanIter[T]{ + start: s.start, + end: s.end, + step: s.step, + next: s.start, + } +} + +func (s *spanIter[T]) Next(n *T) bool { + if s.next >= s.end { return false } *n = s.next @@ -19,12 +35,24 @@ func (s *span[T]) Next(n *T) bool { 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} +func (s spanIter[T]) Iter() Ator[T] { return &s } + +// Span creates a span of integers between start and end. The is analagous to +// the "range" function in Python, but since range already means something in +// Go, span is the chosen name to avoid confusion with Go's concept of range. +func Span[T constraints.Integer](start, end T) Able[T] { + return &span[T]{ + start: start, + end: 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} +func Step[T constraints.Integer](start, end, step T) Able[T] { + return &span[T]{ + start: start, + end: end, + step: step, + } } diff --git a/iter/span_test.go b/iter/span_test.go index 3f22b45..bacd615 100644 --- a/iter/span_test.go +++ b/iter/span_test.go @@ -6,7 +6,7 @@ import ( func TestSpan(t *testing.T) { var n int - s := Span(1, 10) + s := Span(1, 10).Iter() s.Next(&n) if n != 1 { @@ -27,10 +27,12 @@ func TestSpan(t *testing.T) { if old != 30 { t.Errorf("expected 30 to be old but saw %d instead", old) } + + t.Logf("%T", Max(Span[uint8](3, 10))) } func TestStep(t *testing.T) { - s := Step(1, 10, 3) + s := Step(1, 10, 3).Iter() for n := 0; s.Next(&n); { t.Log(n) }