Remove the Foo/flatFoo abstraction in the types package.

Fixes #24.
This commit is contained in:
Aaron Boodman
2015-07-10 11:29:03 -07:00
parent 82a87d548c
commit 96f21c4a60
11 changed files with 338 additions and 404 deletions

View File

@@ -1,13 +1,37 @@
package types
import "io"
import (
"bytes"
"io"
type Blob interface {
Value
Len() uint64
Reader() io.Reader
"github.com/attic-labs/noms/ref"
)
type Blob struct {
data []byte
cr *cachedRef
}
func (fb Blob) Reader() io.Reader {
return bytes.NewBuffer(fb.data)
}
func (fb Blob) Len() uint64 {
return uint64(len(fb.data))
}
func (fb Blob) Ref() ref.Ref {
return fb.cr.Ref(fb)
}
func (fb Blob) Equals(other Value) bool {
if other == nil {
return false
} else {
return fb.Ref() == other.Ref()
}
}
func NewBlob(data []byte) Blob {
return flatBlob{data, &cachedRef{}}
return Blob{data, &cachedRef{}}
}

View File

@@ -1,33 +0,0 @@
package types
import (
"bytes"
"io"
"github.com/attic-labs/noms/ref"
)
type flatBlob struct {
data []byte
cr *cachedRef
}
func (fb flatBlob) Reader() io.Reader {
return bytes.NewBuffer(fb.data)
}
func (fb flatBlob) Len() uint64 {
return uint64(len(fb.data))
}
func (fb flatBlob) Ref() ref.Ref {
return fb.cr.Ref(fb)
}
func (fb flatBlob) Equals(other Value) bool {
if other == nil {
return false
} else {
return fb.Ref() == other.Ref()
}
}

View File

@@ -1,84 +0,0 @@
package types
import (
"github.com/attic-labs/noms/chunks"
. "github.com/attic-labs/noms/dbg"
"github.com/attic-labs/noms/ref"
)
// flatList is a quick 'n easy implementation of List.
// It should eventually be replaced by a chunking implementation.
type flatList struct {
list []future
cr *cachedRef
cs chunks.ChunkSource
}
func valuesToFutures(list []Value) []future {
f := []future{}
for _, v := range list {
f = append(f, futureFromValue(v))
}
return f
}
func newFlatList(list []future, cs chunks.ChunkSource) List {
return flatList{list, &cachedRef{}, cs}
}
func (l flatList) Len() uint64 {
return uint64(len(l.list))
}
func (l flatList) Get(idx uint64) Value {
v, err := l.list[idx].Deref(l.cs)
// This is the kind of thing that makes me feel like hiding deref'ing is probably not the right idea. But we'll go with it for now.
Chk.NoError(err)
return v
}
func (l flatList) Slice(start uint64, end uint64) List {
return newFlatList(l.list[start:end], l.cs)
}
func (l flatList) Set(idx uint64, v Value) List {
b := make([]future, len(l.list))
copy(b, l.list)
b[idx] = futureFromValue(v)
return newFlatList(b, l.cs)
}
func (l flatList) Append(v ...Value) List {
return newFlatList(append(l.list, valuesToFutures(v)...), l.cs)
}
func (l flatList) Insert(idx uint64, v ...Value) List {
b := make([]future, len(l.list)+len(v))
copy(b, l.list[:idx])
copy(b[idx:], valuesToFutures(v))
copy(b[idx+uint64(len(v)):], l.list[idx:])
return newFlatList(b, l.cs)
}
func (l flatList) Remove(start uint64, end uint64) List {
b := make([]future, uint64(len(l.list))-(end-start))
copy(b, l.list[:start])
copy(b[start:], l.list[end:])
return newFlatList(b, l.cs)
}
func (l flatList) RemoveAt(idx uint64) List {
return l.Remove(idx, idx+1)
}
func (l flatList) Ref() ref.Ref {
return l.cr.Ref(l)
}
func (l flatList) Equals(other Value) bool {
if other == nil {
return false
} else {
return l.Ref() == other.Ref()
}
}

View File

@@ -1,88 +0,0 @@
package types
import (
. "github.com/attic-labs/noms/dbg"
"github.com/attic-labs/noms/ref"
)
type mapData map[ref.Ref]MapEntry
type flatMap struct {
m mapData
cr *cachedRef
}
func newFlatMap(m mapData) flatMap {
return flatMap{m, &cachedRef{}}
}
func (fm flatMap) Len() uint64 {
return uint64(len(fm.m))
}
func (fm flatMap) Has(key Value) bool {
_, ok := fm.m[key.Ref()]
return ok
}
func (fm flatMap) Get(key Value) Value {
if v, ok := fm.m[key.Ref()]; ok {
return v.Value
} else {
return nil
}
}
func (fm flatMap) Set(key Value, val Value) Map {
return newFlatMap(buildMapData(fm.m, key, val))
}
func (fm flatMap) SetM(kv ...Value) Map {
return newFlatMap(buildMapData(fm.m, kv...))
}
func (fm flatMap) Remove(k Value) Map {
m := copyMapData(fm.m)
delete(m, k.Ref())
return newFlatMap(m)
}
func (fm flatMap) Iter(cb mapIterCallback) {
for _, v := range fm.m {
if cb(v) {
break
}
}
}
func (fm flatMap) Ref() ref.Ref {
return fm.cr.Ref(fm)
}
func (fm flatMap) Equals(other Value) (res bool) {
if other == nil {
return false
} else {
return fm.Ref() == other.Ref()
}
}
func copyMapData(m mapData) mapData {
r := mapData{}
for k, v := range m {
r[k] = v
}
return r
}
func buildMapData(oldData mapData, kv ...Value) mapData {
Chk.Equal(0, len(kv)%2, "Must specify even number of key/value pairs")
m := copyMapData(oldData)
for i := 0; i < len(kv); i += 2 {
k := kv[i]
v := kv[i+1]
m[k.Ref()] = MapEntry{k, v}
}
return m
}

View File

@@ -1,112 +0,0 @@
package types
import (
"github.com/attic-labs/noms/ref"
)
type setData map[ref.Ref]Value
type flatSet struct {
m setData
cr *cachedRef
}
func newFlatSet(m setData) flatSet {
return flatSet{
m: m,
cr: &cachedRef{},
}
}
func (fs flatSet) Empty() bool {
return fs.Len() == uint64(0)
}
func (fs flatSet) Len() uint64 {
return uint64(len(fs.m))
}
func (fs flatSet) Has(v Value) bool {
_, ok := fs.m[v.Ref()]
return ok
}
func (fs flatSet) Insert(values ...Value) Set {
return newFlatSet(buildSetData(fs.m, values))
}
func (fs flatSet) Remove(values ...Value) Set {
m2 := copySetData(fs.m)
for _, v := range values {
if v != nil {
delete(m2, v.Ref())
}
}
return newFlatSet(m2)
}
func (fs flatSet) Union(others ...Set) (result Set) {
result = fs
for _, other := range others {
other.Iter(func(v Value) (stop bool) {
result = result.Insert(v)
return
})
}
return result
}
func (fs flatSet) Subtract(others ...Set) (result Set) {
result = fs
for _, other := range others {
other.Iter(func(v Value) (stop bool) {
result = result.Remove(v)
return
})
}
return result
}
func (fm flatSet) Iter(cb setIterCallback) {
// TODO: sort iteration order
for _, v := range fm.m {
if cb(v) {
break
}
}
}
func (fm flatSet) Any() Value {
for _, v := range fm.m {
return v
}
return nil
}
func (fs flatSet) Ref() ref.Ref {
return fs.cr.Ref(fs)
}
func (fs flatSet) Equals(other Value) bool {
if other == nil {
return false
} else {
return fs.Ref() == other.Ref()
}
}
func copySetData(m setData) setData {
r := setData{}
for k, v := range m {
r[k] = v
}
return r
}
func buildSetData(old setData, values []Value) setData {
m := copySetData(old)
for _, v := range values {
m[v.Ref()] = v
}
return m
}

View File

@@ -1,31 +0,0 @@
package types
import (
"github.com/attic-labs/noms/ref"
)
// Stupid inefficient temporary implementation of the String interface.
type flatString struct {
s string
cr *cachedRef
}
func (fs flatString) Blob() Blob {
return NewBlob([]byte(fs.s))
}
func (fs flatString) String() string {
return fs.s
}
func (fs flatString) Ref() ref.Ref {
return fs.cr.Ref(fs)
}
func (fs flatString) Equals(other Value) bool {
if other == nil {
return false
} else {
return fs.Ref() == other.Ref()
}
}

View File

@@ -109,7 +109,7 @@ func jsonDecodeList(input []interface{}, s chunks.ChunkSource) (future, error) {
}
output = append(output, outVal)
}
return futureFromValue(newFlatList(output, s)), nil
return futureFromValue(listFromFutures(output, s)), nil
}
func jsonDecodeSet(input []interface{}, s chunks.ChunkSource) (future, error) {

View File

@@ -1,19 +1,86 @@
package types
// TODO: I'm not sure we even want this interface in the long term, because noms is strongly-typed, so we should actually have List<T>.
type List interface {
Value
Len() uint64
Get(idx uint64) Value
// TODO: iterator
Slice(idx uint64, end uint64) List
Set(idx uint64, v Value) List
Append(v ...Value) List
Insert(idx uint64, v ...Value) List
Remove(start uint64, end uint64) List
RemoveAt(idx uint64) List
import (
"github.com/attic-labs/noms/chunks"
. "github.com/attic-labs/noms/dbg"
"github.com/attic-labs/noms/ref"
)
type List struct {
list []future
cr *cachedRef
cs chunks.ChunkSource
}
func NewList(v ...Value) List {
return newFlatList(valuesToFutures(v), nil)
return listFromFutures(valuesToFutures(v), nil)
}
func valuesToFutures(list []Value) []future {
f := []future{}
for _, v := range list {
f = append(f, futureFromValue(v))
}
return f
}
func listFromFutures(list []future, cs chunks.ChunkSource) List {
return List{list, &cachedRef{}, cs}
}
func (l List) Len() uint64 {
return uint64(len(l.list))
}
func (l List) Get(idx uint64) Value {
v, err := l.list[idx].Deref(l.cs)
// This is the kind of thing that makes me feel like hiding deref'ing is probably not the right idea. But we'll go with it for now.
Chk.NoError(err)
return v
}
func (l List) Slice(start uint64, end uint64) List {
return listFromFutures(l.list[start:end], l.cs)
}
func (l List) Set(idx uint64, v Value) List {
b := make([]future, len(l.list))
copy(b, l.list)
b[idx] = futureFromValue(v)
return listFromFutures(b, l.cs)
}
func (l List) Append(v ...Value) List {
return listFromFutures(append(l.list, valuesToFutures(v)...), l.cs)
}
func (l List) Insert(idx uint64, v ...Value) List {
b := make([]future, len(l.list)+len(v))
copy(b, l.list[:idx])
copy(b[idx:], valuesToFutures(v))
copy(b[idx+uint64(len(v)):], l.list[idx:])
return listFromFutures(b, l.cs)
}
func (l List) Remove(start uint64, end uint64) List {
b := make([]future, uint64(len(l.list))-(end-start))
copy(b, l.list[:start])
copy(b[start:], l.list[end:])
return listFromFutures(b, l.cs)
}
func (l List) RemoveAt(idx uint64) List {
return l.Remove(idx, idx+1)
}
func (l List) Ref() ref.Ref {
return l.cr.Ref(l)
}
func (l List) Equals(other Value) bool {
if other == nil {
return false
} else {
return l.Ref() == other.Ref()
}
}

View File

@@ -1,27 +1,77 @@
package types
import "github.com/attic-labs/noms/ref"
import (
. "github.com/attic-labs/noms/dbg"
"github.com/attic-labs/noms/ref"
)
type MapEntry struct {
Key Value
Value Value
type mapData map[ref.Ref]MapEntry
type Map struct {
m mapData
cr *cachedRef
}
func NewMap(kv ...Value) Map {
return newMapFromData(buildMapData(mapData{}, kv...))
}
func (fm Map) Len() uint64 {
return uint64(len(fm.m))
}
func (fm Map) Has(key Value) bool {
_, ok := fm.m[key.Ref()]
return ok
}
func (fm Map) Get(key Value) Value {
if v, ok := fm.m[key.Ref()]; ok {
return v.Value
} else {
return nil
}
}
func (fm Map) Set(key Value, val Value) Map {
return newMapFromData(buildMapData(fm.m, key, val))
}
func (fm Map) SetM(kv ...Value) Map {
return newMapFromData(buildMapData(fm.m, kv...))
}
func (fm Map) Remove(k Value) Map {
m := copyMapData(fm.m)
delete(m, k.Ref())
return newMapFromData(m)
}
type mapIterCallback func(entry MapEntry) bool
type Map interface {
Value
Len() uint64
Has(k Value) bool
Get(k Value) Value
Set(k Value, v Value) Map
SetM(kv ...Value) Map
Remove(k Value) Map
Iter(mapIterCallback)
func (fm Map) Iter(cb mapIterCallback) {
for _, v := range fm.m {
if cb(v) {
break
}
}
}
func NewMap(kv ...Value) Map {
return newFlatMap(buildMapData(mapData{}, kv...))
func (fm Map) Ref() ref.Ref {
return fm.cr.Ref(fm)
}
func (fm Map) Equals(other Value) (res bool) {
if other == nil {
return false
} else {
return fm.Ref() == other.Ref()
}
}
type MapEntry struct {
Key Value
Value Value
}
type MapEntrySlice []MapEntry
@@ -37,3 +87,27 @@ func (mes MapEntrySlice) Swap(i, j int) {
func (mes MapEntrySlice) Less(i, j int) bool {
return ref.Less(mes[i].Key.Ref(), mes[j].Key.Ref())
}
func newMapFromData(m mapData) Map {
return Map{m, &cachedRef{}}
}
func copyMapData(m mapData) mapData {
r := mapData{}
for k, v := range m {
r[k] = v
}
return r
}
func buildMapData(oldData mapData, kv ...Value) mapData {
Chk.Equal(0, len(kv)%2, "Must specify even number of key/value pairs")
m := copyMapData(oldData)
for i := 0; i < len(kv); i += 2 {
k := kv[i]
v := kv[i+1]
m[k.Ref()] = MapEntry{k, v}
}
return m
}

View File

@@ -1,21 +1,118 @@
package types
type setIterCallback func(v Value) bool
type setCombineCallback func(prev Set, v ...Value) Set
import (
"github.com/attic-labs/noms/ref"
)
type Set interface {
Value
Empty() bool
Len() uint64
Has(v Value) bool
Iter(setIterCallback)
Insert(v ...Value) Set
Remove(v ...Value) Set
Union(others ...Set) Set
Subtract(others ...Set) Set
Any() Value
type setData map[ref.Ref]Value
type Set struct {
m setData
cr *cachedRef
}
func NewSet(v ...Value) Set {
return newFlatSet(buildSetData(setData{}, v))
return newSetFromData(buildSetData(setData{}, v))
}
func (fs Set) Empty() bool {
return fs.Len() == uint64(0)
}
func (fs Set) Len() uint64 {
return uint64(len(fs.m))
}
func (fs Set) Has(v Value) bool {
_, ok := fs.m[v.Ref()]
return ok
}
func (fs Set) Insert(values ...Value) Set {
return newSetFromData(buildSetData(fs.m, values))
}
func (fs Set) Remove(values ...Value) Set {
m2 := copySetData(fs.m)
for _, v := range values {
if v != nil {
delete(m2, v.Ref())
}
}
return newSetFromData(m2)
}
func (fs Set) Union(others ...Set) (result Set) {
result = fs
for _, other := range others {
other.Iter(func(v Value) (stop bool) {
result = result.Insert(v)
return
})
}
return result
}
func (fs Set) Subtract(others ...Set) (result Set) {
result = fs
for _, other := range others {
other.Iter(func(v Value) (stop bool) {
result = result.Remove(v)
return
})
}
return result
}
type setIterCallback func(v Value) bool
func (fm Set) Iter(cb setIterCallback) {
// TODO: sort iteration order
for _, v := range fm.m {
if cb(v) {
break
}
}
}
func (fm Set) Any() Value {
for _, v := range fm.m {
return v
}
return nil
}
func (fs Set) Ref() ref.Ref {
return fs.cr.Ref(fs)
}
func (fs Set) Equals(other Value) bool {
if other == nil {
return false
} else {
return fs.Ref() == other.Ref()
}
}
func newSetFromData(m setData) Set {
return Set{
m: m,
cr: &cachedRef{},
}
}
func copySetData(m setData) setData {
r := setData{}
for k, v := range m {
r[k] = v
}
return r
}
func buildSetData(old setData, values []Value) setData {
m := copySetData(old)
for _, v := range values {
m[v.Ref()] = v
}
return m
}

View File

@@ -1,14 +1,34 @@
package types
type String interface {
Value
import (
"github.com/attic-labs/noms/ref"
)
Blob() Blob
// Slurps the entire string into memory. You obviously don't want to do this if the string might be large.
String() string
type String struct {
s string
cr *cachedRef
}
func NewString(s string) String {
return flatString{s, &cachedRef{}}
return String{s, &cachedRef{}}
}
func (fs String) Blob() Blob {
return NewBlob([]byte(fs.s))
}
func (fs String) String() string {
return fs.s
}
func (fs String) Ref() ref.Ref {
return fs.cr.Ref(fs)
}
func (fs String) Equals(other Value) bool {
if other == nil {
return false
} else {
return fs.Ref() == other.Ref()
}
}