Commit aaaa43c9 authored by Andrey Elenskiy's avatar Andrey Elenskiy Committed by Andrey Elenskiy

Fix Prev() to behave like Next() in reverse

Enumerator.Prev() would return the next item if there was no hit.
This fix instead changes Prev to return previous item as expected.
Resolving issue https://github.com/cznic/b/issues/6.
parent bcff30a6
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
# #
# Please keep the list sorted. # Please keep the list sorted.
Andrey Elenskiy <andrey.elenskiy@gmail.com>
Brian Fallik <bfallik@gmail.com> Brian Fallik <bfallik@gmail.com>
Dan Kortschak <dan.kortschak@adelaide.edu.au> Dan Kortschak <dan.kortschak@adelaide.edu.au>
Jan Mercl <0xjnml@gmail.com> Jan Mercl <0xjnml@gmail.com>
......
...@@ -800,13 +800,13 @@ func TestEnumeratorPrev(t *testing.T) { ...@@ -800,13 +800,13 @@ func TestEnumeratorPrev(t *testing.T) {
hit bool hit bool
keys []int keys []int
}{ }{
{5, false, []int{10}}, {5, false, []int{}},
{10, true, []int{10}}, {10, true, []int{10}},
{15, false, []int{20, 10}}, {15, false, []int{10}},
{20, true, []int{20, 10}}, {20, true, []int{20, 10}},
{25, false, []int{30, 20, 10}}, {25, false, []int{20, 10}},
{30, true, []int{30, 20, 10}}, {30, true, []int{30, 20, 10}},
{35, false, []int{}}, {35, false, []int{30, 20, 10}},
} }
for i, test := range table { for i, test := range table {
...@@ -863,6 +863,51 @@ func TestEnumeratorPrev(t *testing.T) { ...@@ -863,6 +863,51 @@ func TestEnumeratorPrev(t *testing.T) {
} }
} }
func TestEnumeratorPrevSanity(t *testing.T) {
// seeking within 3 keys: 10, 20, 30
table := []struct {
k int
hit bool
kOut interface{}
vOut interface{}
errOut error
}{
{10, true, 10, 100, nil},
{20, true, 20, 200, nil},
{30, true, 30, 300, nil},
{35, false, 30, 300, nil},
{25, false, 20, 200, nil},
{15, false, 10, 100, nil},
{5, false, nil, nil, io.EOF},
}
for i, test := range table {
r := TreeNew(cmp)
r.Set(10, 100)
r.Set(20, 200)
r.Set(30, 300)
en, hit := r.Seek(test.k)
if g, e := hit, test.hit; g != e {
t.Fatal(i, g, e)
}
k, v, err := en.Prev()
if g, e := err, test.errOut; g != e {
t.Fatal(i, g, e)
}
if g, e := k, test.kOut; g != e {
t.Fatal(i, g, e)
}
if g, e := v, test.vOut; g != e {
t.Fatal(i, g, e)
}
}
}
func BenchmarkSeekSeq1e3(b *testing.B) { func BenchmarkSeekSeq1e3(b *testing.B) {
benchmarkSeekSeq(b, 1e3) benchmarkSeekSeq(b, 1e3)
} }
......
...@@ -826,13 +826,7 @@ func (e *Enumerator) Next() (k interface{} /*K*/, v interface{} /*V*/, err error ...@@ -826,13 +826,7 @@ func (e *Enumerator) Next() (k interface{} /*K*/, v interface{} /*V*/, err error
} }
if e.ver != e.t.ver { if e.ver != e.t.ver {
f, hit := e.t.Seek(e.k) f, _ := e.t.Seek(e.k)
if !e.hit && hit {
if err = f.next(); err != nil {
return
}
}
*e = *f *e = *f
f.Close() f.Close()
} }
...@@ -849,7 +843,7 @@ func (e *Enumerator) Next() (k interface{} /*K*/, v interface{} /*V*/, err error ...@@ -849,7 +843,7 @@ func (e *Enumerator) Next() (k interface{} /*K*/, v interface{} /*V*/, err error
i := e.q.d[e.i] i := e.q.d[e.i]
k, v = i.k, i.v k, v = i.k, i.v
e.k, e.hit = k, false e.k, e.hit = k, true
e.next() e.next()
return return
} }
...@@ -880,13 +874,7 @@ func (e *Enumerator) Prev() (k interface{} /*K*/, v interface{} /*V*/, err error ...@@ -880,13 +874,7 @@ func (e *Enumerator) Prev() (k interface{} /*K*/, v interface{} /*V*/, err error
} }
if e.ver != e.t.ver { if e.ver != e.t.ver {
f, hit := e.t.Seek(e.k) f, _ := e.t.Seek(e.k)
if !e.hit && hit {
if err = f.prev(); err != nil {
return
}
}
*e = *f *e = *f
f.Close() f.Close()
} }
...@@ -895,15 +883,22 @@ func (e *Enumerator) Prev() (k interface{} /*K*/, v interface{} /*V*/, err error ...@@ -895,15 +883,22 @@ func (e *Enumerator) Prev() (k interface{} /*K*/, v interface{} /*V*/, err error
return return
} }
if !e.hit {
// move to previous because Seek overshoots if there's no hit
if err = e.prev(); err != nil {
return
}
}
if e.i >= e.q.c { if e.i >= e.q.c {
if err = e.next(); err != nil { if err = e.prev(); err != nil {
return return
} }
} }
i := e.q.d[e.i] i := e.q.d[e.i]
k, v = i.k, i.v k, v = i.k, i.v
e.k, e.hit = k, false e.k, e.hit = k, true
e.prev() e.prev()
return return
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment