mirror of https://github.com/emirpasic/gods
commit
7aedbffbed
@ -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
|
||||
}
|
@ -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
|
||||
}
|
@ -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()
|
||||
}
|
@ -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, " ") + "]"
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue