pull/211/merge
Eren Dursun 5 months ago committed by GitHub
commit 4ea6e403b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,4 +1,4 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Copyright (c) 2015, Emir Pasic & Eren Dursun. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@ -6,7 +6,6 @@ package linkedhashmap
import (
"github.com/emirpasic/gods/containers"
"github.com/emirpasic/gods/lists/doublylinkedlist"
)
// Assert Iterator implementation
@ -14,15 +13,17 @@ var _ containers.ReverseIteratorWithKey = (*Iterator)(nil)
// Iterator holding the iterator's state
type Iterator struct {
iterator doublylinkedlist.Iterator
table map[interface{}]interface{}
m *Map
index int
element *element
}
// 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}
m: m,
index: -1,
}
}
// Next moves the iterator to the next element and returns true if there was a next element in the container.
@ -30,53 +31,83 @@ func (m *Map) Iterator() Iterator {
// 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()
if iterator.index < iterator.m.Size() {
iterator.index++
}
if !iterator.m.withinRange(iterator.index) {
iterator.element = nil
return false
}
if iterator.index != 0 {
iterator.element = iterator.element.next
} else {
iterator.element = iterator.m.first
}
return true
}
// 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()
if iterator.index >= 0 {
iterator.index--
}
if !iterator.m.withinRange(iterator.index) {
iterator.element = nil
return false
}
if iterator.index == iterator.m.Size()-1 {
iterator.element = iterator.m.last
} else {
iterator.element = iterator.element.prev
}
return iterator.m.withinRange(iterator.index)
}
// 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]
if iterator.element != nil {
return iterator.element.value
}
return nil
}
// Key returns the current element's key.
// Does not modify the state of the iterator.
func (iterator *Iterator) Key() interface{} {
return iterator.iterator.Value()
return iterator.element.key
}
// 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()
iterator.index = -1
iterator.element = nil
}
// 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()
iterator.index = iterator.m.Size()
iterator.element = nil
}
// 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()
iterator.Begin()
return iterator.Next()
}
// 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()
iterator.End()
return iterator.Prev()
}
// NextTo moves the iterator to the next element from current position that satisfies the condition given by the
@ -106,3 +137,8 @@ func (iterator *Iterator) PrevTo(f func(key interface{}, value interface{}) bool
}
return false
}
// Check that the index is within bounds of the list
func (m *Map) withinRange(index int) bool {
return index >= 0 && index < m.Size()
}

@ -1,4 +1,4 @@
// Copyright (c) 2015, Emir Pasic. All rights reserved.
// Copyright (c) 2015, Emir Pasic & Eren Dursun. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@ -13,9 +13,9 @@ package linkedhashmap
import (
"fmt"
"github.com/emirpasic/gods/lists/doublylinkedlist"
"github.com/emirpasic/gods/maps"
"strings"
"github.com/emirpasic/gods/maps"
)
// Assert Map implementation
@ -23,43 +23,78 @@ 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
table map[interface{}]*element
first *element
last *element
}
type element struct {
key interface{}
value interface{}
prev *element
next *element
}
// New instantiates a linked-hash-map.
func New() *Map {
return &Map{
table: make(map[interface{}]interface{}),
ordering: doublylinkedlist.New(),
table: make(map[interface{}]*element),
}
}
// 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)
if el, contains := m.table[key]; contains {
el.value = value
} else {
e := &element{
key: key,
value: value,
prev: m.last,
}
if m.Size() == 0 {
m.first = e
m.last = e
} else {
m.last.next = e
m.last = e
}
m.table[key] = e
}
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
element := m.table[key]
if element != nil {
found = true
value = element.value
}
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 {
if element, contains := m.table[key]; contains {
if element == m.first {
m.first = element.next
}
if element == m.last {
m.last = element.prev
}
if element.prev != nil {
element.prev.next = element.next
}
if element.next != nil {
element.next.prev = element.prev
}
element = nil
delete(m.table, key)
index := m.ordering.IndexOf(key)
m.ordering.Remove(index)
}
}
@ -70,12 +105,19 @@ func (m *Map) Empty() bool {
// Size returns number of elements in the map.
func (m *Map) Size() int {
return m.ordering.Size()
return len(m.table)
}
// Keys returns all keys in-order
func (m *Map) Keys() []interface{} {
return m.ordering.Values()
keys := make([]interface{}, m.Size())
count := 0
it := m.Iterator()
for it.Next() {
keys[count] = it.Key()
count++
}
return keys
}
// Values returns all values in-order based on the key.
@ -92,8 +134,9 @@ func (m *Map) Values() []interface{} {
// Clear removes all elements from the map.
func (m *Map) Clear() {
m.table = make(map[interface{}]interface{})
m.ordering.Clear()
m.table = make(map[interface{}]*element)
m.first = nil
m.last = nil
}
// String returns a string representation of container
@ -104,5 +147,4 @@ func (m *Map) String() string {
str += fmt.Sprintf("%v:%v ", it.Key(), it.Value())
}
return strings.TrimRight(str, " ") + "]"
}

Loading…
Cancel
Save