| // 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" |
| ) |
| |
| // Assert Map implementation |
| var _ maps.Map = (*Map)(nil) |
| |
| // Map holds the elements in a regular hash table, and uses doubly-linked list to store key ordering. |
| 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, " ") + "]" |
| |
| } |