github.com/EagleQL/Xray-core@v1.4.3/common/cache/lru.go (about)

     1  package cache
     2  
     3  import (
     4  	"container/list"
     5  	sync "sync"
     6  )
     7  
     8  // Lru simple, fast lru cache implementation
     9  type Lru interface {
    10  	Get(key interface{}) (value interface{}, ok bool)
    11  	GetKeyFromValue(value interface{}) (key interface{}, ok bool)
    12  	PeekKeyFromValue(value interface{}) (key interface{}, ok bool) // Peek means check but NOT bring to top
    13  	Put(key, value interface{})
    14  }
    15  
    16  type lru struct {
    17  	capacity         int
    18  	doubleLinkedlist *list.List
    19  	keyToElement     *sync.Map
    20  	valueToElement   *sync.Map
    21  	mu               *sync.Mutex
    22  }
    23  
    24  type lruElement struct {
    25  	key   interface{}
    26  	value interface{}
    27  }
    28  
    29  // NewLru init a lru cache
    30  func NewLru(cap int) Lru {
    31  	return lru{
    32  		capacity:         cap,
    33  		doubleLinkedlist: list.New(),
    34  		keyToElement:     new(sync.Map),
    35  		valueToElement:   new(sync.Map),
    36  		mu:               new(sync.Mutex),
    37  	}
    38  }
    39  
    40  func (l lru) Get(key interface{}) (value interface{}, ok bool) {
    41  	if v, ok := l.keyToElement.Load(key); ok {
    42  		element := v.(*list.Element)
    43  		l.doubleLinkedlist.MoveBefore(element, l.doubleLinkedlist.Front())
    44  		return element.Value.(lruElement).value, true
    45  	}
    46  	return nil, false
    47  }
    48  
    49  func (l lru) GetKeyFromValue(value interface{}) (key interface{}, ok bool) {
    50  	if k, ok := l.valueToElement.Load(value); ok {
    51  		element := k.(*list.Element)
    52  		l.doubleLinkedlist.MoveBefore(element, l.doubleLinkedlist.Front())
    53  		return element.Value.(lruElement).key, true
    54  	}
    55  	return nil, false
    56  }
    57  
    58  func (l lru) PeekKeyFromValue(value interface{}) (key interface{}, ok bool) {
    59  	if k, ok := l.valueToElement.Load(value); ok {
    60  		element := k.(*list.Element)
    61  		return element.Value.(lruElement).key, true
    62  	}
    63  	return nil, false
    64  }
    65  
    66  func (l lru) Put(key, value interface{}) {
    67  	e := lruElement{key, value}
    68  	if v, ok := l.keyToElement.Load(key); ok {
    69  		element := v.(*list.Element)
    70  		element.Value = e
    71  		l.doubleLinkedlist.MoveBefore(element, l.doubleLinkedlist.Front())
    72  	} else {
    73  		l.mu.Lock()
    74  		element := l.doubleLinkedlist.PushFront(e)
    75  		l.keyToElement.Store(key, element)
    76  		l.valueToElement.Store(value, element)
    77  		if l.doubleLinkedlist.Len() > l.capacity {
    78  			toBeRemove := l.doubleLinkedlist.Back()
    79  			l.doubleLinkedlist.Remove(toBeRemove)
    80  			l.keyToElement.Delete(toBeRemove.Value.(lruElement).key)
    81  			l.valueToElement.Delete(toBeRemove.Value.(lruElement).value)
    82  		}
    83  		l.mu.Unlock()
    84  	}
    85  }