diff --git a/iter/iter.go b/iter/iter.go index 4244b41..62fbc0e 100644 --- a/iter/iter.go +++ b/iter/iter.go @@ -43,6 +43,9 @@ func Start[T any](a Able[T]) (T, Ator[T]) { return v, a.Iter() } +// Min gets the minimum value in the iterable collection src. Src must be a +// collection of ordered values. Min requires that src's definition of +// iteration is finite. func Min[T constraints.Ordered](src Able[T]) T { it := src.Iter() var v T @@ -59,6 +62,9 @@ func Min[T constraints.Ordered](src Able[T]) T { return min } +// Max gets the maximum value in the iterable collection src. Src must be a +// collection of ordered values. Max requires that src's definition of +// iteration is finite. func Max[T constraints.Ordered](src Able[T]) T { it := src.Iter() var v T diff --git a/iter/span.go b/iter/span.go deleted file mode 100644 index 554e1ad..0000000 --- a/iter/span.go +++ /dev/null @@ -1,58 +0,0 @@ -package iter - -import ( - "constraints" -) - -type span[T constraints.Integer] struct { - start T - end T - step T -} - -type spanIter[T constraints.Integer] struct { - start T - end T - step T - next T -} - -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 - s.next += s.step - return true -} - -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) Able[T] { - return &span[T]{ - start: start, - end: end, - step: step, - } -} diff --git a/iter/span_test.go b/iter/span_test.go deleted file mode 100644 index bacd615..0000000 --- a/iter/span_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package iter - -import ( - "testing" -) - -func TestSpan(t *testing.T) { - var n int - s := Span(1, 10).Iter() - - 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) - } - - t.Logf("%T", Max(Span[uint8](3, 10))) -} - -func TestStep(t *testing.T) { - s := Step(1, 10, 3).Iter() - for n := 0; s.Next(&n); { - t.Log(n) - } -} diff --git a/span/span.go b/span/span.go new file mode 100644 index 0000000..259eb39 --- /dev/null +++ b/span/span.go @@ -0,0 +1,61 @@ +package span + +import ( + "constraints" + + "github.com/jordanorelli/generic/iter" +) + +type Span[T constraints.Integer] struct { + Start T + End T + Step T +} + +type spanIter[T constraints.Integer] struct { + start T + end T + step T + next T +} + +func (s Span[T]) Iter() 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.step == 0 || s.next < s.start || s.next >= s.end { + return false + } + *n = s.next + s.next += s.step + return true +} + +func (s spanIter[T]) Iter() iter.Ator[T] { return &s } + +// New 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. +// The created span is given a step size of 1. +func New[T constraints.Integer](start, end T) Span[T] { + return Span[T]{ + Start: start, + End: end, + Step: 1, + } +} + +// Step is the same as creating a span with a provided step value +func Step[T constraints.Integer](start, end, step T) Span[T] { + return Span[T]{ + Start: start, + End: end, + Step: step, + } +} diff --git a/span/span_test.go b/span/span_test.go new file mode 100644 index 0000000..95b3466 --- /dev/null +++ b/span/span_test.go @@ -0,0 +1,48 @@ +package span + +import ( + "testing" + + "github.com/jordanorelli/generic/iter" +) + +func TestSpan(t *testing.T) { + var n int + it := New(1, 10).Iter() + + it.Next(&n) + if n != 1 { + t.Errorf("expected n to be 1 but is %d instead", n) + } + for it.Next(&n) { + } + if n != 9 { + t.Errorf("expected n to be 9 but is %d instead", n) + } + + // If the function New returns a value of iter.Able[T], this type parameter + // can be inferred, but when New returns a value of Span[T] (which + // satisfies iter.Able[T]), the type parameter cannot be inferred. I don't + // know why this behavior exists or if this is the intended behavior. + // + + // | + // V + beer := iter.Max[int](New(1, 100)) + if beer != 99 { + t.Errorf("expected 99 beers but saw %d instead", beer) + } + + old := iter.Min[int](New(30, 40)) + if old != 30 { + t.Errorf("expected 30 to be old but saw %d instead", old) + } + + t.Logf("%T", iter.Max[int8](New[int8](3, 10))) +} + +func TestStep(t *testing.T) { + it := Step(1, 10, 3).Iter() + for n := 0; it.Next(&n); { + t.Log(n) + } +}