113 lines
2.1 KiB
Go
113 lines
2.1 KiB
Go
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)
|
|
}
|