mirror of
https://codeberg.org/scip/tablizer.git
synced 2025-12-17 12:31:06 +01:00
127 lines
3.3 KiB
Go
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
|
|
}
|