Skip to content

Commit

Permalink
HW04 is complited
Browse files Browse the repository at this point in the history
  • Loading branch information
DimVlas committed May 11, 2024
1 parent 82c7522 commit 5b57e78
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 51 deletions.
69 changes: 64 additions & 5 deletions hw04_lru_cache/cache.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,84 @@
package hw04lrucache

import "sync"

type Key string

type Cache interface {
Set(key Key, value interface{}) bool
Get(key Key) (interface{}, bool)
Clear()
Set(key Key, value interface{}) bool // Добавить значение в кэш.
Get(key Key) (interface{}, bool) // Получить значение из кэша.
Clear() // Очистить кэш.
}

type lruCache struct {
Cache // Remove me after realization.
type cacheItem struct {
Value interface{}
Key Key
}

type lruCache struct {
capacity int
mtx sync.Mutex
queue List
items map[Key]*ListItem
}

// Создать новый LRU-кэш.
func NewCache(capacity int) Cache {
return &lruCache{
capacity: capacity,
mtx: sync.Mutex{},
queue: NewList(),
items: make(map[Key]*ListItem, capacity),
}
}

// Добавить значение в кэш.
func (c *lruCache) Set(key Key, value interface{}) bool {
c.mtx.Lock()
defer c.mtx.Unlock()

itm, ok := c.items[key]
if ok { // ключ есть в кэше
cacheVal := itm.Value.(*cacheItem)
cacheVal.Value = value
itm.Value = cacheVal
c.queue.MoveToFront(itm)
} else { // ключа нет в кэше
if c.capacity == c.queue.Len() { // кэш полностью заполнен
excessVal := c.queue.Back().Value.(*cacheItem)
delete(c.items, excessVal.Key)

c.queue.Remove(c.queue.Back())
}

cacheVal := &cacheItem{Key: key, Value: value}
itm = c.queue.PushFront(cacheVal)
c.items[key] = itm
}

return ok
}

// Получить значение из кэша.
func (c *lruCache) Get(key Key) (interface{}, bool) {
defer c.mtx.Unlock()
c.mtx.Lock()

itm, ok := c.items[key]

if ok {
c.queue.MoveToFront(itm)

return itm.Value.(*cacheItem).Value, true
}

return nil, false
}

// Очистить кэш.
func (c *lruCache) Clear() {
c.mtx.Lock()
c.queue = NewList()
c.items = make(map[Key]*ListItem, c.capacity)
c.mtx.Unlock()
}
38 changes: 34 additions & 4 deletions hw04_lru_cache/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,43 @@ func TestCache(t *testing.T) {
})

t.Run("purge logic", func(t *testing.T) {
// Write me
c := NewCache(5)
c.Set("100", 100)
c.Set("200", 200)
c.Clear()

val, ok := c.Get("100")
require.False(t, ok)
require.Nil(t, val)
})
}

func TestCacheMultithreading(t *testing.T) {
t.Skip() // Remove me if task with asterisk completed.
t.Run("extrude", func(t *testing.T) {
c := NewCache(5)
c.Set("100", 100)
c.Set("200", 200)
c.Set("300", 300)
c.Set("400", 400)
c.Set("500", 500)
// 500, 400, 300, 200, 100

val, ok := c.Get("100") // 100, 500, 400, 300, 200
require.True(t, ok)
require.Equal(t, 100, val)

ok = c.Set("1000", 1000) // 1000, 100, 500, 400, 300
require.False(t, ok)

val, ok = c.Get("200")
require.False(t, ok)
require.Nil(t, val)

val, ok = c.Get("300") // 100, 500, 400, 300, 200
require.True(t, ok)
require.Equal(t, 300, val)
})
}

