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 }