Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try to improve performances #30

Merged
merged 4 commits into from
Sep 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 0 additions & 36 deletions v2/element.go

This file was deleted.

67 changes: 0 additions & 67 deletions v2/element_test.go

This file was deleted.

95 changes: 95 additions & 0 deletions v2/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package orderedmap

// Element is an element of a null terminated (non circular) intrusive doubly linked list that contains the key of the correspondent element in the ordered map too.
type Element[K comparable, V any] struct {
// Next and previous pointers in the doubly-linked list of elements.
// To simplify the implementation, internally a list l is implemented
// as a ring, such that &l.root is both the next element of the last
// list element (l.Back()) and the previous element of the first list
// element (l.Front()).
next, prev *Element[K, V]

// The key that corresponds to this element in the ordered map.
Key K

// The value stored with this element.
Value V
}

// Next returns the next list element or nil.
func (e *Element[K, V]) Next() *Element[K, V] {
return e.next
}

// Prev returns the previous list element or nil.
func (e *Element[K, V]) Prev() *Element[K, V] {
return e.prev
}

// list represents a null terminated (non circular) intrusive doubly linked list.
// The list is immediately usable after instantiation without the need of a dedicated initialization.
type list[K comparable, V any] struct {
root Element[K, V] // list head and tail
}

func (l *list[K, V]) IsEmpty() bool {
return l.root.next == nil
}

// Front returns the first element of list l or nil if the list is empty.
func (l *list[K, V]) Front() *Element[K, V] {
return l.root.next
}

// Back returns the last element of list l or nil if the list is empty.
func (l *list[K, V]) Back() *Element[K, V] {
return l.root.prev
}

// Remove removes e from its list
func (l *list[K, V]) Remove(e *Element[K, V]) {
if e.prev == nil {
l.root.next = e.next
} else {
e.prev.next = e.next
}
if e.next == nil {
l.root.prev = e.prev
} else {
e.next.prev = e.prev
}
e.next = nil // avoid memory leaks
e.prev = nil // avoid memory leaks
}

// PushFront inserts a new element e with value v at the front of list l and returns e.
func (l *list[K, V]) PushFront(key K, value V) *Element[K, V] {
e := &Element[K, V]{Key: key, Value: value}
if l.root.next == nil {
// It's the first element
l.root.next = e
l.root.prev = e
return e
}

e.next = l.root.next
l.root.next.prev = e
l.root.next = e
return e
}

// PushBack inserts a new element e with value v at the back of list l and returns e.
func (l *list[K, V]) PushBack(key K, value V) *Element[K, V] {
e := &Element[K, V]{Key: key, Value: value}
if l.root.prev == nil {
// It's the first element
l.root.next = e
l.root.prev = e
return e
}

e.prev = l.root.prev
l.root.prev.next = e
l.root.prev = e
return e
}
82 changes: 19 additions & 63 deletions v2/orderedmap.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,13 @@
package orderedmap

import (
"container/list"
)

type orderedMapElement[K comparable, V any] struct {
key K
value V
}

type OrderedMap[K comparable, V any] struct {
kv map[K]*list.Element
ll *list.List
kv map[K]*Element[K, V]
ll list[K, V]
}

func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] {
return &OrderedMap[K, V]{
kv: make(map[K]*list.Element),
ll: list.New(),
kv: make(map[K]*Element[K, V]),
}
}

Expand All @@ -26,7 +16,7 @@ func NewOrderedMap[K comparable, V any]() *OrderedMap[K, V] {
func (m *OrderedMap[K, V]) Get(key K) (value V, ok bool) {
v, ok := m.kv[key]
if ok {
value = v.Value.(*orderedMapElement[K, V]).value
value = v.Value
}

return
Expand All @@ -36,23 +26,22 @@ func (m *OrderedMap[K, V]) Get(key K) (value V, ok bool) {
// will be returned. The returned value will be false if the value was replaced
// (even if the value was the same).
func (m *OrderedMap[K, V]) Set(key K, value V) bool {
_, didExist := m.kv[key]

if !didExist {
element := m.ll.PushBack(&orderedMapElement[K, V]{key, value})
m.kv[key] = element
} else {
m.kv[key].Value.(*orderedMapElement[K, V]).value = value
_, alreadyExist := m.kv[key]
if alreadyExist {
m.kv[key].Value = value
return false
}

return !didExist
element := m.ll.PushBack(key, value)
m.kv[key] = element
return true
}

// GetOrDefault returns the value for a key. If the key does not exist, returns
// the default value instead.
func (m *OrderedMap[K, V]) GetOrDefault(key K, defaultValue V) V {
if value, ok := m.kv[key]; ok {
return value.Value.(*orderedMapElement[K, V]).value
return value.Value
}

return defaultValue
Expand All @@ -61,14 +50,9 @@ func (m *OrderedMap[K, V]) GetOrDefault(key K, defaultValue V) V {
// GetElement returns the element for a key. If the key does not exist, the
// pointer will be nil.
func (m *OrderedMap[K, V]) GetElement(key K) *Element[K, V] {
value, ok := m.kv[key]
element, ok := m.kv[key]
if ok {
element := value.Value.(*orderedMapElement[K, V])
return &Element[K, V]{
element: value,
Key: element.key,
Value: element.value,
}
return element
}

return nil
Expand All @@ -83,14 +67,10 @@ func (m *OrderedMap[K, V]) Len() int {
// replaced it will retain the same position. To ensure most recently set keys
// are always at the end you must always Delete before Set.
func (m *OrderedMap[K, V]) Keys() (keys []K) {
keys = make([]K, m.Len())

element := m.ll.Front()
for i := 0; element != nil; i++ {
keys[i] = element.Value.(*orderedMapElement[K, V]).key
element = element.Next()
keys = make([]K, 0, m.Len())
for el := m.Front(); el != nil; el = el.Next() {
keys = append(keys, el.Key)
}

return keys
}

Expand All @@ -109,45 +89,21 @@ func (m *OrderedMap[K, V]) Delete(key K) (didDelete bool) {
// Front will return the element that is the first (oldest Set element). If
// there are no elements this will return nil.
func (m *OrderedMap[K, V]) Front() *Element[K, V] {
front := m.ll.Front()
if front == nil {
return nil
}

element := front.Value.(*orderedMapElement[K, V])

return &Element[K, V]{
element: front,
Key: element.key,
Value: element.value,
}
return m.ll.Front()
}

// Back will return the element that is the last (most recent Set element). If
// there are no elements this will return nil.
func (m *OrderedMap[K, V]) Back() *Element[K, V] {
back := m.ll.Back()
if back == nil {
return nil
}

element := back.Value.(*orderedMapElement[K, V])

return &Element[K, V]{
element: back,
Key: element.key,
Value: element.value,
}
return m.ll.Back()
}

// Copy returns a new OrderedMap with the same elements.
// Using Copy while there are concurrent writes may mangle the result.
func (m *OrderedMap[K, V]) Copy() *OrderedMap[K, V] {
m2 := NewOrderedMap[K, V]()

for el := m.Front(); el != nil; el = el.Next() {
m2.Set(el.Key, el.Value)
}

return m2
}
Loading