mirror of
https://github.com/dolthub/dolt.git
synced 2026-02-05 02:59:44 -06:00
Add initial Map implementation
This commit is contained in:
97
types/flat_map.go
Normal file
97
types/flat_map.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
. "github.com/attic-labs/noms/dbg"
|
||||
)
|
||||
|
||||
var (
|
||||
emptyString = string("")
|
||||
emptyValuePtr = (*Value)(nil)
|
||||
)
|
||||
|
||||
type internalMap map[string]Value
|
||||
|
||||
type flatMap struct {
|
||||
m internalMap
|
||||
}
|
||||
|
||||
func (fm flatMap) Len() uint64 {
|
||||
return uint64(len(fm.m))
|
||||
}
|
||||
|
||||
func (fm flatMap) Has(key string) bool {
|
||||
_, ok := fm.m[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (fm flatMap) Get(key string) Value {
|
||||
if v, ok := fm.m[key]; ok {
|
||||
return v
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (fm flatMap) Set(key string, val Value) Map {
|
||||
return flatMap{buildMap(fm.m, key, val)}
|
||||
}
|
||||
|
||||
func (fm flatMap) SetM(kv ...interface{}) Map {
|
||||
return flatMap{buildMap(fm.m, kv...)}
|
||||
}
|
||||
|
||||
func (fm flatMap) Remove(k string) Map {
|
||||
m := buildMap(fm.m)
|
||||
delete(m, k)
|
||||
return flatMap{m}
|
||||
}
|
||||
|
||||
func (fm flatMap) Iter(cb IterCallback) {
|
||||
for k, v := range fm.m {
|
||||
if cb(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (fm flatMap) Equals(other Value) (res bool) {
|
||||
if other, ok := other.(Map); ok {
|
||||
res = true
|
||||
fm.Iter(func(k string, v Value) (stop bool) {
|
||||
if other.Get(k) != v {
|
||||
stop = true
|
||||
res = false
|
||||
}
|
||||
return
|
||||
})
|
||||
if !res {
|
||||
return
|
||||
}
|
||||
other.Iter(func(k string, v Value) (stop bool) {
|
||||
if !fm.Has(k) {
|
||||
stop = true
|
||||
res = false
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func buildMap(initialData internalMap, kv ...interface{}) (m internalMap) {
|
||||
Chk.Equal(0, len(kv)%2, "Must specify even number of key/value pairs")
|
||||
m = internalMap{}
|
||||
if initialData != nil {
|
||||
for k, v := range initialData {
|
||||
m[k] = v
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(kv); i += 2 {
|
||||
k := kv[i]
|
||||
v := kv[i+1]
|
||||
Chk.IsType(emptyString, k)
|
||||
Chk.Implements(emptyValuePtr, v)
|
||||
m[k.(string)] = v.(Value)
|
||||
}
|
||||
return
|
||||
}
|
||||
108
types/flat_map_test.go
Normal file
108
types/flat_map_test.go
Normal file
@@ -0,0 +1,108 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewMap(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
m := NewMap()
|
||||
assert.IsType(flatMap{}, m)
|
||||
assert.Equal(uint64(0), m.Len())
|
||||
m = NewMap("foo", NewString("foo"), "bar", NewString("bar"))
|
||||
assert.Equal(uint64(2), m.Len())
|
||||
assert.True(NewString("foo").Equals(m.Get("foo")))
|
||||
assert.True(NewString("bar").Equals(m.Get("bar")))
|
||||
}
|
||||
|
||||
func TestFlatMapHasRemove(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
m1 := NewMap()
|
||||
assert.False(m1.Has("foo"))
|
||||
m2 := m1.Set("foo", NewString("foo"))
|
||||
assert.False(m1.Has("foo"))
|
||||
assert.True(m2.Has("foo"))
|
||||
m3 := m1.Remove("foo")
|
||||
assert.False(m1.Has("foo"))
|
||||
assert.True(m2.Has("foo"))
|
||||
assert.False(m3.Has("foo"))
|
||||
}
|
||||
|
||||
func TestFlatMapSetGet(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
m1 := NewMap()
|
||||
assert.Nil(m1.Get("foo"))
|
||||
m2 := m1.Set("foo", Int32(42))
|
||||
assert.Nil(m1.Get("foo"))
|
||||
assert.True(Int32(42).Equals(m2.Get("foo")))
|
||||
m3 := m2.Set("foo", Int32(43))
|
||||
assert.Nil(m1.Get("foo"))
|
||||
assert.True(Int32(42).Equals(m2.Get("foo")))
|
||||
assert.True(Int32(43).Equals(m3.Get("foo")))
|
||||
m4 := m3.Remove("foo")
|
||||
assert.Nil(m1.Get("foo"))
|
||||
assert.True(Int32(42).Equals(m2.Get("foo")))
|
||||
assert.True(Int32(43).Equals(m3.Get("foo")))
|
||||
assert.Nil(m4.Get("foo"))
|
||||
}
|
||||
|
||||
func TestFlatMapSetM(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
m1 := NewMap()
|
||||
m2 := m1.SetM()
|
||||
assert.True(m1.Equals(m2))
|
||||
m3 := m2.SetM("foo", NewString("bar"), "hot", NewString("dog"))
|
||||
assert.Equal(uint64(2), m3.Len())
|
||||
assert.True(NewString("bar").Equals(m3.Get("foo")))
|
||||
assert.True(NewString("dog").Equals(m3.Get("hot")))
|
||||
m4 := m3.SetM("mon", NewString("key"))
|
||||
assert.Equal(uint64(2), m3.Len())
|
||||
assert.Equal(uint64(3), m4.Len())
|
||||
}
|
||||
|
||||
func TestFlatMapIter(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
m := NewMap()
|
||||
got := map[string]Value{}
|
||||
stop := false
|
||||
cb := func(k string, v Value) bool {
|
||||
got[k] = v
|
||||
return stop
|
||||
}
|
||||
|
||||
m.Iter(cb)
|
||||
assert.Equal(0, len(got))
|
||||
|
||||
m = m.SetM("a", Int32(0), "b", Int32(1))
|
||||
m.Iter(cb)
|
||||
assert.Equal(2, len(got))
|
||||
assert.True(Int32(0).Equals(got["a"]))
|
||||
assert.True(Int32(1).Equals(got["b"]))
|
||||
|
||||
got = map[string]Value{}
|
||||
stop = true
|
||||
m.Iter(cb)
|
||||
assert.Equal(1, len(got))
|
||||
assert.True(Int32(0).Equals(got["a"]))
|
||||
}
|
||||
|
||||
func TestFlatMapEquals(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
m1 := NewMap()
|
||||
m2 := m1
|
||||
m3 := NewMap()
|
||||
|
||||
assert.True(m1.Equals(m2))
|
||||
assert.True(m2.Equals(m1))
|
||||
assert.True(m3.Equals(m2))
|
||||
assert.True(m2.Equals(m3))
|
||||
|
||||
m1 = NewMap("foo", Float32(0.0), "bar", Float32(1.1))
|
||||
m2 = m2.SetM("foo", Float32(0.0), "bar", Float32(1.1))
|
||||
assert.True(m1.Equals(m2))
|
||||
assert.True(m2.Equals(m1))
|
||||
assert.False(m2.Equals(m3))
|
||||
assert.False(m3.Equals(m2))
|
||||
}
|
||||
19
types/map.go
Normal file
19
types/map.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package types
|
||||
|
||||
type IterCallback func(k string, v Value) bool
|
||||
|
||||
type Map interface {
|
||||
Value
|
||||
// TODO: keys should be able to be any noms type
|
||||
Len() uint64
|
||||
Has(k string) bool
|
||||
Get(k string) Value
|
||||
Set(k string, v Value) Map
|
||||
SetM(kv ...interface{}) Map
|
||||
Remove(k string) Map
|
||||
Iter(IterCallback)
|
||||
}
|
||||
|
||||
func NewMap(kv ...interface{}) Map {
|
||||
return flatMap{buildMap(nil, kv...)}
|
||||
}
|
||||
Reference in New Issue
Block a user