diff --git a/iterator/iterator.go b/iterator/iterator.go new file mode 100644 index 0000000..8a1f8d2 --- /dev/null +++ b/iterator/iterator.go @@ -0,0 +1,104 @@ +// Copyright 2021 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 + +import "github.com/duke-git/lancet/v2/lancetconstraints" + +// Iterator is used to iterate over a slice of data. +type Iterator[T any] interface { + HasNext() bool + Next() (T, bool) +} + +// 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} +} + +type sliceIterator[T any] struct { + slice []T + // index int + // step int +} + +func (iter *sliceIterator[T]) HasNext() bool { + if len(iter.slice) == 0 { + return false + } + return true +} + +func (iter *sliceIterator[T]) Next() (T, bool) { + if len(iter.slice) == 0 { + var zero T + return zero, false + } + 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 +} + +// 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 +// } + +// 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 lancetconstraints.Number](start, end, step T) Iterator[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} +} + +type rangeIterator[T lancetconstraints.Number] struct { + start, end, step T +} + +func (iter *rangeIterator[T]) HasNext() bool { + if iter.start >= iter.end { + return false + } + return true +} + +func (iter *rangeIterator[T]) Next() (T, bool) { + if iter.start >= iter.end { + var zero T + return zero, false + } + num := iter.start + 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 new file mode 100644 index 0000000..ae1a685 --- /dev/null +++ b/iterator/iterator_test.go @@ -0,0 +1,39 @@ +// Copyright 2021 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 + +import ( + "testing" + + "github.com/duke-git/lancet/v2/internal" +) + +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}) + for { + item, _ := iter.Next() + if item < 4 { + assert.Equal(true, iter.HasNext()) + } else { + assert.Equal(false, iter.HasNext()) + break + } + } + }) + + t.Run("slice iterator next", func(t *testing.T) { + iter := FromSlice([]int{1, 2, 3, 4}) + for i := 0; i < 4; i++ { + item, ok := iter.Next() + if !ok { + break + } + assert.Equal(i+1, item) + } + }) +} diff --git a/iterator/operation.go b/iterator/operation.go new file mode 100644 index 0000000..45cb868 --- /dev/null +++ b/iterator/operation.go @@ -0,0 +1,55 @@ +// Copyright 2021 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 + +// Map creates a new iterator which applies a function to all items of input iterator. +func Map[T any, U any](iter Iterator[T], iteratee func(item T) U) Iterator[U] { + return &mapIterator[T, U]{ + iter: iter, + iteratee: iteratee, + } +} + +type mapIterator[T any, U any] struct { + iter Iterator[T] + iteratee func(T) U +} + +func (mr *mapIterator[T, U]) HasNext() bool { + return mr.iter.HasNext() +} + +func (mr *mapIterator[T, U]) Next() (U, bool) { + var zero U + item, ok := mr.iter.Next() + if !ok { + return zero, false + } + return mr.iteratee(item), true +} + +// Filter creates a new iterator that returns only the items that pass specified predicate function. +func Filter[T any](iter Iterator[T], predicateFunc func(item T) bool) Iterator[T] { + return &filterIterator[T]{iter: iter, predicateFunc: predicateFunc} +} + +type filterIterator[T any] struct { + iter Iterator[T] + predicateFunc func(T) bool +} + +func (fr *filterIterator[T]) Next() (T, bool) { + for item, ok := fr.iter.Next(); ok; item, ok = fr.iter.Next() { + if fr.predicateFunc(item) { + return item, true + } + } + var zero T + return zero, false +} + +func (fr *filterIterator[T]) HasNext() bool { + return fr.iter.HasNext() +}