diff --git a/lru_cache.go b/lru_cache.go index 71c4ea1..66197e2 100644 --- a/lru_cache.go +++ b/lru_cache.go @@ -2,6 +2,7 @@ package incache import ( "container/list" + "sync" "time" ) @@ -12,16 +13,15 @@ type lruItem[K comparable, V any] struct { } type LRUCache[K comparable, V any] struct { - baseCache + mu sync.RWMutex + size uint m map[K]*list.Element // where the key-value pairs are stored evictionList *list.List } -func newLRU[K comparable, V any](cacheBuilder *CacheBuilder[K, V]) *LRUCache[K, V] { +func NewLRU[K comparable, V any](size uint) *LRUCache[K, V] { return &LRUCache[K, V]{ - baseCache: baseCache{ - size: cacheBuilder.size, - }, + size: size, m: make(map[K]*list.Element), evictionList: list.New(), } @@ -118,7 +118,7 @@ func (c *LRUCache[K, V]) delete(k K) { c.evictionList.Remove(item) } -func (src *LRUCache[K, V]) TransferTo(dst Cache[K, V]) { +func (src *LRUCache[K, V]) TransferTo(dst *LRUCache[K, V]) { src.mu.Lock() defer src.mu.Unlock() @@ -130,7 +130,7 @@ func (src *LRUCache[K, V]) TransferTo(dst Cache[K, V]) { } } -func (src *LRUCache[K, V]) CopyTo(dst Cache[K, V]) { +func (src *LRUCache[K, V]) CopyTo(dst *LRUCache[K, V]) { src.mu.Lock() defer src.mu.Unlock() diff --git a/lru_cache_test.go b/lru_cache_test.go index 74abbe7..591ca7a 100644 --- a/lru_cache_test.go +++ b/lru_cache_test.go @@ -6,9 +6,7 @@ import ( ) func TestSet_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewLRU[string, string](10) c.Set("key1", "value1") if c.m["key1"].Value.(*lruItem[string, string]).value != "value1" { @@ -17,9 +15,7 @@ func TestSet_LRU(t *testing.T) { } func TestGet_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewLRU[string, string](10) c.Set("key1", "value1") if v, ok := c.Get("key1"); !ok || v != "value1" { @@ -28,9 +24,7 @@ func TestGet_LRU(t *testing.T) { } func TestGetAll_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewLRU[string, string](10) c.Set("key1", "value1") c.Set("key2", "value2") @@ -51,9 +45,7 @@ func TestGetAll_LRU(t *testing.T) { } func TestSetWithTimeout_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewLRU[string, string](10) c.SetWithTimeout("key1", "value1", time.Millisecond) @@ -65,9 +57,7 @@ func TestSetWithTimeout_LRU(t *testing.T) { } func TestNotFoundSet_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewLRU[string, string](10) if !c.NotFoundSet("key1", "value1") { t.Errorf("NotFoundSet failed") @@ -79,9 +69,7 @@ func TestNotFoundSet_LRU(t *testing.T) { } func TestNotFoundSetWithTimeout_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewLRU[string, string](10) if !c.NotFoundSetWithTimeout("key1", "value1", 0) { t.Errorf("NotFoundSetWithTimeout failed") @@ -93,9 +81,7 @@ func TestNotFoundSetWithTimeout_LRU(t *testing.T) { } func TestDelete_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewLRU[string, string](10) c.Set("key1", "value1") @@ -107,9 +93,7 @@ func TestDelete_LRU(t *testing.T) { } func TestTransferTo_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewLRU[string, string](10) c.Set("key1", "value1") c.Set("key2", "value2") @@ -117,9 +101,7 @@ func TestTransferTo_LRU(t *testing.T) { c.Set("key4", "value4") c.Set("key5", "value5") - c2 := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c2 := NewLRU[string, string](10) c.TransferTo(c2) @@ -133,9 +115,7 @@ func TestTransferTo_LRU(t *testing.T) { } func TestCopyTo_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewLRU[string, string](10) c.Set("key1", "value1") c.Set("key2", "value2") @@ -143,9 +123,7 @@ func TestCopyTo_LRU(t *testing.T) { c.Set("key4", "value4") c.Set("key5", "value5") - c2 := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c2 := NewLRU[string, string](10) c.CopyTo(c2) @@ -159,9 +137,7 @@ func TestCopyTo_LRU(t *testing.T) { } func TestKeys_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewLRU[string, string](10) c.Set("key1", "value1") c.Set("key2", "value2") @@ -177,9 +153,7 @@ func TestKeys_LRU(t *testing.T) { } func TestPurge_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 3, - }) + c := NewLRU[string, string](10) c.Set("key1", "value1") c.Set("key2", "value2") @@ -201,9 +175,7 @@ func TestPurge_LRU(t *testing.T) { } func TestCount_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewLRU[string, string](10) c.Set("key1", "value1") c.Set("key2", "value2") @@ -224,9 +196,7 @@ func TestCount_LRU(t *testing.T) { } func TestLen_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewLRU[string, string](10) c.Set("key1", "value1") c.Set("key2", "value2") @@ -247,9 +217,7 @@ func TestLen_LRU(t *testing.T) { } func TestEvict_LRU(t *testing.T) { - c := newLRU(&CacheBuilder[string, string]{ - size: 5, - }) + c := NewLRU[string, string](10) c.Set("key1", "value1") c.Set("key2", "value2") diff --git a/mcache.go b/mcache.go index ebbf265..97343b1 100644 --- a/mcache.go +++ b/mcache.go @@ -1,11 +1,13 @@ package incache import ( + "sync" "time" ) type MCache[K comparable, V any] struct { - baseCache + mu sync.RWMutex + size uint m map[K]valueWithTimeout[V] // where the key-value pairs are stored stopCh chan struct{} // Channel to signal timeout goroutine to stop timeInterval time.Duration // Time interval to sleep the goroutine that checks for expired keys @@ -18,14 +20,12 @@ type valueWithTimeout[V any] struct { // New creates a new cache instance with optional configuration provided by the specified options. // The database starts a background goroutine to periodically check for expired keys based on the configured time interval. -func newManual[K comparable, V any](cacheBuilder *CacheBuilder[K, V]) *MCache[K, V] { +func NewManual[K comparable, V any](size uint, timeInterval time.Duration) *MCache[K, V] { c := &MCache[K, V]{ m: make(map[K]valueWithTimeout[V]), stopCh: make(chan struct{}), - timeInterval: cacheBuilder.tmIvl, - baseCache: baseCache{ - size: cacheBuilder.size, - }, + size: size, + timeInterval: timeInterval, } if c.timeInterval > 0 { go c.expireKeys() @@ -179,7 +179,7 @@ func (c *MCache[K, V]) Delete(k K) { // // The source cache and the destination cache are locked during the entire operation. // The function is safe to call concurrently with other operations on any of the source cache or destination cache. -func (src *MCache[K, V]) TransferTo(dst Cache[K, V]) { +func (src *MCache[K, V]) TransferTo(dst *MCache[K, V]) { all := src.GetAll() src.mu.Lock() src.m = make(map[K]valueWithTimeout[V]) @@ -194,7 +194,7 @@ func (src *MCache[K, V]) TransferTo(dst Cache[K, V]) { // // The source cache are the destination cache are locked during the entire operation. // The function is safe to call concurrently with other operations on any of the source cache or Destination cache. -func (src *MCache[K, V]) CopyTo(dst Cache[K, V]) { +func (src *MCache[K, V]) CopyTo(dst *MCache[K, V]) { all := src.GetAll() for k, v := range all { diff --git a/mcache_test.go b/mcache_test.go index 52cc00a..cd0f0df 100644 --- a/mcache_test.go +++ b/mcache_test.go @@ -7,9 +7,7 @@ import ( ) func TestSet(t *testing.T) { - c := newManual(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewManual[string, string](10, 0) c.Set("key1", "value1") if c.m["key1"].value != "value1" { @@ -18,9 +16,7 @@ func TestSet(t *testing.T) { } func TestNotFoundSet(t *testing.T) { - c := newManual(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewManual[string, string](10, 0) key := "key1" value := "value1" @@ -42,9 +38,7 @@ func TestNotFoundSet(t *testing.T) { } func TestNotFoundSetWithTimeout(t *testing.T) { - c := newManual(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewManual[string, string](10, 0) key := "key1" value := "value1" timeout := time.Second @@ -83,9 +77,7 @@ func TestNotFoundSetWithTimeout(t *testing.T) { } func TestSetWithTimeout(t *testing.T) { - c := newManual(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewManual[string, string](10, 0) key := "test" value := "test value" timeout := time.Second @@ -106,9 +98,7 @@ func TestSetWithTimeout(t *testing.T) { } func TestGet(t *testing.T) { - c := newManual(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewManual[string, string](10, 0) c.Set("key1", "value1") @@ -124,9 +114,7 @@ func TestGet(t *testing.T) { } func TestGetAll(t *testing.T) { - cb := New[string, string](3) - - c := cb.Build() + c := NewManual[string, string](10, 0) c.Set("key1", "value1") c.Set("key2", "value2") @@ -144,9 +132,7 @@ func TestGetAll(t *testing.T) { } func TestDelete(t *testing.T) { - c := newManual(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewManual[string, string](10, 0) c.Set("key1", "value1") c.Delete("key1") @@ -158,12 +144,8 @@ func TestDelete(t *testing.T) { } func TestTransferTo(t *testing.T) { - src := newManual(&CacheBuilder[string, string]{ - size: 10, - }) - dst := newManual(&CacheBuilder[string, string]{ - size: 10, - }) + src := NewManual[string, string](10, 0) + dst := NewManual[string, string](10, 0) src.Set("key1", "value1") src.TransferTo(dst) @@ -180,12 +162,8 @@ func TestTransferTo(t *testing.T) { } func TestCopyTo(t *testing.T) { - src := newManual(&CacheBuilder[string, string]{ - size: 10, - }) - dst := newManual(&CacheBuilder[string, string]{ - size: 10, - }) + src := NewManual[string, string](10, 0) + dst := NewManual[string, string](10, 0) src.Set("key1", "value1") src.CopyTo(dst) @@ -202,9 +180,7 @@ func TestCopyTo(t *testing.T) { } func TestKeys(t *testing.T) { - c := newManual(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewManual[string, string](10, 0) c.Set("key1", "value1") c.Set("key2", "value2") @@ -224,10 +200,8 @@ func TestKeys(t *testing.T) { } func TestPurge(t *testing.T) { - c := newManual(&CacheBuilder[string, string]{ - size: 10, - tmIvl: 14, - }) + c := NewManual[string, string](10, time.Millisecond*100) + c.Set("1", "one") c.Set("2", "two") c.SetWithTimeout("3", "three", time.Second) @@ -249,10 +223,7 @@ func TestPurge(t *testing.T) { } func TestCount(t *testing.T) { - c := newManual[int, string](&CacheBuilder[int, string]{ - size: 10, - tmIvl: time.Millisecond * 200, - }) + c := NewManual[int, string](10, 0) c.Set(1, "one") c.Set(2, "two") c.SetWithTimeout(3, "three", time.Millisecond*100) @@ -271,11 +242,7 @@ func TestCount(t *testing.T) { t.Errorf("Count: expected: %d, got: %d", 2, count) } - c = newManual( - &CacheBuilder[int, string]{ - size: 10, - }, - ) + c = NewManual[int, string](10, 0) c.Set(1, "one") c.Set(2, "two") c.SetWithTimeout(3, "three", time.Millisecond*100) @@ -294,9 +261,7 @@ func TestCount(t *testing.T) { } func TestLen(t *testing.T) { - c := newManual(&CacheBuilder[string, string]{ - size: 10, - }) + c := NewManual[string, string](10, 0) c.Set("1", "one") c.Set("2", "two") c.SetWithTimeout("3", "three", time.Millisecond*100) @@ -306,10 +271,8 @@ func TestLen(t *testing.T) { t.Errorf("Len: expected: %d, got: %d", 4, l) } - c = newManual(&CacheBuilder[string, string]{ - size: 10, - tmIvl: time.Millisecond * 150, - }) + c = NewManual[string, string](10, time.Millisecond*100) + c.Set("1", "one") c.Set("2", "two") c.SetWithTimeout("3", "three", time.Millisecond*50) @@ -323,10 +286,7 @@ func TestLen(t *testing.T) { } func TestEvict(t *testing.T) { - c := newManual(&CacheBuilder[string, string]{ - et: Manual, - size: 3, - }) + c := NewManual[string, string](10, 0) c.Set("1", "one") c.Set("2", "two") @@ -335,11 +295,11 @@ func TestEvict(t *testing.T) { fmt.Println(c.Keys()) - if count := c.Count(); count != 3 { - t.Errorf("Count: expected: %d, got: %d", 3, count) + if count := c.Count(); count != 4 { + t.Errorf("Count: expected: %d, got: %d", 4, count) } - c.evict(2) + c.evict(3) if count := c.Count(); count != 1 { t.Errorf("Count: expected: %d, got: %d", 1, count)