Skip to content

Commit

Permalink
Merge pull request #289 from vaskoz/day139
Browse files Browse the repository at this point in the history
Day139
  • Loading branch information
vaskoz committed Jan 9, 2019
2 parents dd4ffe7 + 24c6b83 commit b36b669
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,4 @@ problems from
* [Day 135](https://github.com/vaskoz/dailycodingproblem-go/issues/280)
* [Day 136](https://github.com/vaskoz/dailycodingproblem-go/issues/282)
* [Day 137](https://github.com/vaskoz/dailycodingproblem-go/issues/285)
* [Day 139](https://github.com/vaskoz/dailycodingproblem-go/issues/288)
49 changes: 49 additions & 0 deletions day139/problem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package day139

// Iterator is a simple iterator interface.
type Iterator interface {
Next() interface{}
HasNext() bool
}

// PeekableIterator wraps an iterator and provides the ability to peek.
type PeekableIterator struct {
peek interface{}
peeked bool
Iter Iterator
}

// Peek returns the next element without moving the iterator.
func (p *PeekableIterator) Peek() interface{} {
has := p.Iter.HasNext()
if !p.peeked && !has {
return nil
} else if !p.peeked {
p.peeked = true
p.peek = p.Iter.Next()
}
return p.peek
}

// Next returns the next element and advances the iterator.
func (p *PeekableIterator) Next() interface{} {
has := p.Iter.HasNext()
var result interface{}
if p.peeked {
result = p.peek
} else if has {
result = p.Iter.Next()
}
p.peeked = false
return result
}

// HasNext returns true if there is more to read from the iterator
// and false otherwise.
func (p *PeekableIterator) HasNext() bool {
has := p.Iter.HasNext()
if has || p.peeked {
return true
}
return false
}
89 changes: 89 additions & 0 deletions day139/problem_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package day139

import "testing"

var testcases = []struct {
data []interface{}
}{
{[]interface{}{3, 5, 6, 7, 9}},
{[]interface{}{"foo", "bar", "baz"}},
}

type SliceIterator struct {
Slice []interface{}
pos int
}

func (si *SliceIterator) Next() interface{} {
if si.pos >= len(si.Slice) {
return nil
}
result := si.Slice[si.pos]
si.pos++
return result
}

func (si *SliceIterator) HasNext() bool {
return si.pos < len(si.Slice)
}

func TestPeekableIterator(t *testing.T) {
t.Parallel()
for _, tc := range testcases {
p := PeekableIterator{Iter: &SliceIterator{Slice: tc.data}}
for i := range tc.data {
if result := p.Peek(); result != tc.data[i] {
t.Errorf("Peek should return %v got %v", tc.data[i], result)
}
if more := p.HasNext(); !more {
t.Errorf("There should be more data")
}
if result := p.Next(); result != tc.data[i] {
t.Errorf("Next should return %v got %v", tc.data[i], result)
}
}
if result := p.Peek(); result != nil {
t.Errorf("Peek should return %v got %v", nil, result)
}
if more := p.HasNext(); more {
t.Errorf("There should be NO more data")
}
if result := p.Next(); result != nil {
t.Errorf("Next should return %v got %v", nil, result)
}
}
}

func TestPeekableIteratorNoPeek(t *testing.T) {
t.Parallel()
for _, tc := range testcases {
p := PeekableIterator{Iter: &SliceIterator{Slice: tc.data}}
for i := range tc.data {
if more := p.HasNext(); !more {
t.Errorf("There should be more data")
}
if result := p.Next(); result != tc.data[i] {
t.Errorf("Next should return %v got %v", tc.data[i], result)
}
}
if more := p.HasNext(); more {
t.Errorf("There should be NO more data")
}
if result := p.Next(); result != nil {
t.Errorf("Next should return %v got %v", nil, result)
}
}
}

func BenchmarkPeekableIterator(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testcases {
p := PeekableIterator{Iter: &SliceIterator{Slice: tc.data}}
for range tc.data {
p.Peek()
p.HasNext()
p.Next()
}
}
}
}

0 comments on commit b36b669

Please sign in to comment.