Skip to content

Commit

Permalink
lru: add methods to range with orders
Browse files Browse the repository at this point in the history
  • Loading branch information
yyforyongyu committed Jun 15, 2023
1 parent d209c5e commit 037b70c
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 1 deletion.
28 changes: 27 additions & 1 deletion cache/lru/lru.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func (c *Cache[K, V]) LoadAndDelete(key K) (V, bool) {
return el.Value.value, true
}

// Range iterates the cache.
// Range iterates the cache without any ordering.
func (c *Cache[K, V]) Range(visitor func(K, V) bool) {
// valueVisitor is a closure to help unwrap the value from the cache.
valueVisitor := func(key K, value *Element[entry[K, V]]) bool {
Expand All @@ -215,3 +215,29 @@ func (c *Cache[K, V]) Range(visitor func(K, V) bool) {

c.cache.Range(valueVisitor)
}

// RangeFILO iterates the items with FILO order, behaving like a stack.
func (c *Cache[K, V]) RangeFILO(visitor func(K, V) bool) {
for e := c.ll.Front(); e != nil; e = e.Next() {
next := visitor(e.Value.key, e.Value.value)

// Stops the iteration if the visitor returns false to mimick
// the same behavior of `Range`.
if !next {
return
}
}
}

// RangeFIFO iterates the items with FIFO order, behaving like a queue.
func (c *Cache[K, V]) RangeFIFO(visitor func(K, V) bool) {
for e := c.ll.Back(); e != nil; e = e.Prev() {
next := visitor(e.Value.key, e.Value.value)

// Stops the iteration if the visitor returns false to mimick
// the same behavior of `Range`.
if !next {
return
}
}
}
58 changes: 58 additions & 0 deletions cache/lru/lru_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,3 +387,61 @@ func TestRangeAbort(t *testing.T) {
// Check the number of items visited.
require.Equal(t, numItems/2, visited)
}

// TestRangeFILO checks that the `RangeFILO` method works as expected.
func TestRangeFILO(t *testing.T) {
t.Parallel()

c := NewCache[int, *sizeable](100)

// Create test items.
const numItems = 10
for i := 0; i < numItems; i++ {
_, err := c.Put(i, &sizeable{value: i, size: 1})
require.NoError(t, err)
}

// Create a visitor that checks the items are visited in reverse order.
visited := 0
testVisitor := func(key int, value *sizeable) bool {
visited++

require.Equal(t, numItems-visited, key)
return true
}

// Call the method.
c.RangeFILO(testVisitor)

// Check the number of items visited.
require.Equal(t, numItems, visited)
}

// TestRangeFIFO checks that the `RangeFIFO` method works as expected.
func TestRangeFIFO(t *testing.T) {
t.Parallel()

c := NewCache[int, *sizeable](100)

// Create test items.
const numItems = 10
for i := 0; i < numItems; i++ {
_, err := c.Put(i, &sizeable{value: i, size: 1})
require.NoError(t, err)
}

// Create a visitor that checks the items are visited in order.
visited := 0
testVisitor := func(key int, value *sizeable) bool {
require.Equal(t, visited, key)
visited++

return true
}

// Call the method.
c.RangeFIFO(testVisitor)

// Check the number of items visited.
require.Equal(t, numItems, visited)
}

0 comments on commit 037b70c

Please sign in to comment.