mirror of
https://github.com/dolthub/dolt.git
synced 2026-05-20 19:38:55 -05:00
+1
-1
@@ -22,7 +22,7 @@ type Blob interface {
|
||||
}
|
||||
|
||||
func NewEmptyBlob() Blob {
|
||||
return newBlobLeaf([]byte{})
|
||||
return newBlobLeaf([]byte{}).(Blob)
|
||||
}
|
||||
|
||||
func newBlobLeafBoundaryChecker() boundaryChecker {
|
||||
|
||||
+10
-1
@@ -14,10 +14,19 @@ type blobLeaf struct {
|
||||
ref *ref.Ref
|
||||
}
|
||||
|
||||
func newBlobLeaf(data []byte) blobLeaf {
|
||||
func newBlobLeaf(data []byte) sequence {
|
||||
return blobLeaf{data, &ref.Ref{}}
|
||||
}
|
||||
|
||||
// sequence
|
||||
func (bl blobLeaf) getItem(idx int) sequenceItem {
|
||||
return bl.data[idx]
|
||||
}
|
||||
|
||||
func (bl blobLeaf) seqLen() int {
|
||||
return len(bl.data)
|
||||
}
|
||||
|
||||
// Reader implements the Blob interface
|
||||
func (bl blobLeaf) Reader() io.ReadSeeker {
|
||||
return bytes.NewReader(bl.data)
|
||||
|
||||
@@ -14,16 +14,15 @@ type compoundBlob struct {
|
||||
metaSequenceObject
|
||||
length uint64
|
||||
ref *ref.Ref
|
||||
vr ValueReader
|
||||
}
|
||||
|
||||
func newCompoundBlob(tuples metaSequenceData, vr ValueReader) compoundBlob {
|
||||
return buildCompoundBlob(tuples, BlobType, vr).(compoundBlob)
|
||||
}
|
||||
|
||||
func buildCompoundBlob(tuples metaSequenceData, t *Type, vr ValueReader) Value {
|
||||
func buildCompoundBlob(tuples metaSequenceData, t *Type, vr ValueReader) metaSequence {
|
||||
d.Chk.True(t.Equals(BlobType))
|
||||
return compoundBlob{metaSequenceObject{tuples, BlobType}, tuples.uint64ValuesSum(), &ref.Ref{}, vr}
|
||||
return compoundBlob{metaSequenceObject{tuples, BlobType, vr}, tuples.uint64ValuesSum(), &ref.Ref{}}
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -17,11 +17,10 @@ type compoundList struct {
|
||||
metaSequenceObject
|
||||
length uint64
|
||||
ref *ref.Ref
|
||||
vr ValueReader
|
||||
}
|
||||
|
||||
func buildCompoundList(tuples metaSequenceData, t *Type, vr ValueReader) Value {
|
||||
return compoundList{metaSequenceObject{tuples, t}, tuples.uint64ValuesSum(), &ref.Ref{}, vr}
|
||||
func buildCompoundList(tuples metaSequenceData, t *Type, vr ValueReader) metaSequence {
|
||||
return compoundList{metaSequenceObject{tuples, t, vr}, tuples.uint64ValuesSum(), &ref.Ref{}}
|
||||
}
|
||||
|
||||
func listAsSequenceItems(ls listLeaf) []sequenceItem {
|
||||
@@ -139,12 +138,7 @@ func (cl compoundList) Insert(idx uint64, vs ...Value) List {
|
||||
func (cl compoundList) sequenceCursorAtIndex(idx uint64) *sequenceCursor {
|
||||
// TODO: An optimisation would be to decide at each level whether to step forward or backward across the node to find the insertion point, depending on which is closer. This would make Append much faster.
|
||||
metaCur, leaf, start := cl.cursorAt(idx)
|
||||
return &sequenceCursor{metaCur, leaf, int(idx - start), len(leaf.values), func(otherLeaf sequenceItem, idx int) sequenceItem {
|
||||
return otherLeaf.(listLeaf).values[idx]
|
||||
}, func(mt sequenceItem) (sequenceItem, int) {
|
||||
otherLeaf := readMetaTupleValue(mt, cl.vr).(listLeaf)
|
||||
return otherLeaf, len(otherLeaf.values)
|
||||
}}
|
||||
return newSequenceCursor(metaCur, leaf, int(idx-start))
|
||||
}
|
||||
|
||||
func (cl compoundList) sequenceChunkerAtIndex(idx uint64) *sequenceChunker {
|
||||
|
||||
@@ -14,11 +14,10 @@ type compoundMap struct {
|
||||
metaSequenceObject
|
||||
numLeaves uint64
|
||||
ref *ref.Ref
|
||||
vr ValueReader
|
||||
}
|
||||
|
||||
func buildCompoundMap(tuples metaSequenceData, t *Type, vr ValueReader) Value {
|
||||
return compoundMap{metaSequenceObject{tuples, t}, tuples.numLeavesSum(), &ref.Ref{}, vr}
|
||||
func buildCompoundMap(tuples metaSequenceData, t *Type, vr ValueReader) metaSequence {
|
||||
return compoundMap{metaSequenceObject{tuples, t, vr}, tuples.numLeavesSum(), &ref.Ref{}}
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -97,12 +96,7 @@ func (cm compoundMap) Remove(k Value) Map {
|
||||
func (cm compoundMap) sequenceChunkerAtKey(k Value) (*sequenceChunker, bool) {
|
||||
metaCur, leaf, idx := cm.findLeaf(k)
|
||||
|
||||
cur := &sequenceCursor{metaCur, leaf, idx, len(leaf.data), func(otherLeaf sequenceItem, idx int) sequenceItem {
|
||||
return otherLeaf.(mapLeaf).data[idx]
|
||||
}, func(mt sequenceItem) (sequenceItem, int) {
|
||||
otherLeaf := readMetaTupleValue(mt, cm.vr).(mapLeaf)
|
||||
return otherLeaf, len(otherLeaf.data)
|
||||
}}
|
||||
cur := newSequenceCursor(metaCur, leaf, idx)
|
||||
|
||||
seq := newSequenceChunker(cur, makeMapLeafChunkFn(cm.t, cm.vr), newOrderedMetaSequenceChunkFn(cm.t, cm.vr), newMapLeafBoundaryChecker(), newOrderedMetaSequenceBoundaryChecker)
|
||||
found := idx < len(leaf.data) && leaf.data[idx].key.Equals(k)
|
||||
|
||||
@@ -446,7 +446,7 @@ func TestCompoundMapModifyAfterRead(t *testing.T) {
|
||||
func deriveCompoundMapHeight(m compoundMap) uint64 {
|
||||
// Note: not using mt.childRef.Height() because the purpose of this method is to be redundant.
|
||||
height := uint64(1)
|
||||
if m2, ok := m.tupleAt(0).child.(compoundMap); ok {
|
||||
if m2, ok := m.getItem(0).(metaTuple).child.(compoundMap); ok {
|
||||
height += deriveCompoundMapHeight(m2)
|
||||
}
|
||||
return height
|
||||
|
||||
+4
-14
@@ -15,11 +15,10 @@ type compoundSet struct {
|
||||
metaSequenceObject
|
||||
numLeaves uint64
|
||||
ref *ref.Ref
|
||||
vr ValueReader
|
||||
}
|
||||
|
||||
func buildCompoundSet(tuples metaSequenceData, t *Type, vr ValueReader) Value {
|
||||
return compoundSet{metaSequenceObject{tuples, t}, tuples.numLeavesSum(), &ref.Ref{}, vr}
|
||||
func buildCompoundSet(tuples metaSequenceData, t *Type, vr ValueReader) metaSequence {
|
||||
return compoundSet{metaSequenceObject{tuples, t, vr}, tuples.numLeavesSum(), &ref.Ref{}}
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -88,20 +87,11 @@ func (cs compoundSet) Remove(values ...Value) Set {
|
||||
|
||||
func (cs compoundSet) sequenceCursorAtValue(v Value) (*sequenceCursor, bool) {
|
||||
metaCur, leaf, idx := cs.findLeaf(v)
|
||||
cur := newSetSequenceCursorAtPosition(metaCur, leaf, idx, cs.vr)
|
||||
cur := newSequenceCursor(metaCur, leaf, idx)
|
||||
found := idx < len(leaf.data) && leaf.data[idx].Equals(v)
|
||||
return cur, found
|
||||
}
|
||||
|
||||
func newSetSequenceCursorAtPosition(metaCur *sequenceCursor, leaf setLeaf, idx int, cs ValueReader) *sequenceCursor {
|
||||
return &sequenceCursor{metaCur, leaf, idx, len(leaf.data), func(otherLeaf sequenceItem, idx int) sequenceItem {
|
||||
return otherLeaf.(setLeaf).data[idx]
|
||||
}, func(mt sequenceItem) (sequenceItem, int) {
|
||||
otherLeaf := readMetaTupleValue(mt, cs).(setLeaf)
|
||||
return otherLeaf, len(otherLeaf.data)
|
||||
}}
|
||||
}
|
||||
|
||||
func (cs compoundSet) sequenceChunkerAtValue(v Value) (*sequenceChunker, bool) {
|
||||
cur, found := cs.sequenceCursorAtValue(v)
|
||||
seq := newSequenceChunker(cur, makeSetLeafChunkFn(cs.t, cs.vr), newOrderedMetaSequenceChunkFn(cs.t, cs.vr), newSetLeafBoundaryChecker(), newOrderedMetaSequenceBoundaryChecker)
|
||||
@@ -165,7 +155,7 @@ func (cs compoundSet) elemType() *Type {
|
||||
|
||||
func (cs compoundSet) sequenceCursorAtFirst() *sequenceCursor {
|
||||
metaCur, leaf := newMetaSequenceCursor(cs, cs.vr)
|
||||
return newSetSequenceCursorAtPosition(metaCur, leaf.(setLeaf), 0, cs.vr)
|
||||
return newSequenceCursor(metaCur, leaf.(setLeaf), 0)
|
||||
}
|
||||
|
||||
func (cs compoundSet) valueReader() ValueReader {
|
||||
|
||||
@@ -401,7 +401,7 @@ func TestCompoundSetModifyAfterRead(t *testing.T) {
|
||||
func deriveCompoundSetHeight(s compoundSet) uint64 {
|
||||
// Note: not using mt.childRef.Height() because the purpose of this method is to be redundant.
|
||||
height := uint64(1)
|
||||
if s2, ok := s.tupleAt(0).child.(compoundSet); ok {
|
||||
if s2, ok := s.getItem(0).(metaTuple).child.(compoundSet); ok {
|
||||
height += deriveCompoundSetHeight(s2)
|
||||
}
|
||||
return height
|
||||
|
||||
@@ -109,7 +109,8 @@ func (w *jsonArrayWriter) maybeWriteMetaSequence(v Value, tr *Type) bool {
|
||||
|
||||
w.write(true) // a meta sequence
|
||||
w2 := newJSONArrayWriter(w.vw)
|
||||
for _, tuple := range ms.(metaSequence).data() {
|
||||
for i := 0; i < ms.seqLen(); i++ {
|
||||
tuple := ms.getItem(i).(metaTuple)
|
||||
if tuple.child != nil && w.vw != nil {
|
||||
// Write unwritten chunked sequences. Chunks are lazily written so that intermediate chunked structures like NewList().Append(x).Append(y) don't cause unnecessary churn.
|
||||
w.vw.WriteValue(tuple.child)
|
||||
|
||||
@@ -33,8 +33,8 @@ func TestValueEquals(t *testing.T) {
|
||||
b1 := NewBlob(bytes.NewBufferString("hi"))
|
||||
b2 := NewBlob(bytes.NewBufferString("bye"))
|
||||
return newCompoundBlob([]metaTuple{
|
||||
newMetaTuple(Number(uint64(2)), b1, NewTypedRefFromValue(b1), 2),
|
||||
newMetaTuple(Number(uint64(5)), b2, NewTypedRefFromValue(b2), 5),
|
||||
newMetaTuple(Number(uint64(2)), b1.(sequence), NewTypedRefFromValue(b1), 2),
|
||||
newMetaTuple(Number(uint64(5)), b2.(sequence), NewTypedRefFromValue(b2), 5),
|
||||
}, nil)
|
||||
},
|
||||
func() Value { return NewList() },
|
||||
|
||||
+10
-1
@@ -13,11 +13,20 @@ type listLeaf struct {
|
||||
ref *ref.Ref
|
||||
}
|
||||
|
||||
func newListLeaf(t *Type, v ...Value) List {
|
||||
func newListLeaf(t *Type, v ...Value) sequence {
|
||||
d.Chk.Equal(ListKind, t.Kind())
|
||||
return listLeaf{v, t, &ref.Ref{}}
|
||||
}
|
||||
|
||||
// sequence
|
||||
func (l listLeaf) getItem(idx int) sequenceItem {
|
||||
return l.values[idx]
|
||||
}
|
||||
|
||||
func (l listLeaf) seqLen() int {
|
||||
return len(l.values)
|
||||
}
|
||||
|
||||
func (l listLeaf) Len() uint64 {
|
||||
return uint64(len(l.values))
|
||||
}
|
||||
|
||||
+10
-1
@@ -22,7 +22,7 @@ type mapEntry struct {
|
||||
value Value
|
||||
}
|
||||
|
||||
func newMapLeaf(t *Type, data ...mapEntry) Map {
|
||||
func newMapLeaf(t *Type, data ...mapEntry) sequence {
|
||||
return mapLeaf{data, getIndexFnForMapType(t), t, &ref.Ref{}}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,15 @@ func (m mapLeaf) First() (Value, Value) {
|
||||
return entry.key, entry.value
|
||||
}
|
||||
|
||||
// sequence
|
||||
func (m mapLeaf) getItem(idx int) sequenceItem {
|
||||
return m.data[idx]
|
||||
}
|
||||
|
||||
func (m mapLeaf) seqLen() int {
|
||||
return len(m.data)
|
||||
}
|
||||
|
||||
func (m mapLeaf) Len() uint64 {
|
||||
return uint64(len(m.data))
|
||||
}
|
||||
|
||||
+21
-25
@@ -10,21 +10,18 @@ const (
|
||||
|
||||
// metaSequence is a logical abstraction, but has no concrete "base" implementation. A Meta Sequence is a non-leaf (internal) node of a "probably" tree, which results from the chunking of an ordered or unordered sequence of values.
|
||||
type metaSequence interface {
|
||||
Value
|
||||
data() metaSequenceData
|
||||
tupleAt(idx int) metaTuple
|
||||
tupleSlice(to int) []metaTuple
|
||||
tupleCount() int
|
||||
sequence
|
||||
getChildSequence(idx int) sequence
|
||||
}
|
||||
|
||||
func newMetaTuple(value, child Value, childRef Ref, numLeaves uint64) metaTuple {
|
||||
func newMetaTuple(value Value, child sequence, childRef Ref, numLeaves uint64) metaTuple {
|
||||
d.Chk.NotEqual(Ref{}, childRef)
|
||||
return metaTuple{child, childRef, value, numLeaves}
|
||||
}
|
||||
|
||||
// metaTuple is a node in a Prolly Tree, consisting of data in the node (either tree leaves or other metaSequences), and a Value annotation for exploring the tree (e.g. the largest item if this an ordered sequence).
|
||||
type metaTuple struct {
|
||||
child Value // may be nil
|
||||
child sequence // may be nil
|
||||
childRef Ref
|
||||
value Value
|
||||
numLeaves uint64
|
||||
@@ -61,18 +58,26 @@ func (msd metaSequenceData) last() metaTuple {
|
||||
type metaSequenceObject struct {
|
||||
tuples metaSequenceData
|
||||
t *Type
|
||||
vr ValueReader
|
||||
}
|
||||
|
||||
func (ms metaSequenceObject) tupleAt(idx int) metaTuple {
|
||||
// sequence
|
||||
func (ms metaSequenceObject) getItem(idx int) sequenceItem {
|
||||
return ms.tuples[idx]
|
||||
}
|
||||
|
||||
func (ms metaSequenceObject) tupleSlice(to int) []metaTuple {
|
||||
return ms.tuples[:to]
|
||||
func (ms metaSequenceObject) seqLen() int {
|
||||
return len(ms.tuples)
|
||||
}
|
||||
|
||||
func (ms metaSequenceObject) tupleCount() int {
|
||||
return len(ms.tuples)
|
||||
func (ms metaSequenceObject) getChildSequence(idx int) sequence {
|
||||
mt := ms.tuples[idx]
|
||||
if mt.child != nil {
|
||||
return mt.child
|
||||
}
|
||||
|
||||
child := mt.childRef.TargetValue(ms.vr)
|
||||
return child.(sequence)
|
||||
}
|
||||
|
||||
func (ms metaSequenceObject) data() metaSequenceData {
|
||||
@@ -98,7 +103,7 @@ func (ms metaSequenceObject) Type() *Type {
|
||||
return ms.t
|
||||
}
|
||||
|
||||
type metaBuilderFunc func(tuples metaSequenceData, t *Type, vr ValueReader) Value
|
||||
type metaBuilderFunc func(tuples metaSequenceData, t *Type, vr ValueReader) metaSequence
|
||||
|
||||
var metaFuncMap = map[NomsKind]metaBuilderFunc{}
|
||||
|
||||
@@ -106,7 +111,7 @@ func registerMetaValue(k NomsKind, bf metaBuilderFunc) {
|
||||
metaFuncMap[k] = bf
|
||||
}
|
||||
|
||||
func newMetaSequenceFromData(tuples metaSequenceData, t *Type, vr ValueReader) Value {
|
||||
func newMetaSequenceFromData(tuples metaSequenceData, t *Type, vr ValueReader) metaSequence {
|
||||
if bf, ok := metaFuncMap[t.Kind()]; ok {
|
||||
return bf(tuples, t, vr)
|
||||
}
|
||||
@@ -118,21 +123,12 @@ func newMetaSequenceFromData(tuples metaSequenceData, t *Type, vr ValueReader) V
|
||||
func newMetaSequenceCursor(root metaSequence, vr ValueReader) (*sequenceCursor, Value) {
|
||||
d.Chk.NotNil(root)
|
||||
|
||||
newCursor := func(parent *sequenceCursor, ms metaSequence) *sequenceCursor {
|
||||
return &sequenceCursor{parent, ms, 0, ms.tupleCount(), func(otherMs sequenceItem, idx int) sequenceItem {
|
||||
return otherMs.(metaSequence).tupleAt(idx)
|
||||
}, func(item sequenceItem) (sequenceItem, int) {
|
||||
otherMs := readMetaTupleValue(item, vr).(metaSequence)
|
||||
return otherMs, otherMs.tupleCount()
|
||||
}}
|
||||
}
|
||||
|
||||
cursors := []*sequenceCursor{newCursor(nil, root)}
|
||||
cursors := []*sequenceCursor{newSequenceCursor(nil, root, 0)}
|
||||
for {
|
||||
cursor := cursors[len(cursors)-1]
|
||||
val := readMetaTupleValue(cursor.current(), vr)
|
||||
if ms, ok := val.(metaSequence); ok {
|
||||
cursors = append(cursors, newCursor(cursor, ms))
|
||||
cursors = append(cursors, newSequenceCursor(cursor, ms, 0))
|
||||
} else {
|
||||
return cursor, val
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/attic-labs/noms/ref"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMeta(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
vs := NewTestValueStore()
|
||||
|
||||
flatList := []Value{Number(0), Number(1), Number(2), Number(3), Number(4), Number(5), Number(6), Number(7)}
|
||||
l0 := NewList(flatList[0])
|
||||
lr0 := vs.WriteValue(l0)
|
||||
l1 := NewList(flatList[1])
|
||||
lr1 := vs.WriteValue(l1)
|
||||
l2 := NewList(flatList[2])
|
||||
lr2 := vs.WriteValue(l2)
|
||||
l3 := NewList(flatList[3])
|
||||
lr3 := vs.WriteValue(l3)
|
||||
l4 := NewList(flatList[4])
|
||||
lr4 := vs.WriteValue(l4)
|
||||
l5 := NewList(flatList[5])
|
||||
lr5 := vs.WriteValue(l5)
|
||||
l6 := NewList(flatList[6])
|
||||
lr6 := vs.WriteValue(l6)
|
||||
l7 := NewList(flatList[7])
|
||||
lr7 := vs.WriteValue(l7)
|
||||
|
||||
mtr := l0.Type()
|
||||
|
||||
m0 := compoundList{metaSequenceObject{metaSequenceData{{l0, lr0, Number(1), 1}, {l1, lr1, Number(2), 2}}, mtr}, 0, &ref.Ref{}, vs}
|
||||
lm0 := vs.WriteValue(m0)
|
||||
m1 := compoundList{metaSequenceObject{metaSequenceData{{l2, lr2, Number(1), 1}, {l3, lr3, Number(2), 2}}, mtr}, 0, &ref.Ref{}, vs}
|
||||
lm1 := vs.WriteValue(m1)
|
||||
m2 := compoundList{metaSequenceObject{metaSequenceData{{l4, lr4, Number(1), 1}, {l5, lr5, Number(2), 2}}, mtr}, 0, &ref.Ref{}, vs}
|
||||
lm2 := vs.WriteValue(m2)
|
||||
m3 := compoundList{metaSequenceObject{metaSequenceData{{l6, lr6, Number(1), 1}, {l7, lr7, Number(2), 2}}, mtr}, 0, &ref.Ref{}, vs}
|
||||
lm3 := vs.WriteValue(m3)
|
||||
|
||||
m00 := compoundList{metaSequenceObject{metaSequenceData{{m0, lm0, Number(2), 2}, {m1, lm1, Number(4), 4}}, mtr}, 0, &ref.Ref{}, vs}
|
||||
lm00 := vs.WriteValue(m00)
|
||||
m01 := compoundList{metaSequenceObject{metaSequenceData{{m2, lm2, Number(2), 2}, {m3, lm3, Number(4), 4}}, mtr}, 0, &ref.Ref{}, vs}
|
||||
lm01 := vs.WriteValue(m01)
|
||||
|
||||
rootList := compoundList{metaSequenceObject{metaSequenceData{{m00, lm00, Number(4), 4}, {m01, lm01, Number(8), 8}}, mtr}, 0, &ref.Ref{}, vs}
|
||||
rootRef := vs.WriteValue(rootList).TargetRef()
|
||||
|
||||
rootList = vs.ReadValue(rootRef).(compoundList)
|
||||
|
||||
rootList.IterAll(func(v Value, index uint64) {
|
||||
assert.Equal(flatList[index], v)
|
||||
})
|
||||
}
|
||||
@@ -2,8 +2,6 @@ package types
|
||||
|
||||
import "github.com/attic-labs/noms/d"
|
||||
|
||||
type sequenceItem interface{}
|
||||
|
||||
type boundaryChecker interface {
|
||||
// Write takes an item and returns true if the sequence should chunk after this item, false if not.
|
||||
Write(sequenceItem) bool
|
||||
|
||||
+49
-28
@@ -6,20 +6,41 @@ import (
|
||||
"github.com/attic-labs/noms/d"
|
||||
)
|
||||
|
||||
// sequenceCursor explores a tree of sequence items.
|
||||
type sequenceCursor struct {
|
||||
parent *sequenceCursor
|
||||
item sequenceItem
|
||||
idx, length int
|
||||
getItem getItemFn
|
||||
readChunk readChunkFn
|
||||
type sequenceItem interface{}
|
||||
|
||||
type sequence interface {
|
||||
Value
|
||||
getItem(idx int) sequenceItem
|
||||
seqLen() int
|
||||
}
|
||||
|
||||
// getItemFn takes a parent in the sequence and an index into that parent, and returns the child item, equivalent to `child = parent[idx]`. The parent and the child aren't necessarily the same type.
|
||||
type getItemFn func(parent sequenceItem, idx int) (child sequenceItem)
|
||||
// sequenceCursor explores a tree of sequence items.
|
||||
type sequenceCursor struct {
|
||||
parent *sequenceCursor
|
||||
seq sequence
|
||||
idx int
|
||||
}
|
||||
|
||||
// readChunkFn takes an item in the sequence which references another sequence of items, and returns that sequence along with its length.
|
||||
type readChunkFn func(reference sequenceItem) (sequence sequenceItem, length int)
|
||||
func newSequenceCursor(parent *sequenceCursor, seq sequence, idx int) *sequenceCursor {
|
||||
return &sequenceCursor{parent, seq, idx}
|
||||
}
|
||||
|
||||
func (cur *sequenceCursor) length() int {
|
||||
return cur.seq.seqLen()
|
||||
}
|
||||
|
||||
func (cur *sequenceCursor) getItem(idx int) sequenceItem {
|
||||
return cur.seq.getItem(idx)
|
||||
}
|
||||
|
||||
func (cur *sequenceCursor) sync() {
|
||||
d.Chk.NotNil(cur.parent)
|
||||
cur.seq = cur.parent.getChildSequence()
|
||||
}
|
||||
|
||||
func (cur *sequenceCursor) getChildSequence() sequence {
|
||||
return cur.seq.(metaSequence).getChildSequence(cur.idx)
|
||||
}
|
||||
|
||||
// Returns the value the cursor refers to. Fails an assertion if the cursor doesn't point to a value.
|
||||
func (cur *sequenceCursor) current() sequenceItem {
|
||||
@@ -30,11 +51,11 @@ func (cur *sequenceCursor) current() sequenceItem {
|
||||
|
||||
// Returns the value the cursor refers to, if any. If the cursor doesn't point to a value, returns (nil, false).
|
||||
func (cur *sequenceCursor) maybeCurrent() (sequenceItem, bool) {
|
||||
d.Chk.True(cur.idx >= -1 && cur.idx <= cur.length)
|
||||
if cur.idx == -1 || cur.idx == cur.length {
|
||||
d.Chk.True(cur.idx >= -1 && cur.idx <= cur.length())
|
||||
if cur.idx == -1 || cur.idx == cur.length() {
|
||||
return nil, false
|
||||
}
|
||||
return cur.getItem(cur.item, cur.idx), true
|
||||
return cur.getItem(cur.idx), true
|
||||
}
|
||||
|
||||
func (cur *sequenceCursor) indexInChunk() int {
|
||||
@@ -46,15 +67,15 @@ func (cur *sequenceCursor) advance() bool {
|
||||
}
|
||||
|
||||
func (cur *sequenceCursor) advanceMaybeAllowPastEnd(allowPastEnd bool) bool {
|
||||
if cur.idx < cur.length-1 {
|
||||
if cur.idx < cur.length()-1 {
|
||||
cur.idx++
|
||||
return true
|
||||
}
|
||||
if cur.idx == cur.length {
|
||||
if cur.idx == cur.length() {
|
||||
return false
|
||||
}
|
||||
if cur.parent != nil && cur.parent.advanceMaybeAllowPastEnd(false) {
|
||||
cur.item, cur.length = cur.readChunk(cur.parent.current())
|
||||
cur.sync()
|
||||
cur.idx = 0
|
||||
return true
|
||||
}
|
||||
@@ -78,8 +99,8 @@ func (cur *sequenceCursor) retreatMaybeAllowBeforeStart(allowBeforeStart bool) b
|
||||
}
|
||||
d.Chk.Equal(0, cur.idx)
|
||||
if cur.parent != nil && cur.parent.retreatMaybeAllowBeforeStart(false) {
|
||||
cur.item, cur.length = cur.readChunk(cur.parent.current())
|
||||
cur.idx = cur.length - 1
|
||||
cur.sync()
|
||||
cur.idx = cur.length() - 1
|
||||
return true
|
||||
}
|
||||
if allowBeforeStart {
|
||||
@@ -93,7 +114,7 @@ func (cur *sequenceCursor) clone() *sequenceCursor {
|
||||
if cur.parent != nil {
|
||||
parent = cur.parent.clone()
|
||||
}
|
||||
return &sequenceCursor{parent, cur.item, cur.idx, cur.length, cur.getItem, cur.readChunk}
|
||||
return &sequenceCursor{parent, cur.seq, cur.idx}
|
||||
}
|
||||
|
||||
type sequenceCursorSeekBinaryCompareFn func(item sequenceItem) bool
|
||||
@@ -104,15 +125,15 @@ func (cur *sequenceCursor) seekBinary(compare sequenceCursorSeekBinaryCompareFn)
|
||||
|
||||
if cur.parent != nil {
|
||||
cur.parent.seekBinary(compare)
|
||||
cur.item, cur.length = cur.readChunk(cur.parent.current())
|
||||
cur.sync()
|
||||
}
|
||||
|
||||
cur.idx = sort.Search(cur.length, func(i int) bool {
|
||||
return compare(cur.getItem(cur.item, i))
|
||||
cur.idx = sort.Search(cur.length(), func(i int) bool {
|
||||
return compare(cur.getItem(i))
|
||||
})
|
||||
|
||||
if cur.idx == cur.length {
|
||||
cur.idx = cur.length - 1
|
||||
if cur.idx == cur.length() {
|
||||
cur.idx = cur.length() - 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,12 +145,12 @@ func (cur *sequenceCursor) seekLinear(step sequenceCursorSeekLinearStepFn, carry
|
||||
|
||||
if cur.parent != nil {
|
||||
carry = cur.parent.seekLinear(step, carry)
|
||||
cur.item, cur.length = cur.readChunk(cur.parent.current())
|
||||
cur.sync()
|
||||
}
|
||||
|
||||
cur.idx = 0
|
||||
for i := 0; i < cur.length-1; i++ {
|
||||
found, carryOut := step(carry, cur.getItem(cur.item, i))
|
||||
for i := 0; i < cur.length()-1; i++ {
|
||||
found, carryOut := step(carry, cur.getItem(i))
|
||||
if found {
|
||||
break
|
||||
}
|
||||
|
||||
+50
-172
@@ -3,42 +3,57 @@ package types
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/attic-labs/noms/ref"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func newTestSequenceCursor(items [][]int) *sequenceCursor {
|
||||
parent := &sequenceCursor{nil, items, 0, len(items), func(item sequenceItem, idx int) sequenceItem {
|
||||
return item.([][]int)[idx] // item should be == items
|
||||
}, func(item sequenceItem) (sequenceItem, int) {
|
||||
panic("not reachable")
|
||||
}}
|
||||
type testSequence struct {
|
||||
items []interface{}
|
||||
}
|
||||
|
||||
return &sequenceCursor{parent, items[0], 0, len(items[0]), func(item sequenceItem, idx int) sequenceItem {
|
||||
return item.([]int)[idx]
|
||||
}, func(item sequenceItem) (sequenceItem, int) {
|
||||
return item, len(item.([]int))
|
||||
}}
|
||||
// sequence
|
||||
func (ts testSequence) getItem(idx int) sequenceItem {
|
||||
return ts.items[idx]
|
||||
}
|
||||
|
||||
func (ts testSequence) seqLen() int {
|
||||
return len(ts.items)
|
||||
}
|
||||
|
||||
func (ts testSequence) getChildSequence(idx int) sequence {
|
||||
child := ts.items[idx]
|
||||
return testSequence{child.([]interface{})}
|
||||
}
|
||||
|
||||
func (ts testSequence) Equals(other Value) bool {
|
||||
panic("not reached")
|
||||
}
|
||||
func (ts testSequence) Ref() ref.Ref {
|
||||
panic("not reached")
|
||||
}
|
||||
func (ts testSequence) ChildValues() []Value {
|
||||
panic("not reached")
|
||||
}
|
||||
func (ts testSequence) Chunks() []Ref {
|
||||
panic("not reached")
|
||||
}
|
||||
func (ts testSequence) Type() *Type {
|
||||
panic("not reached")
|
||||
}
|
||||
|
||||
func newTestSequenceCursor(items []interface{}) *sequenceCursor {
|
||||
parent := newSequenceCursor(nil, testSequence{items}, 0)
|
||||
items = items[0].([]interface{})
|
||||
return newSequenceCursor(parent, testSequence{items}, 0)
|
||||
}
|
||||
|
||||
// TODO: Convert all tests to use newTestSequenceCursor3.
|
||||
func newTestSequenceCursor3(items [][][]int) *sequenceCursor {
|
||||
top := &sequenceCursor{nil, items, 0, len(items), func(item sequenceItem, idx int) sequenceItem {
|
||||
return item.([][][]int)[idx] // item should be == items
|
||||
}, func(item sequenceItem) (sequenceItem, int) {
|
||||
panic("not reachable")
|
||||
}}
|
||||
|
||||
middle := &sequenceCursor{top, items[0], 0, len(items[0]), func(item sequenceItem, idx int) sequenceItem {
|
||||
return item.([][]int)[idx]
|
||||
}, func(item sequenceItem) (sequenceItem, int) {
|
||||
return item, len(item.([][]int))
|
||||
}}
|
||||
|
||||
return &sequenceCursor{middle, items[0][0], 0, len(items[0][0]), func(item sequenceItem, idx int) sequenceItem {
|
||||
return item.([]int)[idx]
|
||||
}, func(item sequenceItem) (sequenceItem, int) {
|
||||
return item, len(item.([]int))
|
||||
}}
|
||||
func newTestSequenceCursor3(items []interface{}) *sequenceCursor {
|
||||
top := newSequenceCursor(nil, testSequence{items}, 0)
|
||||
items = items[0].([]interface{})
|
||||
middle := newSequenceCursor(top, testSequence{items}, 0)
|
||||
items = items[0].([]interface{})
|
||||
return newSequenceCursor(middle, testSequence{items}, 0)
|
||||
}
|
||||
|
||||
func TestTestCursor(t *testing.T) {
|
||||
@@ -46,7 +61,7 @@ func TestTestCursor(t *testing.T) {
|
||||
|
||||
var cur *sequenceCursor
|
||||
reset := func() {
|
||||
cur = newTestSequenceCursor([][]int{[]int{100, 101}, []int{102}})
|
||||
cur = newTestSequenceCursor([]interface{}{[]interface{}{100, 101}, []interface{}{102}})
|
||||
}
|
||||
expect := func(expectIdx, expectParentIdx int, expectOk bool, expectVal sequenceItem) {
|
||||
assert.Equal(expectIdx, cur.indexInChunk())
|
||||
@@ -112,14 +127,14 @@ func TestTestCursor(t *testing.T) {
|
||||
|
||||
func TestCursorGetMaxNPrevItemsWithEmptySequence(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
cur := newTestSequenceCursor([][]int{[]int{}})
|
||||
cur := newTestSequenceCursor([]interface{}{[]interface{}{}})
|
||||
assert.Equal([]sequenceItem{}, cur.maxNPrevItems(0))
|
||||
assert.Equal([]sequenceItem{}, cur.maxNPrevItems(1))
|
||||
}
|
||||
|
||||
func TestCursorGetMaxNPrevItemsWithSingleItemSequence(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
cur := newTestSequenceCursor([][]int{[]int{100}, []int{101}, []int{102}})
|
||||
cur := newTestSequenceCursor([]interface{}{[]interface{}{100}, []interface{}{101}, []interface{}{102}})
|
||||
|
||||
assert.Equal([]sequenceItem{}, cur.maxNPrevItems(0))
|
||||
assert.Equal([]sequenceItem{}, cur.maxNPrevItems(1))
|
||||
@@ -152,9 +167,9 @@ func TestCursorGetMaxNPrevItemsWithSingleItemSequence(t *testing.T) {
|
||||
func TestCursorGetMaxNPrevItemsWithMultiItemSequence(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
cur := newTestSequenceCursor([][]int{
|
||||
[]int{100, 101, 102, 103},
|
||||
[]int{104, 105, 106, 107},
|
||||
cur := newTestSequenceCursor([]interface{}{
|
||||
[]interface{}{100, 101, 102, 103},
|
||||
[]interface{}{104, 105, 106, 107},
|
||||
})
|
||||
|
||||
assert.Equal([]sequenceItem{}, cur.maxNPrevItems(0))
|
||||
@@ -226,140 +241,3 @@ func TestCursorGetMaxNPrevItemsWithMultiItemSequence(t *testing.T) {
|
||||
assert.Equal([]sequenceItem{100, 101, 102, 103, 104, 105, 106, 107}, cur.maxNPrevItems(8))
|
||||
assert.Equal([]sequenceItem{100, 101, 102, 103, 104, 105, 106, 107}, cur.maxNPrevItems(9))
|
||||
}
|
||||
|
||||
func TestCursorSeekBinary(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
var cur *sequenceCursor
|
||||
reset := func() {
|
||||
cur = newTestSequenceCursor([][]int{
|
||||
[]int{100, 101, 102, 103},
|
||||
[]int{104, 105, 106, 107},
|
||||
})
|
||||
}
|
||||
|
||||
assertSeeksTo := func(expected sequenceItem, seekTo int) {
|
||||
cur.seekBinary(func(val sequenceItem) bool {
|
||||
switch val := val.(type) {
|
||||
case []int:
|
||||
return val[len(val)-1] >= seekTo
|
||||
case int:
|
||||
return val >= seekTo
|
||||
default:
|
||||
panic("illegal")
|
||||
}
|
||||
})
|
||||
assert.Equal(expected, cur.current())
|
||||
}
|
||||
|
||||
// Test seeking immediately to values on cursor construction.
|
||||
reset()
|
||||
assertSeeksTo(sequenceItem(100), 99)
|
||||
for i := 100; i <= 107; i++ {
|
||||
reset()
|
||||
assertSeeksTo(sequenceItem(i), i)
|
||||
}
|
||||
reset()
|
||||
assertSeeksTo(sequenceItem(107), 108)
|
||||
|
||||
// Test reusing an existing cursor to seek all over the place.
|
||||
reset()
|
||||
assertSeeksTo(sequenceItem(100), 99)
|
||||
for i := 100; i <= 107; i++ {
|
||||
assertSeeksTo(sequenceItem(i), i)
|
||||
}
|
||||
assertSeeksTo(sequenceItem(107), 108)
|
||||
assertSeeksTo(sequenceItem(100), 99)
|
||||
for i := 100; i <= 107; i++ {
|
||||
assertSeeksTo(sequenceItem(i), i)
|
||||
}
|
||||
assertSeeksTo(sequenceItem(107), 108)
|
||||
}
|
||||
|
||||
func TestCursorSeekLinear(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
var cur *sequenceCursor
|
||||
|
||||
assertSeeksTo := func(reset bool, expectedPos sequenceItem, expectedSumUpto, seekTo int) {
|
||||
if reset {
|
||||
cur = newTestSequenceCursor3(
|
||||
[][][]int{
|
||||
[][]int{
|
||||
[]int{100, 101, 102, 103},
|
||||
[]int{104, 105, 106, 107},
|
||||
},
|
||||
[][]int{
|
||||
[]int{108, 109, 110, 111},
|
||||
[]int{112, 113, 114, 115},
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
sumUpto := cur.seekLinear(func(carry interface{}, item sequenceItem) (bool, interface{}) {
|
||||
switch item := item.(type) {
|
||||
case [][]int:
|
||||
last := item[len(item)-1]
|
||||
return seekTo <= last[len(last)-1], carry
|
||||
case []int:
|
||||
return seekTo <= item[len(item)-1], carry
|
||||
case int:
|
||||
return seekTo <= item, item + carry.(int)
|
||||
}
|
||||
panic("illegal")
|
||||
}, 0)
|
||||
pos, _ := cur.maybeCurrent()
|
||||
assert.Equal(expectedPos, pos)
|
||||
assert.Equal(expectedSumUpto, sumUpto)
|
||||
}
|
||||
|
||||
// Test seeking immediately to values on cursor construction.
|
||||
assertSeeksTo(true, sequenceItem(100), 0, 99)
|
||||
|
||||
assertSeeksTo(true, sequenceItem(100), 0, 100)
|
||||
assertSeeksTo(true, sequenceItem(101), 100, 101)
|
||||
assertSeeksTo(true, sequenceItem(102), 201, 102)
|
||||
assertSeeksTo(true, sequenceItem(103), 303, 103)
|
||||
|
||||
assertSeeksTo(true, sequenceItem(104), 0, 104)
|
||||
assertSeeksTo(true, sequenceItem(105), 104, 105)
|
||||
assertSeeksTo(true, sequenceItem(106), 209, 106)
|
||||
assertSeeksTo(true, sequenceItem(107), 315, 107)
|
||||
|
||||
assertSeeksTo(true, sequenceItem(108), 0, 108)
|
||||
assertSeeksTo(true, sequenceItem(109), 108, 109)
|
||||
assertSeeksTo(true, sequenceItem(110), 217, 110)
|
||||
assertSeeksTo(true, sequenceItem(111), 327, 111)
|
||||
|
||||
assertSeeksTo(true, sequenceItem(112), 0, 112)
|
||||
assertSeeksTo(true, sequenceItem(113), 112, 113)
|
||||
assertSeeksTo(true, sequenceItem(114), 225, 114)
|
||||
assertSeeksTo(true, sequenceItem(115), 339, 115)
|
||||
|
||||
assertSeeksTo(true, sequenceItem(115), 339, 116)
|
||||
|
||||
// Test reusing an existing cursor to seek all over the place.
|
||||
assertSeeksTo(false, sequenceItem(100), 0, 99)
|
||||
|
||||
assertSeeksTo(false, sequenceItem(100), 0, 100)
|
||||
assertSeeksTo(false, sequenceItem(101), 100, 101)
|
||||
assertSeeksTo(false, sequenceItem(102), 201, 102)
|
||||
assertSeeksTo(false, sequenceItem(103), 303, 103)
|
||||
|
||||
assertSeeksTo(false, sequenceItem(104), 0, 104)
|
||||
assertSeeksTo(false, sequenceItem(105), 104, 105)
|
||||
assertSeeksTo(false, sequenceItem(106), 209, 106)
|
||||
assertSeeksTo(false, sequenceItem(107), 315, 107)
|
||||
|
||||
assertSeeksTo(false, sequenceItem(108), 0, 108)
|
||||
assertSeeksTo(false, sequenceItem(109), 108, 109)
|
||||
assertSeeksTo(false, sequenceItem(110), 217, 110)
|
||||
assertSeeksTo(false, sequenceItem(111), 327, 111)
|
||||
|
||||
assertSeeksTo(false, sequenceItem(112), 0, 112)
|
||||
assertSeeksTo(false, sequenceItem(113), 112, 113)
|
||||
assertSeeksTo(false, sequenceItem(114), 225, 114)
|
||||
assertSeeksTo(false, sequenceItem(115), 339, 115)
|
||||
|
||||
assertSeeksTo(false, sequenceItem(115), 339, 116)
|
||||
}
|
||||
|
||||
+11
-13
@@ -17,10 +17,19 @@ type setLeaf struct {
|
||||
|
||||
type setData []Value
|
||||
|
||||
func newSetLeaf(t *Type, m ...Value) setLeaf {
|
||||
func newSetLeaf(t *Type, m ...Value) sequence {
|
||||
return setLeaf{m, getIndexFnForSetType(t), t, &ref.Ref{}}
|
||||
}
|
||||
|
||||
// sequence
|
||||
func (s setLeaf) getItem(idx int) sequenceItem {
|
||||
return s.data[idx]
|
||||
}
|
||||
|
||||
func (s setLeaf) seqLen() int {
|
||||
return len(s.data)
|
||||
}
|
||||
|
||||
func (s setLeaf) Empty() bool {
|
||||
return s.Len() == uint64(0)
|
||||
}
|
||||
@@ -197,18 +206,7 @@ func makeSetLeafChunkFn(t *Type, vr ValueReader) makeChunkFn {
|
||||
}
|
||||
|
||||
func (s setLeaf) sequenceCursorAtFirst() *sequenceCursor {
|
||||
return &sequenceCursor{
|
||||
nil,
|
||||
s.data,
|
||||
0,
|
||||
len(s.data),
|
||||
func(parent sequenceItem, idx int) sequenceItem {
|
||||
return s.data[idx]
|
||||
},
|
||||
func(reference sequenceItem) (sequence sequenceItem, length int) {
|
||||
panic("unreachable")
|
||||
},
|
||||
}
|
||||
return newSequenceCursor(nil, s, 0)
|
||||
}
|
||||
|
||||
func (s setLeaf) valueReader() ValueReader {
|
||||
|
||||
Reference in New Issue
Block a user