github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/perf/lru/list.go (about) 1 package lru 2 3 import "unsafe" 4 5 type element struct { 6 next, prev uint32 7 8 key, value any 9 10 expires int64 // nanosecond timestamp 11 index uint32 12 } 13 14 func newList(capacity int) *list { 15 elems := make([]element, capacity+1) 16 l := &list{ 17 elems: elems, 18 root: &elems[0], 19 } 20 21 size := len(elems) 22 for i := 1; i < size; i++ { 23 e := &elems[i] 24 e.index = uint32(i) 25 l.PushBack(e) 26 } 27 return l 28 } 29 30 type list struct { 31 elems []element 32 root *element 33 len int 34 } 35 36 func (l *list) Front() *element { 37 if l.len == 0 { 38 return nil 39 } 40 return l.get(l.root.next) 41 } 42 43 func (l *list) Back() *element { 44 if l.len == 0 { 45 return nil 46 } 47 return l.get(l.root.prev) 48 } 49 50 func (l *list) PushFront(elem *element) *element { 51 return l.insert(elem, l.root) 52 } 53 54 func (l *list) PushBack(elem *element) *element { 55 return l.insert(elem, l.get(l.root.prev)) 56 } 57 58 func (l *list) MoveToFront(elem *element) { 59 l.insert(l.remove(elem), l.root) 60 } 61 62 func (l *list) MoveToBack(elem *element) { 63 l.insert(l.remove(elem), l.get(l.root.prev)) 64 } 65 66 func (l *list) insert(elem, at *element) *element { 67 next := l.get(at.next) 68 at.next = elem.index 69 elem.prev = at.index 70 elem.next = next.index 71 next.prev = elem.index 72 l.len++ 73 return elem 74 } 75 76 func (l *list) remove(elem *element) *element { 77 prev := l.get(elem.prev) 78 next := l.get(elem.next) 79 prev.next = elem.next 80 next.prev = elem.prev 81 l.len-- 82 return elem 83 } 84 85 const elemsize = unsafe.Sizeof(element{}) 86 87 // get uses unsafe trick to eliminate slice bounds checking 88 func (l *list) get(idx uint32) *element { 89 return (*element)(unsafe.Pointer(uintptr(unsafe.Pointer(l.root)) + uintptr(idx)*elemsize)) 90 }