mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-11 15:30:07 +00:00
c6cd0e0c21
1) Added new file map.go, map_test.go 2) Added Map, Hash Method to Item interface 3) Implemented Hash Method for every stack items (Boolean, Array, Int, ...)
166 lines
3.4 KiB
Go
166 lines
3.4 KiB
Go
package stack
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"sort"
|
|
|
|
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
|
)
|
|
|
|
// Map represents a map of key, value pair on the stack.
|
|
// Both key and value are stack Items.
|
|
type Map struct {
|
|
*abstractItem
|
|
val map[Item]Item
|
|
}
|
|
|
|
// NewMap returns a Map stack Item given
|
|
// a map whose keys and values are stack Items.
|
|
func NewMap(val map[Item]Item) (*Map, error) {
|
|
return &Map{
|
|
abstractItem: &abstractItem{},
|
|
val: val,
|
|
}, nil
|
|
}
|
|
|
|
// Map will overwrite the default implementation
|
|
// to allow go to cast this item as an Map.
|
|
func (m *Map) Map() (*Map, error) {
|
|
return m, nil
|
|
}
|
|
|
|
// Boolean overrides the default Boolean method
|
|
// to convert an Map into a Boolean StackItem
|
|
func (m *Map) Boolean() (*Boolean, error) {
|
|
return NewBoolean(true), nil
|
|
}
|
|
|
|
// ContainsKey returns a boolean whose value is true
|
|
// iff the underlying map value contains the Item i
|
|
// as a key.
|
|
func (m *Map) ContainsKey(key Item) (*Boolean, error) {
|
|
for k := range m.Value() {
|
|
if ok, err := CompareHash(k, key); err != nil {
|
|
return nil, err
|
|
} else if ok.Value() == true {
|
|
return ok, nil
|
|
}
|
|
|
|
}
|
|
return NewBoolean(false), nil
|
|
}
|
|
|
|
// Value returns the underlying map's value
|
|
func (m *Map) Value() map[Item]Item {
|
|
return m.val
|
|
}
|
|
|
|
// Remove removes the Item i from the
|
|
// underlying map's value.
|
|
func (m *Map) Remove(key Item) error {
|
|
var d Item
|
|
for k := range m.Value() {
|
|
if ok, err := CompareHash(k, key); err != nil {
|
|
return err
|
|
} else if ok.Value() == true {
|
|
d = k
|
|
}
|
|
|
|
}
|
|
if d != nil {
|
|
delete(m.Value(), d)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Add inserts a new key, value pair of Items into
|
|
// the underlying map's value.
|
|
func (m *Map) Add(key Item, value Item) error {
|
|
for k := range m.Value() {
|
|
if ok, err := CompareHash(k, key); err != nil {
|
|
return err
|
|
} else if ok.Value() == true {
|
|
return errors.New("try to insert duplicate key! ")
|
|
}
|
|
}
|
|
m.Value()[key] = value
|
|
return nil
|
|
}
|
|
|
|
// ValueOfKey tries to get the value of the key Item
|
|
// from the map's underlying value.
|
|
func (m *Map) ValueOfKey(key Item) (Item, error) {
|
|
for k, v := range m.Value() {
|
|
if ok, err := CompareHash(k, key); err != nil {
|
|
return nil, err
|
|
} else if ok.Value() == true {
|
|
return v, nil
|
|
}
|
|
|
|
}
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
// Clear empties the the underlying map's value.
|
|
func (m *Map) Clear() {
|
|
m.val = map[Item]Item{}
|
|
}
|
|
|
|
// CompareHash compare the the Hashes of two items.
|
|
// If they are equal it returns a true boolean. Otherwise
|
|
// it returns false boolean. Item whose hashes are equal are
|
|
// to be considered equal.
|
|
func CompareHash(i1 Item, i2 Item) (*Boolean, error) {
|
|
hash1, err := i1.Hash()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
hash2, err := i2.Hash()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if hash1 == hash2 {
|
|
return NewBoolean(true), nil
|
|
}
|
|
|
|
return NewBoolean(false), nil
|
|
}
|
|
|
|
// Hash overrides the default abstract hash method.
|
|
func (m *Map) Hash() (string, error) {
|
|
var hashSlice sort.StringSlice = []string{}
|
|
var data = fmt.Sprintf("%T ", m)
|
|
|
|
for k, v := range m.Value() {
|
|
hk, err := k.Hash()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
hv, err := v.Hash()
|
|
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
hashSlice = append(hashSlice, hk)
|
|
hashSlice = append(hashSlice, hv)
|
|
}
|
|
hashSlice.Sort()
|
|
|
|
for _, h := range hashSlice {
|
|
data += h
|
|
}
|
|
|
|
return KeyGenerator([]byte(data))
|
|
}
|
|
|
|
// KeyGenerator hashes a byte slice to obtain a unique identifier.
|
|
func KeyGenerator(data []byte) (string, error) {
|
|
h, err := hash.Sha256([]byte(data))
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return h.String(), nil
|
|
}
|