github.com/phuslu/lru@v1.0.16-0.20240421170520-46288a2fd47c/ttl_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 func (s *ttlshard[K, V]) table_Init(size uint32, hasher func(key unsafe.Pointer, seed uintptr) uintptr, seed uintptr) { 13 newsize := ttlNewTableSize(size) 14 if len(s.table_buckets) == 0 { 15 s.table_buckets = make([]uint64, newsize) 16 } 17 s.table_mask = newsize - 1 18 s.table_length = 0 19 s.table_hasher = hasher 20 s.table_seed = seed 21 } 22 23 func ttlNewTableSize(size uint32) (newsize uint32) { 24 newsize = nextPowOf2(size) 25 if float64(newsize)*loadFactor < float64(size) { 26 newsize = nextPowOf2(newsize + 1) 27 } 28 if newsize < 8 { 29 newsize = 8 30 } 31 return 32 } 33 34 // table_Set assigns an index to a key. 35 // Returns the previous index, or false when no index was assigned. 36 func (s *ttlshard[K, V]) table_Set(hash uint32, key K, index uint32) (prev uint32, ok bool) { 37 subhash := hash >> dibBitSize 38 hdib := subhash<<dibBitSize | uint32(1)&maxDIB 39 mask := s.table_mask 40 i := (hdib >> dibBitSize) & mask 41 b0 := unsafe.Pointer(&s.table_buckets[0]) 42 l0 := unsafe.Pointer(&s.list[0]) 43 for { 44 b := (*ttlbucket)(unsafe.Add(b0, uintptr(i)*8)) 45 if b.hdib&maxDIB == 0 { 46 b.hdib = hdib 47 b.index = index 48 s.table_length++ 49 return 50 } 51 if hdib>>dibBitSize == b.hdib>>dibBitSize && (*ttlnode[K, V])(unsafe.Add(l0, uintptr(b.index)*unsafe.Sizeof(s.list[0]))).key == key { 52 prev = b.index 53 b.hdib = hdib 54 b.index = index 55 ok = true 56 return 57 } 58 if b.hdib&maxDIB < hdib&maxDIB { 59 hdib, b.hdib = b.hdib, hdib 60 index, b.index = b.index, index 61 } 62 i = (i + 1) & mask 63 hdib = hdib>>dibBitSize<<dibBitSize | (hdib&maxDIB+1)&maxDIB 64 } 65 } 66 67 // table_Get returns an index for a key. 68 // Returns false when no index has been assign for key. 69 func (s *ttlshard[K, V]) table_Get(hash uint32, key K) (index uint32, ok bool) { 70 subhash := hash >> dibBitSize 71 mask := s.table_mask 72 i := subhash & mask 73 b0 := unsafe.Pointer(&s.table_buckets[0]) 74 l0 := unsafe.Pointer(&s.list[0]) 75 for { 76 b := (*ttlbucket)(unsafe.Add(b0, uintptr(i)*8)) 77 if b.hdib&maxDIB == 0 { 78 return 79 } 80 if b.hdib>>dibBitSize == subhash && (*ttlnode[K, V])(unsafe.Add(l0, uintptr(b.index)*unsafe.Sizeof(s.list[0]))).key == key { 81 return b.index, true 82 } 83 i = (i + 1) & mask 84 } 85 } 86 87 // table_Delete deletes an index for a key. 88 // Returns the deleted index, or false when no index was assigned. 89 func (s *ttlshard[K, V]) table_Delete(hash uint32, key K) (v uint32, ok bool) { 90 subhash := hash >> dibBitSize 91 mask := s.table_mask 92 i := subhash & mask 93 b0 := unsafe.Pointer(&s.table_buckets[0]) 94 l0 := unsafe.Pointer(&s.list[0]) 95 for { 96 b := (*ttlbucket)(unsafe.Add(b0, uintptr(i)*8)) 97 if b.hdib&maxDIB == 0 { 98 return 99 } 100 if b.hdib>>dibBitSize == subhash && (*ttlnode[K, V])(unsafe.Add(l0, uintptr(b.index)*unsafe.Sizeof(s.list[0]))).key == key { 101 old := b.index 102 s.table_delete(i) 103 return old, true 104 } 105 i = (i + 1) & mask 106 } 107 } 108 109 func (s *ttlshard[K, V]) table_delete(i uint32) { 110 mask := s.table_mask 111 b0 := unsafe.Pointer(&s.table_buckets[0]) 112 bi := (*ttlbucket)(unsafe.Add(b0, uintptr(i)*8)) 113 bi.hdib = bi.hdib>>dibBitSize<<dibBitSize | uint32(0)&maxDIB 114 for { 115 pi := i 116 i = (i + 1) & mask 117 bpi := (*ttlbucket)(unsafe.Add(b0, uintptr(pi)*8)) 118 bi = (*ttlbucket)(unsafe.Add(b0, uintptr(i)*8)) 119 if bi.hdib&maxDIB <= 1 { 120 bpi.index = 0 121 bpi.hdib = 0 122 break 123 } 124 bpi.index = bi.index 125 bpi.hdib = bi.hdib>>dibBitSize<<dibBitSize | (bi.hdib&maxDIB-1)&maxDIB 126 } 127 s.table_length-- 128 }