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