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  }