-
Notifications
You must be signed in to change notification settings - Fork 19
/
jsonvalue_internal.go
112 lines (87 loc) · 2.07 KB
/
jsonvalue_internal.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
package jsonvalue
import (
"encoding"
"encoding/base64"
"encoding/json"
"reflect"
"sync/atomic"
)
var internal = struct {
b64 *base64.Encoding
defaultMarshalOption *Opt
predict struct {
bytesPerValue uint64
calcStorage uint64 // upper 32 bits - size; lower 32 bits - value count
}
types struct {
JSONMarshaler reflect.Type
TextMarshaler reflect.Type
}
}{}
func init() {
internal.b64 = base64.StdEncoding
internal.defaultMarshalOption = emptyOptions()
internalAddPredictSizePerValue(16, 1)
internal.types.JSONMarshaler = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
internal.types.TextMarshaler = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
}
func internalLoadPredictSizePerValue() int {
if n := atomic.LoadUint64(&internal.predict.bytesPerValue); n > 0 {
return int(n)
}
v := atomic.LoadUint64(&internal.predict.calcStorage)
total := v >> 32
num := v & 0xFFFFFFFF
return int(total / num)
}
func internalAddPredictSizePerValue(total, num int) {
v := atomic.LoadUint64(&internal.predict.calcStorage)
preTotal := v >> 32
preNum := v & 0xFFFFFFFF
nextTotal := uint64(total) + preTotal
nextNum := uint64(num) + preNum
if nextTotal < 0x7FFFFFFF {
v := (nextTotal << 32) + nextNum
atomic.StoreUint64(&internal.predict.calcStorage, v)
return
}
per := nextTotal / nextNum
atomic.StoreUint64(&internal.predict.bytesPerValue, per)
atomic.StoreUint64(&internal.predict.calcStorage, (per<<32)+1)
}
type pool interface {
get() *V
}
type globalPool struct{}
func (globalPool) get() *V {
return &V{}
}
type poolImpl struct {
pool []V
count int
actual int // actual counted values
rawSize int
}
func newPool(rawSize int) *poolImpl {
per := internalLoadPredictSizePerValue()
cnt := rawSize / per
p := &poolImpl{
pool: make([]V, cnt),
count: cnt,
actual: 0,
rawSize: rawSize,
}
return p
}
func (p *poolImpl) get() *V {
if p.actual < p.count {
v := &p.pool[p.actual]
p.actual++
return v
}
p.actual++
return globalPool{}.get()
}
func (p *poolImpl) release() {
internalAddPredictSizePerValue(p.rawSize, p.actual)
}