Files
dolt/types/set.go
Chris Masone 82338bb5be Change Value.Chunks() to return []types.RefBase
In pursuit of issue #654, we want to be able to figure out all the
refs contained in a given Value, along with the Types of the Values to
which those refs point. Value.Chunks() _almost_ met those needs, but
it returned a slice of ref.Ref, which doesn't convey any type info.

To address this, this patch does two things:
1) RefBase embeds the Value interface, and
2) Chunks() now returns []types.RefBase

RefBase now provides Type() as well, by virtue of embedding Value, so
callers can just iterate through the slice returned from Chunks() and
gather type info for all the refs embedded in a given Value.

I went all the way and made RefBase a Value instead of just adding the
Type() method because both types.Ref and the generated Ref types are
actually all Values, and doing so allowed me to change the definition of
refBuilderFunc in package_registry.go to be more precise. It now returns
RefBase instead of just Value.
2016-03-21 16:13:14 -06:00

122 lines
3.4 KiB
Go

package types
import "github.com/attic-labs/noms/d"
type Set interface {
Value
First() Value
Len() uint64
Empty() bool
Has(key Value) bool
Insert(values ...Value) Set
Remove(values ...Value) Set
Union(others ...Set) Set
Iter(cb setIterCallback)
IterAll(cb setIterAllCallback)
IterAllP(concurrency int, f setIterAllCallback)
Filter(cb setFilterCallback) Set
elemType() Type
sequenceCursorAtFirst() *sequenceCursor
valueReader() ValueReader
}
type indexOfSetFn func(m setData, v Value) int
type setIterCallback func(v Value) bool
type setIterAllCallback func(v Value)
type setFilterCallback func(v Value) (keep bool)
var setType = MakeCompoundType(SetKind, MakePrimitiveType(ValueKind))
func NewSet(v ...Value) Set {
return NewTypedSet(setType, v...)
}
func NewTypedSet(t Type, v ...Value) Set {
return newTypedSet(t, buildSetData(setData{}, v, t)...)
}
func newTypedSet(t Type, data ...Value) Set {
seq := newEmptySequenceChunker(makeSetLeafChunkFn(t, nil), newOrderedMetaSequenceChunkFn(t, nil), newSetLeafBoundaryChecker(), newOrderedMetaSequenceBoundaryChecker)
for _, v := range data {
seq.Append(v)
}
return seq.Done().(Set)
}
func setUnion(set Set, others []Set) Set {
// TODO: This can be done more efficiently by realizing that if two sets have the same meta tuple we only have to traverse one of the subtrees. Bug 794
if len(others) == 0 {
return set
}
assertSetsSameType(set, others...)
vr := set.valueReader()
for _, s := range others {
// This both tries to find a ValueReader to use for the new Set, and asserts that if it does,
// it's the same (or nil) for all Sets. I.e. it should be possible to take the union of a Set
// without a ValueReader (constructed in memory but not written yet) and one with a ValueReader
// (from that source) but not with a *different* ValueReader because this would get complicated.
if vr == nil {
vr = s.valueReader()
}
d.Chk.True(vr == nil || vr == s.valueReader())
}
tr := set.Type()
seq := newEmptySequenceChunker(makeSetLeafChunkFn(tr, vr), newOrderedMetaSequenceChunkFn(tr, vr), newSetLeafBoundaryChecker(), newOrderedMetaSequenceBoundaryChecker)
var lessFunction func(a, b sequenceItem) bool
if isSequenceOrderedByIndexedType(tr) {
lessFunction = func(a, b sequenceItem) bool {
return a.(OrderedValue).Less(b.(OrderedValue))
}
} else {
lessFunction = func(a, b sequenceItem) bool {
return a.(Value).Ref().Less(b.(Value).Ref())
}
}
smallest := func(cursors map[*sequenceCursor]bool) (smallestCursor *sequenceCursor, smallestItem sequenceItem) {
for cursor := range cursors {
currentItem := cursor.current()
if smallestCursor == nil || lessFunction(currentItem, smallestItem) {
smallestCursor = cursor
smallestItem = currentItem
}
}
return
}
cursors := make(map[*sequenceCursor]bool, len(others)+1)
if !set.Empty() {
cursor := set.sequenceCursorAtFirst()
cursors[cursor] = true
}
for _, s := range others {
if !s.Empty() {
cursor := s.sequenceCursorAtFirst()
cursors[cursor] = true
}
}
var last Value
for len(cursors) > 0 {
smallestCursor, smallestItem := smallest(cursors)
d.Chk.NotNil(smallestCursor)
// Don't add same value twice
if last == nil || !last.Equals(smallestItem.(Value)) {
seq.Append(smallestItem)
last = smallestItem.(Value)
}
if !smallestCursor.advance() {
delete(cursors, smallestCursor)
}
}
return seq.Done().(Set)
}