make Elem interface have a method on it, implement that in seq (bleh), implement GoType

This commit is contained in:
Brian Picciano 2014-10-18 20:03:16 -04:00
parent 99b67fa801
commit 4188d0b84a
11 changed files with 432 additions and 196 deletions

View File

@ -28,9 +28,18 @@ func (kv *KV) Hash(i uint32) uint32 {
// compared to another KV, only compares the other key as well. // compared to another KV, only compares the other key as well.
func (kv *KV) Equal(v types.Elem) bool { func (kv *KV) Equal(v types.Elem) bool {
if kv2, ok := v.(*KV); ok { if kv2, ok := v.(*KV); ok {
return equal(kv.Key, kv2.Key) return kv.Key.Equal(kv2.Key)
} }
return equal(kv.Key, v) return kv.Key.Equal(v)
}
func (kv *KV) fullEqual(v types.Elem) bool {
kv2, ok := v.(*KV)
if !ok {
return false
}
return kv.Key.Equal(kv2.Key) && kv.Val.Equal(kv2.Val)
} }
// Implementation of String for Stringer // Implementation of String for Stringer
@ -65,6 +74,38 @@ func (hm *HashMap) FirstRest() (types.Elem, Seq, bool) {
return el, &HashMap{nset.(*Set)}, ok return el, &HashMap{nset.(*Set)}, ok
} }
// Implementation of Equal for types.Elem interface. Completes in O(Nlog(M))
// time if e is another HashMap, where M is the size of the given HashMap
func (hm *HashMap) Equal(e types.Elem) bool {
// This can't just use Set's Equal because that would end up using KeyVal's
// Equal, which is not a true Equal
hm2, ok := e.(*HashMap)
if !ok {
return false
}
var el types.Elem
s := Seq(hm)
size := uint64(0)
for {
el, s, ok = s.FirstRest()
if !ok {
return size == hm2.Size()
}
size++
kv := el.(*KV)
k, v := kv.Key, kv.Val
v2, ok := hm2.Get(k)
if !ok || !v.Equal(v2) {
return false
}
}
}
// Returns a new HashMap with the given value set on the given key. Also returns // Returns a new HashMap with the given value set on the given key. Also returns
// whether or not this was the first time setting that key (false if it was // whether or not this was the first time setting that key (false if it was
// already there and was overwritten). Has the same complexity as Set's SetVal // already there and was overwritten). Has the same complexity as Set's SetVal

View File

