2
* Copyright 2021 ByteDance Inc.
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
8
* http://www.apache.org/licenses/LICENSE-2.0
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.
24
`github.com/bytedance/sonic/internal/rt`
31
_InitCapacity = 4096 // must be a power of 2
34
type _ProgramMap struct {
40
type _ProgramEntry struct {
45
func newProgramMap() *_ProgramMap {
49
b: make([]_ProgramEntry, _InitCapacity),
53
func (self *_ProgramMap) copy() *_ProgramMap {
57
b: make([]_ProgramEntry, len(self.b)),
59
for i, f := range self.b {
65
func (self *_ProgramMap) get(vt *rt.GoType) interface{} {
71
if b := self.b[p]; b.vt == vt {
73
} else if b.vt == nil {
84
func (self *_ProgramMap) add(vt *rt.GoType, fn interface{}) *_ProgramMap {
86
f := float64(atomic.LoadUint64(&p.n) + 1) / float64(p.m + 1)
88
/* check for load factor */
93
/* insert the value */
98
func (self *_ProgramMap) rehash() *_ProgramMap {
99
c := (self.m + 1) << 1
100
r := &_ProgramMap{m: c - 1, b: make([]_ProgramEntry, int(c))}
102
/* rehash every entry */
103
for i := uint32(0); i <= self.m; i++ {
104
if b := self.b[i]; b.vt != nil {
109
/* rebuild successful */
113
func (self *_ProgramMap) insert(vt *rt.GoType, fn interface{}) {
118
for i := uint32(0); i <= self.m; i++ {
119
if b := &self.b[p]; b.vt != nil {
125
atomic.AddUint64(&self.n, 1)
130
/* should never happens */
131
panic("no available slots")
134
/** RCU Program Cache **/
136
type ProgramCache struct {
141
func CreateProgramCache() *ProgramCache {
142
return &ProgramCache {
144
p: unsafe.Pointer(newProgramMap()),
148
func (self *ProgramCache) Get(vt *rt.GoType) interface{} {
149
return (*_ProgramMap)(atomic.LoadPointer(&self.p)).get(vt)
152
func (self *ProgramCache) Compute(vt *rt.GoType, compute func(*rt.GoType, ... interface{}) (interface{}, error), ex ...interface{}) (interface{}, error) {
156
/* use defer to prevent inlining of this function */
158
defer self.m.Unlock()
160
/* double check with write lock held */
161
if val = self.Get(vt); val != nil {
165
/* compute the value */
166
if val, err = compute(vt, ex...); err != nil {
170
/* update the RCU cache */
171
atomic.StorePointer(&self.p, unsafe.Pointer((*_ProgramMap)(atomic.LoadPointer(&self.p)).add(vt, val)))