mirror of
https://github.com/dolthub/dolt.git
synced 2026-02-04 10:25:17 -06:00
Merge pull request #76 from aboodman/order
Switch Map and Set from using a hashtable internally to a sorted list
This commit is contained in:
@@ -34,12 +34,12 @@ func (s User) Equals(p User) bool {
|
||||
func (s User) Ref() ref.Ref {
|
||||
return s.m.Ref()
|
||||
}
|
||||
func (s User) Id() types.String {
|
||||
return s.m.Get(types.NewString("id")).(types.String)
|
||||
func (s User) OAuthToken() types.String {
|
||||
return s.m.Get(types.NewString("oAuthToken")).(types.String)
|
||||
}
|
||||
|
||||
func (s User) SetId(p types.String) User {
|
||||
return UserFromVal(s.m.Set(types.NewString("id"), p))
|
||||
func (s User) SetOAuthToken(p types.String) User {
|
||||
return UserFromVal(s.m.Set(types.NewString("oAuthToken"), p))
|
||||
}
|
||||
func (s User) Name() types.String {
|
||||
return s.m.Get(types.NewString("name")).(types.String)
|
||||
@@ -48,12 +48,12 @@ func (s User) Name() types.String {
|
||||
func (s User) SetName(p types.String) User {
|
||||
return UserFromVal(s.m.Set(types.NewString("name"), p))
|
||||
}
|
||||
func (s User) OAuthToken() types.String {
|
||||
return s.m.Get(types.NewString("oAuthToken")).(types.String)
|
||||
func (s User) Id() types.String {
|
||||
return s.m.Get(types.NewString("id")).(types.String)
|
||||
}
|
||||
|
||||
func (s User) SetOAuthToken(p types.String) User {
|
||||
return UserFromVal(s.m.Set(types.NewString("oAuthToken"), p))
|
||||
func (s User) SetId(p types.String) User {
|
||||
return UserFromVal(s.m.Set(types.NewString("id"), p))
|
||||
}
|
||||
func (s User) OAuthSecret() types.String {
|
||||
return s.m.Get(types.NewString("oAuthSecret")).(types.String)
|
||||
@@ -75,7 +75,7 @@ type PhotosetSet struct {
|
||||
s types.Set
|
||||
}
|
||||
|
||||
type PhotosetSetIterCallback (func (p Photoset) (stop bool))
|
||||
type PhotosetSetIterCallback (func(p Photoset) (stop bool))
|
||||
|
||||
func NewPhotosetSet() PhotosetSet {
|
||||
return PhotosetSet{types.NewSet()}
|
||||
@@ -177,13 +177,6 @@ func (s Photoset) Equals(p Photoset) bool {
|
||||
func (s Photoset) Ref() ref.Ref {
|
||||
return s.m.Ref()
|
||||
}
|
||||
func (s Photoset) Id() types.String {
|
||||
return s.m.Get(types.NewString("id")).(types.String)
|
||||
}
|
||||
|
||||
func (s Photoset) SetId(p types.String) Photoset {
|
||||
return PhotosetFromVal(s.m.Set(types.NewString("id"), p))
|
||||
}
|
||||
func (s Photoset) Title() types.String {
|
||||
return s.m.Get(types.NewString("title")).(types.String)
|
||||
}
|
||||
@@ -191,6 +184,13 @@ func (s Photoset) Title() types.String {
|
||||
func (s Photoset) SetTitle(p types.String) Photoset {
|
||||
return PhotosetFromVal(s.m.Set(types.NewString("title"), p))
|
||||
}
|
||||
func (s Photoset) Id() types.String {
|
||||
return s.m.Get(types.NewString("id")).(types.String)
|
||||
}
|
||||
|
||||
func (s Photoset) SetId(p types.String) Photoset {
|
||||
return PhotosetFromVal(s.m.Set(types.NewString("id"), p))
|
||||
}
|
||||
func (s Photoset) Photos() PhotoSet {
|
||||
return PhotoSetFromVal(s.m.Get(types.NewString("photos")))
|
||||
}
|
||||
@@ -204,7 +204,7 @@ type PhotoSet struct {
|
||||
s types.Set
|
||||
}
|
||||
|
||||
type PhotoSetIterCallback (func (p Photo) (stop bool))
|
||||
type PhotoSetIterCallback (func(p Photo) (stop bool))
|
||||
|
||||
func NewPhotoSet() PhotoSet {
|
||||
return PhotoSet{types.NewSet()}
|
||||
@@ -306,13 +306,6 @@ func (s Photo) Equals(p Photo) bool {
|
||||
func (s Photo) Ref() ref.Ref {
|
||||
return s.m.Ref()
|
||||
}
|
||||
func (s Photo) Id() types.String {
|
||||
return s.m.Get(types.NewString("id")).(types.String)
|
||||
}
|
||||
|
||||
func (s Photo) SetId(p types.String) Photo {
|
||||
return PhotoFromVal(s.m.Set(types.NewString("id"), p))
|
||||
}
|
||||
func (s Photo) Title() types.String {
|
||||
return s.m.Get(types.NewString("title")).(types.String)
|
||||
}
|
||||
@@ -320,12 +313,12 @@ func (s Photo) Title() types.String {
|
||||
func (s Photo) SetTitle(p types.String) Photo {
|
||||
return PhotoFromVal(s.m.Set(types.NewString("title"), p))
|
||||
}
|
||||
func (s Photo) Url() types.String {
|
||||
return s.m.Get(types.NewString("url")).(types.String)
|
||||
func (s Photo) Id() types.String {
|
||||
return s.m.Get(types.NewString("id")).(types.String)
|
||||
}
|
||||
|
||||
func (s Photo) SetUrl(p types.String) Photo {
|
||||
return PhotoFromVal(s.m.Set(types.NewString("url"), p))
|
||||
func (s Photo) SetId(p types.String) Photo {
|
||||
return PhotoFromVal(s.m.Set(types.NewString("id"), p))
|
||||
}
|
||||
func (s Photo) Image() types.Blob {
|
||||
return s.m.Get(types.NewString("image")).(types.Blob)
|
||||
@@ -334,3 +327,10 @@ func (s Photo) Image() types.Blob {
|
||||
func (s Photo) SetImage(p types.Blob) Photo {
|
||||
return PhotoFromVal(s.m.Set(types.NewString("image"), p))
|
||||
}
|
||||
func (s Photo) Url() types.String {
|
||||
return s.m.Get(types.NewString("url")).(types.String)
|
||||
}
|
||||
|
||||
func (s Photo) SetUrl(p types.String) Photo {
|
||||
return PhotoFromVal(s.m.Set(types.NewString("url"), p))
|
||||
}
|
||||
|
||||
@@ -102,13 +102,6 @@ func (s Pitch) Equals(p Pitch) bool {
|
||||
func (s Pitch) Ref() ref.Ref {
|
||||
return s.m.Ref()
|
||||
}
|
||||
func (s Pitch) X() types.Float64 {
|
||||
return s.m.Get(types.NewString("X")).(types.Float64)
|
||||
}
|
||||
|
||||
func (s Pitch) SetX(p types.Float64) Pitch {
|
||||
return PitchFromVal(s.m.Set(types.NewString("X"), p))
|
||||
}
|
||||
func (s Pitch) Z() types.Float64 {
|
||||
return s.m.Get(types.NewString("Z")).(types.Float64)
|
||||
}
|
||||
@@ -116,3 +109,10 @@ func (s Pitch) Z() types.Float64 {
|
||||
func (s Pitch) SetZ(p types.Float64) Pitch {
|
||||
return PitchFromVal(s.m.Set(types.NewString("Z"), p))
|
||||
}
|
||||
func (s Pitch) X() types.Float64 {
|
||||
return s.m.Get(types.NewString("X")).(types.Float64)
|
||||
}
|
||||
|
||||
func (s Pitch) SetX(p types.Float64) Pitch {
|
||||
return PitchFromVal(s.m.Set(types.NewString("X"), p))
|
||||
}
|
||||
|
||||
@@ -116,13 +116,6 @@ func (s Root) Equals(p Root) bool {
|
||||
func (s Root) Ref() ref.Ref {
|
||||
return s.m.Ref()
|
||||
}
|
||||
func (s Root) Value() types.Value {
|
||||
return s.m.Get(types.NewString("value")).(types.Value)
|
||||
}
|
||||
|
||||
func (s Root) SetValue(p types.Value) Root {
|
||||
return RootFromVal(s.m.Set(types.NewString("value"), p))
|
||||
}
|
||||
func (s Root) Parents() types.Set {
|
||||
return s.m.Get(types.NewString("parents")).(types.Set)
|
||||
}
|
||||
@@ -130,3 +123,10 @@ func (s Root) Parents() types.Set {
|
||||
func (s Root) SetParents(p types.Set) Root {
|
||||
return RootFromVal(s.m.Set(types.NewString("parents"), p))
|
||||
}
|
||||
func (s Root) Value() types.Value {
|
||||
return s.m.Get(types.NewString("value")).(types.Value)
|
||||
}
|
||||
|
||||
func (s Root) SetValue(p types.Value) Root {
|
||||
return RootFromVal(s.m.Set(types.NewString("value"), p))
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package types
|
||||
|
||||
import (
|
||||
"github.com/attic-labs/noms/chunks"
|
||||
. "github.com/attic-labs/noms/dbg"
|
||||
"github.com/attic-labs/noms/ref"
|
||||
)
|
||||
|
||||
@@ -25,3 +26,12 @@ func futuresEqual(f1, f2 future) bool {
|
||||
return f1.Ref() == f2.Ref()
|
||||
}
|
||||
}
|
||||
|
||||
func futureEqualsValue(f future, v Value) bool {
|
||||
Chk.NotNil(v)
|
||||
if f.Val() != nil {
|
||||
return f.Val().Equals(v)
|
||||
} else {
|
||||
return f.Ref() == v.Ref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package types
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/attic-labs/noms/chunks"
|
||||
. "github.com/attic-labs/noms/dbg"
|
||||
@@ -114,15 +113,8 @@ func (mes entrySlice) Less(i, j int) bool {
|
||||
}
|
||||
|
||||
func getJSONMap(m Map, s chunks.ChunkSink) (r interface{}, err error) {
|
||||
// Iteration through Map is random, but we need a deterministic order for serialization. Let's order using the refs of the keys in the map.
|
||||
order := entrySlice{}
|
||||
for _, e := range m.m {
|
||||
order = append(order, e)
|
||||
}
|
||||
sort.Sort(order)
|
||||
|
||||
j := []interface{}{}
|
||||
for _, r := range order {
|
||||
for _, r := range m.m {
|
||||
var cjk, cjv interface{}
|
||||
cjk, err = getChildJSON(r.key, s)
|
||||
if err == nil {
|
||||
@@ -142,18 +134,8 @@ func getJSONMap(m Map, s chunks.ChunkSink) (r interface{}, err error) {
|
||||
}
|
||||
|
||||
func getJSONSet(set Set, s chunks.ChunkSink) (r interface{}, err error) {
|
||||
// Iteration through Set is random, but we need a deterministic order for serialization. Let's order using the refs of the values in the set.
|
||||
lookup := setData{}
|
||||
order := ref.RefSlice{}
|
||||
for _, f := range set.m {
|
||||
order = append(order, f.Ref())
|
||||
lookup[f.Ref()] = f
|
||||
}
|
||||
sort.Sort(order)
|
||||
|
||||
j := []interface{}{}
|
||||
for _, r := range order {
|
||||
f := lookup[r]
|
||||
for _, f := range set.m {
|
||||
var cj interface{}
|
||||
cj, err = getChildJSON(f, s)
|
||||
if err != nil {
|
||||
|
||||
74
types/map.go
74
types/map.go
@@ -1,19 +1,21 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/attic-labs/noms/chunks"
|
||||
. "github.com/attic-labs/noms/dbg"
|
||||
"github.com/attic-labs/noms/ref"
|
||||
)
|
||||
|
||||
type mapData map[ref.Ref]mapEntry
|
||||
|
||||
type Map struct {
|
||||
m mapData
|
||||
m mapData // sorted by entry.key.Ref()
|
||||
cs chunks.ChunkSource
|
||||
ref *ref.Ref
|
||||
}
|
||||
|
||||
type mapData []mapEntry
|
||||
|
||||
func NewMap(kv ...Value) Map {
|
||||
return newMapFromData(buildMapData(mapData{}, valuesToFutures(kv)), nil)
|
||||
}
|
||||
@@ -27,18 +29,21 @@ func (fm Map) Len() uint64 {
|
||||
}
|
||||
|
||||
func (fm Map) Has(key Value) bool {
|
||||
_, ok := fm.m[key.Ref()]
|
||||
return ok
|
||||
idx := indexMapData(fm.m, key.Ref())
|
||||
return idx < len(fm.m) && futureEqualsValue(fm.m[idx].key, key)
|
||||
}
|
||||
|
||||
func (fm Map) Get(key Value) Value {
|
||||
if entry, ok := fm.m[key.Ref()]; ok {
|
||||
v, err := entry.value.Deref(fm.cs)
|
||||
Chk.NoError(err)
|
||||
return v
|
||||
} else {
|
||||
return nil
|
||||
idx := indexMapData(fm.m, key.Ref())
|
||||
if idx < len(fm.m) {
|
||||
entry := fm.m[idx]
|
||||
if futureEqualsValue(entry.key, key) {
|
||||
v, err := entry.value.Deref(fm.cs)
|
||||
Chk.NoError(err)
|
||||
return v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fm Map) Set(key Value, val Value) Map {
|
||||
@@ -50,9 +55,12 @@ func (fm Map) SetM(kv ...Value) Map {
|
||||
}
|
||||
|
||||
func (fm Map) Remove(k Value) Map {
|
||||
m := copyMapData(fm.m)
|
||||
delete(m, k.Ref())
|
||||
return newMapFromData(m, fm.cs)
|
||||
idx := indexMapData(fm.m, k.Ref())
|
||||
if idx == len(fm.m) || !futureEqualsValue(fm.m[idx].key, k) {
|
||||
return fm
|
||||
}
|
||||
|
||||
return newMapFromData(append(fm.m[:idx], fm.m[idx+1:]...), fm.cs)
|
||||
}
|
||||
|
||||
type mapIterCallback func(key, value Value) bool
|
||||
@@ -90,23 +98,41 @@ func newMapFromData(m mapData, cs chunks.ChunkSource) Map {
|
||||
return Map{m, cs, &ref.Ref{}}
|
||||
}
|
||||
|
||||
func copyMapData(m mapData) mapData {
|
||||
r := mapData{}
|
||||
for k, v := range m {
|
||||
r[k] = v
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func buildMapData(oldData mapData, futures []future) mapData {
|
||||
// Sadly, Chk.Equals() costs too much.
|
||||
Chk.True(0 == len(futures)%2, "Must specify even number of key/value pairs")
|
||||
|
||||
m := copyMapData(oldData)
|
||||
m := make(mapData, len(oldData), len(oldData)+len(futures))
|
||||
copy(m, oldData)
|
||||
for i := 0; i < len(futures); i += 2 {
|
||||
k := futures[i]
|
||||
v := futures[i+1]
|
||||
m[k.Ref()] = mapEntry{k, v}
|
||||
e := mapEntry{k, v}
|
||||
idx := indexMapData(m, k.Ref())
|
||||
if idx != len(m) && futuresEqual(m[idx].key, k) {
|
||||
m[idx] = e
|
||||
} else {
|
||||
m = append(m, e)
|
||||
}
|
||||
}
|
||||
sort.Sort(m)
|
||||
return m
|
||||
}
|
||||
|
||||
func indexMapData(m mapData, r ref.Ref) int {
|
||||
return sort.Search(len(m), func(i int) bool {
|
||||
return !ref.Less(m[i].key.Ref(), r)
|
||||
})
|
||||
}
|
||||
|
||||
func (md mapData) Len() int {
|
||||
return len(md)
|
||||
}
|
||||
|
||||
func (md mapData) Less(i, j int) bool {
|
||||
return ref.Less(md[i].key.Ref(), md[j].key.Ref())
|
||||
}
|
||||
|
||||
func (md mapData) Swap(i, j int) {
|
||||
md[i], md[j] = md[j], md[i]
|
||||
}
|
||||
|
||||
53
types/set.go
53
types/set.go
@@ -1,15 +1,17 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/attic-labs/noms/chunks"
|
||||
. "github.com/attic-labs/noms/dbg"
|
||||
"github.com/attic-labs/noms/ref"
|
||||
)
|
||||
|
||||
type setData map[ref.Ref]future
|
||||
type setData []future
|
||||
|
||||
type Set struct {
|
||||
m setData
|
||||
m setData // sorted by Ref()
|
||||
cs chunks.ChunkSource
|
||||
ref *ref.Ref
|
||||
}
|
||||
@@ -31,8 +33,8 @@ func (fs Set) Len() uint64 {
|
||||
}
|
||||
|
||||
func (fs Set) Has(v Value) bool {
|
||||
_, ok := fs.m[v.Ref()]
|
||||
return ok
|
||||
idx := indexSetData(fs.m, v.Ref())
|
||||
return idx < len(fs.m) && futureEqualsValue(fs.m[idx], v)
|
||||
}
|
||||
|
||||
func (fs Set) Insert(values ...Value) Set {
|
||||
@@ -43,7 +45,10 @@ func (fs Set) Remove(values ...Value) Set {
|
||||
m2 := copySetData(fs.m)
|
||||
for _, v := range values {
|
||||
if v != nil {
|
||||
delete(m2, v.Ref())
|
||||
idx := indexSetData(fs.m, v.Ref())
|
||||
if idx < len(fs.m) && futureEqualsValue(fs.m[idx], v) {
|
||||
m2 = append(m2[:idx], m2[idx+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
return newSetFromData(m2, fs.cs)
|
||||
@@ -110,17 +115,41 @@ func newSetFromData(m setData, cs chunks.ChunkSource) Set {
|
||||
}
|
||||
|
||||
func copySetData(m setData) setData {
|
||||
r := setData{}
|
||||
for k, f := range m {
|
||||
r[k] = f
|
||||
}
|
||||
r := make(setData, len(m))
|
||||
copy(r, m)
|
||||
return r
|
||||
}
|
||||
|
||||
func buildSetData(old setData, futures []future) setData {
|
||||
m := copySetData(old)
|
||||
r := make(setData, len(old), len(old)+len(futures))
|
||||
copy(r, old)
|
||||
for _, f := range futures {
|
||||
m[f.Ref()] = f
|
||||
idx := indexSetData(r, f.Ref())
|
||||
if idx < len(r) && futuresEqual(r[idx], f) {
|
||||
// We already have this fellow.
|
||||
continue
|
||||
} else {
|
||||
r = append(r, f)
|
||||
}
|
||||
}
|
||||
return m
|
||||
sort.Sort(r)
|
||||
return r
|
||||
}
|
||||
|
||||
func indexSetData(m setData, r ref.Ref) int {
|
||||
return sort.Search(len(m), func(i int) bool {
|
||||
return !ref.Less(m[i].Ref(), r)
|
||||
})
|
||||
}
|
||||
|
||||
func (sd setData) Len() int {
|
||||
return len(sd)
|
||||
}
|
||||
|
||||
func (sd setData) Less(i, j int) bool {
|
||||
return ref.Less(sd[i].Ref(), sd[j].Ref())
|
||||
}
|
||||
|
||||
func (sd setData) Swap(i, j int) {
|
||||
sd[i], sd[j] = sd[j], sd[i]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user