make Elem interface have a method on it, implement that in seq (bleh), implement GoType
This commit is contained in:
parent
99b67fa801
commit
4188d0b84a
@ -28,9 +28,18 @@ func (kv *KV) Hash(i uint32) uint32 {
|
||||
// compared to another KV, only compares the other key as well.
|
||||
func (kv *KV) Equal(v types.Elem) bool {
|
||||
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
|
||||
@ -65,6 +74,38 @@ func (hm *HashMap) FirstRest() (types.Elem, Seq, bool) {
|
||||
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
|
||||
// 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
|
||||
|
@ -14,11 +14,16 @@ func kvints(kvs ...*KV) ([]*KV, []types.Elem) {
|
||||
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
|
||||
func TestHashMapSeq(t *T) {
|
||||
kvs, ints := kvints(
|
||||
KeyVal(1, "one"),
|
||||
KeyVal(2, "two"),
|
||||
keyValV(1, "one"),
|
||||
keyValV(2, "two"),
|
||||
)
|
||||
|
||||
// Testing creation and Seq interface methods
|
||||
@ -29,27 +34,50 @@ func TestHashMapSeq(t *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
|
||||
func TestHashMapGet(t *T) {
|
||||
kvs := []*KV{
|
||||
KeyVal(1, "one"),
|
||||
KeyVal(2, "two"),
|
||||
keyValV(1, "one"),
|
||||
keyValV(2, "two"),
|
||||
}
|
||||
|
||||
// Degenerate case
|
||||
m := NewHashMap()
|
||||
assertEmpty(m, t)
|
||||
v, ok := m.Get(1)
|
||||
v, ok := m.Get(types.GoType{1})
|
||||
assertValue(v, nil, t)
|
||||
assertValue(ok, false, t)
|
||||
|
||||
m = NewHashMap(kvs...)
|
||||
v, ok = m.Get(1)
|
||||
v, ok = m.Get(types.GoType{1})
|
||||
assertSeqContentsHashMap(m, kvs, t)
|
||||
assertValue(v, "one", t)
|
||||
assertValue(v, types.GoType{"one"}, t)
|
||||
assertValue(ok, true, t)
|
||||
|
||||
v, ok = m.Get(3)
|
||||
v, ok = m.Get(types.GoType{3})
|
||||
assertSeqContentsHashMap(m, kvs, t)
|
||||
assertValue(v, nil, t)
|
||||
assertValue(ok, false, t)
|
||||
@ -60,21 +88,21 @@ func TestHashMapSet(t *T) {
|
||||
|
||||
// Set on empty
|
||||
m := NewHashMap()
|
||||
m1, ok := m.Set(1, "one")
|
||||
m1, ok := m.Set(types.GoType{1}, types.GoType{"one"})
|
||||
assertEmpty(m, t)
|
||||
assertSeqContentsHashMap(m1, []*KV{KeyVal(1, "one")}, t)
|
||||
assertSeqContentsHashMap(m1, []*KV{keyValV(1, "one")}, t)
|
||||
assertValue(ok, true, t)
|
||||
|
||||
// Set on same key
|
||||
m2, ok := m1.Set(1, "wat")
|
||||
assertSeqContentsHashMap(m1, []*KV{KeyVal(1, "one")}, t)
|
||||
assertSeqContentsHashMap(m2, []*KV{KeyVal(1, "wat")}, t)
|
||||
m2, ok := m1.Set(types.GoType{1}, types.GoType{"wat"})
|
||||
assertSeqContentsHashMap(m1, []*KV{keyValV(1, "one")}, t)
|
||||
assertSeqContentsHashMap(m2, []*KV{keyValV(1, "wat")}, t)
|
||||
assertValue(ok, false, t)
|
||||
|
||||
// Set on second new key
|
||||
m3, ok := m2.Set(2, "two")
|
||||
assertSeqContentsHashMap(m2, []*KV{KeyVal(1, "wat")}, t)
|
||||
assertSeqContentsHashMap(m3, []*KV{KeyVal(1, "wat"), KeyVal(2, "two")}, t)
|
||||
m3, ok := m2.Set(types.GoType{2}, types.GoType{"two"})
|
||||
assertSeqContentsHashMap(m2, []*KV{keyValV(1, "wat")}, t)
|
||||
assertSeqContentsHashMap(m3, []*KV{keyValV(1, "wat"), keyValV(2, "two")}, t)
|
||||
assertValue(ok, true, t)
|
||||
|
||||
}
|
||||
@ -83,31 +111,31 @@ func TestHashMapSet(t *T) {
|
||||
func TestHashMapDel(t *T) {
|
||||
|
||||
kvs := []*KV{
|
||||
KeyVal(1, "one"),
|
||||
KeyVal(2, "two"),
|
||||
KeyVal(3, "three"),
|
||||
keyValV(1, "one"),
|
||||
keyValV(2, "two"),
|
||||
keyValV(3, "three"),
|
||||
}
|
||||
kvs1 := []*KV{
|
||||
KeyVal(2, "two"),
|
||||
KeyVal(3, "three"),
|
||||
keyValV(2, "two"),
|
||||
keyValV(3, "three"),
|
||||
}
|
||||
|
||||
// Degenerate case
|
||||
m := NewHashMap()
|
||||
m1, ok := m.Del(1)
|
||||
m1, ok := m.Del(types.GoType{1})
|
||||
assertEmpty(m, t)
|
||||
assertEmpty(m1, t)
|
||||
assertValue(ok, false, t)
|
||||
|
||||
// Delete actual key
|
||||
m = NewHashMap(kvs...)
|
||||
m1, ok = m.Del(1)
|
||||
m1, ok = m.Del(types.GoType{1})
|
||||
assertSeqContentsHashMap(m, kvs, t)
|
||||
assertSeqContentsHashMap(m1, kvs1, t)
|
||||
assertValue(ok, true, t)
|
||||
|
||||
// Delete it again!
|
||||
m2, ok := m1.Del(1)
|
||||
m2, ok := m1.Del(types.GoType{1})
|
||||
assertSeqContentsHashMap(m1, kvs1, t)
|
||||
assertSeqContentsHashMap(m2, kvs1, t)
|
||||
assertValue(ok, false, t)
|
||||
|
116
seq/hashset.go
116
seq/hashset.go
@ -30,63 +30,41 @@ func hash(v types.Elem, i uint32) uint32 {
|
||||
case Setable:
|
||||
return vt.Hash(i) % ARITY
|
||||
|
||||
case uint:
|
||||
return uint32(vt) % ARITY
|
||||
case uint8:
|
||||
return uint32(vt) % ARITY
|
||||
case uint32:
|
||||
return uint32(vt) % ARITY
|
||||
case uint64:
|
||||
return uint32(vt) % ARITY
|
||||
case int:
|
||||
return uint32(vt) % ARITY
|
||||
case int8:
|
||||
return uint32(vt) % ARITY
|
||||
case int16:
|
||||
return uint32(vt) % ARITY
|
||||
case int32:
|
||||
return uint32(vt) % ARITY
|
||||
case int64:
|
||||
return uint32(vt) % ARITY
|
||||
case float32:
|
||||
return uint32(vt) % ARITY
|
||||
case float64:
|
||||
return uint32(vt) % ARITY
|
||||
case types.GoType:
|
||||
switch gvt := vt.V.(type) {
|
||||
case uint:
|
||||
return uint32(gvt) % ARITY
|
||||
case uint8:
|
||||
return uint32(gvt) % ARITY
|
||||
case uint32:
|
||||
return uint32(gvt) % ARITY
|
||||
case uint64:
|
||||
return uint32(gvt) % ARITY
|
||||
case int:
|
||||
return uint32(gvt) % ARITY
|
||||
case int8:
|
||||
return uint32(gvt) % ARITY
|
||||
case int16:
|
||||
return uint32(gvt) % ARITY
|
||||
case int32:
|
||||
return uint32(gvt) % ARITY
|
||||
case int64:
|
||||
return uint32(gvt) % ARITY
|
||||
case float32:
|
||||
return uint32(gvt) % ARITY
|
||||
case float64:
|
||||
return uint32(gvt) % ARITY
|
||||
|
||||
case string:
|
||||
return crc32.ChecksumIEEE([]byte(vt)) % ARITY
|
||||
case string:
|
||||
return crc32.ChecksumIEEE([]byte(gvt)) % ARITY
|
||||
|
||||
case []byte:
|
||||
return crc32.ChecksumIEEE(vt) % ARITY
|
||||
|
||||
default:
|
||||
err := fmt.Sprintf("%s not hashable", reflect.TypeOf(v))
|
||||
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
|
||||
case []byte:
|
||||
return crc32.ChecksumIEEE(gvt) % ARITY
|
||||
}
|
||||
return false
|
||||
} else {
|
||||
return v1 == v2
|
||||
}
|
||||
|
||||
err := fmt.Sprintf("%s not hashable", reflect.TypeOf(v))
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// The number of children each node in Set (implemented as a hash tree) can have
|
||||
@ -142,7 +120,7 @@ func (set *Set) shallowTrySetOrInit(val types.Elem) (bool, bool) {
|
||||
set.val = val
|
||||
set.full = true
|
||||
return true, false
|
||||
} else if equal(set.val, val) {
|
||||
} else if set.val.Equal(val) {
|
||||
set.val = val
|
||||
set.full = 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) {
|
||||
if set == nil {
|
||||
return nil, false
|
||||
} else if set.full && equal(val, set.val) {
|
||||
} else if set.full && set.val.Equal(val) {
|
||||
cset := set.clone()
|
||||
cset.val = nil
|
||||
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) {
|
||||
if set == nil {
|
||||
return nil, false
|
||||
} else if set.full && equal(val, set.val) {
|
||||
} else if set.full && set.val.Equal(val) {
|
||||
return set.val, true
|
||||
} else if set.kids == nil {
|
||||
return nil, false
|
||||
@ -301,6 +279,32 @@ func (set *Set) FirstRest() (types.Elem, Seq, bool) {
|
||||
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
|
||||
func (set *Set) String() string {
|
||||
return ToString(set, "#{", "}#")
|
||||
|
@ -6,9 +6,14 @@ import (
|
||||
"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
|
||||
func TestSetSeq(t *T) {
|
||||
ints := []types.Elem{1, "a", 5.0}
|
||||
ints := elemSliceV(nil, 1, "a", 5.0)
|
||||
|
||||
// Testing creation and Seq interface methods
|
||||
s := NewSet(ints...)
|
||||
@ -22,25 +27,48 @@ func TestSetSeq(t *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
|
||||
func TestSetVal(t *T) {
|
||||
ints := []types.Elem{0, 1, 2, 3, 4}
|
||||
ints1 := []types.Elem{0, 1, 2, 3, 4, 5}
|
||||
ints := elemSliceV(0, 1, 2, 3, 4)
|
||||
ints1 := elemSliceV(0, 1, 2, 3, 4, 5)
|
||||
|
||||
// Degenerate case
|
||||
s := NewSet()
|
||||
assertEmpty(s, t)
|
||||
s, ok := s.SetVal(0)
|
||||
assertSeqContentsSet(s, []types.Elem{0}, t)
|
||||
s, ok := s.SetVal(types.GoType{0})
|
||||
assertSeqContentsSet(s, elemSliceV(0), t)
|
||||
assertValue(ok, true, t)
|
||||
|
||||
s = NewSet(ints...)
|
||||
s1, ok := s.SetVal(5)
|
||||
s1, ok := s.SetVal(types.GoType{5})
|
||||
assertSeqContentsSet(s, ints, t)
|
||||
assertSeqContentsSet(s1, ints1, t)
|
||||
assertValue(ok, true, t)
|
||||
|
||||
s2, ok := s1.SetVal(5)
|
||||
s2, ok := s1.SetVal(types.GoType{5})
|
||||
assertSeqContentsSet(s1, ints1, t)
|
||||
assertSeqContentsSet(s2, ints1, t)
|
||||
assertValue(ok, false, t)
|
||||
@ -48,41 +76,41 @@ func TestSetVal(t *T) {
|
||||
|
||||
// Test deleting a value from a Set
|
||||
func TestDelVal(t *T) {
|
||||
ints := []types.Elem{0, 1, 2, 3, 4}
|
||||
ints1 := []types.Elem{0, 1, 2, 3}
|
||||
ints2 := []types.Elem{1, 2, 3, 4}
|
||||
ints3 := []types.Elem{1, 2, 3, 4, 5}
|
||||
ints := elemSliceV(0, 1, 2, 3, 4)
|
||||
ints1 := elemSliceV(0, 1, 2, 3)
|
||||
ints2 := elemSliceV(1, 2, 3, 4)
|
||||
ints3 := elemSliceV(1, 2, 3, 4, 5)
|
||||
|
||||
// Degenerate case
|
||||
s := NewSet()
|
||||
assertEmpty(s, t)
|
||||
s, ok := s.DelVal(0)
|
||||
s, ok := s.DelVal(types.GoType{0})
|
||||
assertEmpty(s, t)
|
||||
assertValue(ok, false, t)
|
||||
|
||||
s = NewSet(ints...)
|
||||
s1, ok := s.DelVal(4)
|
||||
s1, ok := s.DelVal(types.GoType{4})
|
||||
assertSeqContentsSet(s, ints, t)
|
||||
assertSeqContentsSet(s1, ints1, t)
|
||||
assertValue(ok, true, t)
|
||||
|
||||
s1, ok = s1.DelVal(4)
|
||||
s1, ok = s1.DelVal(types.GoType{4})
|
||||
assertSeqContentsSet(s1, ints1, t)
|
||||
assertValue(ok, false, t)
|
||||
|
||||
// 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
|
||||
// the root node).
|
||||
s2, ok := s.DelVal(0)
|
||||
s2, ok := s.DelVal(types.GoType{0})
|
||||
assertSeqContentsSet(s, ints, t)
|
||||
assertSeqContentsSet(s2, ints2, t)
|
||||
assertValue(ok, true, t)
|
||||
|
||||
s2, ok = s2.DelVal(0)
|
||||
s2, ok = s2.DelVal(types.GoType{0})
|
||||
assertSeqContentsSet(s2, ints2, t)
|
||||
assertValue(ok, false, t)
|
||||
|
||||
s3, ok := s2.SetVal(5)
|
||||
s3, ok := s2.SetVal(types.GoType{5})
|
||||
assertSeqContentsSet(s2, ints2, t)
|
||||
assertSeqContentsSet(s3, ints3, t)
|
||||
assertValue(ok, true, t)
|
||||
@ -92,36 +120,36 @@ func TestDelVal(t *T) {
|
||||
func GetVal(t *T) {
|
||||
//Degenerate case
|
||||
s := NewSet()
|
||||
v, ok := s.GetVal(1)
|
||||
v, ok := s.GetVal(types.GoType{1})
|
||||
assertValue(v, nil, t)
|
||||
assertValue(ok, false, t)
|
||||
|
||||
s = NewSet(0, 1, 2, 3, 4)
|
||||
v, ok = s.GetVal(1)
|
||||
s = NewSet(elemSliceV(0, 1, 2, 3, 4)...)
|
||||
v, ok = s.GetVal(types.GoType{1})
|
||||
assertValue(v, 1, t)
|
||||
assertValue(ok, true, t)
|
||||
|
||||
// After delete
|
||||
s, _ = s.DelVal(1)
|
||||
v, ok = s.GetVal(1)
|
||||
s, _ = s.DelVal(types.GoType{1})
|
||||
v, ok = s.GetVal(types.GoType{1})
|
||||
assertValue(v, nil, t)
|
||||
assertValue(ok, false, t)
|
||||
|
||||
// After set
|
||||
s, _ = s.SetVal(1)
|
||||
v, ok = s.GetVal(1)
|
||||
s, _ = s.SetVal(types.GoType{1})
|
||||
v, ok = s.GetVal(types.GoType{1})
|
||||
assertValue(v, 1, t)
|
||||
assertValue(ok, true, t)
|
||||
|
||||
// After delete root node
|
||||
s, _ = s.DelVal(0)
|
||||
v, ok = s.GetVal(0)
|
||||
s, _ = s.DelVal(types.GoType{0})
|
||||
v, ok = s.GetVal(types.GoType{0})
|
||||
assertValue(v, nil, t)
|
||||
assertValue(ok, false, t)
|
||||
|
||||
// After set root node
|
||||
s, _ = s.SetVal(5)
|
||||
v, ok = s.GetVal(5)
|
||||
s, _ = s.SetVal(types.GoType{5})
|
||||
v, ok = s.GetVal(types.GoType{5})
|
||||
assertValue(v, 5, t)
|
||||
assertValue(ok, true, t)
|
||||
}
|
||||
@ -133,25 +161,25 @@ func TestSetSize(t *T) {
|
||||
assertValue(s.Size(), uint64(0), t)
|
||||
|
||||
// Initialization case
|
||||
s = NewSet(0, 1, 2)
|
||||
s = NewSet(elemSliceV(0, 1, 2)...)
|
||||
assertValue(s.Size(), uint64(3), t)
|
||||
|
||||
// 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)
|
||||
s, _ = s.SetVal(3)
|
||||
s, _ = s.SetVal(types.GoType{3})
|
||||
assertValue(s.Size(), uint64(4), t)
|
||||
|
||||
// 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)
|
||||
s, _ = s.DelVal(3)
|
||||
s, _ = s.DelVal(types.GoType{3})
|
||||
assertValue(s.Size(), uint64(3), t)
|
||||
|
||||
// Deleting and setting the root node
|
||||
s, _ = s.DelVal(0)
|
||||
s, _ = s.DelVal(types.GoType{0})
|
||||
assertValue(s.Size(), uint64(2), t)
|
||||
s, _ = s.SetVal(5)
|
||||
s, _ = s.SetVal(types.GoType{5})
|
||||
assertValue(s.Size(), uint64(3), t)
|
||||
|
||||
}
|
||||
@ -162,8 +190,8 @@ func TestUnion(t *T) {
|
||||
empty := NewSet()
|
||||
assertEmpty(empty.Union(empty), t)
|
||||
|
||||
ints1 := []types.Elem{0, 1, 2}
|
||||
ints2 := []types.Elem{3, 4, 5}
|
||||
ints1 := elemSliceV(0, 1, 2)
|
||||
ints2 := elemSliceV(3, 4, 5)
|
||||
intsu := append(ints1, ints2...)
|
||||
s1 := NewSet(ints1...)
|
||||
s2 := NewSet(ints2...)
|
||||
@ -183,10 +211,10 @@ func TestIntersection(t *T) {
|
||||
empty := NewSet()
|
||||
assertEmpty(empty.Intersection(empty), t)
|
||||
|
||||
ints1 := []types.Elem{0, 1, 2}
|
||||
ints2 := []types.Elem{1, 2, 3}
|
||||
ints3 := []types.Elem{4, 5, 6}
|
||||
intsi := []types.Elem{1, 2}
|
||||
ints1 := elemSliceV(0, 1, 2)
|
||||
ints2 := elemSliceV(1, 2, 3)
|
||||
ints3 := elemSliceV(4, 5, 6)
|
||||
intsi := elemSliceV(1, 2)
|
||||
s1 := NewSet(ints1...)
|
||||
s2 := NewSet(ints2...)
|
||||
s3 := NewSet(ints3...)
|
||||
@ -208,9 +236,9 @@ func TestDifference(t *T) {
|
||||
empty := NewSet()
|
||||
assertEmpty(empty.Difference(empty), t)
|
||||
|
||||
ints1 := []types.Elem{0, 1, 2, 3}
|
||||
ints2 := []types.Elem{2, 3, 4}
|
||||
intsd := []types.Elem{0, 1}
|
||||
ints1 := elemSliceV(0, 1, 2, 3)
|
||||
ints2 := elemSliceV(2, 3, 4)
|
||||
intsd := elemSliceV(0, 1)
|
||||
s1 := NewSet(ints1...)
|
||||
s2 := NewSet(ints2...)
|
||||
|
||||
@ -229,9 +257,9 @@ func TestSymDifference(t *T) {
|
||||
empty := NewSet()
|
||||
assertEmpty(empty.SymDifference(empty), t)
|
||||
|
||||
ints1 := []types.Elem{0, 1, 2, 3}
|
||||
ints2 := []types.Elem{2, 3, 4}
|
||||
intsd := []types.Elem{0, 1, 4}
|
||||
ints1 := elemSliceV(0, 1, 2, 3)
|
||||
ints2 := elemSliceV(2, 3, 4)
|
||||
intsd := elemSliceV(0, 1, 4)
|
||||
s1 := NewSet(ints1...)
|
||||
s2 := NewSet(ints2...)
|
||||
|
||||
|
14
seq/lazy.go
14
seq/lazy.go
@ -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
|
||||
func (l *Lazy) String() string {
|
||||
return ToString(l, "<<", ">>")
|
||||
|
@ -7,19 +7,26 @@ import (
|
||||
"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
|
||||
func TestLazyBasic(t *T) {
|
||||
ch := make(chan int)
|
||||
ch := make(chan types.GoType)
|
||||
mapfn := func(el types.Elem) types.Elem {
|
||||
i := el.(int)
|
||||
i := el.(types.GoType)
|
||||
ch <- i
|
||||
return i
|
||||
}
|
||||
|
||||
intl := []types.Elem{0, 1, 2, 3, 4}
|
||||
intl := elemSliceV(0, 1, 2, 3, 4)
|
||||
l := NewList(intl...)
|
||||
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++ {
|
||||
go func() {
|
||||
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 {
|
||||
select {
|
||||
case elch := <-ch:
|
||||
@ -42,7 +51,7 @@ func TestLazyBasic(t *T) {
|
||||
|
||||
// Test that arbitrary Seqs can turn into Lazy
|
||||
func TestToLazy(t *T) {
|
||||
intl := []types.Elem{0, 1, 2, 3, 4}
|
||||
intl := elemSliceV(0, 1, 2, 3, 4)
|
||||
l := NewList(intl...)
|
||||
ll := ToLazy(l)
|
||||
assertSeqContents(ll, intl, t)
|
||||
|
30
seq/list.go
30
seq/list.go
@ -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.
|
||||
func (l *List) String() string {
|
||||
return ToString(l, "(", ")")
|
||||
|
@ -6,6 +6,11 @@ import (
|
||||
"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
|
||||
// filled in correctly
|
||||
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
|
||||
func TestListSeq(t *T) {
|
||||
ints := []types.Elem{1, "a", 5.0}
|
||||
ints := elemSliceV(1, "a", 5.0)
|
||||
|
||||
// Testing creation and Seq interface methods
|
||||
l := NewList(ints...)
|
||||
@ -40,39 +45,62 @@ func TestListSeq(t *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
|
||||
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)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// Test prepending an element to the beginning of a list
|
||||
func TestPrepend(t *T) {
|
||||
// Normal case
|
||||
intl := []types.Elem{3, 2, 1, 0}
|
||||
intl := elemSliceV(3, 2, 1, 0)
|
||||
l := NewList(intl...)
|
||||
nl := l.Prepend(4)
|
||||
nl := l.Prepend(types.GoType{4})
|
||||
assertSaneList(l, t)
|
||||
assertSaneList(nl, 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
|
||||
l = NewList()
|
||||
nl = l.Prepend(0)
|
||||
nl = l.Prepend(types.GoType{0})
|
||||
assertEmpty(l, 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
|
||||
func TestPrependSeq(t *T) {
|
||||
//Normal case
|
||||
intl1 := []types.Elem{3, 4}
|
||||
intl2 := []types.Elem{0, 1, 2}
|
||||
intl1 := elemSliceV(3, 4)
|
||||
intl2 := elemSliceV(0, 1, 2)
|
||||
l1 := NewList(intl1...)
|
||||
l2 := NewList(intl2...)
|
||||
nl := l1.PrependSeq(l2)
|
||||
@ -81,7 +109,7 @@ func TestPrependSeq(t *T) {
|
||||
assertSaneList(nl, t)
|
||||
assertSeqContents(l1, intl1, 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
|
||||
blank1 := NewList()
|
||||
@ -105,34 +133,34 @@ func TestPrependSeq(t *T) {
|
||||
// Test appending to the end of a List
|
||||
func TestAppend(t *T) {
|
||||
// Normal case
|
||||
intl := []types.Elem{3, 2, 1}
|
||||
intl := elemSliceV(3, 2, 1)
|
||||
l := NewList(intl...)
|
||||
nl := l.Append(0)
|
||||
nl := l.Append(types.GoType{0})
|
||||
assertSaneList(l, t)
|
||||
assertSaneList(nl, 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)
|
||||
l = NewList(1)
|
||||
nl = l.Append(0)
|
||||
l = NewList(elemSliceV(1)...)
|
||||
nl = l.Append(types.GoType{0})
|
||||
assertSaneList(l, t)
|
||||
assertSaneList(nl, t)
|
||||
assertSeqContents(l, []types.Elem{1}, t)
|
||||
assertSeqContents(nl, []types.Elem{1, 0}, t)
|
||||
assertSeqContents(l, elemSliceV(1), t)
|
||||
assertSeqContents(nl, elemSliceV(1, 0), t)
|
||||
|
||||
// Degenerate case
|
||||
l = NewList()
|
||||
nl = l.Append(0)
|
||||
nl = l.Append(types.GoType{0})
|
||||
assertEmpty(l, t)
|
||||
assertSaneList(nl, t)
|
||||
assertSeqContents(nl, []types.Elem{0}, t)
|
||||
assertSeqContents(nl, elemSliceV(0), t)
|
||||
}
|
||||
|
||||
// Test retrieving items from a List
|
||||
func TestNth(t *T) {
|
||||
// Normal case, in bounds
|
||||
intl := []types.Elem{0, 2, 4, 6, 8}
|
||||
intl := elemSliceV(0, 2, 4, 6, 8)
|
||||
l := NewList(intl...)
|
||||
r, ok := l.Nth(3)
|
||||
assertSaneList(l, t)
|
||||
|
@ -50,11 +50,11 @@ func testSeqNoOrderGen(t *T, s Seq, ints []types.Elem) Seq {
|
||||
// Test reversing a Seq
|
||||
func TestReverse(t *T) {
|
||||
// Normal case
|
||||
intl := []types.Elem{3, 2, 1}
|
||||
intl := elemSliceV(3, 2, 1)
|
||||
l := NewList(intl...)
|
||||
nl := Reverse(l)
|
||||
assertSeqContents(l, intl, t)
|
||||
assertSeqContents(nl, []types.Elem{1, 2, 3}, t)
|
||||
assertSeqContents(nl, elemSliceV(1, 2, 3), t)
|
||||
|
||||
// Degenerate case
|
||||
l = NewList()
|
||||
@ -65,15 +65,15 @@ func TestReverse(t *T) {
|
||||
|
||||
func testMapGen(t *T, mapFn func(func(types.Elem) types.Elem, Seq) Seq) {
|
||||
fn := func(n types.Elem) types.Elem {
|
||||
return n.(int) + 1
|
||||
return types.GoType{n.(types.GoType).V.(int) + 1}
|
||||
}
|
||||
|
||||
// Normal case
|
||||
intl := []types.Elem{1, 2, 3}
|
||||
intl := elemSliceV(1, 2, 3)
|
||||
l := NewList(intl...)
|
||||
nl := mapFn(fn, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
assertSeqContents(nl, []types.Elem{2, 3, 4}, t)
|
||||
assertSeqContents(nl, elemSliceV(2, 3, 4), t)
|
||||
|
||||
// Degenerate case
|
||||
l = NewList()
|
||||
@ -95,27 +95,31 @@ func TestLMap(t *T) {
|
||||
// Test reducing over a Seq
|
||||
func TestReduce(t *T) {
|
||||
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
|
||||
intl := []types.Elem{1, 2, 3, 4}
|
||||
intl := elemSliceV(1, 2, 3, 4)
|
||||
l := NewList(intl...)
|
||||
r := Reduce(fn, 0, l)
|
||||
r := Reduce(fn, types.GoType{0}, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
assertValue(r, 10, t)
|
||||
|
||||
// Short-circuit case
|
||||
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)
|
||||
assertValue(r, 6, t)
|
||||
|
||||
// Degenerate case
|
||||
l = NewList()
|
||||
r = Reduce(fn, 0, l)
|
||||
r = Reduce(fn, types.GoType{0}, l)
|
||||
assertEmpty(l, t)
|
||||
assertValue(r, 0, t)
|
||||
}
|
||||
@ -123,11 +127,11 @@ func TestReduce(t *T) {
|
||||
// Test the Any function
|
||||
func TestAny(t *T) {
|
||||
fn := func(el types.Elem) bool {
|
||||
return el.(int) > 3
|
||||
return el.(types.GoType).V.(int) > 3
|
||||
}
|
||||
|
||||
// Value found case
|
||||
intl := []types.Elem{1, 2, 3, 4}
|
||||
intl := elemSliceV(1, 2, 3, 4)
|
||||
l := NewList(intl...)
|
||||
r, ok := Any(fn, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
@ -135,7 +139,7 @@ func TestAny(t *T) {
|
||||
assertValue(ok, true, t)
|
||||
|
||||
// Value not found case
|
||||
intl = []types.Elem{1, 2, 3}
|
||||
intl = elemSliceV(1, 2, 3)
|
||||
l = NewList(intl...)
|
||||
r, ok = Any(fn, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
@ -153,18 +157,18 @@ func TestAny(t *T) {
|
||||
// Test the All function
|
||||
func TestAll(t *T) {
|
||||
fn := func(el types.Elem) bool {
|
||||
return el.(int) > 3
|
||||
return el.(types.GoType).V.(int) > 3
|
||||
}
|
||||
|
||||
// All match case
|
||||
intl := []types.Elem{4, 5, 6}
|
||||
intl := elemSliceV(4, 5, 6)
|
||||
l := NewList(intl...)
|
||||
ok := All(fn, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
assertValue(ok, true, t)
|
||||
|
||||
// Not all match case
|
||||
intl = []types.Elem{3, 4, 2, 5}
|
||||
intl = elemSliceV(3, 4, 2, 5)
|
||||
l = NewList(intl...)
|
||||
ok = All(fn, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
@ -179,15 +183,15 @@ func TestAll(t *T) {
|
||||
|
||||
func testFilterGen(t *T, filterFn func(func(types.Elem) bool, Seq) Seq) {
|
||||
fn := func(el types.Elem) bool {
|
||||
return el.(int)%2 != 0
|
||||
return el.(types.GoType).V.(int)%2 != 0
|
||||
}
|
||||
|
||||
// Normal case
|
||||
intl := []types.Elem{1, 2, 3, 4, 5}
|
||||
intl := elemSliceV(1, 2, 3, 4, 5)
|
||||
l := NewList(intl...)
|
||||
r := filterFn(fn, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
assertSeqContents(r, []types.Elem{1, 3, 5}, t)
|
||||
assertSeqContents(r, elemSliceV(1, 3, 5), t)
|
||||
|
||||
// Degenerate cases
|
||||
l = NewList()
|
||||
@ -209,19 +213,19 @@ func TestLFilter(t *T) {
|
||||
// Test Flatten-ing of a Seq
|
||||
func TestFlatten(t *T) {
|
||||
// Normal case
|
||||
intl1 := []types.Elem{0, 1, 2}
|
||||
intl2 := []types.Elem{3, 4, 5}
|
||||
intl1 := elemSliceV(0, 1, 2)
|
||||
intl2 := elemSliceV(3, 4, 5)
|
||||
l1 := NewList(intl1...)
|
||||
l2 := NewList(intl2...)
|
||||
blank := NewList()
|
||||
intl := []types.Elem{-1, l1, l2, 6, blank, 7}
|
||||
intl := elemSliceV(-1, l1, l2, 6, blank, 7)
|
||||
l := NewList(intl...)
|
||||
nl := Flatten(l)
|
||||
assertSeqContents(l1, intl1, t)
|
||||
assertSeqContents(l2, intl2, t)
|
||||
assertEmpty(blank, 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
|
||||
nl = Flatten(blank)
|
||||
@ -231,11 +235,11 @@ func TestFlatten(t *T) {
|
||||
|
||||
func testTakeGen(t *T, takeFn func(uint64, Seq) Seq) {
|
||||
// Normal case
|
||||
intl := []types.Elem{0, 1, 2, 3, 4}
|
||||
intl := elemSliceV(0, 1, 2, 3, 4)
|
||||
l := NewList(intl...)
|
||||
nl := takeFn(3, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
assertSeqContents(nl, []types.Elem{0, 1, 2}, t)
|
||||
assertSeqContents(nl, elemSliceV(0, 1, 2), t)
|
||||
|
||||
// Edge cases
|
||||
nl = takeFn(5, l)
|
||||
@ -269,28 +273,28 @@ func TestLTake(t *T) {
|
||||
|
||||
func testTakeWhileGen(t *T, takeWhileFn func(func(types.Elem) bool, Seq) Seq) {
|
||||
pred := func(el types.Elem) bool {
|
||||
return el.(int) < 3
|
||||
return el.(types.GoType).V.(int) < 3
|
||||
}
|
||||
|
||||
// Normal case
|
||||
intl := []types.Elem{0, 1, 2, 3, 4, 5}
|
||||
intl := elemSliceV(0, 1, 2, 3, 4, 5)
|
||||
l := NewList(intl...)
|
||||
nl := takeWhileFn(pred, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
assertSeqContents(nl, []types.Elem{0, 1, 2}, t)
|
||||
assertSeqContents(nl, elemSliceV(0, 1, 2), t)
|
||||
|
||||
// Edge cases
|
||||
intl = []types.Elem{5, 5, 5}
|
||||
intl = elemSliceV(5, 5, 5)
|
||||
l = NewList(intl...)
|
||||
nl = takeWhileFn(pred, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
assertEmpty(nl, t)
|
||||
|
||||
intl = []types.Elem{0, 1, 2}
|
||||
intl = elemSliceV(0, 1, 2)
|
||||
l = NewList(intl...)
|
||||
nl = takeWhileFn(pred, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
assertSeqContents(nl, []types.Elem{0, 1, 2}, t)
|
||||
assertSeqContents(nl, elemSliceV(0, 1, 2), t)
|
||||
|
||||
// Degenerate case
|
||||
l = NewList()
|
||||
@ -312,11 +316,11 @@ func TestLTakeWhile(t *T) {
|
||||
// Test dropping from a Seq
|
||||
func TestDrop(t *T) {
|
||||
// Normal case
|
||||
intl := []types.Elem{0, 1, 2, 3, 4}
|
||||
intl := elemSliceV(0, 1, 2, 3, 4)
|
||||
l := NewList(intl...)
|
||||
nl := Drop(3, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
assertSeqContents(nl, []types.Elem{3, 4}, t)
|
||||
assertSeqContents(nl, elemSliceV(3, 4), t)
|
||||
|
||||
// Edge cases
|
||||
nl = Drop(5, l)
|
||||
@ -341,24 +345,24 @@ func TestDrop(t *T) {
|
||||
// Test dropping from a Seq until a given condition
|
||||
func TestDropWhile(t *T) {
|
||||
pred := func(el types.Elem) bool {
|
||||
return el.(int) < 3
|
||||
return el.(types.GoType).V.(int) < 3
|
||||
}
|
||||
|
||||
// Normal case
|
||||
intl := []types.Elem{0, 1, 2, 3, 4, 5}
|
||||
intl := elemSliceV(0, 1, 2, 3, 4, 5)
|
||||
l := NewList(intl...)
|
||||
nl := DropWhile(pred, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
assertSeqContents(nl, []types.Elem{3, 4, 5}, t)
|
||||
assertSeqContents(nl, elemSliceV(3, 4, 5), t)
|
||||
|
||||
// Edge cases
|
||||
intl = []types.Elem{5, 5, 5}
|
||||
intl = elemSliceV(5, 5, 5)
|
||||
l = NewList(intl...)
|
||||
nl = DropWhile(pred, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
assertSeqContents(nl, intl, t)
|
||||
|
||||
intl = []types.Elem{0, 1, 2}
|
||||
intl = elemSliceV(0, 1, 2)
|
||||
l = NewList(intl...)
|
||||
nl = DropWhile(pred, l)
|
||||
assertSeqContents(l, intl, t)
|
||||
|
29
seq/util.go
29
seq/util.go
@ -19,6 +19,18 @@ func intSlicesEq(a, b []types.Elem) bool {
|
||||
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)
|
||||
func assertEmpty(s Seq, t *testing.T) {
|
||||
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) {
|
||||
m := map[types.Elem]bool{}
|
||||
m := map[KV]bool{}
|
||||
for i := range kvs {
|
||||
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
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
func keyValV(k, v interface{}) *KV {
|
||||
return KeyVal(types.GoType{k}, types.GoType{v})
|
||||
}
|
||||
|
@ -1,11 +1,38 @@
|
||||
// This package describes ginger's base types and the interfaces covered by them
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Elem is a generic type which can be used as a wrapper type for all ginger
|
||||
// types, both base types and data structures
|
||||
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
|
||||
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)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user