diff --git a/hw04_lru_cache/cache.go b/hw04_lru_cache/cache.go index a43d727..67a2eb0 100644 --- a/hw04_lru_cache/cache.go +++ b/hw04_lru_cache/cache.go @@ -9,13 +9,54 @@ type Cache interface { } type lruCache struct { - Cache // Remove me after realization. - capacity int queue List items map[Key]*ListItem } +type cacheItem struct { + key Key + value interface{} +} + +func (l *lruCache) Set(key Key, value interface{}) bool { + listItem, success := l.items[key] + if success { + listItem.Value = cacheItem{ + key: key, + value: value, + } + l.queue.MoveToFront(listItem) + return true + } + + l.items[key] = l.queue.PushFront(cacheItem{ + key: key, + value: value, + }) + + if l.queue.Len() > l.capacity { + deleteItem := l.queue.Back() + l.queue.Remove(deleteItem) + delete(l.items, deleteItem.Value.(cacheItem).key) + } + return success +} + +func (l *lruCache) Get(key Key) (interface{}, bool) { + listItem, ok := l.items[key] + if ok { + l.queue.MoveToFront(listItem) + return listItem.Value.(cacheItem).value, ok + } + return listItem, ok +} + +func (l *lruCache) Clear() { + l.queue = NewList() + l.items = make(map[Key]*ListItem, l.capacity) +} + func NewCache(capacity int) Cache { return &lruCache{ capacity: capacity, diff --git a/hw04_lru_cache/cache_test.go b/hw04_lru_cache/cache_test.go index 2b43d4c..b311e4c 100644 --- a/hw04_lru_cache/cache_test.go +++ b/hw04_lru_cache/cache_test.go @@ -50,7 +50,35 @@ func TestCache(t *testing.T) { }) t.Run("purge logic", func(t *testing.T) { - // Write me + c := NewCache(3) + + wasInCache := c.Set("Antony", 1) + require.False(t, wasInCache) + + wasInCache = c.Set("Bob", 2) + require.False(t, wasInCache) + + wasInCache = c.Set("Ci", 3) + require.False(t, wasInCache) + + val, ok := c.Get("Ci") + require.True(t, ok) + require.Equal(t, 3, val) + + val, ok = c.Get("Bob") + require.True(t, ok) + require.Equal(t, 2, val) + + val, ok = c.Get("Antony") + require.True(t, ok) + require.Equal(t, 1, val) + + wasInCache = c.Set("Daddy", 4) + require.False(t, wasInCache) + + val, ok = c.Get("ccc") + require.False(t, ok) + require.Nil(t, val) }) } diff --git a/hw04_lru_cache/go.mod b/hw04_lru_cache/go.mod index d05121c..9578214 100644 --- a/hw04_lru_cache/go.mod +++ b/hw04_lru_cache/go.mod @@ -1,4 +1,4 @@ -module github.com/fixme_my_friend/hw04_lru_cache +module github.com/pogpp/home_works/hw04_lru_cache go 1.22 diff --git a/hw04_lru_cache/list.go b/hw04_lru_cache/list.go index 928ebb5..7a6df4e 100644 --- a/hw04_lru_cache/list.go +++ b/hw04_lru_cache/list.go @@ -17,8 +17,85 @@ type ListItem struct { } type list struct { - List // Remove me after realization. - // Place your code here. + head *ListItem // Указатель на первый элемент + tail *ListItem // Указатель на последний элемент + size int +} + +func (l *list) Len() int { + return l.size +} + +func (l *list) Front() *ListItem { + return l.head +} + +func (l *list) Back() *ListItem { + return l.tail +} + +func (l *list) PushFront(v interface{}) *ListItem { + oldFrontItem := l.Front() + item := &ListItem{v, oldFrontItem, nil} + + if oldFrontItem != nil { + oldFrontItem.Prev = item + } + + l.head = item + if l.Back() == nil { + l.tail = item + } + l.size++ + return item +} + +func (l *list) PushBack(v interface{}) *ListItem { + oldTailItem := l.Back() + item := &ListItem{ + Value: v, + Next: nil, + Prev: oldTailItem, + } + if oldTailItem != nil { + oldTailItem.Next = item + } + + l.tail = item + if l.Front() == nil { + l.head = item + } + + l.size++ + return item +} + +func (l *list) Remove(i *ListItem) { + nextItem := i.Next + prevItem := i.Prev + + if prevItem != nil { + prevItem.Next = nextItem + } + + if nextItem != nil { + nextItem.Prev = prevItem + } + + if l.Front() == i && nextItem != nil { + l.head = nextItem + } + + if l.Back() == i && prevItem != nil { + l.tail = prevItem + } + + l.size-- +} + +func (l *list) MoveToFront(i *ListItem) { + l.Remove(i) + l.PushFront(i.Value) } func NewList() List {