github.com/cybriq/giocore@v0.0.7-0.20210703034601-cfb9cb5f3900/text/lru.go (about) 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/cybriq/giocore/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 }