put span in its own package
parent
4032920454
commit
9b9c986876
@ -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,
|
|
||||||
}
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue