github.com/cloudwego/frugal@v0.1.15/internal/binary/encoder/bucket.go (about) 1 /* 2 * Copyright 2022 ByteDance Inc. 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 17 package encoder 18 19 import ( 20 `sync` 21 `unsafe` 22 23 `github.com/cloudwego/frugal/internal/rt` 24 ) 25 26 type _Bucket struct { 27 h int 28 v uint64 29 p unsafe.Pointer 30 } 31 32 func (self _Bucket) String() string { 33 return rt.StringFrom(self.p, int(self.v)) 34 } 35 36 var ( 37 bucketPool sync.Pool 38 ) 39 40 const ( 41 _BucketSize = unsafe.Sizeof(_Bucket{}) 42 ) 43 44 //go:noescape 45 //go:linkname memclrNoHeapPointers runtime.memclrNoHeapPointers 46 //goland:noinspection GoUnusedParameter 47 func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr) 48 49 func newBucket(n int) []_Bucket { 50 var r []_Bucket 51 var v interface{} 52 53 /* attempt to get one from pool */ 54 if v = bucketPool.Get(); v == nil { 55 return make([]_Bucket, n) 56 } 57 58 /* check for capacity, and update it's capacity */ 59 if r = v.([]_Bucket); n <= cap(r) { 60 return bucketClear(r[:n:cap(r)]) 61 } 62 63 /* not enough space, reallocate a new one */ 64 bucketPool.Put(v) 65 return make([]_Bucket, n) 66 } 67 68 func freeBucket(p []_Bucket) { 69 bucketPool.Put(p) 70 } 71 72 func bucketClear(bm []_Bucket) []_Bucket { 73 v := (*rt.GoSlice)(unsafe.Pointer(&bm)) 74 memclrNoHeapPointers(v.Ptr, uintptr(v.Len) * _BucketSize) 75 return bm 76 } 77 78 func bucketAppend64(bm []_Bucket, v uint64) bool { 79 h := hash64(v) 80 i := h % len(bm) 81 82 /* search for an empty slot (linear probing, this must 83 * success, since item count never exceeds the bucket size) */ 84 for bm[i].h != 0 { 85 if bm[i].v == v { 86 return true 87 } else { 88 i = (i + 1) % len(bm) 89 } 90 } 91 92 /* assign the slot */ 93 bm[i].h = h 94 bm[i].v = v 95 return false 96 } 97 98 func bucketAppendStr(bm []_Bucket, p unsafe.Pointer) bool { 99 h := hashstr(p) 100 i := h % len(bm) 101 v := (*rt.GoString)(p) 102 103 /* search for an empty slot (linear probing, this must 104 * success, since item count never exceeds the bucket size) */ 105 for bm[i].h != 0 { 106 if bm[i].h == h && bm[i].v == uint64(v.Len) && (bm[i].p == v.Ptr || bm[i].String() == *(*string)(p)) { 107 return true 108 } else { 109 i = (i + 1) % len(bm) 110 } 111 } 112 113 /* assign the slot */ 114 bm[i].h = h 115 bm[i].p = v.Ptr 116 bm[i].v = uint64(v.Len) 117 return false 118 }