-
Notifications
You must be signed in to change notification settings - Fork 182
/
prefixdb_iterator.go
127 lines (110 loc) · 2.65 KB
/
prefixdb_iterator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package db
import "bytes"
// IteratePrefix is a convenience function for iterating over a key domain
// restricted by prefix.
func IteratePrefix(db DB, prefix []byte) (Iterator, error) {
var start, end []byte
if len(prefix) == 0 {
start = nil
end = nil
} else {
start = cp(prefix)
end = cpIncr(prefix)
}
itr, err := db.Iterator(start, end)
if err != nil {
return nil, err
}
return itr, nil
}
/*
TODO: Make test, maybe rename.
// Like IteratePrefix but the iterator strips the prefix from the keys.
func IteratePrefixStripped(db DB, prefix []byte) Iterator {
start, end := ...
return newPrefixIterator(prefix, start, end, IteratePrefix(db, prefix))
}
*/
// Strips prefix while iterating from Iterator.
type prefixDBIterator struct {
prefix []byte
start []byte
end []byte
source Iterator
valid bool
}
var _ Iterator = (*prefixDBIterator)(nil)
func newPrefixIterator(prefix, start, end []byte, source Iterator) (*prefixDBIterator, error) {
pitrInvalid := &prefixDBIterator{
prefix: prefix,
start: start,
end: end,
source: source,
valid: false,
}
if !source.Valid() {
return pitrInvalid, nil
}
key := source.Key()
if !bytes.HasPrefix(key, prefix) {
return pitrInvalid, nil
}
return &prefixDBIterator{
prefix: prefix,
start: start,
end: end,
source: source,
valid: true,
}, nil
}
// Domain implements Iterator.
func (itr *prefixDBIterator) Domain() (start []byte, end []byte) {
return itr.start, itr.end
}
// Valid implements Iterator.
func (itr *prefixDBIterator) Valid() bool {
return itr.valid && itr.source.Valid()
}
// Next implements Iterator.
func (itr *prefixDBIterator) Next() {
if !itr.valid {
panic("prefixIterator invalid; cannot call Next()")
}
itr.source.Next()
if !itr.source.Valid() || !bytes.HasPrefix(itr.source.Key(), itr.prefix) {
itr.valid = false
}
}
// Next implements Iterator.
func (itr *prefixDBIterator) Key() (key []byte) {
if !itr.valid {
panic("prefixIterator invalid; cannot call Key()")
}
key = itr.source.Key()
return stripPrefix(key, itr.prefix)
}
// Value implements Iterator.
func (itr *prefixDBIterator) Value() (value []byte) {
if !itr.valid {
panic("prefixIterator invalid; cannot call Value()")
}
value = itr.source.Value()
return value
}
// Error implements Iterator.
func (itr *prefixDBIterator) Error() error {
return itr.source.Error()
}
// Close implements Iterator.
func (itr *prefixDBIterator) Close() {
itr.source.Close()
}
func stripPrefix(key []byte, prefix []byte) (stripped []byte) {
if len(key) < len(prefix) {
panic("should not happen")
}
if !bytes.Equal(key[:len(prefix)], prefix) {
panic("should not happen")
}
return key[len(prefix):]
}