github.com/phuslu/lru@v1.0.16-0.20240421170520-46288a2fd47c/lru_shard_table.go (about) 1 // Copyright 2023-2024 Phus Lu. All rights reserved. 2 // Copyright 2019 Joshua J Baker. All rights reserved. 3 // Use of this source code is governed by an ISC-style 4 // license that can be found in the LICENSE file. 5 6 package lru 7 8 import ( 9 "unsafe" 10 ) 11 12 const ( 13 loadFactor = 0.85 // must be above 50% 14 dibBitSize = 8 // 0xFF 15 hashBitSize = 32 - dibBitSize // 0xFFFFFF 16 maxHash = ^uint32(0) >> dibBitSize // max 16777215 17 maxDIB = ^uint32(0) >> hashBitSize // max 255 18 ) 19 20 func (s *lrushard[K, V]) table_Init(size uint32, hasher func(key unsafe.Pointer, seed uintptr) uintptr, seed uintptr) { 21 newsize := lruNewTableSize(size) 22 if len(s.table_buckets) == 0 { 23 s.table_buckets = make([]uint64, newsize) 24 } 25 s.table_mask = newsize - 1 26 s.table_length = 0 27 s.table_hasher = hasher 28 s.table_seed = seed 29 } 30 31 func lruNewTableSize(size uint32) (newsize uint32) { 32 newsize = nextPowOf2(size) 33 if float64(newsize)*loadFactor < float64(size) { 34 newsize = nextPowOf2(newsize + 1) 35 } 36 if newsize < 8 { 37 newsize = 8 38 } 39 return 40 } 41 42 // Set assigns an index to a key. 43 // Returns the previous index, or false when no index was assigned. 44 func (s *lrushard[K, V]) table_Set(hash uint32, key K, index uint32) (prev uint32, ok bool) { 45 subhash := hash >> dibBitSize 46 hdib := subhash<<dibBitSize | uint32(1)&maxDIB 47 mask := s.table_mask 48 i := (hdib >> dibBitSize) & mask 49 b0 := unsafe.Pointer(&s.table_buckets[0]) 50 l0 := unsafe.Pointer(&s.list[0]) 51 for { 52 b := (*lrubucket)(unsafe.Add(b0, uintptr(i)*8)) 53 if b.hdib&maxDIB == 0 { 54 b.hdib = hdib 55 b.index = index 56 s.table_length++ 57 return 58 } 59 if hdib>>dibBitSize == b.hdib>>dibBitSize && (*lrunode[K, V])(unsafe.Add(l0, uintptr(b.index)*unsafe.Sizeof(s.list[0]))).key == key { 60 prev = b.index 61 b.hdib = hdib 62 b.index = index 63 ok = true 64 return 65 } 66 if b.hdib&maxDIB < hdib&maxDIB { 67 hdib, b.hdib = b.hdib, hdib 68 index, b.index = b.index, index 69 } 70 i = (i + 1) & mask 71 hdib = hdib>>dibBitSize<<dibBitSize | (hdib&maxDIB+1)&maxDIB 72 } 73 } 74 75 // table_Get returns an index for a key. 76 // Returns false when no index has been assign for key. 77 func (s *lrushard[K, V]) table_Get(hash uint32, key K) (index uint32, ok bool) { 78 subhash := hash >> dibBitSize 79 mask := s.table_mask 80 i := subhash & mask 81 b0 := unsafe.Pointer(&s.table_buckets[0]) 82 l0 := unsafe.Pointer(&s.list[0]) 83 for { 84 b := (*lrubucket)(unsafe.Add(b0, uintptr(i)*8)) 85 if b.hdib&maxDIB == 0 { 86 return 87 } 88 if b.hdib>>dibBitSize == subhash && (*lrunode[K, V])(unsafe.Add(l0, uintptr(b.index)*unsafe.Sizeof(s.list[0]))).key == key { 89 return b.index, true 90 } 91 i = (i + 1) & mask 92 } 93 } 94 95 // table_Delete deletes an index for a key. 96 // Returns the deleted index, or false when no index was assigned. 97 func (s *lrushard[K, V]) table_Delete(hash uint32, key K) (index uint32, ok bool) { 98 subhash := hash >> dibBitSize 99 mask := s.table_mask 100 i := subhash & mask 101 b0 := unsafe.Pointer(&s.table_buckets[0]) 102 l0 := unsafe.Pointer(&s.list[0]) 103 for { 104 b := (*lrubucket)(unsafe.Add(b0, uintptr(i)*8)) 105 if b.hdib&maxDIB == 0 { 106 return 107 } 108 if b.hdib>>dibBitSize == subhash && (*lrunode[K, V])(unsafe.Add(l0, uintptr(b.index)*unsafe.Sizeof(s.list[0]))).key == key { 109 old := b.index 110 s.table_delete(i) 111 return old, true 112 } 113 i = (i + 1) & mask 114 } 115 } 116 117 func (s *lrushard[K, V]) table_delete(i uint32) { 118 mask := s.table_mask 119 b0 := unsafe.Pointer(&s.table_buckets[0]) 120 bi := (*lrubucket)(unsafe.Add(b0, uintptr(i)*8)) 121 bi.hdib = bi.hdib>>dibBitSize<<dibBitSize | uint32(0)&maxDIB 122 for { 123 pi := i 124 i = (i + 1) & mask 125 bpi := (*lrubucket)(unsafe.Add(b0, uintptr(pi)*8)) 126 bi = (*lrubucket)(unsafe.Add(b0, uintptr(i)*8)) 127 if bi.hdib&maxDIB <= 1 { 128 bpi.index = 0 129 bpi.hdib = 0 130 break 131 } 132 bpi.index = bi.index 133 bpi.hdib = bi.hdib>>dibBitSize<<dibBitSize | (bi.hdib&maxDIB-1)&maxDIB 134 } 135 s.table_length-- 136 }