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:
Aaron Boodman
2015-07-21 09:49:05 -07:00
7 changed files with 145 additions and 98 deletions

View File

@@ -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))
}

View File

@@ -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))
}

View File

@@ -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))
}

View File

@@ -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()
}
}

View File

@@ -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 {

View File

@@ -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]
}

View File

@@ -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]
}