-
Notifications
You must be signed in to change notification settings - Fork 17.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
slices: add iterator-related functions
Fixes #61899 Change-Id: Icbde1ac8293723eefc3251008ae9711e756ed1b3 Reviewed-on: https://go-review.googlesource.com/c/go/+/568477 Auto-Submit: Ian Lance Taylor <iant@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com> Reviewed-by: Alan Donovan <adonovan@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
- Loading branch information
1 parent
cecbf4f
commit 0b5f722
Showing
8 changed files
with
319 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
pkg slices, func All[$0 interface{ ~[]$1 }, $1 interface{}]($0) iter.Seq2[int, $1] #61899 | ||
pkg slices, func AppendSeq[$0 interface{ ~[]$1 }, $1 interface{}]($0, iter.Seq[$1]) $0 #61899 | ||
pkg slices, func Backward[$0 interface{ ~[]$1 }, $1 interface{}]($0) iter.Seq2[int, $1] #61899 | ||
pkg slices, func Collect[$0 interface{}](iter.Seq[$0]) []$0 #61899 | ||
pkg slices, func SortedFunc[$0 interface{}](iter.Seq[$0], func($0, $0) int) []$0 #61899 | ||
pkg slices, func SortedStableFunc[$0 interface{}](iter.Seq[$0], func($0, $0) int) []$0 #61899 | ||
pkg slices, func Sorted[$0 cmp.Ordered](iter.Seq[$0]) []$0 #61899 | ||
pkg slices, func Values[$0 interface{ ~[]$1 }, $1 interface{}]($0) iter.Seq[$1] #61899 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<!-- see ../../3-iter.md --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// Copyright 2024 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package slices | ||
|
||
import ( | ||
"cmp" | ||
"iter" | ||
) | ||
|
||
// All returns an iterator over index-value pairs in the slice. | ||
// The indexes range in the usual order, from 0 through len(s)-1. | ||
func All[Slice ~[]E, E any](s Slice) iter.Seq2[int, E] { | ||
return func(yield func(int, E) bool) { | ||
for i, v := range s { | ||
if !yield(i, v) { | ||
return | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Backward returns an iterator over index-value pairs in the slice, | ||
// traversing it backward. The indexes range from len(s)-1 down to 0. | ||
func Backward[Slice ~[]E, E any](s Slice) iter.Seq2[int, E] { | ||
return func(yield func(int, E) bool) { | ||
for i := len(s) - 1; i >= 0; i-- { | ||
if !yield(i, s[i]) { | ||
return | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Values returns an iterator over the slice elements. | ||
// starting with s[0]. | ||
func Values[Slice ~[]E, E any](s Slice) iter.Seq[E] { | ||
return func(yield func(E) bool) { | ||
for _, v := range s { | ||
if !yield(v) { | ||
return | ||
} | ||
} | ||
} | ||
} | ||
|
||
// AppendSeq appends the values from seq to the slice and | ||
// returns the extended slice. | ||
func AppendSeq[Slice ~[]E, E any](s Slice, seq iter.Seq[E]) Slice { | ||
for v := range seq { | ||
s = append(s, v) | ||
} | ||
return s | ||
} | ||
|
||
// Collect collects values from seq into a new slice and returns it. | ||
func Collect[E any](seq iter.Seq[E]) []E { | ||
return AppendSeq([]E(nil), seq) | ||
} | ||
|
||
// Sorted collects values from seq into a new slice, sorts the slice, | ||
// and returns it. | ||
func Sorted[E cmp.Ordered](seq iter.Seq[E]) []E { | ||
s := Collect(seq) | ||
Sort(s) | ||
return s | ||
} | ||
|
||
// SortedFunc collects values from seq into a new slice, sorts the slice | ||
// using the comparison function, and returns it. | ||
func SortedFunc[E any](seq iter.Seq[E], cmp func(E, E) int) []E { | ||
s := Collect(seq) | ||
SortFunc(s, cmp) | ||
return s | ||
} | ||
|
||
// SortedStableFunc collects values from seq into a new slice. | ||
// It then sorts the slice while keeping the original order of equal elements, | ||
// using the comparison function to compare elements. | ||
// It returns the new slice. | ||
func SortedStableFunc[E any](seq iter.Seq[E], cmp func(E, E) int) []E { | ||
s := Collect(seq) | ||
SortStableFunc(s, cmp) | ||
return s | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
// Copyright 2024 The Go Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package slices_test | ||
|
||
import ( | ||
"iter" | ||
"math/rand/v2" | ||
. "slices" | ||
"testing" | ||
) | ||
|
||
func TestAll(t *testing.T) { | ||
for size := 0; size < 10; size++ { | ||
var s []int | ||
for i := range size { | ||
s = append(s, i) | ||
} | ||
ei, ev := 0, 0 | ||
cnt := 0 | ||
for i, v := range All(s) { | ||
if i != ei || v != ev { | ||
t.Errorf("at iteration %d got %d, %d want %d, %d", cnt, i, v, ei, ev) | ||
} | ||
ei++ | ||
ev++ | ||
cnt++ | ||
} | ||
if cnt != size { | ||
t.Errorf("read %d values expected %d", cnt, size) | ||
} | ||
} | ||
} | ||
|
||
func TestBackward(t *testing.T) { | ||
for size := 0; size < 10; size++ { | ||
var s []int | ||
for i := range size { | ||
s = append(s, i) | ||
} | ||
ei, ev := size-1, size-1 | ||
cnt := 0 | ||
for i, v := range Backward(s) { | ||
if i != ei || v != ev { | ||
t.Errorf("at iteration %d got %d, %d want %d, %d", cnt, i, v, ei, ev) | ||
} | ||
ei-- | ||
ev-- | ||
cnt++ | ||
} | ||
if cnt != size { | ||
t.Errorf("read %d values expected %d", cnt, size) | ||
} | ||
} | ||
} | ||
|
||
func TestValues(t *testing.T) { | ||
for size := 0; size < 10; size++ { | ||
var s []int | ||
for i := range size { | ||
s = append(s, i) | ||
} | ||
ev := 0 | ||
cnt := 0 | ||
for v := range Values(s) { | ||
if v != ev { | ||
t.Errorf("at iteration %d got %d want %d", cnt, v, ev) | ||
} | ||
ev++ | ||
cnt++ | ||
} | ||
if cnt != size { | ||
t.Errorf("read %d values expected %d", cnt, size) | ||
} | ||
} | ||
} | ||
|
||
func testSeq(yield func(int) bool) { | ||
for i := 0; i < 10; i += 2 { | ||
if !yield(i) { | ||
return | ||
} | ||
} | ||
} | ||
|
||
var testSeqResult = []int{0, 2, 4, 6, 8} | ||
|
||
func TestAppendSeq(t *testing.T) { | ||
s := AppendSeq([]int{1, 2}, testSeq) | ||
want := append([]int{1, 2}, testSeqResult...) | ||
if !Equal(s, want) { | ||
t.Errorf("got %v, want %v", s, want) | ||
} | ||
} | ||
|
||
func TestCollect(t *testing.T) { | ||
s := Collect(testSeq) | ||
want := testSeqResult | ||
if !Equal(s, want) { | ||
t.Errorf("got %v, want %v", s, want) | ||
} | ||
} | ||
|
||
var iterTests = [][]string{ | ||
nil, | ||
{"a"}, | ||
{"a", "b"}, | ||
{"b", "a"}, | ||
strs[:], | ||
} | ||
|
||
func TestValuesAppendSeq(t *testing.T) { | ||
for _, prefix := range iterTests { | ||
for _, s := range iterTests { | ||
got := AppendSeq(prefix, Values(s)) | ||
want := append(prefix, s...) | ||
if !Equal(got, want) { | ||
t.Errorf("AppendSeq(%v, Values(%v)) == %v, want %v", prefix, s, got, want) | ||
} | ||
} | ||
} | ||
} | ||
|
||
func TestValuesCollect(t *testing.T) { | ||
for _, s := range iterTests { | ||
got := Collect(Values(s)) | ||
if !Equal(got, s) { | ||
t.Errorf("Collect(Values(%v)) == %v, want %v", s, got, s) | ||
} | ||
} | ||
} | ||
|
||
func TestSorted(t *testing.T) { | ||
s := Sorted(Values(ints[:])) | ||
if !IsSorted(s) { | ||
t.Errorf("sorted %v", ints) | ||
t.Errorf(" got %v", s) | ||
} | ||
} | ||
|
||
func TestSortedFunc(t *testing.T) { | ||
s := SortedFunc(Values(ints[:]), func(a, b int) int { return a - b }) | ||
if !IsSorted(s) { | ||
t.Errorf("sorted %v", ints) | ||
t.Errorf(" got %v", s) | ||
} | ||
} | ||
|
||
func TestSortedStableFunc(t *testing.T) { | ||
n, m := 1000, 100 | ||
data := make(intPairs, n) | ||
for i := range data { | ||
data[i].a = rand.IntN(m) | ||
} | ||
data.initB() | ||
|
||
s := intPairs(SortedStableFunc(Values(data), intPairCmp)) | ||
if !IsSortedFunc(s, intPairCmp) { | ||
t.Errorf("SortedStableFunc didn't sort %d ints", n) | ||
} | ||
if !s.inOrder(false) { | ||
t.Errorf("SortedStableFunc wasn't stable on %d ints", n) | ||
} | ||
|
||
// iterVal converts a Seq2 to a Seq. | ||
iterVal := func(seq iter.Seq2[int, intPair]) iter.Seq[intPair] { | ||
return func(yield func(intPair) bool) { | ||
for _, v := range seq { | ||
if !yield(v) { | ||
return | ||
} | ||
} | ||
} | ||
} | ||
|
||
s = intPairs(SortedStableFunc(iterVal(Backward(data)), intPairCmp)) | ||
if !IsSortedFunc(s, intPairCmp) { | ||
t.Errorf("SortedStableFunc didn't sort %d reverse ints", n) | ||
} | ||
if !s.inOrder(true) { | ||
t.Errorf("SortedStableFunc wasn't stable on %d reverse ints", n) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters