Merge pull request #774 from kalman/set-map-insert-remove

Implement chunked insert/remove for sets and maps.
This commit is contained in:
Ben Kalman
2015-12-16 11:18:29 -08:00
9 changed files with 439 additions and 135 deletions

View File

@@ -172,11 +172,11 @@ 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(list sequenceItem, idx int) sequenceItem {
return list.(listLeaf).values[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) {
list := readMetaTupleValue(mt, cl.cs).(listLeaf)
return list, len(list.values)
otherLeaf := readMetaTupleValue(mt, cl.cs).(listLeaf)
return otherLeaf, len(otherLeaf.values)
}}
}

View File

@@ -34,8 +34,12 @@ func (cm compoundMap) Ref() ref.Ref {
return EnsureRef(cm.ref, cm)
}
func (cm compoundMap) Len() uint64 {
panic("not implemented")
func (cm compoundMap) Len() (length uint64) {
// https://github.com/attic-labs/noms/issues/764
cm.IterAll(func(k, v Value) {
length++
})
return
}
func (cm compoundMap) Empty() bool {
@@ -43,31 +47,16 @@ func (cm compoundMap) Empty() bool {
return false
}
// TODO: seek should return false if it failed to find the value
func (cm compoundMap) findLeaf(key Value) (*sequenceCursor, mapLeaf) {
cursor, leaf := newMetaSequenceCursor(cm, cm.cs)
var seekFn sequenceCursorSeekBinaryCompareFn
if orderedSequenceByIndexedType(cm.t) {
orderedKey := key.(OrderedValue)
seekFn = func(mt sequenceItem) bool {
return !mt.(metaTuple).value.(OrderedValue).Less(orderedKey)
func (cm compoundMap) findLeaf(key Value) (*sequenceCursor, mapLeaf, int) {
cursor, leaf, idx := findLeafInOrderedSequence(cm, cm.t, key, func(v Value) []Value {
entries := v.(mapLeaf).data
res := make([]Value, len(entries))
for i, entry := range entries {
res[i] = entry.key
}
} else {
seekFn = func(mt sequenceItem) bool {
return !mt.(metaTuple).value.(Ref).TargetRef().Less(key.Ref())
}
}
cursor.seekBinary(seekFn)
current := cursor.current().(metaTuple)
if current.ref != valueFromType(cm.cs, leaf, leaf.Type()).Ref() {
leaf = readMetaTupleValue(cursor.current(), cm.cs)
}
return cursor, leaf.(mapLeaf)
return res
}, cm.cs)
return cursor, leaf.(mapLeaf), idx
}
func (cm compoundMap) First() (Value, Value) {
@@ -76,19 +65,52 @@ func (cm compoundMap) First() (Value, Value) {
}
func (cm compoundMap) MaybeGet(key Value) (v Value, ok bool) {
_, leaf := cm.findLeaf(key)
_, leaf, _ := cm.findLeaf(key)
return leaf.MaybeGet(key)
}
func (cm compoundMap) Set(key Value, val Value) Map {
panic("Not implemented")
return cm.SetM(key, val)
}
func (cm compoundMap) SetM(kv ...Value) Map {
panic("Not implemented")
if len(kv) == 0 {
return cm
}
d.Chk.True(len(kv)%2 == 0)
k, v, tail := kv[0], kv[1], kv[2:]
seq, found := cm.sequenceChunkerAtKey(k)
if found {
seq.Skip()
}
seq.Append(mapEntry{k, v})
return seq.Done().(Map).SetM(tail...)
}
func (cm compoundMap) Remove(k Value) Map {
panic("Not implemented")
if seq, found := cm.sequenceChunkerAtKey(k); found {
seq.Skip()
return seq.Done().(Map)
} else {
return cm
}
}
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.cs).(mapLeaf)
return otherLeaf, len(otherLeaf.data)
}}
seq := newSequenceChunker(cur, makeMapLeafChunkFn(cm.t, cm.cs), newMapMetaSequenceChunkFn(cm.t, cm.cs), newMapLeafBoundaryChecker(), newOrderedMetaSequenceBoundaryChecker)
found := idx < len(leaf.data) && leaf.data[idx].key.Equals(k)
return seq, found
}
func (cm compoundMap) IterAllP(concurrency int, f mapIterAllCallback) {
@@ -104,12 +126,12 @@ func (cm compoundMap) Filter(cb mapFilterCallback) Map {
}
func (cm compoundMap) Has(key Value) bool {
_, leaf := cm.findLeaf(key)
_, leaf, _ := cm.findLeaf(key)
return leaf.Has(key)
}
func (cm compoundMap) Get(key Value) Value {
_, leaf := cm.findLeaf(key)
_, leaf, _ := cm.findLeaf(key)
return leaf.Get(key)
}

View File

@@ -10,10 +10,9 @@ import (
)
type testMap struct {
entries []mapEntry
less testMapLessFn
tr Type
entries []mapEntry
less testMapLessFn
tr Type
knownBadKey Value
}
@@ -31,6 +30,29 @@ func (tm testMap) Swap(i, j int) {
tm.entries[i], tm.entries[j] = tm.entries[j], tm.entries[i]
}
func (tm testMap) SetValue(i int, v Value) testMap {
entries := make([]mapEntry, 0, len(tm.entries))
entries = append(entries, tm.entries...)
entries[i].value = v
return testMap{entries, tm.less, tm.tr, tm.knownBadKey}
}
func (tm testMap) Remove(from, to int) testMap {
entries := make([]mapEntry, 0, len(tm.entries)-(to-from))
entries = append(entries, tm.entries[:from]...)
entries = append(entries, tm.entries[to:]...)
return testMap{entries, tm.less, tm.tr, tm.knownBadKey}
}
func (tm testMap) Flatten(from, to int) []Value {
flat := make([]Value, 0, len(tm.entries)*2)
for _, entry := range tm.entries[from:to] {
flat = append(flat, entry.key)
flat = append(flat, entry.value)
}
return flat
}
func (tm testMap) toCompoundMap(cs chunks.ChunkStore) compoundMap {
keyvals := []Value{}
for _, entry := range tm.entries {
@@ -59,36 +81,36 @@ func newTestMap(length int, gen testMapGenFn, less testMapLessFn, tr Type) testM
return testMap{entries, less, MakeCompoundType(MapKind, tr, tr), gen(Int64(mask + 1))}
}
func getTestNativeOrderMap() testMap {
return newTestMap(int(mapPattern*16), func(v Int64) Value {
func getTestNativeOrderMap(scale int) testMap {
return newTestMap(int(mapPattern)*scale, func(v Int64) Value {
return v
}, func(x, y Value) bool {
return !y.(OrderedValue).Less(x.(OrderedValue))
}, MakePrimitiveType(Int64Kind))
}
func getTestRefValueOrderMap() testMap {
func getTestRefValueOrderMap(scale int) testMap {
setType := MakeCompoundType(SetKind, MakePrimitiveType(Int64Kind))
return newTestMap(int(mapPattern*2), func(v Int64) Value {
return newTestMap(int(mapPattern)*scale, func(v Int64) Value {
return NewTypedSet(chunks.NewMemoryStore(), setType, v)
}, func(x, y Value) bool {
return !y.Ref().Less(x.Ref())
}, setType)
}
func getTestRefToNativeOrderMap() testMap {
func getTestRefToNativeOrderMap(scale int) testMap {
refType := MakeCompoundType(RefKind, MakePrimitiveType(Int64Kind))
return newTestMap(int(mapPattern*2), func(v Int64) Value {
return newTestMap(int(mapPattern)*scale, func(v Int64) Value {
return newRef(v.Ref(), refType)
}, func(x, y Value) bool {
return !y.(RefBase).TargetRef().Less(x.(RefBase).TargetRef())
}, refType)
}
func getTestRefToValueOrderMap() testMap {
func getTestRefToValueOrderMap(scale int) testMap {
setType := MakeCompoundType(SetKind, MakePrimitiveType(Int64Kind))
refType := MakeCompoundType(RefKind, setType)
return newTestMap(int(mapPattern*2), func(v Int64) Value {
return newTestMap(int(mapPattern)*scale, func(v Int64) Value {
return newRef(NewTypedSet(chunks.NewMemoryStore(), setType, v).Ref(), refType)
}, func(x, y Value) bool {
return !y.(RefBase).TargetRef().Less(x.(RefBase).TargetRef())
@@ -106,10 +128,10 @@ func TestCompoundMapHas(t *testing.T) {
}
}
doTest(getTestNativeOrderMap())
doTest(getTestRefValueOrderMap())
doTest(getTestRefToNativeOrderMap())
doTest(getTestRefToValueOrderMap())
doTest(getTestNativeOrderMap(16))
doTest(getTestRefValueOrderMap(2))
doTest(getTestRefToNativeOrderMap(2))
doTest(getTestRefToValueOrderMap(2))
}
func TestCompoundMapFirst(t *testing.T) {
@@ -123,10 +145,10 @@ func TestCompoundMapFirst(t *testing.T) {
assert.True(tm.entries[0].value.Equals(actualValue))
}
doTest(getTestNativeOrderMap())
doTest(getTestRefValueOrderMap())
doTest(getTestRefToNativeOrderMap())
doTest(getTestRefToValueOrderMap())
doTest(getTestNativeOrderMap(16))
doTest(getTestRefValueOrderMap(2))
doTest(getTestRefToNativeOrderMap(2))
doTest(getTestRefToValueOrderMap(2))
}
func TestCompoundMapMaybeGet(t *testing.T) {
@@ -144,10 +166,10 @@ func TestCompoundMapMaybeGet(t *testing.T) {
assert.False(ok, "m should not contain %v", tm.knownBadKey)
}
doTest(getTestNativeOrderMap())
doTest(getTestRefValueOrderMap())
doTest(getTestRefToNativeOrderMap())
doTest(getTestRefToValueOrderMap())
doTest(getTestNativeOrderMap(2))
doTest(getTestRefValueOrderMap(2))
doTest(getTestRefToNativeOrderMap(2))
doTest(getTestRefToValueOrderMap(2))
}
func TestCompoundMapIter(t *testing.T) {
@@ -174,10 +196,10 @@ func TestCompoundMapIter(t *testing.T) {
assert.Equal(endAt, idx-1)
}
doTest(getTestNativeOrderMap())
doTest(getTestRefValueOrderMap())
doTest(getTestRefToNativeOrderMap())
doTest(getTestRefToValueOrderMap())
doTest(getTestNativeOrderMap(16))
doTest(getTestRefValueOrderMap(2))
doTest(getTestRefToNativeOrderMap(2))
doTest(getTestRefToValueOrderMap(2))
}
func TestCompoundMapIterAll(t *testing.T) {
@@ -195,8 +217,108 @@ func TestCompoundMapIterAll(t *testing.T) {
})
}
doTest(getTestNativeOrderMap())
doTest(getTestRefValueOrderMap())
doTest(getTestRefToNativeOrderMap())
doTest(getTestRefToValueOrderMap())
doTest(getTestNativeOrderMap(16))
doTest(getTestRefValueOrderMap(2))
doTest(getTestRefToNativeOrderMap(2))
doTest(getTestRefToValueOrderMap(2))
}
func TestCompoundMapSet(t *testing.T) {
assert := assert.New(t)
doTest := func(incr int, tm testMap) {
cs := chunks.NewMemoryStore()
expected := tm.toCompoundMap(cs)
run := func(from, to int) {
actual := tm.Remove(from, to).toCompoundMap(cs).SetM(tm.Flatten(from, to)...)
assert.Equal(expected.Len(), actual.Len())
assert.True(expected.Equals(actual))
}
for i := 0; i < len(tm.entries); i += incr {
run(i, i+1)
}
// TODO: make this pass, and make it fast:
// for i := 0; i < len(tm.entries)-incr; i += incr {
// run(i, i+incr)
// }
// For example, run(256, 384) fails with the native order map.
}
doTest(128, getTestNativeOrderMap(32))
doTest(64, getTestRefValueOrderMap(4))
doTest(64, getTestRefToNativeOrderMap(4))
doTest(64, getTestRefToValueOrderMap(4))
}
func TestCompoundMapSetExistingKeyToExistingValue(t *testing.T) {
assert := assert.New(t)
cs := chunks.NewMemoryStore()
tm := getTestNativeOrderMap(2)
original := tm.toCompoundMap(cs)
actual := original
for _, entry := range tm.entries {
actual = actual.Set(entry.key, entry.value).(compoundMap)
}
assert.Equal(original.Len(), actual.Len())
assert.True(original.Equals(actual))
}
func TestCompoundMapSetExistingKeyToNewValue(t *testing.T) {
assert := assert.New(t)
cs := chunks.NewMemoryStore()
tm := getTestNativeOrderMap(2)
original := tm.toCompoundMap(cs)
expectedWorking := tm
actual := original
for i, entry := range tm.entries {
newValue := Int64(int64(entry.value.(Int64)) + 1)
expectedWorking = expectedWorking.SetValue(i, newValue)
actual = actual.Set(entry.key, newValue).(compoundMap)
}
expected := expectedWorking.toCompoundMap(cs)
assert.Equal(expected.Len(), actual.Len())
assert.True(expected.Equals(actual))
assert.False(original.Equals(actual))
}
func TestCompoundMapRemove(t *testing.T) {
assert := assert.New(t)
doTest := func(incr int, tm testMap) {
cs := chunks.NewMemoryStore()
whole := tm.toCompoundMap(cs)
run := func(i int) {
expected := tm.Remove(i, i+1).toCompoundMap(cs)
actual := whole.Remove(tm.entries[i].key)
assert.Equal(expected.Len(), actual.Len())
assert.True(expected.Equals(actual))
}
for i := 0; i < len(tm.entries); i += incr {
run(i)
}
run(len(tm.entries) - 1)
}
doTest(128, getTestNativeOrderMap(32))
doTest(64, getTestRefValueOrderMap(4))
doTest(64, getTestRefToNativeOrderMap(4))
doTest(64, getTestRefToValueOrderMap(4))
}
func TestCompoundMapRemoveNonexistentKey(t *testing.T) {
assert := assert.New(t)
cs := chunks.NewMemoryStore()
tm := getTestNativeOrderMap(2)
original := tm.toCompoundMap(cs)
actual := original.Remove(Int64(-1)) // rand.Int63 returns non-negative numbers.
assert.Equal(original.Len(), actual.Len())
assert.True(original.Equals(actual))
}

View File

@@ -35,8 +35,12 @@ func (cs compoundSet) Ref() ref.Ref {
return EnsureRef(cs.ref, cs)
}
func (cs compoundSet) Len() uint64 {
panic("not implemented")
func (cs compoundSet) Len() (length uint64) {
// https://github.com/attic-labs/noms/issues/764
cs.IterAll(func(v Value) {
length++
})
return
}
func (cs compoundSet) Empty() bool {
@@ -50,11 +54,54 @@ func (cs compoundSet) First() Value {
}
func (cs compoundSet) Insert(values ...Value) Set {
panic("not implemented")
if len(values) == 0 {
return cs
}
head, tail := values[0], values[1:]
var res Set
if seq, found := cs.sequenceChunkerAtValue(head); !found {
seq.Append(head)
res = seq.Done().(Set)
} else {
res = cs
}
return res.Insert(tail...)
}
func (cs compoundSet) Remove(values ...Value) Set {
panic("not implemented")
if len(values) == 0 {
return cs
}
head, tail := values[0], values[1:]
var res Set
if seq, found := cs.sequenceChunkerAtValue(head); found {
seq.Skip()
res = seq.Done().(Set)
} else {
res = cs
}
return res.Remove(tail...)
}
func (cs compoundSet) sequenceChunkerAtValue(v Value) (*sequenceChunker, bool) {
metaCur, leaf, idx := cs.findLeaf(v)
cur := &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.cs).(setLeaf)
return otherLeaf, len(otherLeaf.data)
}}
seq := newSequenceChunker(cur, makeSetLeafChunkFn(cs.t, cs.cs), newSetMetaSequenceChunkFn(cs.t, cs.cs), newSetLeafBoundaryChecker(), newOrderedMetaSequenceBoundaryChecker)
found := idx < len(leaf.data) && leaf.data[idx].Equals(v)
return seq, found
}
func (cs compoundSet) Union(others ...Set) Set {
@@ -69,35 +116,15 @@ func (cs compoundSet) Filter(cb setFilterCallback) Set {
panic("not implemented")
}
// TODO: seek should return false if it failed to find the value
func (cs compoundSet) findLeaf(key Value) (*sequenceCursor, setLeaf) {
cursor, leaf := newMetaSequenceCursor(cs, cs.cs)
var seekFn sequenceCursorSeekBinaryCompareFn
if orderedSequenceByIndexedType(cs.t) {
orderedKey := key.(OrderedValue)
seekFn = func(mt sequenceItem) bool {
return !mt.(metaTuple).value.(OrderedValue).Less(orderedKey)
}
} else {
seekFn = func(mt sequenceItem) bool {
return !mt.(metaTuple).value.(Ref).TargetRef().Less(key.Ref())
}
}
cursor.seekBinary(seekFn)
current := cursor.current().(metaTuple)
if current.ref != valueFromType(cs.cs, leaf, leaf.Type()).Ref() {
leaf = readMetaTupleValue(cursor.current(), cs.cs)
}
return cursor, leaf.(setLeaf)
func (cs compoundSet) findLeaf(key Value) (*sequenceCursor, setLeaf, int) {
cursor, leaf, idx := findLeafInOrderedSequence(cs, cs.t, key, func(v Value) []Value {
return v.(setLeaf).data
}, cs.cs)
return cursor, leaf.(setLeaf), idx
}
func (cs compoundSet) Has(key Value) bool {
_, leaf := cs.findLeaf(key)
_, leaf, _ := cs.findLeaf(key)
return leaf.Has(key)
}
@@ -127,10 +154,6 @@ func (cs compoundSet) IterAllP(concurrency int, f setIterAllCallback) {
})
}
func orderedSequenceByIndexedType(t Type) bool {
return t.Desc.(CompoundDesc).ElemTypes[0].IsOrdered()
}
func newSetMetaSequenceChunkFn(t Type, cs chunks.ChunkStore) makeChunkFn {
return func(items []sequenceItem) (sequenceItem, Value) {
tuples := make(metaSequenceData, len(items))
@@ -139,9 +162,9 @@ func newSetMetaSequenceChunkFn(t Type, cs chunks.ChunkStore) makeChunkFn {
tuples[i] = v.(metaTuple)
}
lastIndex := tuples[len(tuples)-1].value
lastValue := tuples[len(tuples)-1].value
meta := newMetaSequenceFromData(tuples, t, cs)
ref := WriteValue(meta, cs)
return metaTuple{ref, lastIndex}, meta
return metaTuple{ref, lastValue}, meta
}
}

View File

@@ -29,7 +29,14 @@ func (ts testSet) Swap(i, j int) {
ts.values[i], ts.values[j] = ts.values[j], ts.values[i]
}
func (ts testSet) toCompoundSet(cs chunks.ChunkStore) compoundSet {
func (ts testSet) Remove(from, to int) testSet {
values := make([]Value, 0, len(ts.values)-(to-from))
values = append(values, ts.values[:from]...)
values = append(values, ts.values[to:]...)
return testSet{values, ts.less, ts.tr}
}
func (ts testSet) toCompoundSet(cs chunks.ChunkStore) Set {
return NewTypedSet(cs, ts.tr, ts.values...).(compoundSet)
}
@@ -51,36 +58,36 @@ func newTestSet(length int, gen testSetGenFn, less testSetLessFn, tr Type) testS
return testSet{values, less, MakeCompoundType(SetKind, tr)}
}
func getTestNativeOrderSet() testSet {
return newTestSet(int(setPattern*16), func(v Int64) Value {
func getTestNativeOrderSet(scale int) testSet {
return newTestSet(int(setPattern)*scale, func(v Int64) Value {
return v
}, func(x, y Value) bool {
return !y.(OrderedValue).Less(x.(OrderedValue))
}, MakePrimitiveType(Int64Kind))
}
func getTestRefValueOrderSet() testSet {
func getTestRefValueOrderSet(scale int) testSet {
setType := MakeCompoundType(SetKind, MakePrimitiveType(Int64Kind))
return newTestSet(int(setPattern*2), func(v Int64) Value {
return newTestSet(int(setPattern)*scale, func(v Int64) Value {
return NewTypedSet(chunks.NewMemoryStore(), setType, v)
}, func(x, y Value) bool {
return !y.Ref().Less(x.Ref())
}, setType)
}
func getTestRefToNativeOrderSet() testSet {
func getTestRefToNativeOrderSet(scale int) testSet {
refType := MakeCompoundType(RefKind, MakePrimitiveType(Int64Kind))
return newTestSet(int(setPattern*2), func(v Int64) Value {
return newTestSet(int(setPattern)*scale, func(v Int64) Value {
return newRef(v.Ref(), refType)
}, func(x, y Value) bool {
return !y.(RefBase).TargetRef().Less(x.(RefBase).TargetRef())
}, refType)
}
func getTestRefToValueOrderSet() testSet {
func getTestRefToValueOrderSet(scale int) testSet {
setType := MakeCompoundType(SetKind, MakePrimitiveType(Int64Kind))
refType := MakeCompoundType(RefKind, setType)
return newTestSet(int(setPattern*2), func(v Int64) Value {
return newTestSet(int(setPattern)*scale, func(v Int64) Value {
return newRef(NewTypedSet(chunks.NewMemoryStore(), setType, v).Ref(), refType)
}, func(x, y Value) bool {
return !y.(RefBase).TargetRef().Less(x.(RefBase).TargetRef())
@@ -97,10 +104,10 @@ func TestCompoundSetHas(t *testing.T) {
}
}
doTest(getTestNativeOrderSet())
doTest(getTestRefValueOrderSet())
doTest(getTestRefToNativeOrderSet())
doTest(getTestRefToValueOrderSet())
doTest(getTestNativeOrderSet(16))
doTest(getTestRefValueOrderSet(2))
doTest(getTestRefToNativeOrderSet(2))
doTest(getTestRefToValueOrderSet(2))
}
func TestCompoundSetFirst(t *testing.T) {
@@ -113,10 +120,10 @@ func TestCompoundSetFirst(t *testing.T) {
assert.True(ts.values[0].Equals(actual), "%v != %v", ts.values[0], actual)
}
doTest(getTestNativeOrderSet())
doTest(getTestRefValueOrderSet())
doTest(getTestRefToNativeOrderSet())
doTest(getTestRefToValueOrderSet())
doTest(getTestNativeOrderSet(16))
doTest(getTestRefValueOrderSet(2))
doTest(getTestRefToNativeOrderSet(2))
doTest(getTestRefToValueOrderSet(2))
}
func TestCompoundSetIter(t *testing.T) {
@@ -142,10 +149,10 @@ func TestCompoundSetIter(t *testing.T) {
assert.Equal(endAt, idx-1)
}
doTest(getTestNativeOrderSet())
doTest(getTestRefValueOrderSet())
doTest(getTestRefToNativeOrderSet())
doTest(getTestRefToValueOrderSet())
doTest(getTestNativeOrderSet(16))
doTest(getTestRefValueOrderSet(2))
doTest(getTestRefToNativeOrderSet(2))
doTest(getTestRefToValueOrderSet(2))
}
func TestCompoundSetIterAll(t *testing.T) {
@@ -162,8 +169,89 @@ func TestCompoundSetIterAll(t *testing.T) {
})
}
doTest(getTestNativeOrderSet())
doTest(getTestRefValueOrderSet())
doTest(getTestRefToNativeOrderSet())
doTest(getTestRefToValueOrderSet())
doTest(getTestNativeOrderSet(16))
doTest(getTestRefValueOrderSet(2))
doTest(getTestRefToNativeOrderSet(2))
doTest(getTestRefToValueOrderSet(2))
}
func TestCompoundSetInsert(t *testing.T) {
assert := assert.New(t)
doTest := func(incr int, ts testSet) {
cs := chunks.NewMemoryStore()
expected := ts.toCompoundSet(cs)
run := func(from, to int) {
actual := ts.Remove(from, to).toCompoundSet(cs).Insert(ts.values[from:to]...)
assert.Equal(expected.Len(), actual.Len(), "%d-%d", from, to)
assert.True(expected.Equals(actual))
}
for i := 0; i < len(ts.values); i += incr {
run(i, i+1)
}
run(len(ts.values)-1, len(ts.values))
// TODO: make this pass, and make it fast:
// for i := 0; i < len(ts.values)-incr; i += incr {
// run(i, i+incr)
// }
// For example, run(896, 960) fails for the native order set.
}
doTest(64, getTestNativeOrderSet(32))
doTest(32, getTestRefValueOrderSet(4))
doTest(32, getTestRefToNativeOrderSet(4))
doTest(32, getTestRefToValueOrderSet(4))
}
func TestCompoundSetInsertExistingValue(t *testing.T) {
assert := assert.New(t)
cs := chunks.NewMemoryStore()
ts := getTestNativeOrderSet(2)
original := ts.toCompoundSet(cs)
actual := original.Insert(ts.values[0])
assert.Equal(original.Len(), actual.Len())
assert.True(original.Equals(actual))
}
func TestCompoundSetRemove(t *testing.T) {
assert := assert.New(t)
doTest := func(incr int, ts testSet) {
cs := chunks.NewMemoryStore()
whole := ts.toCompoundSet(cs)
run := func(from, to int) {
expected := ts.Remove(from, to).toCompoundSet(cs)
actual := whole.Remove(ts.values[from:to]...)
assert.Equal(expected.Len(), actual.Len(), "%d-%d", from, to)
assert.True(expected.Equals(actual))
}
for i := 0; i < len(ts.values); i += incr {
run(i, i+1)
}
run(len(ts.values)-1, len(ts.values))
// TODO: make this pass, and make it fast:
// for i := 0; i < len(ts.values)-incr; i += incr {
// run(i, i+incr)
// }
// For example, run(448, 512) fails for the native order set.
}
doTest(64, getTestNativeOrderSet(32))
doTest(32, getTestRefValueOrderSet(4))
doTest(32, getTestRefToNativeOrderSet(4))
doTest(32, getTestRefToValueOrderSet(4))
}
func TestCompoundSetRemoveNonexistentValue(t *testing.T) {
assert := assert.New(t)
cs := chunks.NewMemoryStore()
ts := getTestNativeOrderSet(2)
original := ts.toCompoundSet(cs)
actual := original.Remove(Int64(-1)) // rand.Int63 returns non-negative values.
assert.Equal(original.Len(), actual.Len())
assert.True(original.Equals(actual))
}

View File

@@ -249,7 +249,7 @@ func makeMapLeafChunkFn(t Type, cs chunks.ChunkStore) makeChunkFn {
var indexValue Value
if len(mapData) > 0 {
lastValue := mapData[len(mapData)-1]
if orderedSequenceByIndexedType(t) {
if isSequenceOrderedByIndexedType(t) {
indexValue = lastValue.key
} else {
indexValue = NewRef(lastValue.key.Ref())

View File

@@ -138,11 +138,11 @@ func newMetaSequenceCursor(root metaSequence, cs chunks.ChunkStore) (*sequenceCu
d.Chk.NotNil(root)
newCursor := func(parent *sequenceCursor, ms metaSequence) *sequenceCursor {
return &sequenceCursor{parent, ms, 0, ms.tupleCount(), func(item sequenceItem, idx int) sequenceItem {
return item.(metaSequence).tupleAt(idx)
return &sequenceCursor{parent, ms, 0, ms.tupleCount(), func(otherMs sequenceItem, idx int) sequenceItem {
return otherMs.(metaSequence).tupleAt(idx)
}, func(item sequenceItem) (sequenceItem, int) {
ms := readMetaTupleValue(item, cs).(metaSequence)
return ms, ms.tupleCount()
otherMs := readMetaTupleValue(item, cs).(metaSequence)
return otherMs, otherMs.tupleCount()
}}
}

View File

@@ -0,0 +1,49 @@
package types
import (
"sort"
"github.com/attic-labs/noms/chunks"
)
func isSequenceOrderedByIndexedType(t Type) bool {
return t.Desc.(CompoundDesc).ElemTypes[0].IsOrdered()
}
// Given a leaf in an ordered sequence, returns the values in that leaf which define the ordering of the sequence.
type getLeafOrderedValuesFn func(Value) []Value
// Returns a cursor to |key| in |ms|, plus the leaf + index that |key| is in. |t| is the type of the ordered values.
func findLeafInOrderedSequence(ms metaSequence, t Type, key Value, getValues getLeafOrderedValuesFn, cs chunks.ChunkStore) (cursor *sequenceCursor, leaf Value, idx int) {
cursor, leaf = newMetaSequenceCursor(ms, cs)
if isSequenceOrderedByIndexedType(t) {
orderedKey := key.(OrderedValue)
cursor.seekBinary(func(mt sequenceItem) bool {
return !mt.(metaTuple).value.(OrderedValue).Less(orderedKey)
})
} else {
cursor.seekBinary(func(mt sequenceItem) bool {
return !mt.(metaTuple).value.(Ref).TargetRef().Less(key.Ref())
})
}
if current := cursor.current().(metaTuple); current.ref != valueFromType(cs, leaf, leaf.Type()).Ref() {
leaf = readMetaTupleValue(cursor.current(), cs)
}
if leafData := getValues(leaf); isSequenceOrderedByIndexedType(t) {
orderedKey := key.(OrderedValue)
idx = sort.Search(len(leafData), func(i int) bool {
return !leafData[i].(OrderedValue).Less(orderedKey)
})
} else {
idx = sort.Search(len(leafData), func(i int) bool {
return !leafData[i].Ref().Less(key.Ref())
})
}
return
}

View File

@@ -231,7 +231,7 @@ func makeSetLeafChunkFn(t Type, cs chunks.ChunkStore) makeChunkFn {
var indexValue Value
if len(setData) > 0 {
lastValue := setData[len(setData)-1]
if orderedSequenceByIndexedType(t) {
if isSequenceOrderedByIndexedType(t) {
indexValue = lastValue
} else {
indexValue = NewRef(lastValue.Ref())