Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iterator: general refactoring and reset method #193

Merged
merged 1 commit into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 41 additions & 25 deletions iterator/iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,15 @@ type Iterator[T any] interface {
Next() (item T, ok bool)
}

// StopIterator is an interface for stopping Iterator.
// ResettableIterator supports to reset the iterator
type ResettableIterator[T any] interface {
Iterator[T]
// Reset allows for the iteration process over a sequence to be restarted from the beginning.
// It enables reusing the iterator for multiple traversals without needing to recreate it.
Reset()
}

// StopIterator is an interface for stopping Iterator.
type StopIterator[T any] interface {
Iterator[T]

Expand Down Expand Up @@ -81,8 +89,8 @@ type PrevIterator[T any] interface {
////////////////////////////////////////////////////////////////////////////////////////////////////

// FromSlice returns an iterator over a slice of data.
func FromSlice[T any](slice []T) Iterator[T] {
return &sliceIterator[T]{slice: slice, index: -1}
func FromSlice[T any](slice []T) *SliceIterator[T] {
return &SliceIterator[T]{slice: slice, index: -1}
}

func ToSlice[T any](iter Iterator[T]) []T {
Expand All @@ -93,16 +101,16 @@ func ToSlice[T any](iter Iterator[T]) []T {
return result
}

type sliceIterator[T any] struct {
type SliceIterator[T any] struct {
slice []T
index int
}

func (iter *sliceIterator[T]) HasNext() bool {
func (iter *SliceIterator[T]) HasNext() bool {
return iter.index < len(iter.slice)-1
}

func (iter *sliceIterator[T]) Next() (T, bool) {
func (iter *SliceIterator[T]) Next() (T, bool) {
iter.index++

ok := iter.index >= 0 && iter.index < len(iter.slice)
Expand All @@ -116,7 +124,7 @@ func (iter *sliceIterator[T]) Next() (T, bool) {
}

// Prev implements PrevIterator.
func (iter *sliceIterator[T]) Prev() {
func (iter *SliceIterator[T]) Prev() {
if iter.index == -1 {
panic("Next function should be called Prev")
}
Expand All @@ -128,7 +136,7 @@ func (iter *sliceIterator[T]) Prev() {
}

// Set implements SetIterator.
func (iter *sliceIterator[T]) Set(value T) {
func (iter *SliceIterator[T]) Set(value T) {
if iter.index == -1 {
panic("Next function should be called Set")
}
Expand All @@ -138,52 +146,60 @@ func (iter *sliceIterator[T]) Set(value T) {
iter.slice[iter.index] = value
}

func (iter *SliceIterator[T]) Reset() {
iter.index = -1
}

// FromRange creates a iterator which returns the numeric range between start inclusive and end
// exclusive by the step size. start should be less than end, step shoud be positive.
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) Iterator[T] {
func FromRange[T constraints.Integer | constraints.Float](start, end, step T) *RangeIterator[T] {
if end < start {
panic("RangeIterator: start should be before end")
} else if step <= 0 {
panic("RangeIterator: step should be positive")
}

return &rangeIterator[T]{start: start, end: end, step: step}
return &RangeIterator[T]{start: start, end: end, step: step, current: start}
}

type rangeIterator[T constraints.Integer | constraints.Float] struct {
start, end, step T
type RangeIterator[T constraints.Integer | constraints.Float] struct {
start, end, step, current T
}

func (iter *rangeIterator[T]) HasNext() bool {
return iter.start < iter.end
func (iter *RangeIterator[T]) HasNext() bool {
return iter.current < iter.end
}

func (iter *rangeIterator[T]) Next() (T, bool) {
if iter.start >= iter.end {
func (iter *RangeIterator[T]) Next() (T, bool) {
if iter.current >= iter.end {
var zero T
return zero, false
}
num := iter.start
iter.start += iter.step
num := iter.current
iter.current += iter.step
return num, true
}

// FromRange creates a iterator which returns the numeric range between start inclusive and end
// exclusive by the step size. start should be less than end, step shoud be positive.
func FromChannel[T any](channel <-chan T) Iterator[T] {
return &channelIterator[T]{channel: channel}
func (iter *RangeIterator[T]) Reset() {
iter.current = iter.start
}

// FromChannel creates an iterator which returns items received from the provided channel.
// The iteration continues until the channel is closed.
func FromChannel[T any](channel <-chan T) *ChannelIterator[T] {
return &ChannelIterator[T]{channel: channel}
}

type channelIterator[T any] struct {
type ChannelIterator[T any] struct {
channel <-chan T
}

func (iter *channelIterator[T]) Next() (T, bool) {
func (iter *ChannelIterator[T]) Next() (T, bool) {
item, ok := <-iter.channel
return item, ok
}

func (iter *channelIterator[T]) HasNext() bool {
func (iter *ChannelIterator[T]) HasNext() bool {
return len(iter.channel) == 0
}

Expand Down
75 changes: 72 additions & 3 deletions iterator/iterator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,36 @@ func TestSliceIterator(t *testing.T) {
assert.Equal(false, ok)
})

// Reset
t.Run("slice iterator Reset: ", func(t *testing.T) {
iter1 := FromSlice([]int{1, 2, 3, 4})
for i := 0; i < 4; i++ {
item, ok := iter1.Next()
if !ok {
break
}
assert.Equal(i+1, item)
}

iter1.Reset()

for i := 0; i < 4; i++ {
item, ok := iter1.Next()
if !ok {
break
}
assert.Equal(i+1, item)
}
})

t.Run("slice iterator ToSlice: ", func(t *testing.T) {
iter := FromSlice([]int{1, 2, 3, 4})
item, _ := iter.Next()
assert.Equal(1, item)

data := ToSlice(iter)
data := ToSlice[int](iter)
assert.Equal([]int{2, 3, 4}, data)
})

}

func TestRangeIterator(t *testing.T) {
Expand All @@ -84,6 +105,54 @@ func TestRangeIterator(t *testing.T) {
_, ok = iter.Next()
assert.Equal(false, ok)
assert.Equal(false, iter.HasNext())

iter.Reset()

item, ok = iter.Next()
assert.Equal(1, item)
assert.Equal(true, ok)

item, ok = iter.Next()
assert.Equal(2, item)
assert.Equal(true, ok)

item, ok = iter.Next()
assert.Equal(3, item)
assert.Equal(true, ok)

_, ok = iter.Next()
assert.Equal(false, ok)
assert.Equal(false, iter.HasNext())
})

t.Run("range iterator reset: ", func(t *testing.T) {
iter := FromRange(1, 4, 1)

item, ok := iter.Next()
assert.Equal(1, item)
assert.Equal(true, ok)

item, ok = iter.Next()
assert.Equal(2, item)
assert.Equal(true, ok)

iter.Reset()

item, ok = iter.Next()
assert.Equal(1, item)
assert.Equal(true, ok)

item, ok = iter.Next()
assert.Equal(2, item)
assert.Equal(true, ok)

item, ok = iter.Next()
assert.Equal(3, item)
assert.Equal(true, ok)

_, ok = iter.Next()
assert.Equal(false, ok)
assert.Equal(false, iter.HasNext())
})

}
Expand All @@ -93,7 +162,7 @@ func TestChannelIterator(t *testing.T) {

assert := internal.NewAssert(t, "TestRangeIterator")

iter := FromSlice([]int{1, 2, 3, 4})
var iter Iterator[int] = FromSlice([]int{1, 2, 3, 4})

ctx, cancel := context.WithCancel(context.Background())
iter = FromChannel(ToChannel(ctx, iter, 0))
Expand Down
14 changes: 7 additions & 7 deletions iterator/operation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func TestMapIterator(t *testing.T) {

assert := internal.NewAssert(t, "TestMapIterator")

iter := FromSlice([]int{1, 2, 3, 4})
var iter Iterator[int] = FromSlice([]int{1, 2, 3, 4})

iter = Map(iter, func(n int) int { return n / 2 })

Expand All @@ -34,7 +34,7 @@ func TestFilterIterator(t *testing.T) {

assert := internal.NewAssert(t, "TestFilterIterator")

iter := FromSlice([]int{1, 2, 3, 4})
var iter Iterator[int] = FromSlice([]int{1, 2, 3, 4})

iter = Filter(iter, func(n int) bool { return n < 3 })

Expand All @@ -47,10 +47,10 @@ func TestJoinIterator(t *testing.T) {

assert := internal.NewAssert(t, "TestJoinIterator")

iter1 := FromSlice([]int{1, 2})
iter2 := FromSlice([]int{3, 4})
var iter1 Iterator[int] = FromSlice([]int{1, 2})
var iter2 Iterator[int] = FromSlice([]int{3, 4})

iter := Join(iter1, iter2)
var iter Iterator[int] = Join(iter1, iter2)

item, ok := iter.Next()
assert.Equal(1, item)
Expand All @@ -64,7 +64,7 @@ func TestReduce(t *testing.T) {

assert := internal.NewAssert(t, "TestReduce")

iter := FromSlice([]int{1, 2, 3, 4})
var iter Iterator[int] = FromSlice([]int{1, 2, 3, 4})
sum := Reduce(iter, 0, func(a, b int) int { return a + b })
assert.Equal(10, sum)
}
Expand All @@ -74,7 +74,7 @@ func TestTakeIterator(t *testing.T) {

assert := internal.NewAssert(t, "TestTakeIterator")

iter := FromSlice([]int{1, 2, 3, 4, 5})
var iter Iterator[int] = FromSlice([]int{1, 2, 3, 4, 5})

iter = Take(iter, 3)

Expand Down
Loading