Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add bettermap instead of go map #108

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 106 additions & 0 deletions simplelru/bettermap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package simplelru

type BetterMap struct {
firstMap map[interface{}]interface{}
secondMap map[interface{}]interface{}
deleteNumThresh int32
totalDeleteNum int32
useMapIndex int32
}

func NewBetterMap(deleteNumThresh int32) *BetterMap {
return &BetterMap{
firstMap: make(map[interface{}]interface{}, 0),
secondMap: make(map[interface{}]interface{}, 0),
deleteNumThresh: deleteNumThresh,
totalDeleteNum: 0,
useMapIndex: 1,
}
}

func (bmap *BetterMap) Set(key interface{}, value interface{}) {
if bmap.useMapIndex == 1 {
bmap.firstMap[key] = value
} else {
bmap.secondMap[key] = value
}

}

func (bmap *BetterMap) GetValue(key interface{}) (interface{}, bool) {
if value, ok := bmap.firstMap[key]; ok {
return value, ok
}

value, ok := bmap.secondMap[key]

return value, ok

}

func (bmap *BetterMap) GetValues() []interface{} {
values := make([]interface{}, 0)
if bmap.useMapIndex == 1 {
for _, value := range bmap.firstMap {
values = append(values, value)
}
} else {
for _, value := range bmap.secondMap {
values = append(values, value)
}
}

return values
}

func (bmap *BetterMap) GetMap() map[interface{}]interface{} {
if bmap.useMapIndex == 1 {
return bmap.firstMap
}

return bmap.secondMap
}

func (bmap *BetterMap) GetLen() int {
if bmap.useMapIndex == 1 {
return len(bmap.firstMap)
}

return len(bmap.secondMap)
}

func (bmap *BetterMap) Purge() {
bmap.firstMap = nil
bmap.secondMap = nil
}

func (bmap *BetterMap) DelKey(key interface{}) {
if bmap.useMapIndex == 1 {
delete(bmap.firstMap, key)
bmap.totalDeleteNum++
if bmap.totalDeleteNum >= bmap.deleteNumThresh {
bmap.secondMap = make(map[interface{}]interface{}, len(bmap.firstMap))
for i, v := range bmap.firstMap {
bmap.secondMap[i] = v
}

bmap.useMapIndex = 2
bmap.totalDeleteNum = 0
bmap.firstMap = nil
}
} else {
delete(bmap.secondMap, key)
bmap.totalDeleteNum++
if bmap.totalDeleteNum >= bmap.deleteNumThresh {
bmap.firstMap = make(map[interface{}]interface{}, len(bmap.secondMap))
for i, v := range bmap.secondMap {
bmap.firstMap[i] = v
}

bmap.useMapIndex = 1
bmap.totalDeleteNum = 0
bmap.secondMap = nil
}
}

}
54 changes: 25 additions & 29 deletions simplelru/lru.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ type EvictCallback func(key interface{}, value interface{})
type LRU struct {
size int
evictList *list.List
items map[interface{}]*list.Element
//items map[interface{}]*list.Element
betterMap *BetterMap
onEvict EvictCallback
}

Expand All @@ -25,42 +26,38 @@ type entry struct {
// NewLRU constructs an LRU of the given size
func NewLRU(size int, onEvict EvictCallback) (*LRU, error) {
if size <= 0 {
return nil, errors.New("must provide a positive size")
return nil, errors.New("Must provide a positive size")
}
c := &LRU{
size: size,
evictList: list.New(),
items: make(map[interface{}]*list.Element),
betterMap: NewBetterMap(int32(size)),
onEvict: onEvict,
}
return c, nil
}

// Purge is used to completely clear the cache.
func (c *LRU) Purge() {
for k, v := range c.items {
if c.onEvict != nil {
c.onEvict(k, v.Value.(*entry).value)
}
delete(c.items, k)
}
c.betterMap.Purge()
c.betterMap = NewBetterMap(int32(c.size))
c.evictList.Init()
}

// Add adds a value to the cache. Returns true if an eviction occurred.
func (c *LRU) Add(key, value interface{}) (evicted bool) {
// Check for existing item
if ent, ok := c.items[key]; ok {
c.evictList.MoveToFront(ent)
ent.Value.(*entry).value = value
if ent, ok := c.betterMap.GetValue(key); ok {
c.evictList.MoveToFront(ent.(*list.Element))

ent.(*list.Element).Value.(*entry).value = value
return false
}

// Add new item
ent := &entry{key, value}
entry := c.evictList.PushFront(ent)
c.items[key] = entry

//c.items[key] = entry
c.betterMap.Set(key, entry)
evict := c.evictList.Len() > c.size
// Verify size not exceeded
if evict {
Expand All @@ -71,40 +68,39 @@ func (c *LRU) Add(key, value interface{}) (evicted bool) {

// Get looks up a key's value from the cache.
func (c *LRU) Get(key interface{}) (value interface{}, ok bool) {
if ent, ok := c.items[key]; ok {
c.evictList.MoveToFront(ent)
if ent.Value.(*entry) == nil {
return nil, false
}
return ent.Value.(*entry).value, true

if ent, ok := c.betterMap.GetValue(key); ok {
c.evictList.MoveToFront(ent.(*list.Element))
return ent.(*list.Element).Value.(*entry).value, true
}
return
}

// Contains checks if a key is in the cache, without updating the recent-ness
// or deleting it for being stale.
func (c *LRU) Contains(key interface{}) (ok bool) {
_, ok = c.items[key]
_, ok = c.betterMap.GetValue(key)
return ok
}

// Peek returns the key value (or undefined if not found) without updating
// the "recently used"-ness of the key.
func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) {
var ent *list.Element
if ent, ok = c.items[key]; ok {
return ent.Value.(*entry).value, true

if ent, ok := c.betterMap.GetValue(key); ok {
return ent.(*list.Element).Value.(*entry).value, true
}
return nil, ok
}

// Remove removes the provided key from the cache, returning if the
// key was contained.
func (c *LRU) Remove(key interface{}) (present bool) {
if ent, ok := c.items[key]; ok {
c.removeElement(ent)
if ent, ok := c.betterMap.GetValue(key); ok {
c.removeElement(ent.(*list.Element))
return true
}

return false
}

Expand All @@ -131,7 +127,7 @@ func (c *LRU) GetOldest() (key, value interface{}, ok bool) {

// Keys returns a slice of the keys in the cache, from oldest to newest.
func (c *LRU) Keys() []interface{} {
keys := make([]interface{}, len(c.items))
keys := make([]interface{}, c.betterMap.GetLen())
i := 0
for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() {
keys[i] = ent.Value.(*entry).key
Expand Down Expand Up @@ -170,7 +166,7 @@ func (c *LRU) removeOldest() {
func (c *LRU) removeElement(e *list.Element) {
c.evictList.Remove(e)
kv := e.Value.(*entry)
delete(c.items, kv.key)
c.betterMap.DelKey(kv.key)
if c.onEvict != nil {
c.onEvict(kv.key, kv.value)
}
Expand Down