From 9091c4076cabbea0b8f18b363ea9ac7d8462be48 Mon Sep 17 00:00:00 2001 From: Bob Glickstein Date: Sun, 19 Mar 2023 12:06:52 -0700 Subject: [PATCH] iter, parallel: Improve some more generics decls (#4) * Improve some more generics decls. * Improve generics decls in the parallel package. * Missed some tildes. --- go.mod | 2 ++ iter/accum.go | 4 ++-- iter/chan.go | 2 +- iter/filter.go | 4 ++-- iter/gen.go | 2 +- iter/gomap.go | 4 ++-- iter/map.go | 4 ++-- iter/page.go | 2 +- parallel/parallel.go | 8 ++++---- 9 files changed, 17 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 72bcb5a..c39af09 100644 --- a/go.mod +++ b/go.mod @@ -7,3 +7,5 @@ require ( golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb golang.org/x/sync v0.0.0-20210220032951-036812b2e83c ) + +retract v2.0.0 diff --git a/iter/accum.go b/iter/accum.go index 473f155..720000e 100644 --- a/iter/accum.go +++ b/iter/accum.go @@ -10,7 +10,7 @@ package iter // and // // out[i+1] == f(out[i], inp[i+1]) -func Accum[T any](inp Of[T], f func(T, T) T) Of[T] { +func Accum[F ~func(T, T) T, T any](inp Of[T], f F) Of[T] { return Accumx(inp, func(a, b T) (T, error) { return f(a, b), nil }) @@ -27,7 +27,7 @@ func Accum[T any](inp Of[T], f func(T, T) T) Of[T] { // and // // out[i+1] == f(out[i], inp[i+1]) -func Accumx[T any](inp Of[T], f func(T, T) (T, error)) Of[T] { +func Accumx[F ~func(T, T) (T, error), T any](inp Of[T], f F) Of[T] { return &accumIter[T]{ inp: inp, f: f, diff --git a/iter/chan.go b/iter/chan.go index a6e32c1..18a0540 100644 --- a/iter/chan.go +++ b/iter/chan.go @@ -135,7 +135,7 @@ func toChan[T any](ctx context.Context, inp Of[T]) (<-chan T, func() error) { // The function receives a channel for producing values. // The channel closes when the function exits. // Any error produced by the function is the value of the iterator's Err method. -func Go[T any](f func(ch chan<- T) error) Of[T] { +func Go[F ~func(chan<- T) error, T any](f F) Of[T] { var ( ch = make(chan T) res = &chanIter[T]{ch: ch} diff --git a/iter/filter.go b/iter/filter.go index 3a9f483..7548623 100644 --- a/iter/filter.go +++ b/iter/filter.go @@ -2,7 +2,7 @@ package iter // Filter copies the input iterator to the output, // including only those elements that cause f to return true. -func Filter[T any](inp Of[T], f func(T) bool) Of[T] { +func Filter[F ~func(T) bool, T any](inp Of[T], f F) Of[T] { return &filterIter[T]{inp: inp, f: f} } @@ -34,7 +34,7 @@ func (f *filterIter[T]) Err() error { // discarding the initial elements until the first one that causes f to return true. // That element and the remaining elements of inp are included in the output, // and f is not called again. -func SkipUntil[T any](inp Of[T], f func(T) bool) Of[T] { +func SkipUntil[F ~func(T) bool, T any](inp Of[T], f F) Of[T] { skipping := true return Filter(inp, func(val T) bool { if !skipping { diff --git a/iter/gen.go b/iter/gen.go index 2ded003..a94ce2f 100644 --- a/iter/gen.go +++ b/iter/gen.go @@ -10,7 +10,7 @@ import ( // iteration stops and the error is available via the iterator's Err method. // Otherwise, each call to f should return a value and a true boolean. // When f returns a false boolean, it signals the normal end of iteration. -func Gen[T any](f func() (T, bool, error)) Of[T] { +func Gen[F ~func() (T, bool, error), T any](f F) Of[T] { return &genIter[T]{f: f} } diff --git a/iter/gomap.go b/iter/gomap.go index edc6254..98a0d8f 100644 --- a/iter/gomap.go +++ b/iter/gomap.go @@ -24,7 +24,7 @@ func (*goMapIter[K, V]) Err() error { } // FromMap produces an iterator of key-value pairs from a Go map. -func FromMap[K comparable, V any](m map[K]V) Of[Pair[K, V]] { +func FromMap[M ~map[K]V, K comparable, V any](m M) Of[Pair[K, V]] { return &goMapIter[K, V]{ m: m, keysIter: FromMapKeys(m), @@ -32,7 +32,7 @@ func FromMap[K comparable, V any](m map[K]V) Of[Pair[K, V]] { } // FromMapKeys produces an iterator over the keys of a Go map. -func FromMapKeys[K comparable, V any](m map[K]V) Of[K] { +func FromMapKeys[M ~map[K]V, K comparable, V any](m M) Of[K] { keys := make([]K, 0, len(m)) for k := range m { keys = append(keys, k) diff --git a/iter/map.go b/iter/map.go index cc462da..2bbeda9 100644 --- a/iter/map.go +++ b/iter/map.go @@ -1,7 +1,7 @@ package iter // Map produces an iterator of values transformed from an input iterator by a simple mapping function. -func Map[T, U any](inp Of[T], f func(T) U) Of[U] { +func Map[F ~func(T) U, T, U any](inp Of[T], f F) Of[U] { return Mapx(inp, func(val T) (U, error) { return f(val), nil }) @@ -11,7 +11,7 @@ func Map[T, U any](inp Of[T], f func(T) U) Of[U] { // It produces an iterator of values transformed from an input iterator by a mapping function. // If the mapping function returns an error, // iteration stops and the error is available via the output iterator's Err method. -func Mapx[T, U any](inp Of[T], f func(T) (U, error)) Of[U] { +func Mapx[F ~func(T) (U, error), T, U any](inp Of[T], f F) Of[U] { return &mapIter[T, U]{inp: inp, f: f} } diff --git a/iter/page.go b/iter/page.go index 987405e..f8e4f94 100644 --- a/iter/page.go +++ b/iter/page.go @@ -11,7 +11,7 @@ package iter // // The slice in every non-final call of the callback is guaranteed to have a length of pageSize. // The final call of the callback may contain an empty slice. -func Page[T any](inp Of[T], pageSize int, f func([]T, bool) error) error { +func Page[F ~func(S, bool) error, S ~[]T, T any](inp Of[T], pageSize int, f F) error { page := make([]T, 0, pageSize) for inp.Next() { page = append(page, inp.Val()) diff --git a/parallel/parallel.go b/parallel/parallel.go index 8e94e1d..69d164f 100644 --- a/parallel/parallel.go +++ b/parallel/parallel.go @@ -35,7 +35,7 @@ func (e Error) Unwrap() error { // // The resulting slice has length n. // The value at position i comes from worker i. -func Values[T any](ctx context.Context, n int, f func(context.Context, int) (T, error)) ([]T, error) { +func Values[F ~func(context.Context, int) (T, error), T any](ctx context.Context, n int, f F) ([]T, error) { g, ctx := errgroup.WithContext(ctx) result := make([]T, n) @@ -69,7 +69,7 @@ func Values[T any](ctx context.Context, n int, f func(context.Context, int) (T, // An error from any worker cancels them all. // // The caller gets an iterator over the values produced. -func Producers[T any](ctx context.Context, n int, f func(context.Context, int, func(T) error) error) iter.Of[T] { +func Producers[F ~func(context.Context, int, func(T) error) error, T any](ctx context.Context, n int, f F) iter.Of[T] { ch := make(chan T) g, innerCtx := errgroup.WithContext(ctx) @@ -117,7 +117,7 @@ func Producers[T any](ctx context.Context, n int, f func(context.Context, int, f // After any error, the value-sending callback will return an error. // (Not the original error, however. // For that, the caller should still invoke the close callback.) -func Consumers[T any](ctx context.Context, n int, f func(context.Context, int, T) error) (func(T) error, func() error) { +func Consumers[F ~func(context.Context, int, T) error, T any](ctx context.Context, n int, f F) (func(T) error, func() error) { ch := make(chan T, n) g, ctx := errgroup.WithContext(ctx) @@ -167,7 +167,7 @@ func Consumers[T any](ctx context.Context, n int, f func(context.Context, int, T // // Each call of the callback is synchronous. // Any desired concurrency is the responsibility of the caller. -func Pool[T, U any](n int, f func(T) (U, error)) func(T) (U, error) { +func Pool[F ~func(T) (U, error), T, U any](n int, f F) func(T) (U, error) { var ( running int mu sync.Mutex