Franck Pommereau

reimplemented Go lib with proper dicts

// Go implementation Python3 dicts, translated from a Python version at
// Python3 dicts ported to Go, inspired from a Python version at
// https://code.activestate.com/recipes/578375/
package dicts
......@@ -6,6 +6,7 @@ package dicts
import (
"bytes"
"fmt"
"hash/fnv"
)
type Hashable interface {
......@@ -35,19 +36,16 @@ func hash (key Hashable) uint64 {
}
}
// # Placeholder constants
// FREE = -1
// DUMMY = -2
func StringHash (s string) uint64 {
hash := fnv.New64()
hash.Write([]byte(s))
return hash.Sum64()
}
const _FREE int64 = -1
const _DUMMY int64 = -2
// def __init__(self, *args, **kwds):
// if not hasattr(self, 'keylist'):
// self.clear()
// self.update(*args, **kwds)
func NewDict (items ...Item) Dict {
func MakeDict (items ...Item) Dict {
d := Dict{}
d.Clear()
for _, i := range items {
......@@ -56,21 +54,6 @@ func NewDict (items ...Item) Dict {
return d
}
// def _make_index(n):
// 'New sequence of indices using the smallest possible datatype'
// # if n <= 2**7: return array.array('b', [FREE]) * n # signed char
// # if n <= 2**15: return array.array('h', [FREE]) * n # signed short
// # if n <= 2**31: return array.array('l', [FREE]) * n # signed long
// return [FREE] * n # python integers
//
// def clear(self):
// self.indices = self._make_index(8)
// self.hashlist = []
// self.keylist = []
// self.valuelist = []
// self.used = 0
// self.filled = 0 # used + dummies
func (self *Dict) Clear () {
self.indices = make(map[uint64]int64)
self.itemlist = make([]Item, 0)
......@@ -78,26 +61,10 @@ func (self *Dict) Clear () {
self.filled = 0
}
// def __len__(self):
// return self.used
func (self Dict) Len () uint64 {
return self.used
}
// def _gen_probes(hashvalue, mask):
// 'Same sequence of probes used in the current dictionary design'
// PERTURB_SHIFT = 5
// if hashvalue < 0:
// hashvalue = -hashvalue
// i = hashvalue & mask
// yield i
// perturb = hashvalue
// while True:
// i = (5 * i + perturb + 1) & 0xFFFFFFFFFFFFFFFF
// yield i & mask
// perturb >>= PERTURB_SHIFT
const _PERTURB_SHIFT uint64 = 5
type probe struct {
......@@ -116,22 +83,6 @@ func (self *probe) next () uint64 {
return self.i
}
// def _lookup(self, key, hashvalue):
// 'Same lookup logic as currently used in real dicts'
// assert self.filled < len(self.indices) # At least one open slot
// freeslot = None
// for i in self._gen_probes(hashvalue, len(self.indices)-1):
// index = self.indices[i]
// if index == FREE:
// return (FREE, i) if freeslot is None else (DUMMY, freeslot)
// elif index == DUMMY:
// if freeslot is None:
// freeslot = i
// elif (self.keylist[index] is key or
// self.hashlist[index] == hashvalue
// and self.keylist[index] == key):
// return (index, i)
func (self Dict) lookup (key Hashable, hashvalue uint64) (int64, uint64) {
var freeslot *uint64 = nil
for i, p := first_probe(hashvalue); true; i = p.next() {
......@@ -147,58 +98,34 @@ func (self Dict) lookup (key Hashable, hashvalue uint64) (int64, uint64) {
freeslot = new(uint64)
*freeslot = i
}
} else if self.itemlist[index].Key == &key || (self.itemlist[index].hash == hashvalue && (*(self.itemlist[index].Key)).Eq(key)) {
return index, i
} else {
item := self.itemlist[index]
if item.Key == &key || item.hash == hashvalue && (*item.Key).Eq(key) {
return index, i
}
}
}
// never reached
return 0, 0
}
// def __getitem__(self, key):
// hashvalue = hash(key)
// index, i = self._lookup(key, hashvalue)
// if index < 0:
// raise KeyError(key)
// return self.valuelist[index]
func (self Dict) Get (key Hashable) interface{} {
func (self Dict) Get (key Hashable) *interface{} {
index, _ := self.lookup(key, hash(key))
if index < 0 {
panic("Dict has no such key")
return nil
}
return *(self.itemlist[index].Value)
return self.itemlist[index].Value
}
// def get(self, key, default=None):
// index, i = self._lookup(key, hash(key))
// return self.valuelist[index] if index >= 0 else default
func (self Dict) Fetch (key Hashable, fallback interface{}) interface{} {
func (self Dict) Fetch (key Hashable, fallback interface{}) *interface{} {
index, _ := self.lookup(key, hash(key))
if index < 0 {
return fallback
return &fallback
} else {
return *(self.itemlist[index].Value)
return self.itemlist[index].Value
}
}
// def __setitem__(self, key, value):
// hashvalue = hash(key)
// index, i = self._lookup(key, hashvalue)
// if index < 0:
// self.indices[i] = self.used
// self.hashlist.append(hashvalue)
// self.keylist.append(key)
// self.valuelist.append(value)
// self.used += 1
// if index == FREE:
// self.filled += 1
// if self.filled * 3 > len(self.indices) * 2:
// self._resize(4 * len(self))
// else:
// self.valuelist[index] = value
func (self *Dict) Set (key Hashable, value interface{}) {
hashvalue := hash(key)
index, i := self.lookup(key, hashvalue)
......@@ -214,32 +141,8 @@ func (self *Dict) Set (key Hashable, value interface{}) {
}
}
// def __delitem__(self, key):
// hashvalue = hash(key)
// index, i = self._lookup(key, hashvalue)
// if index < 0:
// raise KeyError(key)
// self.indices[i] = DUMMY
// self.used -= 1
// # If needed, swap with the lastmost entry to avoid leaving a "hole"
// if index != self.used:
// lasthash = self.hashlist[-1]
// lastkey = self.keylist[-1]
// lastvalue = self.valuelist[-1]
// lastindex, j = self._lookup(lastkey, lasthash)
// assert lastindex >= 0 and i != j
// self.indices[j] = index
// self.hashlist[index] = lasthash
// self.keylist[index] = lastkey
// self.valuelist[index] = lastvalue
// # Remove the lastmost entry
// self.hashlist.pop()
// self.keylist.pop()
// self.valuelist.pop()
func (self *Dict) Del (key Hashable) {
hashvalue := hash(key)
index, i := self.lookup(key, hashvalue)
index, i := self.lookup(key, hash(key))
if index < 0 {
return
}
......@@ -257,19 +160,12 @@ func (self *Dict) Del (key Hashable) {
self.itemlist = self.itemlist[:self.used]
}
// def keys(self):
// return list(self.keylist)
// def values(self):
// return list(self.valuelist)
// def items(self):
// return zip(self.keylist, self.valuelist)
type dictiter struct {
type DictIterator struct {
i uint64
d *Dict
}
func (self *dictiter) Next () *Item {
func (self *DictIterator) Next () *Item {
self.i++
if self.i >= self.d.used {
return nil
......@@ -278,8 +174,8 @@ func (self *dictiter) Next () *Item {
}
}
func (self Dict) Iter () (dictiter, *Item) {
it := dictiter{0, &self}
func (self Dict) Iter () (DictIterator, *Item) {
it := DictIterator{0, &self}
if self.used == 0 {
return it, nil
} else {
......@@ -287,23 +183,11 @@ func (self Dict) Iter () (dictiter, *Item) {
}
}
// def __contains__(self, key):
// index, i = self._lookup(key, hash(key))
// return index >= 0
func (self Dict) Has (key Hashable) bool {
index, _ := self.lookup(key, hash(key))
return index >= 0
}
// def popitem(self):
// if not self.keylist:
// raise KeyError('popitem(): dictionary is empty')
// key = self.keylist[-1]
// value = self.valuelist[-1]
// del self[key]
// return key, value
func (self *Dict) Pop () Item {
if self.used == 0 {
panic("cannot Pop from empty Dict")
......@@ -313,9 +197,6 @@ func (self *Dict) Pop () Item {
return item
}
// def __repr__(self):
// return 'Dict(%r)' % self.items()
func (self Dict) String () string {
buf := bytes.NewBufferString("{")
for i := uint64(0); i < self.used; i++ {
......@@ -330,15 +211,6 @@ func (self Dict) String () string {
return buf.String()
}
// def show_structure(self):
// 'Diagnostic method. Not part of the API.'
// print '=' * 50
// print self
// print 'Indices:', self.indices
// for i, row in enumerate(zip(self.hashlist, self.keylist, self.valuelist)):
// print i, row
// print '-' * 50
func (self Item) String () string {
return fmt.Sprintf("Item{%s}",
fmt.Sprintf("%s, %s, %d",
......@@ -353,9 +225,10 @@ func (self Dict) ShowStructure () {
}
fmt.Println()
fmt.Println(self)
fmt.Println("Indices: ", self.indices)
fmt.Println("Indices:", self.indices)
fmt.Println("Items:")
for i := uint64(0); i < self.used; i++ {
fmt.Println(self.itemlist[i])
fmt.Printf(" [%d] %s\n", i, self.itemlist[i])
}
for i:=0; i < 50; i++ {
fmt.Print("-")
......
......@@ -6,7 +6,7 @@ import "fmt"
func StateSpace (init func()Marking, addsucc func(Marking, Set),
print_states bool, print_succs bool) int {
var succ Set
count := 0
count := 1
i := init()
todo := MakeQueue(&i)
seen := MakeSet(&i)
......
......@@ -3,22 +3,23 @@ package snk
import "fmt"
import "bytes"
import "hash/fnv"
import "dicts"
type Marking struct {
id int
data *map[string]*Mset
d *dicts.Dict
i int
}
func (self *Marking) SetId (id int) {
self.id = id
self.i = id
}
func MakeMarking (id ...int) Marking {
m := make(map[string]*Mset)
d := dicts.MakeDict()
if len(id) == 0 {
return Marking{-1, &m}
return Marking{&d, -1}
} else if len(id) == 1 {
return Marking{id[0], &m}
return Marking{&d, id[0]}
} else {
panic("at most one id expected")
}
......@@ -27,14 +28,36 @@ func MakeMarking (id ...int) Marking {
func (self Marking) Hash () uint64 {
var h uint64 = 2471033218594493899
hash := fnv.New64()
for place, tokens := range *self.data {
for iter, item := self.d.Iter(); item != nil; item = iter.Next() {
hash.Reset()
hash.Write([]byte(fmt.Sprintf("[%s]{%x}", place, tokens.Hash())))
hash.Write([]byte(fmt.Sprintf("[%s]{%x}",
fmt.Sprint(*(item.Key)),
(*item.Value).(Mset).Hash())))
h ^= hash.Sum64()
}
return h
}
type place struct {
s string
}
func (self place) Hash () uint64 {
return dicts.StringHash(self.s)
}
func (self place) Eq (other interface{}) bool {
if val, isplace := other.(place); isplace {
return val.s == self.s
} else {
return false
}
}
func (self Marking) Has (p string) bool {
return self.d.Has(place{p})
}
//### a := snk.MakeMarking()
//... a.Set("p1", 1, 2, 3, 4)
//... b := a.Copy()
......@@ -69,15 +92,13 @@ func (self Marking) Hash () uint64 {
//=== true
func (self Marking) Eq (other Marking) bool {
if len(*self.data) != len(*other.data) {
if self.d.Len() != other.d.Len() {
return false
}
for place, left := range *self.data {
if right, found := (*other.data)[place] ; found {
if ! left.Eq(*right) {
return false
}
} else {
for iter, p, m := self.Iter(); p != nil; p, m = iter.Next() {
if ! other.d.Has(place{*p}) {
return false
} else if ! m.Eq(other.Get(*p)) {
return false
}
}
......@@ -86,12 +107,12 @@ func (self Marking) Eq (other Marking) bool {
//+++ snk.MakeMarking().Eq(snk.MakeMarking())
func (self Marking) Set (place string, tokens ...interface{}) {
func (self Marking) Set (p string, tokens ...interface{}) {
if len(tokens) == 0 {
delete(*self.data, place)
self.d.Del(place{p})
} else {
m := MakeMset(tokens...)
(*self.data)[place] = &m
self.d.Set(place{p}, m)
}
}
......@@ -110,12 +131,12 @@ func (self Marking) Set (place string, tokens ...interface{}) {
//... a.Get("p1").Empty()
//=== true
func (self Marking) Update (place string, tokens Mset) {
if _, found := (*self.data)[place] ; found {
(*self.data)[place].Add(tokens)
func (self Marking) Update (p string, tokens Mset) {
if self.Has(p) {
m := self.Get(p)
m.Add(tokens)
} else {
m := tokens.Copy()
(*self.data)[place] = &m
self.d.Set(place{p}, tokens.Copy())
}
}
......@@ -131,9 +152,8 @@ func (self Marking) Update (place string, tokens Mset) {
func (self Marking) Copy () Marking {
copy := MakeMarking()
for key, value := range *self.data {
m := value.Copy()
(*copy.data)[key] = &m
for iter, p, m := self.Iter(); p != nil; p, m = iter.Next() {
copy.Update(*p, *m)
}
return copy
}
......@@ -183,12 +203,8 @@ func (self Marking) Copy () Marking {
//... a.Eq(b)
//=== false
func (self Marking) Get (place string) Mset {
if value, found := (*self.data)[place] ; found {
return *value
} else {
return MakeMset()
}
func (self Marking) Get (p string) Mset {
return (*(self.d.Fetch(place{p}, MakeMset()))).(Mset)
}
//### a := snk.MakeMarking()
......@@ -211,11 +227,7 @@ func (self Marking) Get (place string) Mset {
func (self Marking) NotEmpty (places ...string) bool {
for _, key := range places {
if value, found := (*self.data)[key] ; found {
if value.Empty() {
return false
}
} else {
if self.Get(key).Empty() {
return false
}
}
......@@ -247,8 +259,8 @@ func (self Marking) NotEmpty (places ...string) bool {
//=== false
func (self Marking) Add (other Marking) Marking {
for place, right := range *other.data {
self.Update(place, *right)
for iter, p, m := other.Iter(); p != nil; p, m = iter.Next() {
self.Update(*p, *m)
}
return self
}
......@@ -259,21 +271,21 @@ func (self Marking) Add (other Marking) Marking {
//... b := snk.MakeMarking()
//... b.Set("p2", 2, 4)
//... b.Set("p3", 1)
//... a.Add(b)
//... c := snk.MakeMarking()
//... c.Set("p1", 1, 2, 2, 3)
//... c.Set("p2", 1, 1, 2, 4, 4)
//... c.Set("p3", 1)
//... a.Add(b)
//... a.Eq(c)
//=== true
func (self Marking) Sub (other Marking) Marking {
for place, right := range *other.data {
if left, found := (*self.data)[place] ; found {
left.Sub(*right)
if left.Empty() {
delete(*self.data, place)
}
for iter, p, m := other.Iter(); p != nil; p, m = iter.Next() {
mine := self.Get(*p)
if m.Geq(mine) {
self.d.Del(place{*p})
} else {
mine.Sub(*m)
}
}
return self
......@@ -293,12 +305,8 @@ func (self Marking) Sub (other Marking) Marking {
//=== true
func (self Marking) Geq (other Marking) bool {
for key, value := range *other.data {
if mine, found := (*self.data)[key] ; found {
if ! mine.Geq(*value) {
return false
}
} else {
for iter, p, m := other.Iter(); p != nil; p, m = iter.Next() {
if ! self.Get(*p).Geq(*m) {
return false
}
}
......@@ -350,21 +358,30 @@ func (self Marking) Geq (other Marking) bool {
//... a.Geq(b)
//=== false
func (self Marking) Iter (place string) (MsetIterator, interface{}) {
mset, found := (*self.data)[place]
if found {
return mset.Iter()
type MarkingIterator struct {
iter *dicts.DictIterator
}
func (self MarkingIterator) Next () (*string, *Mset) {
next := self.iter.Next()
if next == nil {
return nil, nil
} else {
return MakeMset().Iter()
p := (*next.Key).(place)
m := (*next.Value).(Mset)
return &(p.s), &m
}
}
func (self Marking) IterDup (place string) (MsetIterator, interface{}) {
mset, found := (*self.data)[place]
if found {
return mset.IterDup()
func (self Marking) Iter () (MarkingIterator, *string, *Mset) {
iter, item := self.d.Iter()
myiter := MarkingIterator{&iter}
if item == nil {
return myiter, nil, nil
} else {
return MakeMset().Iter()
p := (*item.Key).(place)
m := (*item.Value).(Mset)
return myiter, &(p.s), &m
}
}
......@@ -372,7 +389,7 @@ func (self Marking) IterDup (place string) (MsetIterator, interface{}) {
//... a.Set("p1", 1, 2, 2, 3)
//... a.Set("p2", 1, 1, 4)
//... fmt.Print("{")
//... for i, p := a.Iter("p1"); p != nil; p = i.Next() { fmt.Print(*p, ", ") }
//... for i, p := a.Get("p1").Iter(); p != nil; p = i.Next() { fmt.Print(*p, ", ") }
//... fmt.Println("}")
//... nil
//>>> eval(out) == {1, 2, 3}
......@@ -381,24 +398,25 @@ func (self Marking) IterDup (place string) (MsetIterator, interface{}) {
//... a.Set("p1", 1, 2, 2, 3)
//... a.Set("p2", 1, 1, 4)
//... fmt.Print("{")
//... for i, p := a.Iter("p3"); p != nil; p = i.Next() { fmt.Print(*p, ", ") }
//... for i, p := a.Get("p3").Iter(); p != nil; p = i.Next() { fmt.Print(*p, ", ") }
//... fmt.Println("}")
//... nil
//=== {}
func (self Marking) String () string {
buf := bytes.NewBufferString("")
if self.id >= 0 {
buf.WriteString(fmt.Sprintf("[%d] ", self.id))
if self.i >= 0 {
buf.WriteString(fmt.Sprintf("[%d] ", self.i))
}
buf.WriteString("{")
i := 0
for key, value := range *self.data {
if i > 0 {
comma := false
for iter, p, m := self.Iter(); p != nil; p, m = iter.Next() {
if comma {
buf.WriteString(", ")
} else {
comma = true
}
i += 1
buf.WriteString(fmt.Sprintf(`"%s": %s`, key, value))
buf.WriteString(fmt.Sprintf(`"%s": %s`, *p, *m))
}
buf.WriteString("}")
return buf.String()
......
......@@ -4,52 +4,73 @@ import "fmt"
import "bytes"
import "hash/fnv"
import "hashstructure"
import "dicts"
type Mset struct {
data *map[interface{}]int
d *dicts.Dict
}
func (self Mset) Hash () uint64 {
var h uint64 = 13124430844775843711
hash := fnv.New64()
for value, count := range *self.data {
hv, err := hashstructure.Hash(value, nil)
for iter, item := self.d.Iter(); item != nil; item = iter.Next() {
hv, err := hashstructure.Hash(*(item.Key), nil)
if err != nil {
panic(err)
}
hash.Reset()
hash.Write([]byte(fmt.Sprintf("[%x]{%x}", hv, count)))
hash.Write([]byte(fmt.Sprintf("[%x]{%x}", hv, *(item.Value))))
h ^= hash.Sum64()
}
return h
}
type AsString struct {
val *interface{}
}
func (self AsString) Hash () uint64 {
return dicts.StringHash(fmt.Sprint(*(self.val)))
}
func (self AsString) Eq (other interface{}) bool {
if v, ok := other.(AsString); ok {
return fmt.Sprint(*(self.val)) == fmt.Sprint(*(v.val))
} else {
return fmt.Sprint(*(self.val)) == fmt.Sprint(other)
}
}
func i2h (v interface{}) dicts.Hashable {
return AsString{&v}
}
func h2i (v *dicts.Hashable) *interface{} {
return (*v).(AsString).val
}
//+++ snk.MakeMset(1, 2, 2, 3, 3, 3).Hash() == snk.MakeMset(3, 3, 3, 2, 2, 1).Hash()
//+++ snk.MakeMset(1, 2, 2, 3, 3, 3).Hash() == snk.MakeMset(3, 2, 1, 3, 2, 3).Hash()
func MakeMset (values ...interface{}) Mset {
m := make(map[interface{}]int)
mset := Mset{&m}
dict := dicts.MakeDict()
mset := Mset{&dict}
for _, elt := range values {
if count, found := (*mset.data)[elt]; found {
(*mset.data)[elt] = count + 1
} else {
(*mset.data)[elt] = 1
}
h := i2h(elt)
count := (*mset.d.Fetch(h, uint64(0))).(uint64)
mset.d.Set(h, count + 1)
}
return mset
}
func (self Mset) Eq (other Mset) bool {
if len(*self.data) != len(*other.data) {
if self.d.Len() != other.d.Len() {
return false
}
for key, left := range *self.data {
if right, found := (*other.data)[key]; found {
if left != right {
return false
}
} else {
for iter, item := self.d.Iter(); item != nil; item = iter.Next() {
if ! other.d.Has(*(item.Key)) {
return false
} else if (*item.Value).(uint64) != (*other.d.Get(*(item.Key))).(uint64) {
return false
}
}
......@@ -65,18 +86,18 @@ func (self Mset) Eq (other Mset) bool {
func (self Mset) Copy () Mset {
copy := MakeMset()
for key, value := range *self.data {
(*copy.data)[key] = value
for iter, item := self.d.Iter(); item != nil; item = iter.Next() {
copy.d.Set(*(item.Key), *(item.Value))
}
return copy
}
//+++ snk.MakeMset(1, 2, 2, 3, 3, 3).Copy().Eq(snk.MakeMset(1, 2, 2, 3, 3, 3))
func (self Mset) Len () int {
count := 0
for _, value := range *self.data {
count += value
func (self Mset) Len () uint64 {
count := uint64(0)
for iter, item := self.d.Iter(); item != nil; item = iter.Next() {
count += (*(item.Value)).(uint64)
}
return count
}
......@@ -85,12 +106,9 @@ func (self Mset) Len () int {
//+++ snk.MakeMset().Len() == 0
func (self Mset) Add (other Mset) Mset {
for key, value := range *other.data {
if count, found := (*self.data)[key] ; found {
(*self.data)[key] = value + count
} else {
(*self.data)[key] = value
}
for iter, item := other.d.Iter(); item != nil; item = iter.Next() {
count := (*(self.d.Fetch(*(item.Key), uint64(0)))).(uint64)
self.d.Set(*(item.Key), count + (*(item.Value)).(uint64))
}
return self
}
......@@ -102,13 +120,13 @@ func (self Mset) Add (other Mset) Mset {
//=== true
func (self Mset) Sub (other Mset) Mset {
for key, value := range *other.data {
if count, found := (*self.data)[key] ; found {
if count > value {
(*self.data)[key] = count - value
} else {
delete(*self.data, key)
}
for iter, item := other.d.Iter(); item != nil; item = iter.Next() {
left := (*(self.d.Fetch(*(item.Key), uint64(0)))).(uint64)
right := (*(item.Value)).(uint64)
if left <= right {
self.d.Del(*(item.Key))
} else {
self.d.Set(*(item.Key), left - right)
}
}
return self
......@@ -127,12 +145,9 @@ func (self Mset) Sub (other Mset) Mset {
//=== true
func (self Mset) Geq (other Mset) bool {
for key, value := range *other.data {
if count, found := (*self.data)[key] ; found {
if count < value {
return false
}
} else {
for iter, item := other.d.Iter(); item != nil; item = iter.Next() {
count := (*(self.d.Fetch(*(item.Key), uint64(0)))).(uint64)
if count < (*item.Value).(uint64) {
return false
}
}
......@@ -149,19 +164,15 @@ func (self Mset) Geq (other Mset) bool {
//--- snk.MakeMset().Geq(snk.MakeMset(1))
func (self Mset) Empty () bool {
return len(*self.data) == 0
return self.d.Len() == 0
}
//+++ snk.MakeMset().Empty()
//+++ snk.MakeMset().Empty()
//--- snk.MakeMset(1, 2).Empty()
func (self Mset) Count (value interface{}) int {
if count, found := (*self.data)[value] ; found {
return count
} else {
return 0
}
func (self Mset) Count (value interface{}) uint64 {
return (*(self.d.Fetch(i2h(value), uint64(0)))).(uint64)
}
//### snk.MakeMset(1, 2, 2, 3, 3, 3).Count(1)
......@@ -174,62 +185,42 @@ func (self Mset) Count (value interface{}) int {
//=== 3
type MsetIterator struct {
done bool
ask chan bool
rep chan interface{}
iter dicts.DictIterator
dup bool
count uint64
current *dicts.Item
}
func (self MsetIterator) Next() interface{} {
var rep interface{}
if self.done {
func (self *MsetIterator) Next () *interface{} {
if self.current == nil {
return nil
}
self.ask <- true
rep = <- self.rep
if rep == nil {
self.done = true
}
return rep
}
func (self MsetIterator) Stop() {
if ! self.done {
self.ask <- false
self.done = true
}
}
func (self Mset) iterate (it MsetIterator, dup bool) {
for key, num := range *self.data {
if !dup {
num = 1
}
for i := 0; i < num; i++ {
if it.done {
return
}
if <- it.ask {
it.rep <- key
} else {
return
}
} else if self.count == 0 {
self.current = self.iter.Next()
if self.current == nil {
return nil
} else if self.dup {
self.count = (*(self.current.Value)).(uint64) - 1
}
} else if self.dup {
self.count--
}
if <- it.ask {
it.rep <- nil
}
return h2i(self.current.Key)
}
func (self Mset) Iter () (MsetIterator, interface{}) {
it := MsetIterator{false, make(chan bool), make(chan interface{})}
go self.iterate(it, false)
return it, it.Next()
func (self Mset) Iter () (MsetIterator, *interface{}) {
iter, item := self.d.Iter()
myiter := MsetIterator{iter, false, 0, item}
if item == nil {
return myiter, nil
} else {
return myiter, h2i(item.Key)
}
}
func (self Mset) IterDup () (MsetIterator, interface{}) {
it := MsetIterator{false, make(chan bool), make(chan interface{})}
go self.iterate(it, true)
return it, it.Next()
func (self Mset) IterDup () (MsetIterator, *interface{}) {
iter, item := self.d.Iter()
myiter := MsetIterator{iter, true, (*(item.Value)).(uint64) - 1, item}
return myiter, h2i(item.Key)
}
//### a := snk.MakeMset(1, 2, 2, 3, 3, 3)
......@@ -246,15 +237,14 @@ func (self Mset) IterDup () (MsetIterator, interface{}) {
func (self Mset) String () string {
buf := bytes.NewBufferString("[")
count := 0
for key, value := range *self.data {
for i := 0; i < value; i += 1 {
if count > 0 {
buf.WriteString(", ")
}
buf.WriteString(fmt.Sprint(key))
count += 1
comma := false
for iter, val := self.IterDup(); val != nil; val = iter.Next() {
if comma {
buf.WriteString(", ")
} else {
comma = true
}
buf.WriteString(fmt.Sprint(*val))
}
buf.WriteString("]")
return buf.String()
......@@ -268,18 +258,24 @@ func (self Mset) String () string {
//... a
//>>> list(sorted(eval(out))) == [1, 2, 2, 3, 3, 3]
type mapfunc func (interface{}, int) (interface{}, int)
type mapfunc func (interface{}, uint64) (interface{}, uint64)
func (self Mset) Map (f mapfunc) Mset {
copy := MakeMset()
for k0, n0 := range *self.data {
k1, n1 := f(k0, n0)
(*copy.data)[k1] = n1
for iter, item := self.d.Iter(); item != nil; item = iter.Next() {
k := *h2i(item.Key)
v := (*(item.Value)).(uint64)
k, v = f(k, v)
copy.d.Set(i2h(k), v)
}
return copy
}
//### a := snk.MakeMset(1, 2, 2)
//... b := a.Map(func (v interface{}, n int) (interface{}, int) {return v.(int)+1, n})
//... b := a.Map(func (v interface{}, n uint64) (interface{}, uint64) {return v.(int)+1, n})
//... b.Eq(snk.MakeMset(2, 3, 3))
//=== true
func (self Mset) ShowStructure () {
self.d.ShowStructure()
}
......
......@@ -28,17 +28,17 @@ func (self Set) NotEmpty () bool {
}
//+++ snk.MakeSet().Empty()
//--- snk.MakeSet(snk.MakeMarking()).Empty()
//--- snk.MakeSet(&a).Empty()
//--- snk.MakeSet().NotEmpty()
//+++ snk.MakeSet(snk.MakeMarking()).NotEmpty()
//+++ snk.MakeSet(&a).NotEmpty()
func (self Set) Len () int {
return len(self.data)
}
//+++ snk.MakeSet().Len() == 0
//+++ snk.MakeSet(snk.MakeMarking()).Len() == 1
//+++ snk.MakeSet(snk.MakeMarking(), snk.MakeMarking()).Len() == 1
//+++ snk.MakeSet(&a).Len() == 1
//+++ snk.MakeSet(&a, &a).Len() == 1
func (self Set) lookup (m *Marking) (uint64, bool) {
slot := m.Hash()
......@@ -66,12 +66,13 @@ func (self *Set) AddPtr (m *Marking) {
}
}
//### s := snk.MakeSet(a, b)
//### s := snk.MakeSet(&a, &b)
//... s.Len()
//=== 2
//### s := snk.MakeSet(a, b)
//... s.Add(c).Add(c)
//### s := snk.MakeSet(&a, &b)
//... s.Add(c)
//... s.Add(c)
//... s.Len()
//=== 3
......@@ -88,6 +89,6 @@ func (self Set) Has (m *Marking) bool {
return found
}
//+++ snk.MakeSet(a, b).Has(a)
//+++ snk.MakeSet(a, b).Has(b)
//--- snk.MakeSet(a, b).Has(c)
//+++ snk.MakeSet(&a, &b).Has(&a)
//+++ snk.MakeSet(&a, &b).Has(&b)
//--- snk.MakeSet(&a, &b).Has(&c)
......
......@@ -144,10 +144,10 @@ class CodeGenerator (ast.CodeGenerator) :
pvar = node.CTX.names.fresh(base="p" + node.variable)
ivar = node.CTX.names.fresh(base="i" + node.variable)
self.fill("%s := true" % bvar)
self.fill("for %s, %s := %s.Iter(%s); %s != nil; %s = %s.Next() {"
self.fill("for %s, %s := %s.Get(%s).Iter(); %s != nil; %s = %s.Next() {"
% (ivar, pvar, node.marking, S(node.place.name), pvar, pvar, ivar))
with self.indent() :
self.fill("%s = %s.(%s)"
self.fill("%s = (*%s).(%s)"
% (node.variable, pvar, self.typedef[node.place.type]))
self.fill("if ")
self.visit(node.guard)
......@@ -165,10 +165,10 @@ class CodeGenerator (ast.CodeGenerator) :
def visit_ForeachToken (self, node) :
ivar = node.NAMES.fresh(base="i" + node.variable)
pvar = node.NAMES.fresh(base="p" + node.variable)
self.fill("for %s, %s := %s.Iter(%s); %s != nil; %s = %s.Next() {"
self.fill("for %s, %s := %s.Get(%s).Iter(); %s != nil; %s = %s.Next() {"
% (ivar, pvar, node.marking, S(node.place.name), pvar, pvar, ivar))
with self.indent() :
self.fill("%s = %s.(%s)"
self.fill("%s = (*%s).(%s)"
% (node.variable, pvar, self.typedef[node.place.type]))
self.children_visit(node.body, True)
self.fill("}")
......@@ -190,7 +190,7 @@ class CodeGenerator (ast.CodeGenerator) :
self.fill("for %s, %s := %s.Iter(); %s != nil; %s = %s.Next() {"
% (ivar, pvar, node.variable, pvar, pvar, ivar))
with self.indent() :
self.fill("_, %s = %s.(%s)"
self.fill("_, %s = (*%s).(%s)"
% (bvar, pvar, self.typedef[node.place.type]))
self.fill("if ! %s { break }" % bvar)
self.fill("}")
......
......@@ -75,7 +75,7 @@ def main () :
args = parser.parse_args()
if args.mode in "gml" and args.size :
n, _ = statespace(False, False, False)
print("%s reachable states")
print("%s reachable states" % n)
elif args.mode == "d" and args.size :
_, n = statespace(False, False, False)
print("%s deadlocks")
......
import os, os.path
import os, os.path, subprocess
def walk(root='libs/go/src/snk') :
for dirpath, dirnames, filenames in os.walk(root) :
......@@ -16,7 +16,6 @@ class Test (object) :
self.expected = list(expected)
self.pychecks = []
def codegen (self, outfile, indent=" ") :
outfile.write(' // %s:%s\n' % (self.path, self.lineno))
if self.path in self.idx :
outfile.write(' ' + '\n '.join(self.idx[self.path]) + '\n')
outfile.write(' fmt.Println("### %s:%s")\n' % (self.path, self.lineno))
......@@ -27,7 +26,7 @@ class Test (object) :
if self.source[-1] == "nil" and output[-1] == "<nil>" :
output.pop(-1)
if self.expected and self.expected != output :
print("#### %s:%s" % (self.path, self.lineno))
print("\n#### %s:%s" % (self.path, self.lineno))
print("\n".join(self.source))
print("## expected:")
print("\n".join(self.expected))
......@@ -48,7 +47,7 @@ class Test (object) :
res = "raised %s: %s" % (err.__class__.__name__, err)
if res is not True :
ret = 1
print("#### %s:%s" % (self.path, self.lineno))
print("\n#### %s:%s" % (self.path, self.lineno))
print("\n".join(self.source))
if res is False :
print("## failed")
......@@ -62,6 +61,7 @@ def extract (root, path) :
package = None
imports = set()
tests = []
declare = []
for num, line in enumerate(open(os.path.join(root, path))) :
if line.startswith('package ') :
package = line.split()[-1]
......@@ -83,10 +83,12 @@ def extract (root, path) :
Test.idx[path].append(line[6:].rstrip())
elif line.startswith("//$$$ ") :
imports.update(line[6:].strip().split())
elif line.startswith("//%%% ") :
declare.append(line[6:].rstrip())
print("+ %s (%s) = %s tests" % (path, package, len(tests)))
return package, imports, tests
return package, declare, imports, tests
def codegen (packages, imports, tests, out) :
def codegen (packages, declare, imports, tests, out) :
funcs = []
out.write('package main\n\nimport "fmt"\n')
for p in packages :
......@@ -94,6 +96,9 @@ def codegen (packages, imports, tests, out) :
for p in imports - packages :
out.write('import "%s"\n' % p)
out.write("\n")
for d in declare :
out.write("%s\n" % d)
out.write("\n")
for i, t in enumerate(tests) :
name = "test%03u" % i
funcs.append(name)
......@@ -105,12 +110,37 @@ def codegen (packages, imports, tests, out) :
out.write(" %s()\n" % name)
out.write('}')
def getlmap(path) :
m = {}
loc = None
for n, l in enumerate(open(path)) :
if l.strip().startswith('fmt.Println("### ') :
loc = l.split("### ")[-1].split('"')[0]
elif loc is None :
m[n] = "%s:%s" % (path, n+1)
else :
m[n] = loc
return m
def run (gopath, binpath=None, outpath=None) :
if binpath is None :
binpath = os.path.splitext(gopath)[0]
if outpath is None :
outpath = binpath + ".out"
if os.system("go build %s" % gopath) != 0 :
try :
subprocess.check_output(["go", "build", gopath], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as err :
tr = getlmap(gopath)
out = err.output.decode()
for line in out.splitlines() :
try :
path, lineno, message = line.split(":", 2)
if path.endswith(gopath) :
print("%s:%s" % (tr[int(lineno)], message))
else :
print(line)
except ValueError :
print(line)
sys.exit()
if os.system("%s > %s" % (os.path.join("./", binpath), outpath)) != 0 :
sys.exit()
......@@ -142,14 +172,17 @@ if __name__ == "__main__" :
sys.exit(1)
if not gofile.endswith(".go") :
gofile += ".go"
packages, imports, tests = set(), set(), []
packages, declare, imports, tests = set(), [], set(), []
for path in walk(root) :
p, i, t = extract(root, path)
p, d, i, t = extract(root, path)
packages.add(p)
declare.extend(d)
imports.update(i)
tests.extend(t)
codegen(packages, imports, tests, open(gofile, "w"))
codegen(packages, declare, imports, tests, open(gofile, "w"))
print("= %s tests" % len(tests))
output = run(gofile)
failed = check(tests, output)
if failed :
print()
print("= %s tests failed (out of %s)" % (failed, len(tests)))
......
......@@ -23,7 +23,7 @@ func max (init int, values ...int) int {
return m
}
func inc (v interface{}, n int) (interface{}, int) {
func inc (v interface{}, n uint64) (interface{}, uint64) {
return v.(int)+1, n
}
......