diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b6a2ef..2bf17cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ [comment]: # (Changes since last release go here) +## 2.1.6 - Feb 15th 2023 + +* Added `GetAndMoveToBack()` and `GetAndMoveToFront()` methods + ## 2.1.5 - Dec 13th 2022 * Added `Value()` method diff --git a/orderedmap.go b/orderedmap.go index e60d15f..ef5eb5f 100644 --- a/orderedmap.go +++ b/orderedmap.go @@ -119,6 +119,7 @@ func (om *OrderedMap[K, V]) GetPair(key K) *Pair[K, V] { // Set sets the key-value pair, and returns what `Get` would have returned // on that key prior to the call to `Set`. + func (om *OrderedMap[K, V]) Set(key K, value V) (val V, present bool) { if pair, present := om.pairs[key]; present { oldValue := pair.Value @@ -216,7 +217,8 @@ func (e *KeyNotFoundError[K]) Error() string { } // MoveAfter moves the value associated with key to its new position after the one associated with markKey. -// Returns an error iff key or markKey are not present in the map. +// Returns an error iff key or markKey are not present in the map. If an error is returned, +// it will be a KeyNotFoundError. func (om *OrderedMap[K, V]) MoveAfter(key, markKey K) error { elements, err := om.getElements(key, markKey) if err != nil { @@ -227,7 +229,8 @@ func (om *OrderedMap[K, V]) MoveAfter(key, markKey K) error { } // MoveBefore moves the value associated with key to its new position before the one associated with markKey. -// Returns an error iff key or markKey are not present in the map. +// Returns an error iff key or markKey are not present in the map. If an error is returned, +// it will be a KeyNotFoundError. func (om *OrderedMap[K, V]) MoveBefore(key, markKey K) error { elements, err := om.getElements(key, markKey) if err != nil { @@ -249,24 +252,46 @@ func (om *OrderedMap[K, V]) getElements(keys ...K) ([]*list.Element[*Pair[K, V]] return elements, nil } -// MoveToBack moves the value associated with key to the back of the ordered map. -// Returns an error iff key is not present in the map. +// MoveToBack moves the value associated with key to the back of the ordered map, +// i.e. makes it the newest pair in the map. +// Returns an error iff key is not present in the map. If an error is returned, +// it will be a KeyNotFoundError. func (om *OrderedMap[K, V]) MoveToBack(key K) error { - pair, present := om.pairs[key] - if !present { - return &KeyNotFoundError[K]{key} - } - om.list.MoveToBack(pair.element) - return nil + _, err := om.GetAndMoveToBack(key) + return err } -// MoveToFront moves the value associated with key to the front of the ordered map. -// Returns an error iff key is not present in the map. +// MoveToFront moves the value associated with key to the front of the ordered map, +// i.e. makes it the oldest pair in the map. +// Returns an error iff key is not present in the map. If an error is returned, +// it will be a KeyNotFoundError. func (om *OrderedMap[K, V]) MoveToFront(key K) error { - pair, present := om.pairs[key] - if !present { - return &KeyNotFoundError[K]{key} + _, err := om.GetAndMoveToFront(key) + return err +} + +// GetAndMoveToBack combines Get and MoveToBack in the same call. If an error is returned, +// it will be a KeyNotFoundError. +func (om *OrderedMap[K, V]) GetAndMoveToBack(key K) (val V, err error) { + if pair, present := om.pairs[key]; present { + val = pair.Value + om.list.MoveToBack(pair.element) + } else { + err = &KeyNotFoundError[K]{key} } - om.list.MoveToFront(pair.element) - return nil + + return +} + +// GetAndMoveToFront combines Get and MoveToFront in the same call. If an error is returned, +// it will be a KeyNotFoundError. +func (om *OrderedMap[K, V]) GetAndMoveToFront(key K) (val V, err error) { + if pair, present := om.pairs[key]; present { + val = pair.Value + om.list.MoveToFront(pair.element) + } else { + err = &KeyNotFoundError[K]{key} + } + + return } diff --git a/orderedmap_test.go b/orderedmap_test.go index 9812f06..a3137eb 100644 --- a/orderedmap_test.go +++ b/orderedmap_test.go @@ -264,7 +264,36 @@ func TestMove(t *testing.T) { []any{"28", "bar", 28, "100", "baz", "baz", "baz", 100}) err = om.MoveToFront(100) - assert.NotEqual(t, err, nil) + assert.Equal(t, &KeyNotFoundError[int]{100}, err) +} + +func TestGetAndMove(t *testing.T) { + om := New[int, any]() + om.Set(1, "bar") + om.Set(2, 28) + om.Set(3, 100) + om.Set(4, "baz") + om.Set(5, "28") + om.Set(6, "100") + om.Set(7, "baz") + om.Set(8, "baz") + + value, err := om.GetAndMoveToBack(3) + assert.Nil(t, err) + assert.Equal(t, 100, value) + assertOrderedPairsEqual(t, om, + []int{1, 2, 4, 5, 6, 7, 8, 3}, + []any{"bar", 28, "baz", "28", "100", "baz", "baz", 100}) + + value, err = om.GetAndMoveToFront(5) + assert.Nil(t, err) + assert.Equal(t, "28", value) + assertOrderedPairsEqual(t, om, + []int{5, 1, 2, 4, 6, 7, 8, 3}, + []any{"28", "bar", 28, "baz", "100", "baz", "baz", 100}) + + value, err = om.GetAndMoveToBack(100) + assert.Equal(t, &KeyNotFoundError[int]{100}, err) } func TestAddPairs(t *testing.T) { diff --git a/test_utils.go b/test_utils.go index 963cf0e..9f1cc3b 100644 --- a/test_utils.go +++ b/test_utils.go @@ -9,6 +9,8 @@ import ( "github.com/stretchr/testify/assert" ) +// assertOrderedPairsEqual asserts that the map contains the given keys and values +// from oldest to newest. func assertOrderedPairsEqual[K comparable, V any]( t *testing.T, orderedMap *OrderedMap[K, V], expectedKeys []K, expectedValues []V, ) {