From eb66d038ac4680bd4b695b0c454f8f07190c8a73 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Tue, 29 Nov 2022 13:58:48 +0800 Subject: [PATCH] feat: update iterator package --- iterator/iterator.go | 160 +++++++++++++++++++++++++++----------- iterator/iterator_test.go | 33 +++++--- iterator/operation.go | 10 ++- 3 files changed, 145 insertions(+), 58 deletions(-) diff --git a/iterator/iterator.go b/iterator/iterator.go index 8a1f8d2..7266109 100644 --- a/iterator/iterator.go +++ b/iterator/iterator.go @@ -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 -// 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 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 { + // Next checks if there is a next value in the iteration or not 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. -func FromSlice[T any](data []T) Iterator[T] { - // return &sliceIterator[T]{slice: data, index: 0, step: 1} - return &sliceIterator[T]{slice: data} +func FromSlice[T any](slice []T) Iterator[T] { + return &sliceIterator[T]{slice: slice, index: -1} +} + +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 { slice []T - // index int - // step int + index int } func (iter *sliceIterator[T]) HasNext() bool { - if len(iter.slice) == 0 { - return false - } - return true + return iter.index < len(iter.slice)-1 } func (iter *sliceIterator[T]) Next() (T, bool) { - if len(iter.slice) == 0 { - var zero T - return zero, false + iter.index++ + ok := iter.index >= 0 && iter.index < len(iter.slice) + var item T + if ok { + item = iter.slice[iter.index] } - item := iter.slice[0] - iter.slice = iter.slice[1:] - return item, true + return item, ok + + // 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 -func (iter *sliceIterator[T]) Count() int { - count := len(iter.slice) - iter.slice = []T{} - return count +// Prev implements PrevIterator. +func (iter *sliceIterator[T]) Prev() { + if iter.index == -1 { + panic("Next function should be called Prev") + } + if iter.HasNext() { + iter.index-- + } else { + iter.index = len(iter.slice) - 1 + } } -// func (iter *sliceIterator[T]) Begin(data []T) Iterator[T] { -// iter.data = data -// iter.index = 0 -// iter.step = 1 - -// return iter -// } - -// func (iter *sliceIterator[T]) End(data []T) Iterator[T] { -// iter.data = data -// iter.index = len(data) -// iter.step = 1 - -// return iter -// } +// Set implements SetIterator. +func (iter *sliceIterator[T]) Set(value T) { + if iter.index == -1 { + panic("Next function should be called Set") + } + if iter.index >= len(iter.slice) || len(iter.slice) == 0 { + panic("No element in current iterator") + } + iter.slice[iter.index] = value +} // 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. @@ -96,9 +172,3 @@ func (iter *rangeIterator[T]) Next() (T, bool) { iter.start += iter.step return num, true } - -func (iter *rangeIterator[T]) Count() int { - count := (iter.end - iter.start) / iter.step - iter.start = iter.end - return int(count) -} diff --git a/iterator/iterator_test.go b/iterator/iterator_test.go index ae1a685..da62d3c 100644 --- a/iterator/iterator_test.go +++ b/iterator/iterator_test.go @@ -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 // Package iterator implements some feature of C++ STL iterators @@ -13,27 +13,38 @@ import ( func TestSliceIterator(t *testing.T) { assert := internal.NewAssert(t, "TestSliceIterator") - t.Run("slice iterator has next", func(t *testing.T) { - iter := FromSlice([]int{1, 2, 3, 4}) + // HashNext + t.Run("slice iterator HasNext: ", func(t *testing.T) { + iter1 := FromSlice([]int{1, 2, 3, 4}) for { - item, _ := iter.Next() - if item < 4 { - assert.Equal(true, iter.HasNext()) - } else { - assert.Equal(false, iter.HasNext()) + item, _ := iter1.Next() + + if item == 4 { + assert.Equal(false, iter1.HasNext()) break + } else { + assert.Equal(true, iter1.HasNext()) } } + + iter2 := FromSlice([]int{}) + assert.Equal(false, iter2.HasNext()) }) - t.Run("slice iterator next", func(t *testing.T) { - iter := FromSlice([]int{1, 2, 3, 4}) + //Next + t.Run("slice iterator Next: ", func(t *testing.T) { + iter1 := FromSlice([]int{1, 2, 3, 4}) for i := 0; i < 4; i++ { - item, ok := iter.Next() + item, ok := iter1.Next() if !ok { break } assert.Equal(i+1, item) } + + iter2 := FromSlice([]int{}) + _, ok := iter2.Next() + assert.Equal(false, ok) }) + } diff --git a/iterator/operation.go b/iterator/operation.go index 45cb868..d725c3c 100644 --- a/iterator/operation.go +++ b/iterator/operation.go @@ -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 -// 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 // Map creates a new iterator which applies a function to all items of input iterator.