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/treebidimap_test.go b/maps/treebidimap/treebidimap_test.go index bc7f4fa..686b578 100644 --- a/maps/treebidimap/treebidimap_test.go +++ b/maps/treebidimap/treebidimap_test.go @@ -473,7 +473,6 @@ func TestMapIteratorLast(t *testing.T) { } } -//noinspection GoBoolExpressions func TestMapSerialization(t *testing.T) { for i := 0; i < 10; i++ { original := NewWith(utils.StringComparator, utils.StringComparator) @@ -483,42 +482,43 @@ func TestMapSerialization(t *testing.T) { original.Put("b", "2") original.Put("a", "1") - assert := func(m *Map, txt string) { - 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) - } - } - - assert(original, "A") + assertSerialization(original, "A", t) serialized, err := original.ToJSON() if err != nil { t.Errorf("Got error %v", err) } - assert(original, "B") + assertSerialization(original, "B", t) deserialized := NewWith(utils.StringComparator, utils.StringComparator) err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) } - assert(deserialized, "C") + assertSerialization(deserialized, "C", t) + } +} + +//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) } } diff --git a/maps/treemap/treemap_test.go b/maps/treemap/treemap_test.go index d718c91..bb054b3 100644 --- a/maps/treemap/treemap_test.go +++ b/maps/treemap/treemap_test.go @@ -440,7 +440,6 @@ func TestMapIteratorLast(t *testing.T) { } } -//noinspection GoBoolExpressions func TestMapSerialization(t *testing.T) { for i := 0; i < 10; i++ { original := NewWithStringComparator() @@ -450,42 +449,43 @@ func TestMapSerialization(t *testing.T) { original.Put("b", "2") original.Put("a", "1") - assert := func(m *Map, txt string) { - 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) - } - } - - assert(original, "A") + assertSerialization(original, "A", t) serialized, err := original.ToJSON() if err != nil { t.Errorf("Got error %v", err) } - assert(original, "B") + assertSerialization(original, "B", t) deserialized := NewWithStringComparator() err = deserialized.FromJSON(serialized) if err != nil { t.Errorf("Got error %v", err) } - assert(deserialized, "C") + assertSerialization(deserialized, "C", t) + } +} + +//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) } }