From c3967b90d45771f87fe5b2fd29eaa217eb4d43f4 Mon Sep 17 00:00:00 2001 From: disksing Date: Wed, 27 Nov 2019 14:49:07 +0800 Subject: [PATCH] add comments and tests --- algorithm.go | 31 +++++++++---- algorithm_test.go | 76 +++++++++++++++++++++++++++++++ go.sum | 1 + iterators.go | 52 +++++++++++++++++++++- list_iter.go | 89 +++++++++++++++++++++++++++++++++++++ slice.go => slice_iter.go | 5 +++ string.go => string_iter.go | 11 +++-- 7 files changed, 252 insertions(+), 13 deletions(-) create mode 100644 list_iter.go rename slice.go => slice_iter.go (94%) rename string.go => string_iter.go (83%) diff --git a/algorithm.go b/algorithm.go index c096b88..fb8e357 100644 --- a/algorithm.go +++ b/algorithm.go @@ -102,7 +102,7 @@ func FindEnd(first, last, sFirst, sLast ForwardReader) ForwardReader { return FindEndBy(first, last, sFirst, sLast, _eq) } -// FindEnd searches for the last occurrence of the sequence [sFirst, sLast) in +// FindEndBy searches for the last occurrence of the sequence [sFirst, sLast) in // the range [first, last). If [sFirst, sLast) is empty or such sequence is // found, last is returned. Elements are compared using the given binary // predicate pred. @@ -281,7 +281,8 @@ func FillN(first ForwardWriter, count int, v Any) { } } -// Transform +// Transform applies the given function to the range [first, last) and stores +// the result in another range, beginning at dFirst. func Transform(first, last ForwardReader, dFirst ForwardWriter, op UnaryOperation) ForwardWriter { for ; _ne(first, last); dFirst, first = NextWriter(dFirst), NextReader(first) { dFirst.Write(op(first.Read())) @@ -289,7 +290,9 @@ func Transform(first, last ForwardReader, dFirst ForwardWriter, op UnaryOperatio return dFirst } -// TransformBinary +// TransformBinary applies the given function to the two ranges [first, last), +// [first2, first2+last-first) and stores the result in another range, beginning +// at dFirst. func TransformBinary(first1, last1, first2 ForwardReader, dFirst ForwardWriter, op BinaryOperation) ForwardWriter { for ; _ne(first1, last1); dFirst, first1, first2 = NextWriter(dFirst), NextReader(first1), NextReader(first2) { dFirst.Write(op(first1.Read(), first2.Read())) @@ -297,14 +300,17 @@ func TransformBinary(first1, last1, first2 ForwardReader, dFirst ForwardWriter, return dFirst } -// Generate +// Generate assigns each element in range [first, last) a value generated by the +// given function object g. func Generate(first, last ForwardWriter, g Generator) { for ; _ne(first, last); first = NextWriter(first) { first.Write(g()) } } -// GenerateN +// GenerateN assigns values, generated by given function object g, to the first +// count elements in the range beginning at first, if count>0. Does nothing +// otherwise. func GenerateN(first ForwardWriter, count int, g Generator) ForwardWriter { for ; count > 0; count-- { first.Write(g()) @@ -313,12 +319,15 @@ func GenerateN(first ForwardWriter, count int, g Generator) ForwardWriter { return first } -// Remove +// Remove removes all elements equal to v from the range [first, last) and +// returns a past-the-end iterator for the new end of the range. func Remove(first, last ForwardReadWriter, v Any) ForwardReadWriter { return RemoveIf(first, last, _eq1(v)) } -// RemoveIf +// RemoveIf removes all elements which predicate function returns true from the +// range [first, last) and returns a past-the-end iterator for the new end of +// the range. func RemoveIf(first, last ForwardReadWriter, pred UnaryPredicate) ForwardReadWriter { first = FindIf(first, last, pred).(ForwardReadWriter) if _ne(first, last) { @@ -332,12 +341,16 @@ func RemoveIf(first, last ForwardReadWriter, pred UnaryPredicate) ForwardReadWri return first } -// RemoveCopy +// RemoveCopy copies elements from the range [first, last), to another range +// beginning at dFirst, omitting the elements equal to v. Source and destination +// ranges cannot overlap. func RemoveCopy(first, last ForwardReader, dFirst ForwardWriter, v Any) ForwardWriter { return RemoveCopyIf(first, last, dFirst, _eq1(v)) } -// RemoveCopyIf +// RemoveCopyIf copies elements from the range [first, last), to another range +// beginning at dFirst, omitting the elements which predicate function returns +// true. Source and destination ranges cannot overlap. func RemoveCopyIf(first, last ForwardReader, dFirst ForwardWriter, pred UnaryPredicate) ForwardWriter { for ; _ne(first, last); first = NextReader(first) { if !pred(first.Read()) { diff --git a/algorithm_test.go b/algorithm_test.go index 6dbe9f6..e30c709 100644 --- a/algorithm_test.go +++ b/algorithm_test.go @@ -284,6 +284,82 @@ func TestFillN(t *testing.T) { } } +func TestTransform(t *testing.T) { + a := randIntSlice() + var b []int + for _, x := range a { + b = append(b, x*2) + } + Transform(begin(a), end(a), begin(a), func(x Any) Any { return x.(int) * 2 }) + sliceEqual(assert.New(t), a, b) +} + +func TestTransformBinary(t *testing.T) { + a, b := randIntSlice(), randIntSlice() + if len(a) > len(b) { + a, b = b, a + } + c := make([]int, len(a)) + TransformBinary(begin(a), end(a), begin(b), begin(c), func(x, y Any) Any { return x.(int) * y.(int) }) + for i := range a { + a[i] *= b[i] + } + sliceEqual(assert.New(t), a, c) +} + +func TestGenerate(t *testing.T) { + assert := assert.New(t) + var i int + g := func() Any { i++; return i } + a := randIntSlice() + Generate(begin(a), end(a), g) + for i := range a { + assert.Equal(i+1, a[i]) + } +} + +func TestGenerateN(t *testing.T) { + assert := assert.New(t) + var i int + g := func() Any { i++; return i } + a := randIntSlice() + b := append(a[:0:0], a...) + n := rand.Intn(len(a) + 1) + GenerateN(begin(a), n, g) + for i := range a { + if i < n { + assert.Equal(i+1, a[i]) + } else { + assert.Equal(a[i], b[i]) + } + } +} + +func TestRemove(t *testing.T) { + assert := assert.New(t) + a := randIntSlice() + b := append(a[:0:0], a...) + c := append(a[:0:0], a...) + var d, e []int + f := func(x Any) bool { return x.(int)%2 == 0 } + + count1 := Count(begin(a), end(a), 1) + countf := CountIf(begin(a), end(a), f) + SliceErase(&a, Remove(begin(a), end(a), 1)) + SliceErase(&b, RemoveIf(begin(b), end(b), f)) + RemoveCopy(begin(c), end(c), SliceBackInserter(&d), 1) + RemoveCopyIf(begin(c), end(c), SliceBackInserter(&e), f) + + assert.Equal(Count(begin(a), end(a), 1), 0) + assert.True(NoneOf(begin(b), end(b), f)) + assert.Equal(Count(begin(d), end(d), 1), 0) + assert.True(NoneOf(begin(e), end(e), f)) + assert.Equal(len(a), len(c)-count1) + assert.Equal(len(b), len(c)-countf) + assert.Equal(len(d), len(c)-count1) + assert.Equal(len(e), len(c)-countf) +} + func TestMinmax(t *testing.T) { assert := assert.New(t) a, b := randInt(), randInt() diff --git a/go.sum b/go.sum index e863f51..8fdee58 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/iterators.go b/iterators.go index e06b2ad..a814fa6 100644 --- a/iterators.go +++ b/iterators.go @@ -1,13 +1,17 @@ package iter type ( - Iter interface{} + // Iter marks an iterator. + Iter interface{} + // Reader is a readable iterator. Reader interface { Read() Any } + // Writer is a writable iterator. Writer interface { Write(Any) } + // ReadWriter is an interface that groups Reader and Writer. ReadWriter interface { Reader Writer @@ -15,180 +19,225 @@ type ( ) type ( + // ForwardIter is an iterator that moves forward. ForwardIter interface { Next() ForwardIter } + // ForwardReader is an interface that groups ForwardIter and Reader. ForwardReader interface { ForwardIter Reader } + // ForwardWriter is an interface that groups ForwardIter and Writer. ForwardWriter interface { ForwardIter Writer } + // ForwardReadWriter is an interface that groups ForwardIter and + // ReadWriter. ForwardReadWriter interface { ForwardIter ReadWriter } ) +// NextReader moves a ForwardReader to next. func NextReader(r ForwardReader) ForwardReader { return r.Next().(ForwardReader) } +// NextWriter moves a ForwardWriter to next. func NextWriter(w ForwardWriter) ForwardWriter { return w.Next().(ForwardWriter) } +// NextReadWriter moves a ReadWriter to next. func NextReadWriter(rw ForwardReadWriter) ForwardReadWriter { return rw.Next().(ForwardReadWriter) } type ( + // BackwardIter is an iterator moves backward. BackwardIter interface { Prev() BackwardIter } + // BackwardReader is an interface that groups BackwardIter and Reader. BackwardReader interface { BackwardIter Reader } + // BackwardWriter is an interface that groups BackwardIter and Writer. BackwardWriter interface { BackwardIter Writer } + // BackwardReadWriter is an interface that groups BackwardIter and + // ReadWriter. BackwardReadWriter interface { BackwardIter ReadWriter } ) +// PrevReader moves a BackwardReader to prev. func PrevReader(r BackwardReader) BackwardReader { return r.Prev().(BackwardReader) } +// PrevWriter moves a BackwardWriter to prev. func PrevWriter(w BackwardWriter) BackwardWriter { return w.Prev().(BackwardWriter) } +// PrevReadWriter moves a BackwardReadWriter to prev. func PrevReadWriter(rw BackwardReadWriter) BackwardReadWriter { return rw.Prev().(BackwardReadWriter) } type ( + // BidiIter is an iterator that moves both direction. BidiIter interface { ForwardIter BackwardIter } + // BidiReader is an interface that groups BidiIter and Reader. BidiReader interface { BidiIter Reader } + // BidiWriter is an interface that groups BidiIter and Writer. BidiWriter interface { BidiIter Writer } + // BidiReadWriter is an interface that groups BidiIter and ReadWriter. BidiReadWriter interface { BidiIter ReadWriter } ) +// NextBidiIter moves a BidiIter to next. func NextBidiIter(bi BidiIter) BidiIter { return bi.Next().(BidiIter) } +// PrevBidiIter moves a BidiIter to prev. func PrevBidiIter(bi BidiIter) BidiIter { return bi.Prev().(BidiIter) } +// NextBidiReader moves a BidiReader to next. func NextBidiReader(br BidiReader) BidiReader { return br.Next().(BidiReader) } +// PrevBidiReader moves a BidiReader to prev. func PrevBidiReader(br BidiReader) BidiReader { return br.Prev().(BidiReader) } +// NextBidiWriter moves a BidiWriter to next. func NextBidiWriter(br BidiWriter) BidiWriter { return br.Next().(BidiWriter) } +// PrevBidiWriter moves a BidiWriter to prev. func PrevBidiWriter(br BidiWriter) BidiWriter { return br.Prev().(BidiWriter) } +// NextBidiReadWriter moves a BidiReadWriter to next. func NextBidiReadWriter(br BidiReadWriter) BidiReadWriter { return br.Next().(BidiReadWriter) } +// PrevBidiReadWriter moves a BidiReadWriter to prev. func PrevBidiReadWriter(br BidiReadWriter) BidiReadWriter { return br.Prev().(BidiReadWriter) } type ( + // RandomIter is a random access iterator. RandomIter interface { BidiIter AdvanceN(n int) RandomIter Distance(RandomIter) int } + // RandomReader is an interface that groups RandomIter and Reader. RandomReader interface { RandomIter Reader } + // RandomWriter is an interface that groups RandomIter and Writer. RandomWriter interface { RandomIter Writer } + // RandomReadWriter is an interface that groups RandomIter and + // ReadWriter. RandomReadWriter interface { RandomIter ReadWriter } ) +// NextRandomIter moves a RandomIter to next. func NextRandomIter(bi RandomIter) RandomIter { return bi.Next().(RandomIter) } +// PrevRandomIter moves a RandomIter to prev. func PrevRandomIter(bi RandomIter) RandomIter { return bi.Prev().(RandomIter) } +// NextRandomReader moves a RandomReader to next. func NextRandomReader(br RandomReader) RandomReader { return br.Next().(RandomReader) } +// PrevRandomReader moves a RandomReader to prev. func PrevRandomReader(br RandomReader) RandomReader { return br.Prev().(RandomReader) } +// NextRandomWriter moves a RandomWriter to next. func NextRandomWriter(br RandomWriter) RandomWriter { return br.Next().(RandomWriter) } +// PrevRandomWriter moves a RandomWriter to prev. func PrevRandomWriter(br RandomWriter) RandomWriter { return br.Prev().(RandomWriter) } +// NextRandomReadWriter moves a RandomReadWriter to next. func NextRandomReadWriter(br RandomReadWriter) RandomReadWriter { return br.Next().(RandomReadWriter) } +// PrevRandomReadWriter moves a RandomReadWriter to prev. func PrevRandomReadWriter(br RandomReadWriter) RandomReadWriter { return br.Prev().(RandomReadWriter) } +// AdvanceNReader moves a RandomReader by step N. func AdvanceNReader(rr RandomReader, n int) RandomReader { return rr.AdvanceN(n).(RandomReader) } +// AdvanceNWriter moves a RandomWriter by step N. func AdvanceNWriter(rw RandomWriter, n int) RandomWriter { return rw.AdvanceN(n).(RandomWriter) } +// AdvanceNReadWriter moves a RandomReadWriter by step N. func AdvanceNReadWriter(rw RandomReadWriter, n int) RandomReadWriter { return rw.AdvanceN(n).(RandomReadWriter) } +// Distance returns the distance of two iterators. func Distance(first, last Iter) int { if f, ok := first.(RandomIter); ok { if l, ok := last.(RandomIter); ok { @@ -216,6 +265,7 @@ func Distance(first, last Iter) int { panic("cannot get distance") } +// AdvanceN moves an iterator by step N. func AdvanceN(it Iter, n int) Iter { if it2, ok := it.(RandomIter); ok { return it2.AdvanceN(n) diff --git a/list_iter.go b/list_iter.go new file mode 100644 index 0000000..96da3ea --- /dev/null +++ b/list_iter.go @@ -0,0 +1,89 @@ +package iter + +import "container/list" + +type ListIter struct { + l *list.List + e *list.Element +} + +func ListBegin(l *list.List) *ListIter { + return &ListIter{ + l: l, + e: l.Front(), + } +} + +func ListEnd(l *list.List) *ListIter { + return &ListIter{ + l: l, + } +} + +func ListRBegin(l *list.List) *ListIter { + return &ListIter{ + l: l, + e: l.Back(), + } +} + +func ListREnd(l *list.List) *ListIter { + return &ListIter{ + l: l, + } +} + +func (l *ListIter) Equal(x Any) bool { + return l.e == x.(*ListIter).e +} + +func (l *ListIter) Next() ForwardIter { + return &ListIter{ + l: l.l, + e: l.e.Next(), + } +} + +func (l *ListIter) Prev() BackwardIter { + return &ListIter{ + l: l.l, + e: l.e.Prev(), + } +} + +func (l *ListIter) Read() Any { + return l.e.Value +} + +func (l *ListIter) Write(x Any) { + l.e.Value = x +} + +func ListBackInserter(l *list.List) ForwardWriter { + return &listBackInserter{l: l} +} + +type listBackInserter struct { + l *list.List +} + +func (li *listBackInserter) Next() ForwardIter { + return li +} + +func (li *listBackInserter) Write(x Any) { + li.l.PushBack(x) +} + +type listInserter struct { + l *list.List + e *list.Element +} + +func (li *listInserter) Next() ForwardIter { + return li +} + +func (li *listInserter) Write(x Any) { + li.l.InsertBefore(x, li.e) +} diff --git a/slice.go b/slice_iter.go similarity index 94% rename from slice.go rename to slice_iter.go index 36297f5..91b660d 100644 --- a/slice.go +++ b/slice_iter.go @@ -114,3 +114,8 @@ func (bi *sliceBackInserter) Next() ForwardIter { func (bi *sliceBackInserter) Write(x Any) { bi.s.Set(reflect.Append(bi.s, reflect.ValueOf(x))) } + +func SliceErase(s interface{}, it Iter) { + v := reflect.ValueOf(s).Elem() + v.Set(v.Slice(0, Distance(SliceBegin(v), it))) +} diff --git a/string.go b/string_iter.go similarity index 83% rename from string.go rename to string_iter.go index 1ebd3f2..f1e2424 100644 --- a/string.go +++ b/string_iter.go @@ -1,9 +1,12 @@ package iter -import "fmt" - -import "strings" +import ( + "fmt" + "strings" +) +// StringIter is the iterator to access a string in bytes. To travise a string +// by rune, convert the string to []rune then use SliceIter. type StringIter struct { s string i int @@ -82,6 +85,8 @@ func (it StringIter) Distance(it2 RandomIter) int { return d } +// MakeString creates a string by range spesified by [first, last). The value +// type should be byte or rune. func MakeString(first, last ForwardReader) string { var s strings.Builder for ; _ne(first, last); first = NextReader(first) {