Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2899885c42 | |||
| b92e16fa4d |
4
go.mod
4
go.mod
@@ -1,3 +1,5 @@
|
||||
module git.wntrmute.dev/kyle/go-mru
|
||||
|
||||
go 1.17
|
||||
go 1.22
|
||||
|
||||
require github.com/benbjohnson/clock v1.3.5
|
||||
|
||||
2
go.sum
Normal file
2
go.sum
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
|
||||
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
36
mru.go
36
mru.go
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
type item struct {
|
||||
V interface{}
|
||||
V any
|
||||
access int64
|
||||
}
|
||||
|
||||
@@ -28,22 +28,22 @@ type Cache struct {
|
||||
}
|
||||
|
||||
// New must be used to create a new Cache.
|
||||
func New(cap int) *Cache {
|
||||
func New(icap int) *Cache {
|
||||
return &Cache{
|
||||
store: map[string]*Item{},
|
||||
access: newTimestamps(cap),
|
||||
cap: cap,
|
||||
store: map[string]*item{},
|
||||
access: newTimestamps(icap),
|
||||
cap: icap,
|
||||
clock: clock.New(),
|
||||
mtx: &sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cache) lock() {
|
||||
m.mtx.lock()
|
||||
c.mtx.Lock()
|
||||
}
|
||||
|
||||
func (c *Cache) unlock() {
|
||||
m.mtx.unlock()
|
||||
c.mtx.Unlock()
|
||||
}
|
||||
|
||||
// Len returns the number of items currently in the cache.
|
||||
@@ -53,6 +53,10 @@ func (c *Cache) Len() int {
|
||||
|
||||
// evict should remove the least-recently-used cache item.
|
||||
func (c *Cache) evict() {
|
||||
if c.access.Len() == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
k := c.access.K(0)
|
||||
c.evictKey(k)
|
||||
}
|
||||
@@ -79,8 +83,8 @@ func (c *Cache) sanityCheck() {
|
||||
// data structures are consistent. It is not normally required, and it
|
||||
// is primarily used in testing.
|
||||
func (c *Cache) ConsistencyCheck() error {
|
||||
m.lock()
|
||||
defer m.unlock()
|
||||
c.lock()
|
||||
defer c.unlock()
|
||||
if err := c.access.ConsistencyCheck(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -110,9 +114,9 @@ func (c *Cache) ConsistencyCheck() error {
|
||||
}
|
||||
|
||||
// Store adds the value v to the cache under the k.
|
||||
func (c *Cache) Store(k string, v interface{}) {
|
||||
m.lock()
|
||||
defer m.unlock()
|
||||
func (c *Cache) Store(k string, v any) {
|
||||
c.lock()
|
||||
defer c.unlock()
|
||||
|
||||
c.sanityCheck()
|
||||
|
||||
@@ -124,7 +128,7 @@ func (c *Cache) Store(k string, v interface{}) {
|
||||
c.evictKey(k)
|
||||
}
|
||||
|
||||
itm := &Item{
|
||||
itm := &item{
|
||||
V: v,
|
||||
access: c.clock.Now().UnixNano(),
|
||||
}
|
||||
@@ -135,9 +139,9 @@ func (c *Cache) Store(k string, v interface{}) {
|
||||
|
||||
// Get returns the value stored in the cache. If the item isn't present,
|
||||
// it will return false.
|
||||
func (c *Cache) Get(k string) (interface{}, bool) {
|
||||
m.lock()
|
||||
defer m.unlock()
|
||||
func (c *Cache) Get(k string) (any, bool) {
|
||||
c.lock()
|
||||
defer c.unlock()
|
||||
|
||||
c.sanityCheck()
|
||||
|
||||
|
||||
@@ -20,6 +20,11 @@ func TestBasicCacheEviction(t *testing.T) {
|
||||
t.Fatal("cache should have size 0")
|
||||
}
|
||||
|
||||
c.evict()
|
||||
if err := c.ConsistencyCheck(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
c.Store("raven", 1)
|
||||
if err := c.ConsistencyCheck(); err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -3,6 +3,7 @@ package mru
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
)
|
||||
|
||||
@@ -19,10 +20,10 @@ type timestamps struct {
|
||||
cap int
|
||||
}
|
||||
|
||||
func newTimestamps(cap int) *timestamps {
|
||||
func newTimestamps(icap int) *timestamps {
|
||||
return ×tamps{
|
||||
ts: make([]timestamp, 0, cap),
|
||||
cap: cap,
|
||||
ts: make([]timestamp, 0, icap),
|
||||
cap: icap,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +48,7 @@ func (ts *timestamps) Swap(i, j int) {
|
||||
}
|
||||
|
||||
func (ts *timestamps) Find(k string) (int, bool) {
|
||||
for i := 0; i < len(ts.ts); i++ {
|
||||
for i := range len(ts.ts) {
|
||||
if ts.ts[i].k == k {
|
||||
return i, true
|
||||
}
|
||||
@@ -93,8 +94,8 @@ func (ts *timestamps) Delete(i int) {
|
||||
ts.ts = append(ts.ts[:i], ts.ts[i+1:]...)
|
||||
}
|
||||
|
||||
func (ts *timestamps) Dump() {
|
||||
func (ts *timestamps) Dump(w io.Writer) {
|
||||
for i := range ts.ts {
|
||||
fmt.Printf("%d: %s, %d\n", i, ts.K(i), ts.T(i))
|
||||
fmt.Fprintf(w, "%d: %s, %d\n", i, ts.K(i), ts.T(i))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,5 +46,4 @@ func TestTimestamps(t *testing.T) {
|
||||
if ts.K(2) != "owl" {
|
||||
t.Fatalf("third key should be owl, have %s", ts.K(2))
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user