Files
tablizer/vendor/github.com/glycerine/greenpack/msgp/nilbits.go
2024-05-14 12:10:58 +02:00

127 lines
3.3 KiB
Go

package msgp
import (
"fmt"
//"runtime/debug"
)
const MaxNestedStructPointerDepth = 8
// NilBitsStack is a helper for Unmarshal
// methods to track where we are when
// deserializing from empty/nil/missing
// fields.
type NilBitsStack struct {
// simulate getting nils on the wire
AlwaysNil bool
LifoAlwaysNil int // this lifo always had false in it, so change it to a count.
LifoBts [MaxNestedStructPointerDepth][]byte // caps our static tree depth at 8, but avoids all memory allocation during the decode hotpath.
// UnsafeZeroCopy will make strings point to the
// original msgpack buffers. This is unsafe because
// if the buffer changes the string will change/be
// invalid/not protected against re-use. But for
// processing and disposing of single messages, one-at-at-time,
// without re-using any part of a message (or making a copy of strings explicitly with copy()
// if you must) then we can avoid all allocations for strings.
UnsafeZeroCopy bool
}
func (r *NilBitsStack) Init(cfg *RuntimeConfig) {
if cfg != nil {
r.UnsafeZeroCopy = cfg.UnsafeZeroCopy
}
}
func (r *NilBitsStack) IsNil(bts []byte) bool {
if r.AlwaysNil {
return true
}
if len(bts) != 0 && bts[0] == mnil {
return true
}
return false
}
// OnlyNilSlice is a slice that contains
// only the msgpack nil (0xc0) bytes.
var OnlyNilSlice = []byte{mnil}
// AlwaysNilString returns a string representation
// of the internal state of the NilBitsStack for
// debugging purposes.
func (r *NilBitsStack) AlwaysNilString() string {
s := "bottom: "
for i := 0; i > r.LifoAlwaysNil; i++ {
s += "T"
}
/* for _, v := range r.LifoAlwaysNil {
if v {
s += "T"
} else {
s += "f"
}
}
*/
return s
}
// PushAlwaysNil will set r.AlwaysNil to true
// and store bts on the internal stack.
func (r *NilBitsStack) PushAlwaysNil(bts []byte) []byte {
//fmt.Printf("PushAlwaysNil(), pre we are '%v'. Called from: stack is '%v'\n", r.AlwaysNilString(), string(debug.Stack()))
// save current state
if r.LifoAlwaysNil == MaxNestedStructPointerDepth {
panic(fmt.Sprintf("we hit our maximum nested struct-inside-struct depth! you must recompile msgp with github.com/glycerine/greenpack/msgp/nilbits.go: MaxNestedStructPointerDepth set to greater than the current value of %v, and then regenerate your msgp Unmarshaling code.", MaxNestedStructPointerDepth))
}
r.LifoBts[r.LifoAlwaysNil] = bts
r.LifoAlwaysNil++
// set reader r to always return nils
r.AlwaysNil = true
return OnlyNilSlice
}
// PopAlwaysNil pops the last []byte off the internal
// stack and returns it. If the stack is empty
// we panic.
func (r *NilBitsStack) PopAlwaysNil() (bts []byte) {
//fmt.Printf("my NilBitsTack.PopAlwaysNil() called!! ... stack is '%v'\n", string(debug.Stack()))
// defer func() {
// fmt.Printf("len of bts returned by PopAlwaysNil: %v, and debug string: '%v'\n",
// len(bts), r.AlwaysNilString())
// }()
n := r.LifoAlwaysNil
if n == 0 {
panic("PopAlwaysNil called on empty lifo")
}
if n < 0 {
panic("PopAlwaysNil called on illegal-less-thab-empty lifo")
}
bts = r.LifoBts[n-1]
r.LifoAlwaysNil--
if r.LifoAlwaysNil == 0 {
r.AlwaysNil = false
}
return bts
}
func ShowFound(found []bool) string {
s := "["
for i := range found {
if found[i] {
s += "1,"
} else {
s += "0,"
}
}
s += "]"
return s
}