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  }