func TestCacheMultithreading(_ *testing.T) {
c := NewCache(10)
wg := &sync.WaitGroup{}
wg.Add(2)
Expand Down
59 changes: 19 additions & 40 deletions hw04_lru_cache/list.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package hw04lrucache

import "sync"

type List interface {
Len() int
Front() *ListItem
Back() *ListItem
PushFront(v interface{}) *ListItem
PushBack(v interface{}) *ListItem
Remove(i *ListItem)
MoveToFront(i *ListItem)
Len() int // Кол-во элементов в списке.
Front() *ListItem // Первый элемент списка.
Back() *ListItem // Последний элемент списка.
PushFront(v interface{}) *ListItem // Добавление элемента в начало списка.
PushBack(v interface{}) *ListItem // Добавление элемента в конец списка.
Remove(i *ListItem) // Удаление элемента из списка.
MoveToFront(i *ListItem) // Переместить элемент вперед.
}

type ListItem struct {
Expand All @@ -24,27 +22,28 @@ type list struct {
back *ListItem
}

// Кол-во элементов в списке
// Создать новый двусвязный список.
func NewList() List {
return new(list)
}

// Кол-во элементов в списке.
func (lst *list) Len() int {
return lst.len
}

// Первый элемент списка
// Первый элемент списка.
func (lst *list) Front() *ListItem {
return lst.front
}

// Последний элемент списка
// Последний элемент списка.
func (lst *list) Back() *ListItem {
return lst.back
}

// Добавление элемента в начало списка
// Добавление элемента в начало списка.
func (lst *list) PushFront(v interface{}) *ListItem {
var mtx sync.Mutex
defer mtx.Unlock()

mtx.Lock()
itm := &ListItem{
Value: v,
Next: lst.front,
Expand All @@ -61,12 +60,8 @@ func (lst *list) PushFront(v interface{}) *ListItem {
return itm
}

// Добавление элемента в конец списка
// Добавление элемента в конец списка.
func (lst *list) PushBack(v interface{}) *ListItem {
var mtx sync.Mutex
defer mtx.Unlock()

mtx.Lock()
itm := &ListItem{
Value: v,
Prev: lst.back,
Expand All @@ -83,17 +78,12 @@ func (lst *list) PushBack(v interface{}) *ListItem {
return itm
}

// Удаление элемента из списка
// Удаление элемента из списка.
func (lst *list) Remove(i *ListItem) {
var mtx sync.Mutex

if i == nil {
return
}

mtx.Lock()
defer mtx.Unlock()

if i.Prev == nil && i.Next == nil { // единственный элемент
lst.front = nil
lst.back = nil
Expand All @@ -120,17 +110,12 @@ func (lst *list) Remove(i *ListItem) {
lst.len--
}

// переместить элемент вперед
// Переместить элемент вперед.
func (lst *list) MoveToFront(i *ListItem) {
if i.Prev == nil { // первый элемент
return
}

var mtx sync.Mutex
defer mtx.Unlock()

mtx.Lock()

if i.Next != nil { // элемент из середины
i.Prev.Next = i.Next // предыдущий ссылается на следующий
i.Next.Prev = i.Prev // следующий ссылается на предыдущий
Expand All @@ -143,10 +128,4 @@ func (lst *list) MoveToFront(i *ListItem) {
i.Next = lst.front
lst.front = i
i.Next.Prev = i

}

// Создать новый двусвязный список
func NewList() List {
return new(list)
}
2 changes: 0 additions & 2 deletions hw04_lru_cache/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ func TestList(t *testing.T) {
require.Equal(t, 0, l.Len())
require.Nil(t, l.Front())
require.Nil(t, l.Back())

})

t.Run("single back", func(t *testing.T) {
Expand Down Expand Up @@ -70,7 +69,6 @@ func TestList(t *testing.T) {
require.Equal(t, 33, l.Front().Value)
require.Equal(t, 22, l.Front().Next.Value)
require.Equal(t, 11, l.Back().Value)

})

t.Run("complex", func(t *testing.T) {
Expand Down

0 comments on commit 5b57e78

Please sign in to comment.