github.com/maypok86/otter@v1.2.1/internal/hashtable/bucket.go (about)

     1  // Copyright (c) 2023 Alexey Mayshev. All rights reserved.
     2  // Copyright (c) 2021 Andrey Pechkurov
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  // Unless required by applicable law or agreed to in writing, software
    11  // distributed under the License is distributed on an "AS IS" BASIS,
    12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  //
    16  // Copyright notice. This code is a fork of xsync.MapOf from this file with some changes:
    17  // https://github.com/puzpuzpuz/xsync/blob/main/mapof.go
    18  //
    19  // Use of this source code is governed by a MIT license that can be found
    20  // at https://github.com/puzpuzpuz/xsync/blob/main/LICENSE
    21  
    22  package hashtable
    23  
    24  import (
    25  	"sync"
    26  	"unsafe"
    27  
    28  	"github.com/maypok86/otter/internal/xruntime"
    29  )
    30  
    31  // paddedBucket is a CL-sized map bucket holding up to
    32  // bucketSize nodes.
    33  type paddedBucket struct {
    34  	// ensure each bucket takes two cache lines on both 32 and 64-bit archs
    35  	padding [xruntime.CacheLineSize - unsafe.Sizeof(bucket{})]byte
    36  
    37  	bucket
    38  }
    39  
    40  type bucket struct {
    41  	hashes [bucketSize]uint64
    42  	nodes  [bucketSize]unsafe.Pointer
    43  	next   unsafe.Pointer
    44  	mutex  sync.Mutex
    45  }
    46  
    47  func (root *paddedBucket) isEmpty() bool {
    48  	b := root
    49  	for {
    50  		for i := 0; i < bucketSize; i++ {
    51  			if b.nodes[i] != nil {
    52  				return false
    53  			}
    54  		}
    55  		if b.next == nil {
    56  			return true
    57  		}
    58  		b = (*paddedBucket)(b.next)
    59  	}
    60  }
    61  
    62  func (root *paddedBucket) add(h uint64, nodePtr unsafe.Pointer) {
    63  	b := root
    64  	for {
    65  		for i := 0; i < bucketSize; i++ {
    66  			if b.nodes[i] == nil {
    67  				b.hashes[i] = h
    68  				b.nodes[i] = nodePtr
    69  				return
    70  			}
    71  		}
    72  		if b.next == nil {
    73  			newBucket := &paddedBucket{}
    74  			newBucket.hashes[0] = h
    75  			newBucket.nodes[0] = nodePtr
    76  			b.next = unsafe.Pointer(newBucket)
    77  			return
    78  		}
    79  		b = (*paddedBucket)(b.next)
    80  	}
    81  }