Franck Pommereau

set implementation use less memory

......@@ -33,13 +33,13 @@ func Hash (value interface{}) uint64 {
// compare any values
//
type equatable interface {
type Equatable interface {
Eq (interface{}) bool
}
func Eq (a, b interface{}) bool {
i, ok := a.(equatable)
i, ok := a.(Equatable)
if ok {
return i.Eq(b)
}
......@@ -50,7 +50,7 @@ func Eq (a, b interface{}) bool {
// dict type
//
type Item struct {
type DictItem struct {
Key *interface{}
Value *interface{}
hash uint64
......@@ -58,7 +58,7 @@ type Item struct {
type Dict struct {
indices map[uint64]int64
itemlist []Item
itemlist []DictItem
used uint64
filled uint64
keyhash uint64
......@@ -66,7 +66,7 @@ type Dict struct {
func (self *Dict) Clear () {
self.indices = make(map[uint64]int64)
self.itemlist = make([]Item, 0)
self.itemlist = make([]DictItem, 0)
self.used = 0
self.filled = 0
self.keyhash = 0
......@@ -80,14 +80,14 @@ func (self Dict) Copy (copiers ...copyfunc) Dict {
for k, v := range self.indices {
d.indices[k] = v
}
d.itemlist = make([]Item, len(self.itemlist))
d.itemlist = make([]DictItem, len(self.itemlist))
if len(copiers) == 0 {
copy(d.itemlist, self.itemlist)
} else if len(copiers) == 1 {
cpk := copiers[0]
for index, item := range self.itemlist {
k := cpk(*(item.Key))
d.itemlist[index] = Item{&k, item.Value, item.hash}
d.itemlist[index] = DictItem{&k, item.Value, item.hash}
}
} else if len(copiers) == 2 {
cpk := copiers[0]
......@@ -95,7 +95,7 @@ func (self Dict) Copy (copiers ...copyfunc) Dict {
for index, item := range self.itemlist {
k := cpk(*(item.Key))
v := cpv(*(item.Value))
d.itemlist[index] = Item{&k, &v, item.hash}
d.itemlist[index] = DictItem{&k, &v, item.hash}
}
} else {
panic("at most two copiers are allowed")
......@@ -106,7 +106,7 @@ func (self Dict) Copy (copiers ...copyfunc) Dict {
return d
}
func MakeDict (items ...Item) Dict {
func MakeDict (items ...DictItem) Dict {
d := Dict{}
d.Clear()
for _, i := range items {
......@@ -173,7 +173,7 @@ func (self Dict) Get (key interface{}) *interface{} {
return self.itemlist[index].Value
}
func (self Dict) GetItem (key interface{}) *Item {
func (self Dict) GetItem (key interface{}) *DictItem {
index, _ := self.lookup(key, Hash(key))
if index < 0 {
return nil
......@@ -195,14 +195,14 @@ func (self *Dict) Set (key interface{}, value interface{}) {
index, i := self.lookup(key, hashvalue)
if index < 0 {
self.indices[i] = int64(self.used)
self.itemlist = append(self.itemlist, Item{&key, &value, hashvalue})
self.itemlist = append(self.itemlist, DictItem{&key, &value, hashvalue})
self.used++
if index == _FREE {
self.filled++
}
self.keyhash += hashvalue
} else {
self.itemlist[index] = Item{&key, &value, hashvalue}
self.itemlist[index] = DictItem{&key, &value, hashvalue}
}
}
......@@ -232,7 +232,7 @@ type DictIterator struct {
d *Dict
}
func (self *DictIterator) Next () *Item {
func (self *DictIterator) Next () *DictItem {
self.i++
if self.i >= self.d.used {
return nil
......@@ -241,7 +241,7 @@ func (self *DictIterator) Next () *Item {
}
}
func (self Dict) Iter () (DictIterator, *Item) {
func (self Dict) Iter () (DictIterator, *DictItem) {
it := DictIterator{0, &self}
if self.used == 0 {
return it, nil
......@@ -255,7 +255,7 @@ func (self Dict) Has (key interface{}) bool {
return index >= 0
}
func (self *Dict) Pop () Item {
func (self *Dict) Pop () DictItem {
if self.used == 0 {
panic("cannot Pop from empty Dict")
}
......@@ -313,8 +313,8 @@ func (self Dict) String () string {
return buf.String()
}
func (self Item) String () string {
return fmt.Sprintf("Item{%s}",
func (self DictItem) String () string {
return fmt.Sprintf("DictItem{%s}",
fmt.Sprintf("%#v, %#v, %#v",
fmt.Sprint(*(self.Key)),
fmt.Sprint(*(self.Value)),
......
......@@ -143,14 +143,14 @@ type visitOpts struct {
StructField string
}
type hashable interface {
type Hashable interface {
Hash () uint64
}
func (w *walker) visit(v reflect.Value, opts *visitOpts) (uint64, error) {
// Call method Hash() is any
i, ok := v.Interface().(hashable)
i, ok := v.Interface().(Hashable)
if ok {
return i.Hash(), nil
}
......
// Python3 dicts ported to Go, inspired from a Python version at
// https://code.activestate.com/recipes/578375/
package dicts
import (
"bytes"
"fmt"
)
//
// set type
//
type SetItem struct {
Key *interface{}
hash uint64
}
type Set struct {
indices map[uint64]int64
itemlist []SetItem
used uint64
filled uint64
keyhash uint64
}
func (self *Set) Clear () {
self.indices = make(map[uint64]int64)
self.itemlist = make([]SetItem, 0)
self.used = 0
self.filled = 0
self.keyhash = 0
}
func (self Set) Copy (copiers ...copyfunc) Set {
s := Set{}
s.indices = make(map[uint64]int64)
for k, v := range self.indices {
s.indices[k] = v
}
s.itemlist = make([]SetItem, len(self.itemlist))
if len(copiers) == 0 {
copy(s.itemlist, self.itemlist)
} else if len(copiers) == 1 {
cpk := copiers[0]
for index, item := range self.itemlist {
k := cpk(*(item.Key))
s.itemlist[index] = SetItem{&k, item.hash}
}
} else {
panic("at most one copier is allowed")
}
s.used = self.used
s.filled = self.filled
s.keyhash = self.keyhash
return s
}
func MakeSet (items ...interface{}) Set {
s := Set{}
s.Clear()
for _, i := range items {
s.Add(i)
}
return s
}
func (self Set) Len () uint64 {
return self.used
}
func (self Set) lookup (key interface{}, hashvalue uint64) (int64, uint64) {
var freeslot uint64
var fsempty bool = true
for i, p := first_probe(hashvalue); true; i = p.next() {
index, found := self.indices[i]
if ! found {
if fsempty {
return _FREE, i
} else {
return _DUMMY, freeslot
}
} else if index == _DUMMY {
if fsempty {
fsempty = false
freeslot = i
}
} else {
item := self.itemlist[index]
if item.Key == &key || item.hash == hashvalue && Eq(*(item.Key), key) {
return index, i
}
}
}
// never reached
panic("unreachable code has been reached")
return 0, 0
}
func (self Set) Get (key interface{}) *interface{} {
index, _ := self.lookup(key, Hash(key))
if index < 0 {
return nil
}
return self.itemlist[index].Key
}
func (self Set) Fetch (key interface{}, fallback interface{}) *interface{} {
index, _ := self.lookup(key, Hash(key))
if index < 0 {
return &fallback
} else {
return self.itemlist[index].Key
}
}
func (self *Set) Add (key interface{}) {
hashvalue := Hash(key)
index, i := self.lookup(key, hashvalue)
if index < 0 {
self.indices[i] = int64(self.used)
self.itemlist = append(self.itemlist, SetItem{&key, hashvalue})
self.used++
if index == _FREE {
self.filled++
}
self.keyhash += hashvalue
} else {
self.itemlist[index] = SetItem{&key, hashvalue}
}
}
func (self *Set) Del (key interface{}) {
hashvalue := Hash(key)
index, i := self.lookup(key, hashvalue)
if index < 0 {
return
}
self.indices[i] = _DUMMY
self.used--
if uint64(index) != self.used {
lastitem := self.itemlist[self.used]
lastindex, j := self.lookup(*(lastitem.Key), lastitem.hash)
if lastindex < 0 || i == j {
panic("inconsistent Set internal state")
}
self.indices[j] = index
self.itemlist[index] = lastitem
}
self.itemlist = self.itemlist[:self.used]
self.keyhash -= hashvalue
}
type SetIterator struct {
i uint64
s *Set
}
func (self *SetIterator) Next () *SetItem {
self.i++
if self.i >= self.s.used {
return nil
} else {
return &(self.s.itemlist[self.i])
}
}
func (self Set) Iter () (SetIterator, *SetItem) {
it := SetIterator{0, &self}
if self.used == 0 {
return it, nil
} else {
return it, &(self.itemlist[0])
}
}
func (self Set) Has (key interface{}) bool {
index, _ := self.lookup(key, Hash(key))
return index >= 0
}
func (self *Set) Pop () SetItem {
if self.used == 0 {
panic("cannot Pop from empty Set")
}
item := self.itemlist[self.used-1]
self.Del(*(item.Key))
self.keyhash -= item.hash
return item
}
func (self Set) Hash () uint64 {
return self.keyhash
}
func (self Set) Eq (other interface{}) bool {
s, ok := other.(Set)
if ok {
if self.Len() != s.Len() {
return false
} else if self.keyhash != s.keyhash {
return false
}
for i := uint64(0); i < self.used; i++ {
value := s.Get(*(self.itemlist[i].Key))
if value == nil {
return false
}
}
return true
} else {
return false
}
}
//
//
//
func (self Set) String () string {
buf := bytes.NewBufferString("{")
for i := uint64(0); i < self.used; i++ {
if i > 0 {
buf.WriteString(", ")
}
buf.WriteString(fmt.Sprintf("%#v", *(self.itemlist[i].Key)))
}
buf.WriteString("}")
return buf.String()
}
func (self SetItem) String () string {
return fmt.Sprintf("SetItem{%s}",
fmt.Sprintf("%#v, %#v",
fmt.Sprint(*(self.Key)),
self.hash))
}
func (self Set) ShowStructure () {
for i:=0; i < 50; i++ {
fmt.Print("=")
}
fmt.Println()
fmt.Println(self)
fmt.Println("Indices:", self.indices)
fmt.Println("Items:")
for i := uint64(0); i < self.used; i++ {
fmt.Printf(" [%d] %s\n", i, self.itemlist[i])
}
for i:=0; i < 50; i++ {
fmt.Print("-")
}
fmt.Println()
}
......@@ -142,7 +142,7 @@ type MsetIterator struct {
iter dicts.DictIterator
dup bool
count uint64
current *dicts.Item
current *dicts.DictItem
}
func (self *MsetIterator) Next () *interface{} {
......
......@@ -3,23 +3,7 @@ package zn
import "dicts"
type Set struct {
d *dicts.Dict
}
type _z struct {
}
func (self _z) Hash () uint64 {
return 8806599771745799646
}
func (self _z) Eq (other interface{}) bool {
_, ok := other.(_z)
if ok {
return true
} else {
return false
}
s *dicts.Set
}
//*** a := zn.MakeMarking()
......@@ -30,19 +14,19 @@ func (self _z) Eq (other interface{}) bool {
//*** c.Set("p3", 3)
func MakeSet (markings ...Marking) Set {
dict := dicts.MakeDict()
set := dicts.MakeSet()
for _, m := range markings {
dict.Set(m, _z{})
set.Add(m)
}
return Set{&dict}
return Set{&set}
}
func (self Set) Empty () bool {
return self.d.Len() == 0
return self.s.Len() == 0
}
func (self Set) NotEmpty () bool {
return self.d.Len() > 0
return self.s.Len() > 0
}
//+++ zn.MakeSet().Empty()
......@@ -51,7 +35,7 @@ func (self Set) NotEmpty () bool {
//+++ zn.MakeSet(a).NotEmpty()
func (self Set) Len () uint64 {
return self.d.Len()
return self.s.Len()
}
//+++ zn.MakeSet().Len() == 0
......@@ -59,7 +43,7 @@ func (self Set) Len () uint64 {
//+++ zn.MakeSet(a, a).Len() == 1
func (self *Set) Add (m Marking) {
self.d.Set(m, _z{})
self.s.Add(m)
}
//### s := zn.MakeSet(a, b)
......@@ -73,22 +57,22 @@ func (self *Set) Add (m Marking) {
//=== 3
func (self Set) Get (m Marking) (bool, Marking) {
i := self.d.GetItem(m)
if i == nil {
return false, Marking{nil, -1}
k := self.s.Get(m)
if k == nil {
return false, MakeMarking()
} else {
return true, (*(i.Key)).(Marking)
return true, (*k).(Marking)
}
}
//### x := a.Copy()
//... x.SetId(42)
//... x.Id = 42
//... s := zn.MakeSet(x, b)
//... s.Get(a)
//=== true [42] {"p1": [1]}
func (self Set) Has (m Marking) bool {
return self.d.Has(m)
return self.s.Has(m)
}
//+++ zn.MakeSet(a, b).Has(a)
......@@ -96,7 +80,7 @@ func (self Set) Has (m Marking) bool {
//--- zn.MakeSet(a, b).Has(c)
type SetIterator struct {
i dicts.DictIterator
i dicts.SetIterator
}
func (self *SetIterator) Next () *Marking {
......@@ -110,7 +94,7 @@ func (self *SetIterator) Next () *Marking {
}
func (self Set) Iter () (SetIterator, *Marking) {
i, f := self.d.Iter()
i, f := self.s.Iter()
if f == nil {
return SetIterator{i}, nil
} else {
......@@ -119,12 +103,12 @@ func (self Set) Iter () (SetIterator, *Marking) {
}
}
//### a.SetId(1)
//... b.SetId(2)
//... c.SetId(3)
//### a.Id = 1
//... b.Id = 2
//... c.Id = 3
//... s := zn.MakeSet(a, b, c)
//... for i, m := s.Iter(); m != nil; m = i.Next() { fmt.Println(*m) }
//... for i, m := s.Iter(); m != nil; m = i.Next() { fmt.Println((*m).Id) }
//... nil
//=== [1] {"p1": [1]}
//=== [2] {"p1": [1], "p2": [2]}
//=== [3] {"p1": [1], "p2": [2], "p3": [3]}
//=== 1
//=== 2
//=== 3
......