167 lines
4.1 KiB
Go
167 lines
4.1 KiB
Go
package seq
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/mediocregopher/ginger/types"
|
|
)
|
|
|
|
// Hash maps are built on top of hash sets. KeyVal implements Setable, but the
|
|
// Hash and Equal methods only apply to the key and ignore the value.
|
|
|
|
// Container for a key/value pair, used by HashMap to hold its data
|
|
type KV struct {
|
|
Key types.Elem
|
|
Val types.Elem
|
|
}
|
|
|
|
func KeyVal(key, val types.Elem) *KV {
|
|
return &KV{key, val}
|
|
}
|
|
|
|
// Implementation of Hash for Setable. Only actually hashes the Key field
|
|
func (kv *KV) Hash(i uint32) uint32 {
|
|
return hash(kv.Key, i)
|
|
}
|
|
|
|
// Implementation of Equal for Setable. Only actually compares the key field. If
|
|
// 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 kv.Key.Equal(kv2.Key)
|
|
}
|
|
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
|
|
func (kv *KV) String() string {
|
|
return fmt.Sprintf("%v -> %v", kv.Key, kv.Val)
|
|
}
|
|
|
|
// HashMaps are actually built on top of Sets, just with some added convenience
|
|
// methods for interacting with them as actual key/val stores
|
|
type HashMap struct {
|
|
set *Set
|
|
}
|
|
|
|
// Returns a new HashMap of the given KVs (or possibly just an empty HashMap)
|
|
func NewHashMap(kvs ...*KV) *HashMap {
|
|
ints := make([]types.Elem, len(kvs))
|
|
for i := range kvs {
|
|
ints[i] = kvs[i]
|
|
}
|
|
return &HashMap{
|
|
set: NewSet(ints...),
|
|
}
|
|
}
|
|
|
|
// Implementation of FirstRest for Seq interface. First return value will
|
|
// always be a *KV or nil. Completes in O(log(N)) time.
|
|
func (hm *HashMap) FirstRest() (types.Elem, Seq, bool) {
|
|
if hm == nil {
|
|
return nil, nil, false
|
|
}
|
|
el, nset, ok := hm.set.FirstRest()
|
|
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
|
|
// method.
|
|
func (hm *HashMap) Set(key, val types.Elem) (*HashMap, bool) {
|
|
if hm == nil {
|
|
hm = NewHashMap()
|
|
}
|
|
|
|
nset, ok := hm.set.SetVal(KeyVal(key, val))
|
|
return &HashMap{nset}, ok
|
|
}
|
|
|
|
// Returns a new HashMap with the given key removed from it. Also returns
|
|
// whether or not the key was already there (true if so, false if not). Has the
|
|
// same time complexity as Set's DelVal method.
|
|
func (hm *HashMap) Del(key types.Elem) (*HashMap, bool) {
|
|
if hm == nil {
|
|
hm = NewHashMap()
|
|
}
|
|
|
|
nset, ok := hm.set.DelVal(KeyVal(key, nil))
|
|
return &HashMap{nset}, ok
|
|
}
|
|
|
|
// Returns a value for a given key from the HashMap, along with a boolean
|
|
// indicating whether or not the value was found. Has the same time complexity
|
|
// as Set's GetVal method.
|
|
func (hm *HashMap) Get(key types.Elem) (types.Elem, bool) {
|
|
if hm == nil {
|
|
return nil, false
|
|
} else if kv, ok := hm.set.GetVal(KeyVal(key, nil)); ok {
|
|
return kv.(*KV).Val, true
|
|
} else {
|
|
return nil, false
|
|
}
|
|
}
|
|
|
|
// Same as FirstRest, but returns values already casted, which may be convenient
|
|
// in some cases.
|
|
func (hm *HashMap) FirstRestKV() (*KV, *HashMap, bool) {
|
|
if el, nhm, ok := hm.FirstRest(); ok {
|
|
return el.(*KV), nhm.(*HashMap), true
|
|
} else {
|
|
return nil, nil, false
|
|
}
|
|
}
|
|
|
|
// Implementation of String for Stringer interface
|
|
func (hm *HashMap) String() string {
|
|
return ToString(hm, "{", "}")
|
|
}
|
|
|
|
// Returns the number of KVs in the HashMap. Has the same complexity as Set's
|
|
// Size method.
|
|
func (hm *HashMap) Size() uint64 {
|
|
return hm.set.Size()
|
|
}
|