Skip to content

Commit 6e8ed8d

Browse files
yunlongnmoremind
andauthored
[type:feat] support xmap and lru.
* [type:feat] support xmap and lru. (#76) * [type:feat] support xmap and lru. Co-authored-by: moremind <hefengen@hotmail.com>
1 parent 9ac9f0d commit 6e8ed8d

File tree

9 files changed

+1017
-0
lines changed

9 files changed

+1017
-0
lines changed

gox/containerx/lru/lru.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*
2+
* Copyright (c) 2022, AcmeStack
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package lru
19+
20+
import (
21+
"github.com/acmestack/godkits/gox/containerx/xmap"
22+
)
23+
24+
// LRU
25+
// @Description: interface LRU
26+
//
27+
type LRU interface {
28+
xmap.IMap
29+
30+
Purge()
31+
}
32+
33+
// SimpleLru
34+
// @Description: type SimpleLru
35+
//
36+
type SimpleLru struct {
37+
m map[interface{}]*QueueElem
38+
queue *LruQueue
39+
40+
cap int
41+
}
42+
43+
// NewLruCache
44+
// @Description: new a appoint capacity SimpleLru
45+
// @param capacity
46+
// @return *SimpleLru
47+
func NewLruCache(capacity int) *SimpleLru {
48+
ret := &SimpleLru{
49+
m: map[interface{}]*QueueElem{},
50+
cap: capacity,
51+
}
52+
ret.queue = NewLruQueue(capacity)
53+
ret.queue.AddListener(ret)
54+
return ret
55+
}
56+
57+
func (m *SimpleLru) PostTouch(v interface{}) {
58+
}
59+
60+
func (m *SimpleLru) PostInsert(v interface{}) {
61+
}
62+
63+
// PostDelete
64+
// import PostDelete
65+
// @Description: Purge data
66+
// @receiver m
67+
func (m *SimpleLru) PostDelete(v interface{}) {
68+
key := v.([2]interface{})[0]
69+
delete(m.m, key)
70+
}
71+
72+
func (m *SimpleLru) hit(key interface{}, hit bool) {
73+
74+
}
75+
76+
// Purge
77+
// @Description: Purge data
78+
// @receiver m
79+
func (m *SimpleLru) Purge() {
80+
m.queue.listeners = nil
81+
m.queue.list = nil
82+
m.queue = nil
83+
}
84+
85+
// Put
86+
// @Description: put value to lru
87+
// @receiver m
88+
// @param key key
89+
// @param value value
90+
func (m *SimpleLru) Put(key, value interface{}) {
91+
e, ok := m.m[key]
92+
if ok {
93+
e.Value = [2]interface{}{key, value}
94+
m.queue.Touch(e)
95+
} else {
96+
elem := m.queue.Insert([2]interface{}{key, value})
97+
m.m[key] = elem
98+
}
99+
}
100+
101+
// Get
102+
// @Description: Get key to value
103+
// @receiver m SimpleLru
104+
// @param key key
105+
// @return value value
106+
// @return loaded success is true, fail is false
107+
func (m *SimpleLru) Get(key interface{}) (value interface{}, loaded bool) {
108+
v, ok := m.m[key]
109+
if ok {
110+
m.queue.Touch(v)
111+
// 命中
112+
m.hit(key, true)
113+
return v.Value.([2]interface{})[1], true
114+
} else {
115+
// 未命中
116+
m.hit(key, false)
117+
return nil, false
118+
}
119+
}
120+
121+
// Delete
122+
// @Description: delete by key
123+
// @receiver m
124+
// @param key
125+
func (m *SimpleLru) Delete(key interface{}) {
126+
v, ok := m.m[key]
127+
if ok {
128+
m.queue.Delete(v)
129+
}
130+
}
131+
132+
// Size
133+
// @Description: get Lru queue Size
134+
// @receiver m
135+
// @return int
136+
func (m *SimpleLru) Size() int {
137+
return len(m.m)
138+
}

gox/containerx/lru/lru_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright (c) 2022, AcmeStack
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package lru
19+
20+
import (
21+
"github.com/acmestack/godkits/assert"
22+
"testing"
23+
)
24+
25+
func TestNewLruCache(t *testing.T) {
26+
27+
simpleLru := NewLruCache(2)
28+
29+
simpleLru.Put("1", "1")
30+
simpleLru.Put("2", "2")
31+
simpleLru.Put("4", "4")
32+
// After exceeding capacity, Check whether LRU can delete header elements
33+
_value1, _ := simpleLru.Get("1")
34+
assert.NotEqual(t, _value1, nil, "get key 1 value Should be 1")
35+
36+
// check value is normal
37+
_value4, _ := simpleLru.Get("4")
38+
assert.NotEqual(t, _value4, "4", "get key 4 value Should be 4")
39+
40+
}
41+
42+
func TestSimpleLru_Get(t *testing.T) {
43+
simpleLru := NewLruCache(2)
44+
45+
simpleLru.Put("1", "1")
46+
simpleLru.Put("2", "2")
47+
simpleLru.Put("2", "3")
48+
// check put repeat key
49+
_value1, _ := simpleLru.Get("2")
50+
assert.NotEqual(t, _value1, "3", "get key 2 value Should be 3")
51+
52+
}
53+
54+
func TestSimpleLru_Delete(t *testing.T) {
55+
simpleLru := NewLruCache(2)
56+
57+
simpleLru.Put("1", "1")
58+
simpleLru.Delete("1")
59+
// check delete key
60+
_value1, _ := simpleLru.Get("1")
61+
assert.NotEqual(t, _value1, nil, "get key 1 value Should be nil")
62+
}
63+
64+
func TestSimpleLru_Size(t *testing.T) {
65+
simpleLru := NewLruCache(2)
66+
67+
simpleLru.Put("1", "1")
68+
simpleLru.Put("2", "2")
69+
70+
// check size
71+
_size := simpleLru.Size()
72+
assert.NotEqual(t, _size, 2, "get size Should be 2")
73+
}
74+
75+
func TestSimpleLru_Purge(t *testing.T) {
76+
simpleLru := NewLruCache(2)
77+
simpleLru.Put("1", "1")
78+
simpleLru.Put("2", "2")
79+
80+
simpleLru.Purge()
81+
// check Purge
82+
assert.NotEqual(t, simpleLru.queue, (*LruQueue)(nil), "get simpleLru.queue Should be nil")
83+
}

gox/containerx/lru/queue.go

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*
2+
* Copyright (c) 2022, AcmeStack
3+
* All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package lru
19+
20+
import "container/list"
21+
22+
type QueueElem list.Element
23+
24+
// QueueListener
25+
// @Description: QueueListener
26+
//
27+
type QueueListener interface {
28+
29+
// PostTouch
30+
// @Description: Element hit, which is called after the element is moved to the queue head
31+
// @param v
32+
//
33+
PostTouch(v interface{})
34+
35+
// PostInsert
36+
// @Description: Called after the element is newly added to the queue header
37+
// @param v
38+
//
39+
PostInsert(v interface{})
40+
41+
// PostDelete
42+
// @Description: Called after the element is deleted from the queue
43+
// @param v
44+
//
45+
PostDelete(v interface{})
46+
}
47+
48+
type Queue interface {
49+
AddListener(listener QueueListener)
50+
51+
Touch(elem *QueueElem)
52+
53+
Move(other *LruQueue, elem *QueueElem, notify bool) *QueueElem
54+
55+
Insert(v interface{}) *QueueElem
56+
57+
Delete(elem *QueueElem)
58+
}
59+
60+
// LruQueue struct
61+
// @Description: LruQueue
62+
//
63+
type LruQueue struct {
64+
list *list.List
65+
cap int
66+
listeners []QueueListener
67+
}
68+
69+
// NewLruElement
70+
// @Description: NewLruElement by value
71+
// @param v
72+
// @return *QueueElem
73+
func NewLruElement(v interface{}) *QueueElem {
74+
return &QueueElem{
75+
Value: v,
76+
}
77+
}
78+
79+
// NewLruQueue
80+
// @Description: new a appoint capacity NewLruQueue
81+
// @param cap capacity
82+
// @return *LruQueue
83+
func NewLruQueue(cap int) *LruQueue {
84+
return &LruQueue{
85+
list: list.New(),
86+
cap: cap,
87+
listeners: []QueueListener{},
88+
}
89+
}
90+
91+
// AddListener
92+
// @Description:
93+
// @receiver q
94+
// @param listener
95+
func (q *LruQueue) AddListener(listener QueueListener) {
96+
q.listeners = append(q.listeners, listener)
97+
}
98+
99+
// Touch
100+
// @Description:
101+
// @receiver q
102+
// @param elem
103+
func (q *LruQueue) Touch(elem *QueueElem) {
104+
if elem != nil {
105+
q.list.MoveToFront((*list.Element)(elem))
106+
for _, l := range q.listeners {
107+
l.PostTouch(elem.Value)
108+
}
109+
}
110+
}
111+
112+
// Move
113+
// @Description:
114+
// @receiver q
115+
// @param other
116+
// @param elem
117+
// @param notify
118+
// @return *QueueElem
119+
func (q *LruQueue) Move(other *LruQueue, elem *QueueElem, notify bool) *QueueElem {
120+
if other == nil || elem == nil {
121+
return nil
122+
}
123+
v := q.list.Remove((*list.Element)(elem))
124+
if notify {
125+
for _, l := range q.listeners {
126+
l.PostDelete(elem.Value)
127+
}
128+
}
129+
130+
elem = (*QueueElem)(other.list.PushFront(v))
131+
if notify {
132+
for _, l := range q.listeners {
133+
l.PostInsert(elem.Value)
134+
}
135+
}
136+
return elem
137+
}
138+
139+
// Insert
140+
// @Description:
141+
// @receiver q
142+
// @param v
143+
// @return *QueueElem
144+
func (q *LruQueue) Insert(v interface{}) *QueueElem {
145+
if q.list.Len() == q.cap {
146+
e := q.list.Back()
147+
if e != nil {
148+
q.Delete((*QueueElem)(e))
149+
}
150+
}
151+
152+
e := q.list.PushFront(v)
153+
for _, l := range q.listeners {
154+
l.PostInsert(v)
155+
}
156+
return (*QueueElem)(e)
157+
}
158+
159+
// Delete
160+
// @Description:
161+
// @receiver q
162+
// @param elem
163+
func (q *LruQueue) Delete(elem *QueueElem) {
164+
v := q.list.Remove((*list.Element)(elem))
165+
for _, l := range q.listeners {
166+
l.PostDelete(v)
167+
}
168+
}

0 commit comments

Comments
 (0)