mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-15 02:02:27 +08:00
feat: update iterator package
This commit is contained in:
@@ -1,68 +1,144 @@
|
|||||||
// Copyright 2021 dudaodong@gmail.com. All rights resulterved.
|
// Copyright 2022 dudaodong@gmail.com. All rights resulterved.
|
||||||
// Use of this source code is governed by MIT license
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
// Package iterator implements some feature of C++ STL iterators
|
// Package iterator provides a way to iterate over values stored in containers.
|
||||||
|
// note:
|
||||||
|
// 1. Full feature iterator is complicated, this pacakge is just a experiment to explore how iterators could work in Go.
|
||||||
|
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
||||||
|
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
||||||
|
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
||||||
|
// Hope that Go can support iterator in future. see https://github.com/golang/go/discussions/54245 and https://github.com/golang/go/discussions/56413
|
||||||
package iterator
|
package iterator
|
||||||
|
|
||||||
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
import "github.com/duke-git/lancet/v2/lancetconstraints"
|
||||||
|
|
||||||
// Iterator is used to iterate over a slice of data.
|
// Iterator supports iterating over a sequence of values of type `E`.
|
||||||
type Iterator[T any] interface {
|
type Iterator[T any] interface {
|
||||||
|
// Next checks if there is a next value in the iteration or not
|
||||||
HasNext() bool
|
HasNext() bool
|
||||||
Next() (T, bool)
|
// Next returns the next value in the iteration if there is one,
|
||||||
|
// and reports whether the returned value is valid.
|
||||||
|
// Once Next returns ok==false, the iteration is over,
|
||||||
|
// and all subsequent calls will return ok==false.
|
||||||
|
Next() (item T, ok bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StopIterator is an interface for stopping Iterator.
|
||||||
|
type StopIterator[T any] interface {
|
||||||
|
Iterator[T]
|
||||||
|
|
||||||
|
// Stop indicates that the iterator will no longer be used.
|
||||||
|
// After a call to Stop, future calls to Next may panic.
|
||||||
|
// Stop may be called multiple times;
|
||||||
|
// all calls after the first will have no effect.
|
||||||
|
Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteIter is an Iter that implements a Delete method.
|
||||||
|
type DeleteIterator[T any] interface {
|
||||||
|
Iterator[T]
|
||||||
|
|
||||||
|
// Delete deletes the current iterator element;
|
||||||
|
// that is, the one returned by the last call to Next.
|
||||||
|
// Delete should panic if called before Next or after
|
||||||
|
// Next returns false.
|
||||||
|
Delete()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetIterator is an Iter that implements a Set method.
|
||||||
|
type SetIterator[T any] interface {
|
||||||
|
Iterator[T]
|
||||||
|
|
||||||
|
// Set replaces the current iterator element with v.
|
||||||
|
// Set should panic if called before Next or after
|
||||||
|
// Next returns false.
|
||||||
|
Set(v T)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrevIterator is an iterator with a Prev method.
|
||||||
|
type PrevIterator[T any] interface {
|
||||||
|
Iterator[T]
|
||||||
|
|
||||||
|
// Prev moves the iterator to the previous position.
|
||||||
|
// After calling Prev, Next will return the value at
|
||||||
|
// that position in the container. For example, after
|
||||||
|
// it.Next() returning (v, true)
|
||||||
|
// it.Prev()
|
||||||
|
// another call to it.Next will again return (v, true).
|
||||||
|
// Calling Prev before calling Next may panic.
|
||||||
|
// Calling Prev after Next returns false will move
|
||||||
|
// to the last element, or, if there are no elements,
|
||||||
|
// to the iterator's initial state.
|
||||||
|
Prev()
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Functions that create an Iterator from some other type. //
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// FromSlice returns an iterator over a slice of data.
|
// FromSlice returns an iterator over a slice of data.
|
||||||
func FromSlice[T any](data []T) Iterator[T] {
|
func FromSlice[T any](slice []T) Iterator[T] {
|
||||||
// return &sliceIterator[T]{slice: data, index: 0, step: 1}
|
return &sliceIterator[T]{slice: slice, index: -1}
|
||||||
return &sliceIterator[T]{slice: data}
|
}
|
||||||
|
|
||||||
|
func ToSlice[T any](iter Iterator[T]) []T {
|
||||||
|
result := []T{}
|
||||||
|
for item, ok := iter.Next(); ok; item, ok = iter.Next() {
|
||||||
|
result = append(result, item)
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
type sliceIterator[T any] struct {
|
type sliceIterator[T any] struct {
|
||||||
slice []T
|
slice []T
|
||||||
// index int
|
index int
|
||||||
// step int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iter *sliceIterator[T]) HasNext() bool {
|
func (iter *sliceIterator[T]) HasNext() bool {
|
||||||
if len(iter.slice) == 0 {
|
return iter.index < len(iter.slice)-1
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iter *sliceIterator[T]) Next() (T, bool) {
|
func (iter *sliceIterator[T]) Next() (T, bool) {
|
||||||
if len(iter.slice) == 0 {
|
iter.index++
|
||||||
var zero T
|
ok := iter.index >= 0 && iter.index < len(iter.slice)
|
||||||
return zero, false
|
var item T
|
||||||
|
if ok {
|
||||||
|
item = iter.slice[iter.index]
|
||||||
}
|
}
|
||||||
item := iter.slice[0]
|
return item, ok
|
||||||
iter.slice = iter.slice[1:]
|
|
||||||
return item, true
|
// if len(iter.slice) == 0 {
|
||||||
|
// var zero T
|
||||||
|
// return zero, false
|
||||||
|
// }
|
||||||
|
// iter.index++
|
||||||
|
// item := iter.slice[0]
|
||||||
|
// iter.slice = iter.slice[1:]
|
||||||
|
// return item, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count
|
// Prev implements PrevIterator.
|
||||||
func (iter *sliceIterator[T]) Count() int {
|
func (iter *sliceIterator[T]) Prev() {
|
||||||
count := len(iter.slice)
|
if iter.index == -1 {
|
||||||
iter.slice = []T{}
|
panic("Next function should be called Prev")
|
||||||
return count
|
}
|
||||||
|
if iter.HasNext() {
|
||||||
|
iter.index--
|
||||||
|
} else {
|
||||||
|
iter.index = len(iter.slice) - 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (iter *sliceIterator[T]) Begin(data []T) Iterator[T] {
|
// Set implements SetIterator.
|
||||||
// iter.data = data
|
func (iter *sliceIterator[T]) Set(value T) {
|
||||||
// iter.index = 0
|
if iter.index == -1 {
|
||||||
// iter.step = 1
|
panic("Next function should be called Set")
|
||||||
|
}
|
||||||
// return iter
|
if iter.index >= len(iter.slice) || len(iter.slice) == 0 {
|
||||||
// }
|
panic("No element in current iterator")
|
||||||
|
}
|
||||||
// func (iter *sliceIterator[T]) End(data []T) Iterator[T] {
|
iter.slice[iter.index] = value
|
||||||
// iter.data = data
|
}
|
||||||
// iter.index = len(data)
|
|
||||||
// iter.step = 1
|
|
||||||
|
|
||||||
// return iter
|
|
||||||
// }
|
|
||||||
|
|
||||||
// FromRange creates a iterator which returns the numeric range between start inclusive and end
|
// 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.
|
// exclusive by the step size. start should be less than end, step shoud be positive.
|
||||||
@@ -96,9 +172,3 @@ func (iter *rangeIterator[T]) Next() (T, bool) {
|
|||||||
iter.start += iter.step
|
iter.start += iter.step
|
||||||
return num, true
|
return num, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (iter *rangeIterator[T]) Count() int {
|
|
||||||
count := (iter.end - iter.start) / iter.step
|
|
||||||
iter.start = iter.end
|
|
||||||
return int(count)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021 dudaodong@gmail.com. All rights resulterved.
|
// Copyright 2022 dudaodong@gmail.com. All rights resulterved.
|
||||||
// Use of this source code is governed by MIT license
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
// Package iterator implements some feature of C++ STL iterators
|
// Package iterator implements some feature of C++ STL iterators
|
||||||
@@ -13,27 +13,38 @@ import (
|
|||||||
func TestSliceIterator(t *testing.T) {
|
func TestSliceIterator(t *testing.T) {
|
||||||
assert := internal.NewAssert(t, "TestSliceIterator")
|
assert := internal.NewAssert(t, "TestSliceIterator")
|
||||||
|
|
||||||
t.Run("slice iterator has next", func(t *testing.T) {
|
// HashNext
|
||||||
iter := FromSlice([]int{1, 2, 3, 4})
|
t.Run("slice iterator HasNext: ", func(t *testing.T) {
|
||||||
|
iter1 := FromSlice([]int{1, 2, 3, 4})
|
||||||
for {
|
for {
|
||||||
item, _ := iter.Next()
|
item, _ := iter1.Next()
|
||||||
if item < 4 {
|
|
||||||
assert.Equal(true, iter.HasNext())
|
if item == 4 {
|
||||||
} else {
|
assert.Equal(false, iter1.HasNext())
|
||||||
assert.Equal(false, iter.HasNext())
|
|
||||||
break
|
break
|
||||||
|
} else {
|
||||||
|
assert.Equal(true, iter1.HasNext())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iter2 := FromSlice([]int{})
|
||||||
|
assert.Equal(false, iter2.HasNext())
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("slice iterator next", func(t *testing.T) {
|
//Next
|
||||||
iter := FromSlice([]int{1, 2, 3, 4})
|
t.Run("slice iterator Next: ", func(t *testing.T) {
|
||||||
|
iter1 := FromSlice([]int{1, 2, 3, 4})
|
||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
item, ok := iter.Next()
|
item, ok := iter1.Next()
|
||||||
if !ok {
|
if !ok {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
assert.Equal(i+1, item)
|
assert.Equal(i+1, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iter2 := FromSlice([]int{})
|
||||||
|
_, ok := iter2.Next()
|
||||||
|
assert.Equal(false, ok)
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
// Copyright 2021 dudaodong@gmail.com. All rights resulterved.
|
// Copyright 2022 dudaodong@gmail.com. All rights resulterved.
|
||||||
// Use of this source code is governed by MIT license
|
// Use of this source code is governed by MIT license
|
||||||
|
|
||||||
// Package iterator implements some feature of C++ STL iterators
|
// Package iterator provides a way to iterate over values stored in containers.
|
||||||
|
// note:
|
||||||
|
// 1. Full feature iterator is complicated, this pacakge is just a experiment to explore how iterators could work in Go.
|
||||||
|
// 2. The functionality of this package is very simple and limited, may not meet the actual dev needs.
|
||||||
|
// 3. It is currently under development, unstable, and will not be completed for some time in the future.
|
||||||
|
// So, based on above factors, you may not use it in production. but, anyone is welcome to improve it.
|
||||||
|
// Hope that Go can support iterator in future. see https://github.com/golang/go/discussions/54245 and https://github.com/golang/go/discussions/56413
|
||||||
package iterator
|
package iterator
|
||||||
|
|
||||||
// Map creates a new iterator which applies a function to all items of input iterator.
|
// Map creates a new iterator which applies a function to all items of input iterator.
|
||||||
|
|||||||
Reference in New Issue
Block a user