diff --git a/README.md b/README.md index 9c1dd32..79f1a23 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Implementation of various data structures and algorithms in Go. - [Maps](#maps) - [HashMap](#hashmap) - [TreeMap](#treemap) + - [LinkedHashMap](#linkedhashmap) - [HashBidiMap](#hashbidimap) - [TreeBidiMap](#treebidimap) - [Trees](#trees) @@ -63,23 +64,24 @@ Containers are either ordered or unordered. All ordered containers provide [stat | **Data** | **Structure** | **Ordered** | **[Iterator](#iterator)** | **[Enumerable](#enumerable)** | **Referenced by** | | :--- | :--- | :---: | :---: | :---: | :---: | -| **[Lists](#lists)** | +| [Lists](#lists) | | | [ArrayList](#arraylist) | yes | yes* | yes | index | | | [SinglyLinkedList](#singlylinkedlist) | yes | yes | yes | index | | | [DoublyLinkedList](#doublylinkedlist) | yes | yes* | yes | index | -| **[Sets](#sets)** | +| [Sets](#sets) | | | [HashSet](#hashset) | no | no | no | index | | | [TreeSet](#treeset) | yes | yes* | yes | index | | | [LinkedHashSet](#linkedhashset) | yes | yes* | yes | index | -| **[Stacks](#stacks)** | +| [Stacks](#stacks) | | | [LinkedListStack](#linkedliststack) | yes | yes | no | index | | | [ArrayStack](#arraystack) | yes | yes* | no | index | -| **[Maps](#maps)** | +| [Maps](#maps) | | | [HashMap](#hashmap) | no | no | no | key | | | [TreeMap](#treemap) | yes | yes* | yes | key | +| | [LinkedHashMap](#linkedhashmap) | yes | yes* | yes | key | | | [HashBidiMap](#hashbidimap) | no | no | no | key* | -| **[Trees](#trees)** | | | [TreeBidiMap](#treebidimap) | yes | yes* | yes | key* | +| [Trees](#trees) | | | [RedBlackTree](#redblacktree) | yes | yes* | no | key | | | [AVLTree](#avltree) | yes | yes* | no | key | | | [BTree](#btree) | yes | yes* | no | key | @@ -487,6 +489,34 @@ func main() { } ``` +#### LinkedHashMap + +A [map](#maps) that preserves insertion-order. It is backed by a hash table to store values and [doubly-linked list](doublylinkedlist) to store ordering. + +Implements [Map](#maps), [IteratorWithKey](#iteratorwithkey), [EnumerableWithKey](#enumerablewithkey), [JSONSerializer](#jsonserializer) and [JSONDeserializer](#jsondeserializer) interfaces. + +```go +package main + +import "github.com/emirpasic/gods/maps/linkedhashmap" + +func main() { + m := linkedhashmap.New() // empty (keys are of type int) + m.Put(2, "b") // 2->b + m.Put(1, "x") // 2->b, 1->x (insertion-order) + m.Put(1, "a") // 2->b, 1->a (insertion-order) + _, _ = m.Get(2) // b, true + _, _ = m.Get(3) // nil, false + _ = m.Values() // []interface {}{"b", "a"} (insertion-order) + _ = m.Keys() // []interface {}{2, 1} (insertion-order) + m.Remove(1) // 2->b + m.Clear() // empty + m.Empty() // true + m.Size() // 0 +} + +``` + #### HashBidiMap A [map](#maps) based on two hashmaps. Keys are unordered. diff --git a/examples/linkedhashmap/linkedhashmap.go b/examples/linkedhashmap/linkedhashmap.go new file mode 100644 index 0000000..6443481 --- /dev/null +++ b/examples/linkedhashmap/linkedhashmap.go @@ -0,0 +1,23 @@ +// Copyright (c) 2015, Emir Pasic. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import "github.com/emirpasic/gods/maps/linkedhashmap" + +// LinkedHashMapExample to demonstrate basic usage of LinkedHashMapExample +func main() { + m := linkedhashmap.New() // empty (keys are of type int) + m.Put(2, "b") // 2->b + m.Put(1, "x") // 2->b, 1->x (insertion-order) + m.Put(1, "a") // 2->b, 1->a (insertion-order) + _, _ = m.Get(2) // b, true + _, _ = m.Get(3) // nil, false + _ = m.Values() // []interface {}{"b", "a"} (insertion-order) + _ = m.Keys() // []interface {}{2, 1} (insertion-order) + m.Remove(1) // 2->b + m.Clear() // empty + m.Empty() // true + m.Size() // 0 +} diff --git a/maps/hashbidimap/serialization.go b/maps/hashbidimap/serialization.go index 9f6247e..3db41d4 100644 --- a/maps/hashbidimap/serialization.go +++ b/maps/hashbidimap/serialization.go @@ -14,12 +14,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Map)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the map. func (m *Map) ToJSON() ([]byte, error) { return m.forwardMap.ToJSON() } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the map from the input JSON representation. func (m *Map) FromJSON(data []byte) error { elements := make(map[string]interface{}) err := json.Unmarshal(data, &elements) diff --git a/maps/hashmap/serialization.go b/maps/hashmap/serialization.go index b8e9026..b06eb7e 100644 --- a/maps/hashmap/serialization.go +++ b/maps/hashmap/serialization.go @@ -15,7 +15,7 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Map)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the map. func (m *Map) ToJSON() ([]byte, error) { elements := make(map[string]interface{}) for key, value := range m.m { @@ -24,7 +24,7 @@ func (m *Map) ToJSON() ([]byte, error) { return json.Marshal(&elements) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the map from the input JSON representation. func (m *Map) FromJSON(data []byte) error { elements := make(map[string]interface{}) err := json.Unmarshal(data, &elements) diff --git a/maps/linkedhashmap/enumerable.go b/maps/linkedhashmap/enumerable.go new file mode 100644 index 0000000..644b00f --- /dev/null +++ b/maps/linkedhashmap/enumerable.go @@ -0,0 +1,80 @@ +// Copyright (c) 2015, Emir Pasic. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package linkedhashmap + +import "github.com/emirpasic/gods/containers" + +func assertEnumerableImplementation() { + var _ containers.EnumerableWithKey = (*Map)(nil) +} + +// Each calls the given function once for each element, passing that element's key and value. +func (m *Map) Each(f func(key interface{}, value interface{})) { + iterator := m.Iterator() + for iterator.Next() { + f(iterator.Key(), iterator.Value()) + } +} + +// Map invokes the given function once for each element and returns a container +// containing the values returned by the given function as key/value pairs. +func (m *Map) Map(f func(key1 interface{}, value1 interface{}) (interface{}, interface{})) *Map { + newMap := New() + iterator := m.Iterator() + for iterator.Next() { + key2, value2 := f(iterator.Key(), iterator.Value()) + newMap.Put(key2, value2) + } + return newMap +} + +// Select returns a new container containing all elements for which the given function returns a true value. +func (m *Map) Select(f func(key interface{}, value interface{}) bool) *Map { + newMap := New() + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), iterator.Value()) { + newMap.Put(iterator.Key(), iterator.Value()) + } + } + return newMap +} + +// Any passes each element of the container to the given function and +// returns true if the function ever returns true for any element. +func (m *Map) Any(f func(key interface{}, value interface{}) bool) bool { + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), iterator.Value()) { + return true + } + } + return false +} + +// All passes each element of the container to the given function and +// returns true if the function returns true for all elements. +func (m *Map) All(f func(key interface{}, value interface{}) bool) bool { + iterator := m.Iterator() + for iterator.Next() { + if !f(iterator.Key(), iterator.Value()) { + return false + } + } + return true +} + +// Find passes each element of the container to the given function and returns +// the first (key,value) for which the function is true or nil,nil otherwise if no element +// matches the criteria. +func (m *Map) Find(f func(key interface{}, value interface{}) bool) (interface{}, interface{}) { + iterator := m.Iterator() + for iterator.Next() { + if f(iterator.Key(), iterator.Value()) { + return iterator.Key(), iterator.Value() + } + } + return nil, nil +} diff --git a/maps/linkedhashmap/iterator.go b/maps/linkedhashmap/iterator.go new file mode 100644 index 0000000..d846efc --- /dev/null +++ b/maps/linkedhashmap/iterator.go @@ -0,0 +1,81 @@ +// Copyright (c) 2015, Emir Pasic. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package linkedhashmap + +import ( + "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/lists/doublylinkedlist" +) + +func assertIteratorImplementation() { + var _ containers.ReverseIteratorWithKey = (*Iterator)(nil) +} + +// Iterator holding the iterator's state +type Iterator struct { + iterator doublylinkedlist.Iterator + table map[interface{}]interface{} +} + +// Iterator returns a stateful iterator whose elements are key/value pairs. +func (m *Map) Iterator() Iterator { + return Iterator{ + iterator: m.ordering.Iterator(), + table: m.table} +} + +// Next moves the iterator to the next element and returns true if there was a next element in the container. +// If Next() returns true, then next element's key and value can be retrieved by Key() and Value(). +// If Next() was called for the first time, then it will point the iterator to the first element if it exists. +// Modifies the state of the iterator. +func (iterator *Iterator) Next() bool { + return iterator.iterator.Next() +} + +// Prev moves the iterator to the previous element and returns true if there was a previous element in the container. +// If Prev() returns true, then previous element's key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Prev() bool { + return iterator.iterator.Prev() +} + +// Value returns the current element's value. +// Does not modify the state of the iterator. +func (iterator *Iterator) Value() interface{} { + key := iterator.iterator.Value() + return iterator.table[key] +} + +// Key returns the current element's key. +// Does not modify the state of the iterator. +func (iterator *Iterator) Key() interface{} { + return iterator.iterator.Value() +} + +// Begin resets the iterator to its initial state (one-before-first) +// Call Next() to fetch the first element if any. +func (iterator *Iterator) Begin() { + iterator.iterator.Begin() +} + +// End moves the iterator past the last element (one-past-the-end). +// Call Prev() to fetch the last element if any. +func (iterator *Iterator) End() { + iterator.iterator.End() +} + +// First moves the iterator to the first element and returns true if there was a first element in the container. +// If First() returns true, then first element's key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator +func (iterator *Iterator) First() bool { + return iterator.iterator.First() +} + +// Last moves the iterator to the last element and returns true if there was a last element in the container. +// If Last() returns true, then last element's key and value can be retrieved by Key() and Value(). +// Modifies the state of the iterator. +func (iterator *Iterator) Last() bool { + return iterator.iterator.Last() +} diff --git a/maps/linkedhashmap/linkedhashmap.go b/maps/linkedhashmap/linkedhashmap.go new file mode 100644 index 0000000..02e2391 --- /dev/null +++ b/maps/linkedhashmap/linkedhashmap.go @@ -0,0 +1,109 @@ +// Copyright (c) 2015, Emir Pasic. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package linkedhashmap is a map that preserves insertion-order. +// +// It is backed by a hash table to store values and doubly-linked list to store ordering. +// +// Structure is not thread safe. +// +// Reference: http://en.wikipedia.org/wiki/Associative_array +package linkedhashmap + +import ( + "fmt" + "github.com/emirpasic/gods/lists/doublylinkedlist" + "github.com/emirpasic/gods/maps" + "strings" +) + +func assertMapImplementation() { + var _ maps.Map = (*Map)(nil) +} + +// Map holds the elements in a red-black tree +type Map struct { + table map[interface{}]interface{} + ordering *doublylinkedlist.List +} + +// New instantiates a linked-hash-map. +func New() *Map { + return &Map{ + table: make(map[interface{}]interface{}), + ordering: doublylinkedlist.New(), + } +} + +// Put inserts key-value pair into the map. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (m *Map) Put(key interface{}, value interface{}) { + if _, contains := m.table[key]; !contains { + m.ordering.Append(key) + } + m.table[key] = value +} + +// Get searches the element in the map by key and returns its value or nil if key is not found in tree. +// Second return parameter is true if key was found, otherwise false. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (m *Map) Get(key interface{}) (value interface{}, found bool) { + value = m.table[key] + found = value != nil + return +} + +// Remove removes the element from the map by key. +// Key should adhere to the comparator's type assertion, otherwise method panics. +func (m *Map) Remove(key interface{}) { + if _, contains := m.table[key]; contains { + delete(m.table, key) + index := m.ordering.IndexOf(key) + m.ordering.Remove(index) + } +} + +// Empty returns true if map does not contain any elements +func (m *Map) Empty() bool { + return m.Size() == 0 +} + +// Size returns number of elements in the map. +func (m *Map) Size() int { + return m.ordering.Size() +} + +// Keys returns all keys in-order +func (m *Map) Keys() []interface{} { + return m.ordering.Values() +} + +// Values returns all values in-order based on the key. +func (m *Map) Values() []interface{} { + values := make([]interface{}, m.Size()) + count := 0 + it := m.Iterator() + for it.Next() { + values[count] = it.Value() + count++ + } + return values +} + +// Clear removes all elements from the map. +func (m *Map) Clear() { + m.table = make(map[interface{}]interface{}) + m.ordering.Clear() +} + +// String returns a string representation of container +func (m *Map) String() string { + str := "LinkedHashMap\nmap[" + it := m.Iterator() + for it.Next() { + str += fmt.Sprintf("%v:%v ", it.Key(), it.Value()) + } + return strings.TrimRight(str, " ") + "]" + +} diff --git a/maps/linkedhashmap/linkedhashmap_test.go b/maps/linkedhashmap/linkedhashmap_test.go new file mode 100644 index 0000000..78437f1 --- /dev/null +++ b/maps/linkedhashmap/linkedhashmap_test.go @@ -0,0 +1,643 @@ +// Copyright (c) 2015, Emir Pasic. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package linkedhashmap + +import ( + "fmt" + "testing" +) + +func TestMapPut(t *testing.T) { + m := New() + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite + + if actualValue := m.Size(); actualValue != 7 { + t.Errorf("Got %v expected %v", actualValue, 7) + } + if actualValue, expectedValue := m.Keys(), []interface{}{5, 6, 7, 3, 4, 1, 2}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := m.Values(), []interface{}{"e", "f", "g", "c", "d", "a", "b"}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + // key,expectedValue,expectedFound + tests1 := [][]interface{}{ + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, "e", true}, + {6, "f", true}, + {7, "g", true}, + {8, nil, false}, + } + + for _, test := range tests1 { + // retrievals + actualValue, actualFound := m.Get(test[0]) + if actualValue != test[1] || actualFound != test[2] { + t.Errorf("Got %v expected %v", actualValue, test[1]) + } + } +} + +func TestMapRemove(t *testing.T) { + m := New() + m.Put(5, "e") + m.Put(6, "f") + m.Put(7, "g") + m.Put(3, "c") + m.Put(4, "d") + m.Put(1, "x") + m.Put(2, "b") + m.Put(1, "a") //overwrite + + m.Remove(5) + m.Remove(6) + m.Remove(7) + m.Remove(8) + m.Remove(5) + + if actualValue, expectedValue := m.Keys(), []interface{}{3, 4, 1, 2}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + + if actualValue, expectedValue := m.Values(), []interface{}{"c", "d", "a", "b"}; !sameElements(actualValue, expectedValue) { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := m.Size(); actualValue != 4 { + t.Errorf("Got %v expected %v", actualValue, 4) + } + + tests2 := [][]interface{}{ + {1, "a", true}, + {2, "b", true}, + {3, "c", true}, + {4, "d", true}, + {5, nil, false}, + {6, nil, false}, + {7, nil, false}, + {8, nil, false}, + } + + for _, test := range tests2 { + actualValue, actualFound := m.Get(test[0]) + if actualValue != test[1] || actualFound != test[2] { + t.Errorf("Got %v expected %v", actualValue, test[1]) + } + } + + m.Remove(1) + m.Remove(4) + m.Remove(2) + m.Remove(3) + m.Remove(2) + m.Remove(2) + + if actualValue, expectedValue := fmt.Sprintf("%s", m.Keys()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue, expectedValue := fmt.Sprintf("%s", m.Values()), "[]"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if actualValue := m.Size(); actualValue != 0 { + t.Errorf("Got %v expected %v", actualValue, 0) + } + if actualValue := m.Empty(); actualValue != true { + t.Errorf("Got %v expected %v", actualValue, true) + } +} + +func sameElements(a []interface{}, b []interface{}) bool { + // If one is nil, the other must also be nil. + if (a == nil) != (b == nil) { + return false + } + + if len(a) != len(b) { + return false + } + + for i := range a { + if a[i] != b[i] { + return false + } + } + + return true +} + +func TestMapEach(t *testing.T) { + m := New() + m.Put("c", 1) + m.Put("a", 2) + m.Put("b", 3) + count := 0 + m.Each(func(key interface{}, value interface{}) { + count++ + if actualValue, expectedValue := count, value; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + switch value { + case 1: + if actualValue, expectedValue := key, "c"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 2: + if actualValue, expectedValue := key, "a"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case 3: + if actualValue, expectedValue := key, "b"; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + }) +} + +func TestMapMap(t *testing.T) { + m := New() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + mappedMap := m.Map(func(key1 interface{}, value1 interface{}) (key2 interface{}, value2 interface{}) { + return key1, value1.(int) * value1.(int) + }) + if actualValue, _ := mappedMap.Get("c"); actualValue != 9 { + t.Errorf("Got %v expected %v", actualValue, "mapped: c") + } + if actualValue, _ := mappedMap.Get("a"); actualValue != 1 { + t.Errorf("Got %v expected %v", actualValue, "mapped: a") + } + if actualValue, _ := mappedMap.Get("b"); actualValue != 4 { + t.Errorf("Got %v expected %v", actualValue, "mapped: b") + } + if mappedMap.Size() != 3 { + t.Errorf("Got %v expected %v", mappedMap.Size(), 3) + } +} + +func TestMapSelect(t *testing.T) { + m := New() + m.Put("c", 3) + m.Put("b", 1) + m.Put("a", 2) + selectedMap := m.Select(func(key interface{}, value interface{}) bool { + return key.(string) >= "a" && key.(string) <= "b" + }) + if actualValue, _ := selectedMap.Get("b"); actualValue != 1 { + t.Errorf("Got %v expected %v", actualValue, "value: a") + } + if actualValue, _ := selectedMap.Get("a"); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, "value: b") + } + if selectedMap.Size() != 2 { + t.Errorf("Got %v expected %v", selectedMap.Size(), 2) + } +} + +func TestMapAny(t *testing.T) { + m := New() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + any := m.Any(func(key interface{}, value interface{}) bool { + return value.(int) == 3 + }) + if any != true { + t.Errorf("Got %v expected %v", any, true) + } + any = m.Any(func(key interface{}, value interface{}) bool { + return value.(int) == 4 + }) + if any != false { + t.Errorf("Got %v expected %v", any, false) + } +} + +func TestMapAll(t *testing.T) { + m := New() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + all := m.All(func(key interface{}, value interface{}) bool { + return key.(string) >= "a" && key.(string) <= "c" + }) + if all != true { + t.Errorf("Got %v expected %v", all, true) + } + all = m.All(func(key interface{}, value interface{}) bool { + return key.(string) >= "a" && key.(string) <= "b" + }) + if all != false { + t.Errorf("Got %v expected %v", all, false) + } +} + +func TestMapFind(t *testing.T) { + m := New() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + foundKey, foundValue := m.Find(func(key interface{}, value interface{}) bool { + return key.(string) == "c" + }) + if foundKey != "c" || foundValue != 3 { + t.Errorf("Got %v -> %v expected %v -> %v", foundKey, foundValue, "c", 3) + } + foundKey, foundValue = m.Find(func(key interface{}, value interface{}) bool { + return key.(string) == "x" + }) + if foundKey != nil || foundValue != nil { + t.Errorf("Got %v at %v expected %v at %v", foundValue, foundKey, nil, nil) + } +} + +func TestMapChaining(t *testing.T) { + m := New() + m.Put("c", 3) + m.Put("a", 1) + m.Put("b", 2) + chainedMap := m.Select(func(key interface{}, value interface{}) bool { + return value.(int) > 1 + }).Map(func(key interface{}, value interface{}) (interface{}, interface{}) { + return key.(string) + key.(string), value.(int) * value.(int) + }) + if actualValue := chainedMap.Size(); actualValue != 2 { + t.Errorf("Got %v expected %v", actualValue, 2) + } + if actualValue, found := chainedMap.Get("aa"); actualValue != nil || found { + t.Errorf("Got %v expected %v", actualValue, nil) + } + if actualValue, found := chainedMap.Get("bb"); actualValue != 4 || !found { + t.Errorf("Got %v expected %v", actualValue, 4) + } + if actualValue, found := chainedMap.Get("cc"); actualValue != 9 || !found { + t.Errorf("Got %v expected %v", actualValue, 9) + } +} + +func TestMapIteratorNextOnEmpty(t *testing.T) { + m := New() + it := m.Iterator() + it = m.Iterator() + for it.Next() { + t.Errorf("Shouldn't iterate on empty map") + } +} + +func TestMapIteratorPrevOnEmpty(t *testing.T) { + m := New() + it := m.Iterator() + it = m.Iterator() + for it.Prev() { + t.Errorf("Shouldn't iterate on empty map") + } +} + +func TestMapIteratorNext(t *testing.T) { + m := New() + m.Put("c", 1) + m.Put("a", 2) + m.Put("b", 3) + + it := m.Iterator() + count := 0 + for it.Next() { + count++ + key := it.Key() + value := it.Value() + switch key { + case "c": + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "a": + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "b": + if actualValue, expectedValue := value, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := value, count; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + } + if actualValue, expectedValue := count, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestMapIteratorPrev(t *testing.T) { + m := New() + m.Put("c", 1) + m.Put("a", 2) + m.Put("b", 3) + + it := m.Iterator() + for it.Next() { + } + countDown := m.Size() + for it.Prev() { + key := it.Key() + value := it.Value() + switch key { + case "c": + if actualValue, expectedValue := value, 1; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "a": + if actualValue, expectedValue := value, 2; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + case "b": + if actualValue, expectedValue := value, 3; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + default: + t.Errorf("Too many") + } + if actualValue, expectedValue := value, countDown; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + countDown-- + } + if actualValue, expectedValue := countDown, 0; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } +} + +func TestMapIteratorBegin(t *testing.T) { + m := New() + it := m.Iterator() + it.Begin() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + for it.Next() { + } + it.Begin() + it.Next() + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + +func TestMapTreeIteratorEnd(t *testing.T) { + m := New() + it := m.Iterator() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it.End() + it.Prev() + if key, value := it.Key(), it.Value(); key != 2 || value != "b" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 2, "b") + } +} + +func TestMapIteratorFirst(t *testing.T) { + m := New() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it := m.Iterator() + if actualValue, expectedValue := it.First(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 3 || value != "c" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 3, "c") + } +} + +func TestMapIteratorLast(t *testing.T) { + m := New() + m.Put(3, "c") + m.Put(1, "a") + m.Put(2, "b") + it := m.Iterator() + if actualValue, expectedValue := it.Last(), true; actualValue != expectedValue { + t.Errorf("Got %v expected %v", actualValue, expectedValue) + } + if key, value := it.Key(), it.Value(); key != 2 || value != "b" { + t.Errorf("Got %v,%v expected %v,%v", key, value, 2, "b") + } +} + +func TestMapSerialization(t *testing.T) { + for i := 0; i < 10; i++ { + original := New() + original.Put("d", "4") + original.Put("e", "5") + original.Put("c", "3") + original.Put("b", "2") + original.Put("a", "1") + + assertSerialization(original, "A", t) + + serialized, err := original.ToJSON() + if err != nil { + t.Errorf("Got error %v", err) + } + assertSerialization(original, "B", t) + + deserialized := New() + err = deserialized.FromJSON(serialized) + if err != nil { + t.Errorf("Got error %v", err) + } + assertSerialization(deserialized, "C", t) + } +} + +//noinspection GoBoolExpressions +func assertSerialization(m *Map, txt string, t *testing.T) { + if actualValue := m.Keys(); false || + actualValue[0].(string) != "d" || + actualValue[1].(string) != "e" || + actualValue[2].(string) != "c" || + actualValue[3].(string) != "b" || + actualValue[4].(string) != "a" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[d,e,c,b,a]") + } + if actualValue := m.Values(); false || + actualValue[0].(string) != "4" || + actualValue[1].(string) != "5" || + actualValue[2].(string) != "3" || + actualValue[3].(string) != "2" || + actualValue[4].(string) != "1" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[4,5,3,2,1]") + } + if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue) + } +} + +func benchmarkGet(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + m.Get(n) + } + } +} + +func benchmarkPut(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + } +} + +func benchmarkRemove(b *testing.B, m *Map, size int) { + for i := 0; i < b.N; i++ { + for n := 0; n < size; n++ { + m.Remove(n) + } + } +} + +func BenchmarkTreeMapGet100(b *testing.B) { + b.StopTimer() + size := 100 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeMapGet1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeMapGet10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeMapGet100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkGet(b, m, size) +} + +func BenchmarkTreeMapPut100(b *testing.B) { + b.StopTimer() + size := 100 + m := New() + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeMapPut1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeMapPut10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeMapPut100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkPut(b, m, size) +} + +func BenchmarkTreeMapRemove100(b *testing.B) { + b.StopTimer() + size := 100 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkTreeMapRemove1000(b *testing.B) { + b.StopTimer() + size := 1000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkTreeMapRemove10000(b *testing.B) { + b.StopTimer() + size := 10000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} + +func BenchmarkTreeMapRemove100000(b *testing.B) { + b.StopTimer() + size := 100000 + m := New() + for n := 0; n < size; n++ { + m.Put(n, struct{}{}) + } + b.StartTimer() + benchmarkRemove(b, m, size) +} diff --git a/maps/linkedhashmap/serialization.go b/maps/linkedhashmap/serialization.go new file mode 100644 index 0000000..4f723cf --- /dev/null +++ b/maps/linkedhashmap/serialization.go @@ -0,0 +1,103 @@ +// Copyright (c) 2015, Emir Pasic. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package linkedhashmap + +import ( + "bytes" + "encoding/json" + "github.com/emirpasic/gods/containers" + "github.com/emirpasic/gods/utils" +) + +func assertSerializationImplementation() { + var _ containers.JSONSerializer = (*Map)(nil) + var _ containers.JSONDeserializer = (*Map)(nil) +} + +// ToJSON outputs the JSON representation of map. +func (m *Map) ToJSON() ([]byte, error) { + var b []byte + buf := bytes.NewBuffer(b) + + buf.WriteRune('{') + + it := m.Iterator() + lastIndex := m.Size() - 1 + index := 0 + + for it.Next() { + km, err := json.Marshal(it.Key()) + if err != nil { + return nil, err + } + buf.Write(km) + + buf.WriteRune(':') + + vm, err := json.Marshal(it.Value()) + if err != nil { + return nil, err + } + buf.Write(vm) + + if index != lastIndex { + buf.WriteRune(',') + } + + index++ + } + + buf.WriteRune('}') + + return buf.Bytes(), nil +} + +// FromJSON populates map from the input JSON representation. +//func (m *Map) FromJSON(data []byte) error { +// elements := make(map[string]interface{}) +// err := json.Unmarshal(data, &elements) +// if err == nil { +// m.Clear() +// for key, value := range elements { +// m.Put(key, value) +// } +// } +// return err +//} + +// FromJSON populates map from the input JSON representation. +func (m *Map) FromJSON(data []byte) error { + elements := make(map[string]interface{}) + err := json.Unmarshal(data, &elements) + if err != nil { + return err + } + + index := make(map[string]int) + var keys []interface{} + for key := range elements { + keys = append(keys, key) + esc, _ := json.Marshal(key) + index[key] = bytes.Index(data, esc) + } + + byIndex := func(a, b interface{}) int { + key1 := a.(string) + key2 := b.(string) + index1 := index[key1] + index2 := index[key2] + return index1 - index2 + } + + utils.Sort(keys, byIndex) + + m.Clear() + + for _, key := range keys { + m.Put(key, elements[key.(string)]) + } + + return nil +} diff --git a/maps/treebidimap/serialization.go b/maps/treebidimap/serialization.go index f9a7850..17204f9 100644 --- a/maps/treebidimap/serialization.go +++ b/maps/treebidimap/serialization.go @@ -15,7 +15,7 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Map)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the map. func (m *Map) ToJSON() ([]byte, error) { elements := make(map[string]interface{}) it := m.Iterator() @@ -25,7 +25,7 @@ func (m *Map) ToJSON() ([]byte, error) { return json.Marshal(&elements) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the map from the input JSON representation. func (m *Map) FromJSON(data []byte) error { elements := make(map[string]interface{}) err := json.Unmarshal(data, &elements) diff --git a/maps/treebidimap/treebidimap_test.go b/maps/treebidimap/treebidimap_test.go index 0ef5165..686b578 100644 --- a/maps/treebidimap/treebidimap_test.go +++ b/maps/treebidimap/treebidimap_test.go @@ -474,34 +474,52 @@ func TestMapIteratorLast(t *testing.T) { } func TestMapSerialization(t *testing.T) { - m := NewWithStringComparators() - m.Put("a", "1") - m.Put("b", "2") - m.Put("c", "3") - - var err error - assert := func() { - if actualValue := m.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { - t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") - } - if actualValue := m.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" { - t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") - } - if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) + for i := 0; i < 10; i++ { + original := NewWith(utils.StringComparator, utils.StringComparator) + original.Put("d", "4") + original.Put("e", "5") + original.Put("c", "3") + original.Put("b", "2") + original.Put("a", "1") + + assertSerialization(original, "A", t) + + serialized, err := original.ToJSON() + if err != nil { + t.Errorf("Got error %v", err) } + assertSerialization(original, "B", t) + + deserialized := NewWith(utils.StringComparator, utils.StringComparator) + err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) } + assertSerialization(deserialized, "C", t) } +} - assert() - - json, err := m.ToJSON() - assert() - - err = m.FromJSON(json) - assert() +//noinspection GoBoolExpressions +func assertSerialization(m *Map, txt string, t *testing.T) { + if actualValue := m.Keys(); false || + actualValue[0].(string) != "a" || + actualValue[1].(string) != "b" || + actualValue[2].(string) != "c" || + actualValue[3].(string) != "d" || + actualValue[4].(string) != "e" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]") + } + if actualValue := m.Values(); false || + actualValue[0].(string) != "1" || + actualValue[1].(string) != "2" || + actualValue[2].(string) != "3" || + actualValue[3].(string) != "4" || + actualValue[4].(string) != "5" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]") + } + if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue) + } } func benchmarkGet(b *testing.B, m *Map, size int) { diff --git a/maps/treemap/serialization.go b/maps/treemap/serialization.go index 25f4a6f..d856300 100644 --- a/maps/treemap/serialization.go +++ b/maps/treemap/serialization.go @@ -11,12 +11,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Map)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the map. func (m *Map) ToJSON() ([]byte, error) { return m.tree.ToJSON() } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the map from the input JSON representation. func (m *Map) FromJSON(data []byte) error { return m.tree.FromJSON(data) } diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index a73e873..bb054b3 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -441,34 +441,52 @@ func TestMapIteratorLast(t *testing.T) { } func TestMapSerialization(t *testing.T) { - m := NewWithStringComparator() - m.Put("a", "1") - m.Put("b", "2") - m.Put("c", "3") - - var err error - assert := func() { - if actualValue := m.Keys(); actualValue[0].(string) != "a" || actualValue[1].(string) != "b" || actualValue[2].(string) != "c" { - t.Errorf("Got %v expected %v", actualValue, "[a,b,c]") - } - if actualValue := m.Values(); actualValue[0].(string) != "1" || actualValue[1].(string) != "2" || actualValue[2].(string) != "3" { - t.Errorf("Got %v expected %v", actualValue, "[1,2,3]") - } - if actualValue, expectedValue := m.Size(), 3; actualValue != expectedValue { - t.Errorf("Got %v expected %v", actualValue, expectedValue) + for i := 0; i < 10; i++ { + original := NewWithStringComparator() + original.Put("d", "4") + original.Put("e", "5") + original.Put("c", "3") + original.Put("b", "2") + original.Put("a", "1") + + assertSerialization(original, "A", t) + + serialized, err := original.ToJSON() + if err != nil { + t.Errorf("Got error %v", err) } + assertSerialization(original, "B", t) + + deserialized := NewWithStringComparator() + err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) } + assertSerialization(deserialized, "C", t) } +} - assert() - - json, err := m.ToJSON() - assert() - - err = m.FromJSON(json) - assert() +//noinspection GoBoolExpressions +func assertSerialization(m *Map, txt string, t *testing.T) { + if actualValue := m.Keys(); false || + actualValue[0].(string) != "a" || + actualValue[1].(string) != "b" || + actualValue[2].(string) != "c" || + actualValue[3].(string) != "d" || + actualValue[4].(string) != "e" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[a,b,c,d,e]") + } + if actualValue := m.Values(); false || + actualValue[0].(string) != "1" || + actualValue[1].(string) != "2" || + actualValue[2].(string) != "3" || + actualValue[3].(string) != "4" || + actualValue[4].(string) != "5" { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, "[1,2,3,4,5]") + } + if actualValue, expectedValue := m.Size(), 5; actualValue != expectedValue { + t.Errorf("[%s] Got %v expected %v", txt, actualValue, expectedValue) + } } func benchmarkGet(b *testing.B, m *Map, size int) { diff --git a/sets/hashset/serialization.go b/sets/hashset/serialization.go index af7bfe8..7b8506d 100644 --- a/sets/hashset/serialization.go +++ b/sets/hashset/serialization.go @@ -14,12 +14,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Set)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the set. func (set *Set) ToJSON() ([]byte, error) { return json.Marshal(set.Values()) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the set from the input JSON representation. func (set *Set) FromJSON(data []byte) error { elements := []interface{}{} err := json.Unmarshal(data, &elements) diff --git a/sets/linkedhashset/iterator.go b/sets/linkedhashset/iterator.go index dfdbfc5..3d190d9 100644 --- a/sets/linkedhashset/iterator.go +++ b/sets/linkedhashset/iterator.go @@ -20,7 +20,7 @@ type Iterator struct { // Iterator returns a stateful iterator whose values can be fetched by an index. func (set *Set) Iterator() Iterator { - return Iterator{iterator: set.list.Iterator()} + return Iterator{iterator: set.ordering.Iterator()} } // Next moves the iterator to the next element and returns true if there was a next element in the container. diff --git a/sets/linkedhashset/linkedhashset.go b/sets/linkedhashset/linkedhashset.go index 6bce5f6..e589a12 100644 --- a/sets/linkedhashset/linkedhashset.go +++ b/sets/linkedhashset/linkedhashset.go @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package linkedhashset implements a set that preserves insertion-order and is backed a hash tables to store values and doubly-linked list to store ordering. +// Package linkedhashset is a set that preserves insertion-order. +// +// It is backed by a hash table to store values and doubly-linked list to store ordering. // // Note that insertion-order is not affected if an element is re-inserted into the set. // @@ -24,8 +26,8 @@ func assertSetImplementation() { // Set holds elements in go's native map type Set struct { - items map[interface{}]struct{} - list *doublylinkedlist.List + table map[interface{}]struct{} + ordering *doublylinkedlist.List } var itemExists = struct{}{} @@ -33,8 +35,8 @@ var itemExists = struct{}{} // New instantiates a new empty set and adds the passed values, if any, to the set func New(values ...interface{}) *Set { set := &Set{ - items: make(map[interface{}]struct{}), - list: doublylinkedlist.New(), + table: make(map[interface{}]struct{}), + ordering: doublylinkedlist.New(), } if len(values) > 0 { set.Add(values...) @@ -46,13 +48,10 @@ func New(values ...interface{}) *Set { // Note that insertion-order is not affected if an element is re-inserted into the set. func (set *Set) Add(items ...interface{}) { for _, item := range items { - - if _, contains := set.items[item]; contains { - continue + if _, contains := set.table[item]; !contains { + set.table[item] = itemExists + set.ordering.Append(item) } - - set.items[item] = itemExists - set.list.Append(item) } } @@ -60,14 +59,11 @@ func (set *Set) Add(items ...interface{}) { // Slow operation, worst-case O(n^2). func (set *Set) Remove(items ...interface{}) { for _, item := range items { - - if _, contains := set.items[item]; !contains { - continue + if _, contains := set.table[item]; contains { + delete(set.table, item) + index := set.ordering.IndexOf(item) + set.ordering.Remove(index) } - - delete(set.items, item) - index := set.list.IndexOf(item) - set.list.Remove(index) } } @@ -76,7 +72,7 @@ func (set *Set) Remove(items ...interface{}) { // Returns true if no arguments are passed at all, i.e. set is always superset of empty set. func (set *Set) Contains(items ...interface{}) bool { for _, item := range items { - if _, contains := set.items[item]; !contains { + if _, contains := set.table[item]; !contains { return false } } @@ -90,13 +86,13 @@ func (set *Set) Empty() bool { // Size returns number of elements within the set. func (set *Set) Size() int { - return set.list.Size() + return set.ordering.Size() } // Clear clears all values in the set. func (set *Set) Clear() { - set.items = make(map[interface{}]struct{}) - set.list.Clear() + set.table = make(map[interface{}]struct{}) + set.ordering.Clear() } // Values returns all items in the set. diff --git a/sets/linkedhashset/serialization.go b/sets/linkedhashset/serialization.go index 806b908..7e7d291 100644 --- a/sets/linkedhashset/serialization.go +++ b/sets/linkedhashset/serialization.go @@ -14,12 +14,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Set)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the set. func (set *Set) ToJSON() ([]byte, error) { return json.Marshal(set.Values()) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the set from the input JSON representation. func (set *Set) FromJSON(data []byte) error { elements := []interface{}{} err := json.Unmarshal(data, &elements) diff --git a/sets/treeset/serialization.go b/sets/treeset/serialization.go index 10b1599..a53bfcc 100644 --- a/sets/treeset/serialization.go +++ b/sets/treeset/serialization.go @@ -14,12 +14,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Set)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the set. func (set *Set) ToJSON() ([]byte, error) { return json.Marshal(set.Values()) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the set from the input JSON representation. func (set *Set) FromJSON(data []byte) error { elements := []interface{}{} err := json.Unmarshal(data, &elements) diff --git a/stacks/arraystack/serialization.go b/stacks/arraystack/serialization.go index d1ad81d..c4ff549 100644 --- a/stacks/arraystack/serialization.go +++ b/stacks/arraystack/serialization.go @@ -11,12 +11,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Stack)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the stack. func (stack *Stack) ToJSON() ([]byte, error) { return stack.list.ToJSON() } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the stack from the input JSON representation. func (stack *Stack) FromJSON(data []byte) error { return stack.list.FromJSON(data) } diff --git a/stacks/linkedliststack/serialization.go b/stacks/linkedliststack/serialization.go index ac6a68c..63337a1 100644 --- a/stacks/linkedliststack/serialization.go +++ b/stacks/linkedliststack/serialization.go @@ -11,12 +11,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Stack)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the stack. func (stack *Stack) ToJSON() ([]byte, error) { return stack.list.ToJSON() } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the stack from the input JSON representation. func (stack *Stack) FromJSON(data []byte) error { return stack.list.FromJSON(data) } diff --git a/trees/avltree/serialization.go b/trees/avltree/serialization.go index 0630d87..363de7f 100644 --- a/trees/avltree/serialization.go +++ b/trees/avltree/serialization.go @@ -15,7 +15,7 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Tree)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the tree. func (tree *Tree) ToJSON() ([]byte, error) { elements := make(map[string]interface{}) it := tree.Iterator() @@ -25,7 +25,7 @@ func (tree *Tree) ToJSON() ([]byte, error) { return json.Marshal(&elements) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the tree from the input JSON representation. func (tree *Tree) FromJSON(data []byte) error { elements := make(map[string]interface{}) err := json.Unmarshal(data, &elements) diff --git a/trees/binaryheap/serialization.go b/trees/binaryheap/serialization.go index 299319b..00d0c77 100644 --- a/trees/binaryheap/serialization.go +++ b/trees/binaryheap/serialization.go @@ -11,12 +11,12 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Heap)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the heap. func (heap *Heap) ToJSON() ([]byte, error) { return heap.list.ToJSON() } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the heap from the input JSON representation. func (heap *Heap) FromJSON(data []byte) error { return heap.list.FromJSON(data) } diff --git a/trees/btree/serialization.go b/trees/btree/serialization.go index 95c817e..4385167 100644 --- a/trees/btree/serialization.go +++ b/trees/btree/serialization.go @@ -15,7 +15,7 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Tree)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the tree. func (tree *Tree) ToJSON() ([]byte, error) { elements := make(map[string]interface{}) it := tree.Iterator() @@ -25,7 +25,7 @@ func (tree *Tree) ToJSON() ([]byte, error) { return json.Marshal(&elements) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the tree from the input JSON representation. func (tree *Tree) FromJSON(data []byte) error { elements := make(map[string]interface{}) err := json.Unmarshal(data, &elements) diff --git a/trees/redblacktree/serialization.go b/trees/redblacktree/serialization.go index 7969fc5..a1b8a77 100644 --- a/trees/redblacktree/serialization.go +++ b/trees/redblacktree/serialization.go @@ -15,7 +15,7 @@ func assertSerializationImplementation() { var _ containers.JSONDeserializer = (*Tree)(nil) } -// ToJSON outputs the JSON representation of list's elements. +// ToJSON outputs the JSON representation of the tree. func (tree *Tree) ToJSON() ([]byte, error) { elements := make(map[string]interface{}) it := tree.Iterator() @@ -25,7 +25,7 @@ func (tree *Tree) ToJSON() ([]byte, error) { return json.Marshal(&elements) } -// FromJSON populates list's elements from the input JSON representation. +// FromJSON populates the tree from the input JSON representation. func (tree *Tree) FromJSON(data []byte) error { elements := make(map[string]interface{}) err := json.Unmarshal(data, &elements)