Skip to content

Commit

Permalink
Support EachIter based on 1.23 iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
amikai committed Jul 20, 2024
1 parent 629afd9 commit 3f0ba08
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 0 deletions.
42 changes: 42 additions & 0 deletions bench_iteration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,48 @@ func BenchmarkEach(b *testing.B) {
}
}

func BenchmarkEachIter(b *testing.B) {
var tmp, n int

b.StopTimer()
sel := DocW().Find("td")
b.StartTimer()
for i := 0; i < b.N; i++ {
for range sel.EachIter() {
tmp++
}
if n == 0 {
n = tmp
}
}
if n != 59 {
b.Fatalf("want 59, got %d", n)
}
}

func BenchmarkEachIterWithBreak(b *testing.B) {
var tmp, n int

b.StopTimer()
sel := DocW().Find("td")
b.StartTimer()
for i := 0; i < b.N; i++ {
tmp = 0
for range sel.EachIter() {
tmp++
if tmp >= 10 {
break
}
}
if n == 0 {
n = tmp
}
}
if n != 10 {
b.Fatalf("want 10, got %d", n)
}
}

func BenchmarkMap(b *testing.B) {
var tmp, n int

Expand Down
14 changes: 14 additions & 0 deletions iteration.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package goquery

import "iter"

// Each iterates over a Selection object, executing a function for each
// matched element. It returns the current Selection object. The function
// f is called for each element in the selection with the index of the
Expand All @@ -12,6 +14,18 @@ func (s *Selection) Each(f func(int, *Selection)) *Selection {
return s
}

// EachIter returns an iterator that yields the Selection object in order.
// The implementation is similar to Each, but it returns an iterator instead.
func (s *Selection) EachIter() iter.Seq2[int, *Selection] {
return func(yield func(int, *Selection) bool) {
for i, n := range s.Nodes {
if !yield(i, newSingleSelection(n, s.document)) {
return
}
}
}
}

// EachWithBreak iterates over a Selection object, executing a function for each
// matched element. It is identical to Each except that it is possible to break
// out of the loop by returning false in the callback function. It returns the
Expand Down
36 changes: 36 additions & 0 deletions iteration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,39 @@ func TestGenericMap(t *testing.T) {
t.Errorf("Expected Map array result to have a length of 3, found %v.", len(vals))
}
}

func TestEachIter(t *testing.T) {
var cnt int

sel := Doc().Find(".hero-unit .row-fluid")

for i, s := range sel.EachIter() {
cnt++
t.Logf("At index %v, node %v", i, s.Nodes[0].Data)
}

sel = sel.Find("a")

if cnt != 4 {
t.Errorf("Expected Each() to call function 4 times, got %v times.", cnt)
}
assertLength(t, sel.Nodes, 6)
}

func TestEachIterWithBreak(t *testing.T) {
var cnt int

sel := Doc().Find(".hero-unit .row-fluid")
for i, s := range sel.EachIter() {
cnt++
t.Logf("At index %v, node %v", i, s.Nodes[0].Data)
break
}

sel = sel.Find("a")

if cnt != 1 {
t.Errorf("Expected Each() to call function 1 time, got %v times.", cnt)
}
assertLength(t, sel.Nodes, 6)
}

0 comments on commit 3f0ba08

Please sign in to comment.