lru.go raw
1 // SPDX-License-Identifier: Unlicense OR MIT
2
3 package text
4
5 import (
6 "golang.org/x/image/math/fixed"
7
8 "github.com/p9c/p9/pkg/gel/gio/op"
9 )
10
11 type layoutCache struct {
12 m map[layoutKey]*layoutElem
13 head, tail *layoutElem
14 }
15
16 type pathCache struct {
17 m map[pathKey]*path
18 head, tail *path
19 }
20
21 type layoutElem struct {
22 next, prev *layoutElem
23 key layoutKey
24 layout []Line
25 }
26
27 type path struct {
28 next, prev *path
29 key pathKey
30 val op.CallOp
31 }
32
33 type layoutKey struct {
34 ppem fixed.Int26_6
35 maxWidth int
36 str string
37 }
38
39 type pathKey struct {
40 ppem fixed.Int26_6
41 str string
42 }
43
44 const maxSize = 1000
45
46 func (l *layoutCache) Get(k layoutKey) ([]Line, bool) {
47 if lt, ok := l.m[k]; ok {
48 l.remove(lt)
49 l.insert(lt)
50 return lt.layout, true
51 }
52 return nil, false
53 }
54
55 func (l *layoutCache) Put(k layoutKey, lt []Line) {
56 if l.m == nil {
57 l.m = make(map[layoutKey]*layoutElem)
58 l.head = new(layoutElem)
59 l.tail = new(layoutElem)
60 l.head.prev = l.tail
61 l.tail.next = l.head
62 }
63 val := &layoutElem{key: k, layout: lt}
64 l.m[k] = val
65 l.insert(val)
66 if len(l.m) > maxSize {
67 oldest := l.tail.next
68 l.remove(oldest)
69 delete(l.m, oldest.key)
70 }
71 }
72
73 func (l *layoutCache) remove(lt *layoutElem) {
74 lt.next.prev = lt.prev
75 lt.prev.next = lt.next
76 }
77
78 func (l *layoutCache) insert(lt *layoutElem) {
79 lt.next = l.head
80 lt.prev = l.head.prev
81 lt.prev.next = lt
82 lt.next.prev = lt
83 }
84
85 func (c *pathCache) Get(k pathKey) (op.CallOp, bool) {
86 if v, ok := c.m[k]; ok {
87 c.remove(v)
88 c.insert(v)
89 return v.val, true
90 }
91 return op.CallOp{}, false
92 }
93
94 func (c *pathCache) Put(k pathKey, v op.CallOp) {
95 if c.m == nil {
96 c.m = make(map[pathKey]*path)
97 c.head = new(path)
98 c.tail = new(path)
99 c.head.prev = c.tail
100 c.tail.next = c.head
101 }
102 val := &path{key: k, val: v}
103 c.m[k] = val
104 c.insert(val)
105 if len(c.m) > maxSize {
106 oldest := c.tail.next
107 c.remove(oldest)
108 delete(c.m, oldest.key)
109 }
110 }
111
112 func (c *pathCache) remove(v *path) {
113 v.next.prev = v.prev
114 v.prev.next = v.next
115 }
116
117 func (c *pathCache) insert(v *path) {
118 v.next = c.head
119 v.prev = c.head.prev
120 v.prev.next = v
121 v.next.prev = v
122 }
123