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  }