@ -14,11 +14,16 @@ func kvints(kvs ...*KV) ([]*KV, []types.Elem) {
return kvs, ints return kvs, ints
} }
// Test that HashMap implements types.Elem (compile-time check)
func TestHashMapElem(t *T) {
_ = types.Elem(NewHashMap())
}
// Test creating a Set and calling the Seq interface methods on it // Test creating a Set and calling the Seq interface methods on it
func TestHashMapSeq(t *T) { func TestHashMapSeq(t *T) {
kvs, ints := kvints( kvs, ints := kvints(
KeyVal(1, "one"), keyValV(1, "one"),
KeyVal(2, "two"), keyValV(2, "two"),
) )
// Testing creation and Seq interface methods // Testing creation and Seq interface methods
@ -29,27 +34,50 @@ func TestHashMapSeq(t *T) {
assertEmpty(ms, t) assertEmpty(ms, t)
} }
// Test that the Equal method on HashMaps works
func TestHashMapEqual(t *T) {
hm, hm2 := NewHashMap(), NewHashMap()
assertValue(hm.Equal(hm2), true, t)
assertValue(hm2.Equal(hm), true, t)
hm = NewHashMap(keyValV(1, "one"), keyValV(2, "two"))
assertValue(hm.Equal(hm2), false, t)
assertValue(hm2.Equal(hm), false, t)
hm2 = NewHashMap(keyValV(1, "one"))
assertValue(hm.Equal(hm2), false, t)
assertValue(hm2.Equal(hm), false, t)
hm2 = NewHashMap(keyValV(1, "one"), keyValV(2, "three?"))
assertValue(hm.Equal(hm2), false, t)
assertValue(hm2.Equal(hm), false, t)
hm2 = NewHashMap(keyValV(1, "one"), keyValV(2, "two"))
assertValue(hm.Equal(hm2), true, t)
assertValue(hm2.Equal(hm), true, t)
}
// Test getting values from a HashMap // Test getting values from a HashMap
func TestHashMapGet(t *T) { func TestHashMapGet(t *T) {
kvs := []*KV{ kvs := []*KV{
KeyVal(1, "one"), keyValV(1, "one"),
KeyVal(2, "two"), keyValV(2, "two"),
} }
// Degenerate case // Degenerate case
m := NewHashMap() m := NewHashMap()
assertEmpty(m, t) assertEmpty(m, t)
v, ok := m.Get(1) v, ok := m.Get(types.GoType{1})
assertValue(v, nil, t) assertValue(v, nil, t)
assertValue(ok, false, t) assertValue(ok, false, t)
m = NewHashMap(kvs...) m = NewHashMap(kvs...)
v, ok = m.Get(1) v, ok = m.Get(types.GoType{1})
assertSeqContentsHashMap(m, kvs, t) assertSeqContentsHashMap(m, kvs, t)
assertValue(v, "one", t) assertValue(v, types.GoType{"one"}, t)
assertValue(ok, true, t) assertValue(ok, true, t)
v, ok = m.Get(3) v, ok = m.Get(types.GoType{3})
assertSeqContentsHashMap(m, kvs, t) assertSeqContentsHashMap(m, kvs, t)
assertValue(v, nil, t) assertValue(v, nil, t)
assertValue(ok, false, t) assertValue(ok, false, t)
@ -60,21 +88,21 @@ func TestHashMapSet(t *T) {
// Set on empty // Set on empty
m := NewHashMap() m := NewHashMap()
m1, ok := m.Set(1, "one") m1, ok := m.Set(types.GoType{1}, types.GoType{"one"})
assertEmpty(m, t) assertEmpty(m, t)
assertSeqContentsHashMap(m1, []*KV{KeyVal(1, "one")}, t) assertSeqContentsHashMap(m1, []*KV{keyValV(1, "one")}, t)
assertValue(ok, true, t) assertValue(ok, true, t)
// Set on same key // Set on same key
m2, ok := m1.Set(1, "wat") m2, ok := m1.Set(types.GoType{1}, types.GoType{"wat"})
assertSeqContentsHashMap(m1, []*KV{KeyVal(1, "one")}, t) assertSeqContentsHashMap(m1, []*KV{keyValV(1, "one")}, t)
assertSeqContentsHashMap(m2, []*KV{KeyVal(1, "wat")}, t) assertSeqContentsHashMap(m2, []*KV{keyValV(1, "wat")}, t)
assertValue(ok, false, t) assertValue(ok, false, t)
// Set on second new key // Set on second new key
m3, ok := m2.Set(2, "two") m3, ok := m2.Set(types.GoType{2}, types.GoType{"two"})
assertSeqContentsHashMap(m2, []*KV{KeyVal(1, "wat")}, t) assertSeqContentsHashMap(m2, []*KV{keyValV(1, "wat")}, t)
assertSeqContentsHashMap(m3, []*KV{KeyVal(1, "wat"), KeyVal(2, "two")}, t) assertSeqContentsHashMap(m3, []*KV{keyValV(1, "wat"), keyValV(2, "two")}, t)
assertValue(ok, true, t) assertValue(ok, true, t)
} }
@ -83,31 +111,31 @@ func TestHashMapSet(t *T) {
func TestHashMapDel(t *T) { func TestHashMapDel(t *T) {
kvs := []*KV{ kvs := []*KV{
KeyVal(1, "one"), keyValV(1, "one"),
KeyVal(2, "two"), keyValV(2, "two"),
KeyVal(3, "three"), keyValV(3, "three"),
} }
kvs1 := []*KV{ kvs1 := []*KV{
KeyVal(2, "two"), keyValV(2, "two"),
KeyVal(3, "three"), keyValV(3, "three"),
} }
// Degenerate case // Degenerate case
m := NewHashMap() m := NewHashMap()
m1, ok := m.Del(1) m1, ok := m.Del(types.GoType{1})
assertEmpty(m, t) assertEmpty(m, t)
assertEmpty(m1, t) assertEmpty(m1, t)
assertValue(ok, false, t) assertValue(ok, false, t)
// Delete actual key // Delete actual key
m = NewHashMap(kvs...) m = NewHashMap(kvs...)
m1, ok = m.Del(1) m1, ok = m.Del(types.GoType{1})
assertSeqContentsHashMap(m, kvs, t) assertSeqContentsHashMap(m, kvs, t)
assertSeqContentsHashMap(m1, kvs1, t) assertSeqContentsHashMap(m1, kvs1, t)
assertValue(ok, true, t) assertValue(ok, true, t)
// Delete it again! // Delete it again!
m2, ok := m1.Del(1) m2, ok := m1.Del(types.GoType{1})
assertSeqContentsHashMap(m1, kvs1, t) assertSeqContentsHashMap(m1, kvs1, t)
assertSeqContentsHashMap(m2, kvs1, t) assertSeqContentsHashMap(m2, kvs1, t)
assertValue(ok, false, t) assertValue(ok, false, t)

View File

@ -30,64 +30,42 @@ func hash(v types.Elem, i uint32) uint32 {
case Setable: case Setable:
return vt.Hash(i) % ARITY return vt.Hash(i) % ARITY
case types.GoType:
switch gvt := vt.V.(type) {
case uint: case uint:
return uint32(vt) % ARITY return uint32(gvt) % ARITY
case uint8: case uint8:
return uint32(vt) % ARITY return uint32(gvt) % ARITY
case uint32: case uint32:
return uint32(vt) % ARITY return uint32(gvt) % ARITY
case uint64: case uint64:
return uint32(vt) % ARITY return uint32(gvt) % ARITY
case int: case int:
return uint32(vt) % ARITY return uint32(gvt) % ARITY
case int8: case int8:
return uint32(vt) % ARITY return uint32(gvt) % ARITY
case int16: case int16:
return uint32(vt) % ARITY return uint32(gvt) % ARITY
case int32: case int32:
return uint32(vt) % ARITY return uint32(gvt) % ARITY
case int64: case int64:
return uint32(vt) % ARITY return uint32(gvt) % ARITY
case float32: case float32:
return uint32(vt) % ARITY return uint32(gvt) % ARITY
case float64: case float64:
return uint32(vt) % ARITY return uint32(gvt) % ARITY
case string: case string:
return crc32.ChecksumIEEE([]byte(vt)) % ARITY return crc32.ChecksumIEEE([]byte(gvt)) % ARITY
case []byte: case []byte:
return crc32.ChecksumIEEE(vt) % ARITY return crc32.ChecksumIEEE(gvt) % ARITY
}
}
default:
err := fmt.Sprintf("%s not hashable", reflect.TypeOf(v)) err := fmt.Sprintf("%s not hashable", reflect.TypeOf(v))
panic(err) panic(err)
} }
}
// Returns whether two values (potentially Setable's) are equivalent
func equal(v1, v2 types.Elem) bool {
if v1t, ok := v1.(Setable); ok {
return v1t.Equal(v2)
} else if v2t, ok := v2.(Setable); ok {
return v2t.Equal(v1)
} else if v1t, ok := v1.([]byte); ok {
if v2t, ok := v2.([]byte); ok {
if len(v1t) != len(v2t) {
return false
}
for i := range v1t {
if v1t[i] != v2t[i] {
return false
}
}
return true
}
return false
} else {
return v1 == v2
}
}
// The number of children each node in Set (implemented as a hash tree) can have // The number of children each node in Set (implemented as a hash tree) can have
const ARITY = 32 const ARITY = 32
@ -142,7 +120,7 @@ func (set *Set) shallowTrySetOrInit(val types.Elem) (bool, bool) {
set.val = val set.val = val
set.full = true set.full = true
return true, false return true, false
} else if equal(set.val, val) { } else if set.val.Equal(val) {
set.val = val set.val = val
set.full = true set.full = true
return true, true return true, true
@ -215,7 +193,7 @@ func (set *Set) SetVal(val types.Elem) (*Set, bool) {
func (set *Set) internalDelVal(val types.Elem, i uint32) (*Set, bool) { func (set *Set) internalDelVal(val types.Elem, i uint32) (*Set, bool) {
if set == nil { if set == nil {
return nil, false return nil, false
} else if set.full && equal(val, set.val) { } else if set.full && set.val.Equal(val) {
cset := set.clone() cset := set.clone()
cset.val = nil cset.val = nil
cset.full = false cset.full = false
@ -247,7 +225,7 @@ func (set *Set) DelVal(val types.Elem) (*Set, bool) {
func (set *Set) internalGetVal(val types.Elem, i uint32) (types.Elem, bool) { func (set *Set) internalGetVal(val types.Elem, i uint32) (types.Elem, bool) {
if set == nil { if set == nil {
return nil, false return nil, false
} else if set.full && equal(val, set.val) { } else if set.full && set.val.Equal(val) {
return set.val, true return set.val, true
} else if set.kids == nil { } else if set.kids == nil {
return nil, false return nil, false
@ -301,6 +279,32 @@ func (set *Set) FirstRest() (types.Elem, Seq, bool) {
return el, Seq(restSet), ok return el, Seq(restSet), ok
} }
// Implementation of Equal for types.Elem interface. Completes in O(Nlog(M))
// time if e is another Set, where M is the size of the given Set
func (set *Set) Equal(e types.Elem) bool {
set2, ok := e.(*Set)
if !ok {
return false
}
var el types.Elem
s := Seq(set)
size := uint64(0)
for {
el, s, ok = s.FirstRest()
if !ok {
return size == set2.Size()
}
size++
_, ok = set2.GetVal(el)
if !ok {
return false
}
}
}
// Implementation of String for Stringer interface // Implementation of String for Stringer interface
func (set *Set) String() string { func (set *Set) String() string {
return ToString(set, "#{", "}#") return ToString(set, "#{", "}#")

View File

@ -6,9 +6,14 @@ import (
"github.com/mediocregopher/ginger/types" "github.com/mediocregopher/ginger/types"
) )
// Test that HashSet implements types.Elem (compile-time check)
func TestSetElem(t *T) {
_ = types.Elem(NewSet())
}
// Test creating a Set and calling the Seq interface methods on it // Test creating a Set and calling the Seq interface methods on it
func TestSetSeq(t *T) { func TestSetSeq(t *T) {
ints := []types.Elem{1, "a", 5.0} ints := elemSliceV(nil, 1, "a", 5.0)
// Testing creation and Seq interface methods // Testing creation and Seq interface methods
s := NewSet(ints...) s := NewSet(ints...)
@ -22,25 +27,48 @@ func TestSetSeq(t *T) {
assertValue(len(ToSlice(s)), 0, t) assertValue(len(ToSlice(s)), 0, t)
} }
// Test that the Equal method on Sets works
func TestSetEqual(t *T) {
s, s2 := NewSet(), NewSet()
assertValue(s.Equal(s2), true, t)
assertValue(s2.Equal(s), true, t)
s = NewSet(elemSliceV(0, 1, 2)...)
assertValue(s.Equal(s2), false, t)
assertValue(s2.Equal(s), false, t)
s2 = NewSet(elemSliceV(0, 1)...)
assertValue(s.Equal(s2), false, t)
assertValue(s2.Equal(s), false, t)
s2 = NewSet(elemSliceV(0, 1, 3)...)
assertValue(s.Equal(s2), false, t)
assertValue(s2.Equal(s), false, t)
s2 = NewSet(elemSliceV(0, 1, 2)...)
assertValue(s.Equal(s2), true, t)
assertValue(s2.Equal(s), true, t)
}
// Test setting a value on a Set // Test setting a value on a Set
func TestSetVal(t *T) { func TestSetVal(t *T) {
ints := []types.Elem{0, 1, 2, 3, 4} ints := elemSliceV(0, 1, 2, 3, 4)
ints1 := []types.Elem{0, 1, 2, 3, 4, 5} ints1 := elemSliceV(0, 1, 2, 3, 4, 5)
// Degenerate case // Degenerate case
s := NewSet() s := NewSet()
assertEmpty(s, t) assertEmpty(s, t)
s, ok := s.SetVal(0) s, ok := s.SetVal(types.GoType{0})
assertSeqContentsSet(s, []types.Elem{0}, t) assertSeqContentsSet(s, elemSliceV(0), t)
assertValue(ok, true, t) assertValue(ok, true, t)
s = NewSet(ints...) s = NewSet(ints...)
s1, ok := s.SetVal(5) s1, ok := s.SetVal(types.GoType{5})
assertSeqContentsSet(s, ints, t) assertSeqContentsSet(s, ints, t)
assertSeqContentsSet(s1, ints1, t) assertSeqContentsSet(s1, ints1, t)
assertValue(ok, true, t) assertValue(ok, true, t)
s2, ok := s1.SetVal(5) s2, ok := s1.SetVal(types.GoType{5})
assertSeqContentsSet(s1, ints1, t) assertSeqContentsSet(s1, ints1, t)
assertSeqContentsSet(s2, ints1, t) assertSeqContentsSet(s2, ints1, t)
assertValue(ok, false, t) assertValue(ok, false, t)
@ -48,41 +76,41 @@ func TestSetVal(t *T) {
// Test deleting a value from a Set // Test deleting a value from a Set
func TestDelVal(t *T) { func TestDelVal(t *T) {
ints := []types.Elem{0, 1, 2, 3, 4} ints := elemSliceV(0, 1, 2, 3, 4)
ints1 := []types.Elem{0, 1, 2, 3} ints1 := elemSliceV(0, 1, 2, 3)
ints2 := []types.Elem{1, 2, 3, 4} ints2 := elemSliceV(1, 2, 3, 4)
ints3 := []types.Elem{1, 2, 3, 4, 5} ints3 := elemSliceV(1, 2, 3, 4, 5)
// Degenerate case // Degenerate case
s := NewSet() s := NewSet()
assertEmpty(s, t) assertEmpty(s, t)
s, ok := s.DelVal(0) s, ok := s.DelVal(types.GoType{0})
assertEmpty(s, t) assertEmpty(s, t)
assertValue(ok, false, t) assertValue(ok, false, t)
s = NewSet(ints...) s = NewSet(ints...)
s1, ok := s.DelVal(4) s1, ok := s.DelVal(types.GoType{4})
assertSeqContentsSet(s, ints, t) assertSeqContentsSet(s, ints, t)
assertSeqContentsSet(s1, ints1, t) assertSeqContentsSet(s1, ints1, t)
assertValue(ok, true, t) assertValue(ok, true, t)
s1, ok = s1.DelVal(4) s1, ok = s1.DelVal(types.GoType{4})
assertSeqContentsSet(s1, ints1, t) assertSeqContentsSet(s1, ints1, t)
assertValue(ok, false, t) assertValue(ok, false, t)
// 0 is the value on the root node of s, which is kind of a special case. We // 0 is the value on the root node of s, which is kind of a special case. We
// want to test deleting it and setting a new value (which should get put on // want to test deleting it and setting a new value (which should get put on
// the root node). // the root node).
s2, ok := s.DelVal(0) s2, ok := s.DelVal(types.GoType{0})
assertSeqContentsSet(s, ints, t) assertSeqContentsSet(s, ints, t)
assertSeqContentsSet(s2, ints2, t) assertSeqContentsSet(s2, ints2, t)
assertValue(ok, true, t) assertValue(ok, true, t)
s2, ok = s2.DelVal(0) s2, ok = s2.DelVal(types.GoType{0})
assertSeqContentsSet(s2, ints2, t) assertSeqContentsSet(s2, ints2, t)
assertValue(ok, false, t) assertValue(ok, false, t)
s3, ok := s2.SetVal(5) s3, ok := s2.SetVal(types.GoType{5})
assertSeqContentsSet(s2, ints2, t) assertSeqContentsSet(s2, ints2, t)
assertSeqContentsSet(s3, ints3, t) assertSeqContentsSet(s3, ints3, t)
assertValue(ok, true, t) assertValue(ok, true, t)
@ -92,36 +120,36 @@ func TestDelVal(t *T) {
func GetVal(t *T) { func GetVal(t *T) {
//Degenerate case //Degenerate case
s := NewSet() s := NewSet()
v, ok := s.GetVal(1) v, ok := s.GetVal(types.GoType{1})
assertValue(v, nil, t) assertValue(v, nil, t)
assertValue(ok, false, t) assertValue(ok, false, t)
s = NewSet(0, 1, 2, 3, 4) s = NewSet(elemSliceV(0, 1, 2, 3, 4)...)
v, ok = s.GetVal(1) v, ok = s.GetVal(types.GoType{1})
assertValue(v, 1, t) assertValue(v, 1, t)
assertValue(ok, true, t) assertValue(ok, true, t)
// After delete // After delete
s, _ = s.DelVal(1) s, _ = s.DelVal(types.GoType{1})
v, ok = s.GetVal(1) v, ok = s.GetVal(types.GoType{1})
assertValue(v, nil, t) assertValue(v, nil, t)
assertValue(ok, false, t) assertValue(ok, false, t)
// After set // After set
s, _ = s.SetVal(1) s, _ = s.SetVal(types.GoType{1})
v, ok = s.GetVal(1) v, ok = s.GetVal(types.GoType{1})
assertValue(v, 1, t) assertValue(v, 1, t)
assertValue(ok, true, t) assertValue(ok, true, t)
// After delete root node // After delete root node
s, _ = s.DelVal(0) s, _ = s.DelVal(types.GoType{0})
v, ok = s.GetVal(0) v, ok = s.GetVal(types.GoType{0})
assertValue(v, nil, t) assertValue(v, nil, t)
assertValue(ok, false, t) assertValue(ok, false, t)
// After set root node // After set root node
s, _ = s.SetVal(5) s, _ = s.SetVal(types.GoType{5})
v, ok = s.GetVal(5) v, ok = s.GetVal(types.GoType{5})
assertValue(v, 5, t) assertValue(v, 5, t)
assertValue(ok, true, t) assertValue(ok, true, t)
} }
@ -133,25 +161,25 @@ func TestSetSize(t *T) {
assertValue(s.Size(), uint64(0), t) assertValue(s.Size(), uint64(0), t)
// Initialization case // Initialization case
s = NewSet(0, 1, 2) s = NewSet(elemSliceV(0, 1, 2)...)
assertValue(s.Size(), uint64(3), t) assertValue(s.Size(), uint64(3), t)
// Setting (both value not in and a value already in) // Setting (both value not in and a value already in)
s, _ = s.SetVal(3) s, _ = s.SetVal(types.GoType{3})
assertValue(s.Size(), uint64(4), t) assertValue(s.Size(), uint64(4), t)
s, _ = s.SetVal(3) s, _ = s.SetVal(types.GoType{3})
assertValue(s.Size(), uint64(4), t) assertValue(s.Size(), uint64(4), t)
// Deleting (both value already in and a value not in) // Deleting (both value already in and a value not in)
s, _ = s.DelVal(3) s, _ = s.DelVal(types.GoType{3})
assertValue(s.Size(), uint64(3), t) assertValue(s.Size(), uint64(3), t)
s, _ = s.DelVal(3) s, _ = s.DelVal(types.GoType{3})
assertValue(s.Size(), uint64(3), t) assertValue(s.Size(), uint64(3), t)
// Deleting and setting the root node // Deleting and setting the root node
s, _ = s.DelVal(0) s, _ = s.DelVal(types.GoType{0})
assertValue(s.Size(), uint64(2), t) assertValue(s.Size(), uint64(2), t)
s, _ = s.SetVal(5) s, _ = s.SetVal(types.GoType{5})
assertValue(s.Size(), uint64(3), t) assertValue(s.Size(), uint64(3), t)
} }
@ -162,8 +190,8 @@ func TestUnion(t *T) {
empty := NewSet() empty := NewSet()
assertEmpty(empty.Union(empty), t) assertEmpty(empty.Union(empty), t)
ints1 := []types.Elem{0, 1, 2} ints1 := elemSliceV(0, 1, 2)
ints2 := []types.Elem{3, 4, 5} ints2 := elemSliceV(3, 4, 5)
intsu := append(ints1, ints2...) intsu := append(ints1, ints2...)
s1 := NewSet(ints1...) s1 := NewSet(ints1...)
s2 := NewSet(ints2...) s2 := NewSet(ints2...)
@ -183,10 +211,10 @@ func TestIntersection(t *T) {
empty := NewSet() empty := NewSet()
assertEmpty(empty.Intersection(empty), t) assertEmpty(empty.Intersection(empty), t)
ints1 := []types.Elem{0, 1, 2} ints1 := elemSliceV(0, 1, 2)
ints2 := []types.Elem{1, 2, 3} ints2 := elemSliceV(1, 2, 3)
ints3 := []types.Elem{4, 5, 6} ints3 := elemSliceV(4, 5, 6)
intsi := []types.Elem{1, 2} intsi := elemSliceV(1, 2)
s1 := NewSet(ints1...) s1 := NewSet(ints1...)
s2 := NewSet(ints2...) s2 := NewSet(ints2...)
s3 := NewSet(ints3...) s3 := NewSet(ints3...)
@ -208,9 +236,9 @@ func TestDifference(t *T) {
empty := NewSet() empty := NewSet()
assertEmpty(empty.Difference(empty), t) assertEmpty(empty.Difference(empty), t)
ints1 := []types.Elem{0, 1, 2, 3} ints1 := elemSliceV(0, 1, 2, 3)
ints2 := []types.Elem{2, 3, 4} ints2 := elemSliceV(2, 3, 4)
intsd := []types.Elem{0, 1} intsd := elemSliceV(0, 1)
s1 := NewSet(ints1...) s1 := NewSet(ints1...)
s2 := NewSet(ints2...) s2 := NewSet(ints2...)
@ -229,9 +257,9 @@ func TestSymDifference(t *T) {
empty := NewSet() empty := NewSet()
assertEmpty(empty.SymDifference(empty), t) assertEmpty(empty.SymDifference(empty), t)
ints1 := []types.Elem{0, 1, 2, 3} ints1 := elemSliceV(0, 1, 2, 3)
ints2 := []types.Elem{2, 3, 4} ints2 := elemSliceV(2, 3, 4)
intsd := []types.Elem{0, 1, 4} intsd := elemSliceV(0, 1, 4)
s1 := NewSet(ints1...) s1 := NewSet(ints1...)
s2 := NewSet(ints2...) s2 := NewSet(ints2...)

View File

@ -50,6 +50,20 @@ func (l *Lazy) FirstRest() (types.Elem, Seq, bool) {
} }
} }
// Implementation of Equal for types.Elem interface. Treats a List as another
// Lazy. Completes in O(N) time if e is another List or List.
func (l *Lazy) Equal(e types.Elem) bool {
var ls2 *List
if l2, ok := e.(*Lazy); ok {
ls2 = ToList(l2)
} else if ls2, ok = e.(*List); ok {
} else {
return false
}
ls := ToList(l)
return ls.Equal(ls2)
}
// Implementation of String for Stringer // Implementation of String for Stringer
func (l *Lazy) String() string { func (l *Lazy) String() string {
return ToString(l, "<<", ">>") return ToString(l, "<<", ">>")

View File

@ -7,19 +7,26 @@ import (
"github.com/mediocregopher/ginger/types" "github.com/mediocregopher/ginger/types"
) )
// Test that Lazy implements types.Elem (compile-time check)
func TestLazyElem(t *T) {
_ = types.Elem(NewLazy(nil))
}
// Test lazy operation and thread-safety // Test lazy operation and thread-safety
func TestLazyBasic(t *T) { func TestLazyBasic(t *T) {
ch := make(chan int) ch := make(chan types.GoType)
mapfn := func(el types.Elem) types.Elem { mapfn := func(el types.Elem) types.Elem {
i := el.(int) i := el.(types.GoType)
ch <- i ch <- i
return i return i
} }
intl := []types.Elem{0, 1, 2, 3, 4} intl := elemSliceV(0, 1, 2, 3, 4)
l := NewList(intl...) l := NewList(intl...)
ml := LMap(mapfn, l) ml := LMap(mapfn, l)
// ml is a lazy list of intl, which will write to ch the first time any of
// the elements are read. This for loop ensures ml is thread-safe
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
go func() { go func() {
mlintl := ToSlice(ml) mlintl := ToSlice(ml)
@ -29,6 +36,8 @@ func TestLazyBasic(t *T) {
}() }()
} }
// This loop and subsequent close ensure that ml only ever "creates" each
// element once
for _, el := range intl { for _, el := range intl {
select { select {
case elch := <-ch: case elch := <-ch:
@ -42,7 +51,7 @@ func TestLazyBasic(t *T) {
// Test that arbitrary Seqs can turn into Lazy // Test that arbitrary Seqs can turn into Lazy
func TestToLazy(t *T) { func TestToLazy(t *T) {
intl := []types.Elem{0, 1, 2, 3, 4} intl := elemSliceV(0, 1, 2, 3, 4)
l := NewList(intl...) l := NewList(intl...)
ll := ToLazy(l) ll := ToLazy(l)
assertSeqContents(ll, intl, t) assertSeqContents(ll, intl, t)

View File

@ -39,6 +39,36 @@ func (l *List) FirstRest() (types.Elem, Seq, bool) {
} }
} }
// Implementation of Equal for types.Elem interface. Completes in O(N) time if e
// is another List.
func (l *List) Equal(e types.Elem) bool {
l2, ok := e.(*List)
if !ok {
return false
}
var el, el2 types.Elem
var ok2 bool
s, s2 := Seq(l), Seq(l2)
for {
el, s, ok = s.FirstRest()
el2, s2, ok2 = s2.FirstRest()
if !ok && !ok2 {
return true
}
if ok != ok2 {
return false
}
if !el.Equal(el2) {
return false
}
}
}
// Implementation of String for Stringer interface. // Implementation of String for Stringer interface.
func (l *List) String() string { func (l *List) String() string {
return ToString(l, "(", ")") return ToString(l, "(", ")")

View File

@ -6,6 +6,11 @@ import (
"github.com/mediocregopher/ginger/types" "github.com/mediocregopher/ginger/types"
) )
// Test that List implements types.Elem (compile-time check)
func TestListElem(t *T) {
_ = types.Elem(NewList())
}
// Asserts that the given list is properly formed and has all of its size fields // Asserts that the given list is properly formed and has all of its size fields
// filled in correctly // filled in correctly
func assertSaneList(l *List, t *T) { func assertSaneList(l *List, t *T) {
@ -22,7 +27,7 @@ func assertSaneList(l *List, t *T) {
// Test creating a list and calling the Seq interface methods on it // Test creating a list and calling the Seq interface methods on it
func TestListSeq(t *T) { func TestListSeq(t *T) {
ints := []types.Elem{1, "a", 5.0} ints := elemSliceV(1, "a", 5.0)
// Testing creation and Seq interface methods // Testing creation and Seq interface methods
l := NewList(ints...) l := NewList(ints...)
@ -40,39 +45,62 @@ func TestListSeq(t *T) {
assertValue(emptyl, nilpointer, t) assertValue(emptyl, nilpointer, t)
} }
// Test that the Equal method on Lists works
func TestListEqual(t *T) {
l, l2 := NewList(), NewList()
assertValue(l.Equal(l2), true, t)
assertValue(l2.Equal(l), true, t)
l2 = NewList(elemSliceV(1, 2, 3)...)
assertValue(l.Equal(l2), false, t)
assertValue(l2.Equal(l), false, t)
l = NewList(elemSliceV(1, 2, 3, 4)...)
assertValue(l.Equal(l2), false, t)
assertValue(l2.Equal(l), false, t)
l2 = NewList(elemSliceV(1, 2, 3, 4)...)
assertValue(l.Equal(l2), true, t)
assertValue(l2.Equal(l), true, t)
}
// Test the string representation of a List // Test the string representation of a List
func TestStringSeq(t *T) { func TestStringSeq(t *T) {
l := NewList(0, 1, 2, 3) l := NewList(elemSliceV(0, 1, 2, 3)...)
assertValue(l.String(), "( 0 1 2 3 )", t) assertValue(l.String(), "( 0 1 2 3 )", t)
l = NewList(0, 1, 2, NewList(3, 4), 5, NewList(6, 7, 8)) l = NewList(elemSliceV(
0, 1, 2,
NewList(elemSliceV(3, 4)...),
5,
NewList(elemSliceV(6, 7, 8)...))...)
assertValue(l.String(), "( 0 1 2 ( 3 4 ) 5 ( 6 7 8 ) )", t) assertValue(l.String(), "( 0 1 2 ( 3 4 ) 5 ( 6 7 8 ) )", t)
} }
// Test prepending an element to the beginning of a list // Test prepending an element to the beginning of a list
func TestPrepend(t *T) { func TestPrepend(t *T) {
// Normal case // Normal case
intl := []types.Elem{3, 2, 1, 0} intl := elemSliceV(3, 2, 1, 0)
l := NewList(intl...) l := NewList(intl...)
nl := l.Prepend(4) nl := l.Prepend(types.GoType{4})
assertSaneList(l, t) assertSaneList(l, t)
assertSaneList(nl, t) assertSaneList(nl, t)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertSeqContents(nl, []types.Elem{4, 3, 2, 1, 0}, t) assertSeqContents(nl, elemSliceV(4, 3, 2, 1, 0), t)
// Degenerate case // Degenerate case
l = NewList() l = NewList()
nl = l.Prepend(0) nl = l.Prepend(types.GoType{0})
assertEmpty(l, t) assertEmpty(l, t)
assertSaneList(nl, t) assertSaneList(nl, t)
assertSeqContents(nl, []types.Elem{0}, t) assertSeqContents(nl, elemSliceV(0), t)
} }
// Test prepending a Seq to the beginning of a list // Test prepending a Seq to the beginning of a list
func TestPrependSeq(t *T) { func TestPrependSeq(t *T) {
//Normal case //Normal case
intl1 := []types.Elem{3, 4} intl1 := elemSliceV(3, 4)
intl2 := []types.Elem{0, 1, 2} intl2 := elemSliceV(0, 1, 2)
l1 := NewList(intl1...) l1 := NewList(intl1...)
l2 := NewList(intl2...) l2 := NewList(intl2...)
nl := l1.PrependSeq(l2) nl := l1.PrependSeq(l2)
@ -81,7 +109,7 @@ func TestPrependSeq(t *T) {
assertSaneList(nl, t) assertSaneList(nl, t)
assertSeqContents(l1, intl1, t) assertSeqContents(l1, intl1, t)
assertSeqContents(l2, intl2, t) assertSeqContents(l2, intl2, t)
assertSeqContents(nl, []types.Elem{0, 1, 2, 3, 4}, t) assertSeqContents(nl, elemSliceV(0, 1, 2, 3, 4), t)
// Degenerate cases // Degenerate cases
blank1 := NewList() blank1 := NewList()
@ -105,34 +133,34 @@ func TestPrependSeq(t *T) {
// Test appending to the end of a List // Test appending to the end of a List
func TestAppend(t *T) { func TestAppend(t *T) {
// Normal case // Normal case
intl := []types.Elem{3, 2, 1} intl := elemSliceV(3, 2, 1)
l := NewList(intl...) l := NewList(intl...)
nl := l.Append(0) nl := l.Append(types.GoType{0})
assertSaneList(l, t) assertSaneList(l, t)
assertSaneList(nl, t) assertSaneList(nl, t)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertSeqContents(nl, []types.Elem{3, 2, 1, 0}, t) assertSeqContents(nl, elemSliceV(3, 2, 1, 0), t)
// Edge case (algorithm gets weird here) // Edge case (algorithm gets weird here)
l = NewList(1) l = NewList(elemSliceV(1)...)
nl = l.Append(0) nl = l.Append(types.GoType{0})
assertSaneList(l, t) assertSaneList(l, t)
assertSaneList(nl, t) assertSaneList(nl, t)
assertSeqContents(l, []types.Elem{1}, t) assertSeqContents(l, elemSliceV(1), t)
assertSeqContents(nl, []types.Elem{1, 0}, t) assertSeqContents(nl, elemSliceV(1, 0), t)
// Degenerate case // Degenerate case
l = NewList() l = NewList()
nl = l.Append(0) nl = l.Append(types.GoType{0})
assertEmpty(l, t) assertEmpty(l, t)
assertSaneList(nl, t) assertSaneList(nl, t)
assertSeqContents(nl, []types.Elem{0}, t) assertSeqContents(nl, elemSliceV(0), t)
} }
// Test retrieving items from a List // Test retrieving items from a List
func TestNth(t *T) { func TestNth(t *T) {
// Normal case, in bounds // Normal case, in bounds
intl := []types.Elem{0, 2, 4, 6, 8} intl := elemSliceV(0, 2, 4, 6, 8)
l := NewList(intl...) l := NewList(intl...)
r, ok := l.Nth(3) r, ok := l.Nth(3)
assertSaneList(l, t) assertSaneList(l, t)

View File

@ -50,11 +50,11 @@ func testSeqNoOrderGen(t *T, s Seq, ints []types.Elem) Seq {
// Test reversing a Seq // Test reversing a Seq
func TestReverse(t *T) { func TestReverse(t *T) {
// Normal case // Normal case
intl := []types.Elem{3, 2, 1} intl := elemSliceV(3, 2, 1)
l := NewList(intl...) l := NewList(intl...)
nl := Reverse(l) nl := Reverse(l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertSeqContents(nl, []types.Elem{1, 2, 3}, t) assertSeqContents(nl, elemSliceV(1, 2, 3), t)
// Degenerate case // Degenerate case
l = NewList() l = NewList()
@ -65,15 +65,15 @@ func TestReverse(t *T) {
func testMapGen(t *T, mapFn func(func(types.Elem) types.Elem, Seq) Seq) { func testMapGen(t *T, mapFn func(func(types.Elem) types.Elem, Seq) Seq) {
fn := func(n types.Elem) types.Elem { fn := func(n types.Elem) types.Elem {
return n.(int) + 1 return types.GoType{n.(types.GoType).V.(int) + 1}
} }
// Normal case // Normal case
intl := []types.Elem{1, 2, 3} intl := elemSliceV(1, 2, 3)
l := NewList(intl...) l := NewList(intl...)
nl := mapFn(fn, l) nl := mapFn(fn, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertSeqContents(nl, []types.Elem{2, 3, 4}, t) assertSeqContents(nl, elemSliceV(2, 3, 4), t)
// Degenerate case // Degenerate case
l = NewList() l = NewList()
@ -95,27 +95,31 @@ func TestLMap(t *T) {
// Test reducing over a Seq // Test reducing over a Seq
func TestReduce(t *T) { func TestReduce(t *T) {
fn := func(acc, el types.Elem) (types.Elem, bool) { fn := func(acc, el types.Elem) (types.Elem, bool) {
return acc.(int) + el.(int), false acci := acc.(types.GoType).V.(int)
eli := el.(types.GoType).V.(int)
return types.GoType{acci + eli}, false
} }
// Normal case // Normal case
intl := []types.Elem{1, 2, 3, 4} intl := elemSliceV(1, 2, 3, 4)
l := NewList(intl...) l := NewList(intl...)
r := Reduce(fn, 0, l) r := Reduce(fn, types.GoType{0}, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertValue(r, 10, t) assertValue(r, 10, t)
// Short-circuit case // Short-circuit case
fns := func(acc, el types.Elem) (types.Elem, bool) { fns := func(acc, el types.Elem) (types.Elem, bool) {
return acc.(int) + el.(int), el.(int) > 2 acci := acc.(types.GoType).V.(int)
eli := el.(types.GoType).V.(int)
return types.GoType{acci + eli}, eli > 2
} }
r = Reduce(fns, 0, l) r = Reduce(fns, types.GoType{0}, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertValue(r, 6, t) assertValue(r, 6, t)
// Degenerate case // Degenerate case
l = NewList() l = NewList()
r = Reduce(fn, 0, l) r = Reduce(fn, types.GoType{0}, l)
assertEmpty(l, t) assertEmpty(l, t)
assertValue(r, 0, t) assertValue(r, 0, t)
} }
@ -123,11 +127,11 @@ func TestReduce(t *T) {
// Test the Any function // Test the Any function
func TestAny(t *T) { func TestAny(t *T) {
fn := func(el types.Elem) bool { fn := func(el types.Elem) bool {
return el.(int) > 3 return el.(types.GoType).V.(int) > 3
} }
// Value found case // Value found case
intl := []types.Elem{1, 2, 3, 4} intl := elemSliceV(1, 2, 3, 4)
l := NewList(intl...) l := NewList(intl...)
r, ok := Any(fn, l) r, ok := Any(fn, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
@ -135,7 +139,7 @@ func TestAny(t *T) {
assertValue(ok, true, t) assertValue(ok, true, t)
// Value not found case // Value not found case
intl = []types.Elem{1, 2, 3} intl = elemSliceV(1, 2, 3)
l = NewList(intl...) l = NewList(intl...)
r, ok = Any(fn, l) r, ok = Any(fn, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
@ -153,18 +157,18 @@ func TestAny(t *T) {
// Test the All function // Test the All function
func TestAll(t *T) { func TestAll(t *T) {
fn := func(el types.Elem) bool { fn := func(el types.Elem) bool {
return el.(int) > 3 return el.(types.GoType).V.(int) > 3
} }
// All match case // All match case
intl := []types.Elem{4, 5, 6} intl := elemSliceV(4, 5, 6)
l := NewList(intl...) l := NewList(intl...)
ok := All(fn, l) ok := All(fn, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertValue(ok, true, t) assertValue(ok, true, t)
// Not all match case // Not all match case
intl = []types.Elem{3, 4, 2, 5} intl = elemSliceV(3, 4, 2, 5)
l = NewList(intl...) l = NewList(intl...)
ok = All(fn, l) ok = All(fn, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
@ -179,15 +183,15 @@ func TestAll(t *T) {
func testFilterGen(t *T, filterFn func(func(types.Elem) bool, Seq) Seq) { func testFilterGen(t *T, filterFn func(func(types.Elem) bool, Seq) Seq) {
fn := func(el types.Elem) bool { fn := func(el types.Elem) bool {
return el.(int)%2 != 0 return el.(types.GoType).V.(int)%2 != 0
} }
// Normal case // Normal case
intl := []types.Elem{1, 2, 3, 4, 5} intl := elemSliceV(1, 2, 3, 4, 5)
l := NewList(intl...) l := NewList(intl...)
r := filterFn(fn, l) r := filterFn(fn, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertSeqContents(r, []types.Elem{1, 3, 5}, t) assertSeqContents(r, elemSliceV(1, 3, 5), t)
// Degenerate cases // Degenerate cases
l = NewList() l = NewList()
@ -209,19 +213,19 @@ func TestLFilter(t *T) {
// Test Flatten-ing of a Seq // Test Flatten-ing of a Seq
func TestFlatten(t *T) { func TestFlatten(t *T) {
// Normal case // Normal case
intl1 := []types.Elem{0, 1, 2} intl1 := elemSliceV(0, 1, 2)
intl2 := []types.Elem{3, 4, 5} intl2 := elemSliceV(3, 4, 5)
l1 := NewList(intl1...) l1 := NewList(intl1...)
l2 := NewList(intl2...) l2 := NewList(intl2...)
blank := NewList() blank := NewList()
intl := []types.Elem{-1, l1, l2, 6, blank, 7} intl := elemSliceV(-1, l1, l2, 6, blank, 7)
l := NewList(intl...) l := NewList(intl...)
nl := Flatten(l) nl := Flatten(l)
assertSeqContents(l1, intl1, t) assertSeqContents(l1, intl1, t)
assertSeqContents(l2, intl2, t) assertSeqContents(l2, intl2, t)
assertEmpty(blank, t) assertEmpty(blank, t)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertSeqContents(nl, []types.Elem{-1, 0, 1, 2, 3, 4, 5, 6, 7}, t) assertSeqContents(nl, elemSliceV(-1, 0, 1, 2, 3, 4, 5, 6, 7), t)
// Degenerate case // Degenerate case
nl = Flatten(blank) nl = Flatten(blank)
@ -231,11 +235,11 @@ func TestFlatten(t *T) {
func testTakeGen(t *T, takeFn func(uint64, Seq) Seq) { func testTakeGen(t *T, takeFn func(uint64, Seq) Seq) {
// Normal case // Normal case
intl := []types.Elem{0, 1, 2, 3, 4} intl := elemSliceV(0, 1, 2, 3, 4)
l := NewList(intl...) l := NewList(intl...)
nl := takeFn(3, l) nl := takeFn(3, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertSeqContents(nl, []types.Elem{0, 1, 2}, t) assertSeqContents(nl, elemSliceV(0, 1, 2), t)
// Edge cases // Edge cases
nl = takeFn(5, l) nl = takeFn(5, l)
@ -269,28 +273,28 @@ func TestLTake(t *T) {
func testTakeWhileGen(t *T, takeWhileFn func(func(types.Elem) bool, Seq) Seq) { func testTakeWhileGen(t *T, takeWhileFn func(func(types.Elem) bool, Seq) Seq) {
pred := func(el types.Elem) bool { pred := func(el types.Elem) bool {
return el.(int) < 3 return el.(types.GoType).V.(int) < 3
} }
// Normal case // Normal case
intl := []types.Elem{0, 1, 2, 3, 4, 5} intl := elemSliceV(0, 1, 2, 3, 4, 5)
l := NewList(intl...) l := NewList(intl...)
nl := takeWhileFn(pred, l) nl := takeWhileFn(pred, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertSeqContents(nl, []types.Elem{0, 1, 2}, t) assertSeqContents(nl, elemSliceV(0, 1, 2), t)
// Edge cases // Edge cases
intl = []types.Elem{5, 5, 5} intl = elemSliceV(5, 5, 5)
l = NewList(intl...) l = NewList(intl...)
nl = takeWhileFn(pred, l) nl = takeWhileFn(pred, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertEmpty(nl, t) assertEmpty(nl, t)
intl = []types.Elem{0, 1, 2} intl = elemSliceV(0, 1, 2)
l = NewList(intl...) l = NewList(intl...)
nl = takeWhileFn(pred, l) nl = takeWhileFn(pred, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertSeqContents(nl, []types.Elem{0, 1, 2}, t) assertSeqContents(nl, elemSliceV(0, 1, 2), t)
// Degenerate case // Degenerate case
l = NewList() l = NewList()
@ -312,11 +316,11 @@ func TestLTakeWhile(t *T) {
// Test dropping from a Seq // Test dropping from a Seq
func TestDrop(t *T) { func TestDrop(t *T) {
// Normal case // Normal case
intl := []types.Elem{0, 1, 2, 3, 4} intl := elemSliceV(0, 1, 2, 3, 4)
l := NewList(intl...) l := NewList(intl...)
nl := Drop(3, l) nl := Drop(3, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertSeqContents(nl, []types.Elem{3, 4}, t) assertSeqContents(nl, elemSliceV(3, 4), t)
// Edge cases // Edge cases
nl = Drop(5, l) nl = Drop(5, l)
@ -341,24 +345,24 @@ func TestDrop(t *T) {
// Test dropping from a Seq until a given condition // Test dropping from a Seq until a given condition
func TestDropWhile(t *T) { func TestDropWhile(t *T) {
pred := func(el types.Elem) bool { pred := func(el types.Elem) bool {
return el.(int) < 3 return el.(types.GoType).V.(int) < 3
} }
// Normal case // Normal case
intl := []types.Elem{0, 1, 2, 3, 4, 5} intl := elemSliceV(0, 1, 2, 3, 4, 5)
l := NewList(intl...) l := NewList(intl...)
nl := DropWhile(pred, l) nl := DropWhile(pred, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertSeqContents(nl, []types.Elem{3, 4, 5}, t) assertSeqContents(nl, elemSliceV(3, 4, 5), t)
// Edge cases // Edge cases
intl = []types.Elem{5, 5, 5} intl = elemSliceV(5, 5, 5)
l = NewList(intl...) l = NewList(intl...)
nl = DropWhile(pred, l) nl = DropWhile(pred, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)
assertSeqContents(nl, intl, t) assertSeqContents(nl, intl, t)
intl = []types.Elem{0, 1, 2} intl = elemSliceV(0, 1, 2)
l = NewList(intl...) l = NewList(intl...)
nl = DropWhile(pred, l) nl = DropWhile(pred, l)
assertSeqContents(l, intl, t) assertSeqContents(l, intl, t)

View File

@ -19,6 +19,18 @@ func intSlicesEq(a, b []types.Elem) bool {
return true return true
} }
func elemSliceV(a ...interface{}) []types.Elem {
ret := make([]types.Elem, 0, len(a))
for i := range a {
if e, ok := a[i].(types.Elem); ok {
ret = append(ret, e)
} else {
ret = append(ret, types.GoType{a[i]})
}
}
return ret
}
// Asserts that the given Seq is empty (contains no elements) // Asserts that the given Seq is empty (contains no elements)
func assertEmpty(s Seq, t *testing.T) { func assertEmpty(s Seq, t *testing.T) {
if Size(s) != 0 { if Size(s) != 0 {
@ -59,7 +71,7 @@ func assertSeqContentsSet(s Seq, ints []types.Elem, t *testing.T) {
} }
func assertSeqContentsHashMap(s Seq, kvs []*KV, t *testing.T) { func assertSeqContentsHashMap(s Seq, kvs []*KV, t *testing.T) {
m := map[types.Elem]bool{} m := map[KV]bool{}
for i := range kvs { for i := range kvs {
m[*kvs[i]] = true m[*kvs[i]] = true
} }
@ -76,9 +88,16 @@ func assertSeqContentsHashMap(s Seq, kvs []*KV, t *testing.T) {
} }
// Asserts that v1 is the same as v2 // Asserts that v1 is the same as v2
func assertValue(v1, v2 types.Elem, t *testing.T) { func assertValue(v1, v2 interface{}, t *testing.T) {
if gv1, ok := v1.(types.GoType); ok {
v1 = gv1.V
}
if gv2, ok := v2.(types.GoType); ok {
v2 = gv2.V
}
if v1 != v2 { if v1 != v2 {
t.Fatalf("Value wrong: %v not %v", v1, v2) t.Logf("Value wrong: %v not %v", v1, v2)
panic("bail")
} }
} }
@ -88,3 +107,7 @@ func assertInMap(v1 types.Elem, m map[types.Elem]bool, t *testing.T) {
t.Fatalf("Value not in set: %v not in %v", v1, m) t.Fatalf("Value not in set: %v not in %v", v1, m)
} }
} }
func keyValV(k, v interface{}) *KV {
return KeyVal(types.GoType{k}, types.GoType{v})
}

View File

@ -1,11 +1,38 @@
// This package describes ginger's base types and the interfaces covered by them // This package describes ginger's base types and the interfaces covered by them
package types package types
import (
"fmt"
)
// Elem is a generic type which can be used as a wrapper type for all ginger // Elem is a generic type which can be used as a wrapper type for all ginger
// types, both base types and data structures // types, both base types and data structures
type Elem interface { type Elem interface {
// Returns whether one element is equal to another. Since all ginger values
// are immutable, this must be a deep-equals check.
Equal(Elem) bool
} }
// Number can either be either an Int or a Float // Number can either be either an Int or a Float
type Number interface { type Number interface {
Elem
}
// Wraps a go type like int, string, or []byte. GoType is a struct whose only
// field is an interface{}, so using a pointer to is not necessary. Just pass
// around the value type.
type GoType struct {
V interface{}
}
func (g GoType) Equal(e Elem) bool {
if g2, ok := e.(GoType); ok {
return g.V == g2.V
}
return false
}
func (g GoType) String() string {
return fmt.Sprintf("%v", g.V)
} }