mirror of
https://github.com/golang/go
synced 2024-11-24 15:10:02 -07:00
gob: keep free lists of encoder and decoder states.
Avoids 3 mallocs in a round trip encoding/decoding a struct. R=rsc, rsc1 CC=golang-dev https://golang.org/cl/4278052
This commit is contained in:
parent
bcd747204d
commit
eb864e92db
@ -50,7 +50,7 @@ func testError(t *testing.T) {
|
|||||||
func TestUintCodec(t *testing.T) {
|
func TestUintCodec(t *testing.T) {
|
||||||
defer testError(t)
|
defer testError(t)
|
||||||
b := new(bytes.Buffer)
|
b := new(bytes.Buffer)
|
||||||
encState := newEncoderState(nil, b)
|
encState := newEncoderState(b)
|
||||||
for _, tt := range encodeT {
|
for _, tt := range encodeT {
|
||||||
b.Reset()
|
b.Reset()
|
||||||
encState.encodeUint(tt.x)
|
encState.encodeUint(tt.x)
|
||||||
@ -58,7 +58,7 @@ func TestUintCodec(t *testing.T) {
|
|||||||
t.Errorf("encodeUint: %#x encode: expected % x got % x", tt.x, tt.b, b.Bytes())
|
t.Errorf("encodeUint: %#x encode: expected % x got % x", tt.x, tt.b, b.Bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
decState := newDecodeState(nil, b)
|
decState := newDecodeState(b)
|
||||||
for u := uint64(0); ; u = (u + 1) * 7 {
|
for u := uint64(0); ; u = (u + 1) * 7 {
|
||||||
b.Reset()
|
b.Reset()
|
||||||
encState.encodeUint(u)
|
encState.encodeUint(u)
|
||||||
@ -75,9 +75,9 @@ func TestUintCodec(t *testing.T) {
|
|||||||
func verifyInt(i int64, t *testing.T) {
|
func verifyInt(i int64, t *testing.T) {
|
||||||
defer testError(t)
|
defer testError(t)
|
||||||
var b = new(bytes.Buffer)
|
var b = new(bytes.Buffer)
|
||||||
encState := newEncoderState(nil, b)
|
encState := newEncoderState(b)
|
||||||
encState.encodeInt(i)
|
encState.encodeInt(i)
|
||||||
decState := newDecodeState(nil, b)
|
decState := newDecodeState(b)
|
||||||
decState.buf = make([]byte, 8)
|
decState.buf = make([]byte, 8)
|
||||||
j := decState.decodeInt()
|
j := decState.decodeInt()
|
||||||
if i != j {
|
if i != j {
|
||||||
@ -111,9 +111,16 @@ var complexResult = []byte{0x07, 0xFE, 0x31, 0x40, 0xFE, 0x33, 0x40}
|
|||||||
// The result of encoding "hello" with field number 7
|
// The result of encoding "hello" with field number 7
|
||||||
var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
|
var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
|
||||||
|
|
||||||
func newencoderState(b *bytes.Buffer) *encoderState {
|
func newDecodeState(buf *bytes.Buffer) *decoderState {
|
||||||
|
d := new(decoderState)
|
||||||
|
d.b = buf
|
||||||
|
d.buf = make([]byte, uint64Size)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func newEncoderState(b *bytes.Buffer) *encoderState {
|
||||||
b.Reset()
|
b.Reset()
|
||||||
state := newEncoderState(nil, b)
|
state := &encoderState{enc: nil, b: b}
|
||||||
state.fieldnum = -1
|
state.fieldnum = -1
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
@ -127,7 +134,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
{
|
{
|
||||||
data := struct{ a bool }{true}
|
data := struct{ a bool }{true}
|
||||||
instr := &encInstr{encBool, 6, 0, 0}
|
instr := &encInstr{encBool, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(boolResult, b.Bytes()) {
|
if !bytes.Equal(boolResult, b.Bytes()) {
|
||||||
t.Errorf("bool enc instructions: expected % x got % x", boolResult, b.Bytes())
|
t.Errorf("bool enc instructions: expected % x got % x", boolResult, b.Bytes())
|
||||||
@ -139,7 +146,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a int }{17}
|
data := struct{ a int }{17}
|
||||||
instr := &encInstr{encInt, 6, 0, 0}
|
instr := &encInstr{encInt, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(signedResult, b.Bytes()) {
|
if !bytes.Equal(signedResult, b.Bytes()) {
|
||||||
t.Errorf("int enc instructions: expected % x got % x", signedResult, b.Bytes())
|
t.Errorf("int enc instructions: expected % x got % x", signedResult, b.Bytes())
|
||||||
@ -151,7 +158,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a uint }{17}
|
data := struct{ a uint }{17}
|
||||||
instr := &encInstr{encUint, 6, 0, 0}
|
instr := &encInstr{encUint, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(unsignedResult, b.Bytes()) {
|
if !bytes.Equal(unsignedResult, b.Bytes()) {
|
||||||
t.Errorf("uint enc instructions: expected % x got % x", unsignedResult, b.Bytes())
|
t.Errorf("uint enc instructions: expected % x got % x", unsignedResult, b.Bytes())
|
||||||
@ -163,7 +170,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a int8 }{17}
|
data := struct{ a int8 }{17}
|
||||||
instr := &encInstr{encInt8, 6, 0, 0}
|
instr := &encInstr{encInt8, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(signedResult, b.Bytes()) {
|
if !bytes.Equal(signedResult, b.Bytes()) {
|
||||||
t.Errorf("int8 enc instructions: expected % x got % x", signedResult, b.Bytes())
|
t.Errorf("int8 enc instructions: expected % x got % x", signedResult, b.Bytes())
|
||||||
@ -175,7 +182,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a uint8 }{17}
|
data := struct{ a uint8 }{17}
|
||||||
instr := &encInstr{encUint8, 6, 0, 0}
|
instr := &encInstr{encUint8, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(unsignedResult, b.Bytes()) {
|
if !bytes.Equal(unsignedResult, b.Bytes()) {
|
||||||
t.Errorf("uint8 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
|
t.Errorf("uint8 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
|
||||||
@ -187,7 +194,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a int16 }{17}
|
data := struct{ a int16 }{17}
|
||||||
instr := &encInstr{encInt16, 6, 0, 0}
|
instr := &encInstr{encInt16, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(signedResult, b.Bytes()) {
|
if !bytes.Equal(signedResult, b.Bytes()) {
|
||||||
t.Errorf("int16 enc instructions: expected % x got % x", signedResult, b.Bytes())
|
t.Errorf("int16 enc instructions: expected % x got % x", signedResult, b.Bytes())
|
||||||
@ -199,7 +206,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a uint16 }{17}
|
data := struct{ a uint16 }{17}
|
||||||
instr := &encInstr{encUint16, 6, 0, 0}
|
instr := &encInstr{encUint16, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(unsignedResult, b.Bytes()) {
|
if !bytes.Equal(unsignedResult, b.Bytes()) {
|
||||||
t.Errorf("uint16 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
|
t.Errorf("uint16 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
|
||||||
@ -211,7 +218,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a int32 }{17}
|
data := struct{ a int32 }{17}
|
||||||
instr := &encInstr{encInt32, 6, 0, 0}
|
instr := &encInstr{encInt32, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(signedResult, b.Bytes()) {
|
if !bytes.Equal(signedResult, b.Bytes()) {
|
||||||
t.Errorf("int32 enc instructions: expected % x got % x", signedResult, b.Bytes())
|
t.Errorf("int32 enc instructions: expected % x got % x", signedResult, b.Bytes())
|
||||||
@ -223,7 +230,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a uint32 }{17}
|
data := struct{ a uint32 }{17}
|
||||||
instr := &encInstr{encUint32, 6, 0, 0}
|
instr := &encInstr{encUint32, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(unsignedResult, b.Bytes()) {
|
if !bytes.Equal(unsignedResult, b.Bytes()) {
|
||||||
t.Errorf("uint32 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
|
t.Errorf("uint32 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
|
||||||
@ -235,7 +242,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a int64 }{17}
|
data := struct{ a int64 }{17}
|
||||||
instr := &encInstr{encInt64, 6, 0, 0}
|
instr := &encInstr{encInt64, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(signedResult, b.Bytes()) {
|
if !bytes.Equal(signedResult, b.Bytes()) {
|
||||||
t.Errorf("int64 enc instructions: expected % x got % x", signedResult, b.Bytes())
|
t.Errorf("int64 enc instructions: expected % x got % x", signedResult, b.Bytes())
|
||||||
@ -247,7 +254,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a uint64 }{17}
|
data := struct{ a uint64 }{17}
|
||||||
instr := &encInstr{encUint64, 6, 0, 0}
|
instr := &encInstr{encUint64, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(unsignedResult, b.Bytes()) {
|
if !bytes.Equal(unsignedResult, b.Bytes()) {
|
||||||
t.Errorf("uint64 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
|
t.Errorf("uint64 enc instructions: expected % x got % x", unsignedResult, b.Bytes())
|
||||||
@ -259,7 +266,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a float32 }{17}
|
data := struct{ a float32 }{17}
|
||||||
instr := &encInstr{encFloat32, 6, 0, 0}
|
instr := &encInstr{encFloat32, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(floatResult, b.Bytes()) {
|
if !bytes.Equal(floatResult, b.Bytes()) {
|
||||||
t.Errorf("float32 enc instructions: expected % x got % x", floatResult, b.Bytes())
|
t.Errorf("float32 enc instructions: expected % x got % x", floatResult, b.Bytes())
|
||||||
@ -271,7 +278,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a float64 }{17}
|
data := struct{ a float64 }{17}
|
||||||
instr := &encInstr{encFloat64, 6, 0, 0}
|
instr := &encInstr{encFloat64, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(floatResult, b.Bytes()) {
|
if !bytes.Equal(floatResult, b.Bytes()) {
|
||||||
t.Errorf("float64 enc instructions: expected % x got % x", floatResult, b.Bytes())
|
t.Errorf("float64 enc instructions: expected % x got % x", floatResult, b.Bytes())
|
||||||
@ -283,7 +290,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a []byte }{[]byte("hello")}
|
data := struct{ a []byte }{[]byte("hello")}
|
||||||
instr := &encInstr{encUint8Array, 6, 0, 0}
|
instr := &encInstr{encUint8Array, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(bytesResult, b.Bytes()) {
|
if !bytes.Equal(bytesResult, b.Bytes()) {
|
||||||
t.Errorf("bytes enc instructions: expected % x got % x", bytesResult, b.Bytes())
|
t.Errorf("bytes enc instructions: expected % x got % x", bytesResult, b.Bytes())
|
||||||
@ -295,7 +302,7 @@ func TestScalarEncInstructions(t *testing.T) {
|
|||||||
b.Reset()
|
b.Reset()
|
||||||
data := struct{ a string }{"hello"}
|
data := struct{ a string }{"hello"}
|
||||||
instr := &encInstr{encString, 6, 0, 0}
|
instr := &encInstr{encString, 6, 0, 0}
|
||||||
state := newencoderState(b)
|
state := newEncoderState(b)
|
||||||
instr.op(instr, state, unsafe.Pointer(&data))
|
instr.op(instr, state, unsafe.Pointer(&data))
|
||||||
if !bytes.Equal(bytesResult, b.Bytes()) {
|
if !bytes.Equal(bytesResult, b.Bytes()) {
|
||||||
t.Errorf("string enc instructions: expected % x got % x", bytesResult, b.Bytes())
|
t.Errorf("string enc instructions: expected % x got % x", bytesResult, b.Bytes())
|
||||||
@ -315,7 +322,7 @@ func execDec(typ string, instr *decInstr, state *decoderState, t *testing.T, p u
|
|||||||
|
|
||||||
func newDecodeStateFromData(data []byte) *decoderState {
|
func newDecodeStateFromData(data []byte) *decoderState {
|
||||||
b := bytes.NewBuffer(data)
|
b := bytes.NewBuffer(data)
|
||||||
state := newDecodeState(nil, b)
|
state := newDecodeState(b)
|
||||||
state.fieldnum = -1
|
state.fieldnum = -1
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
@ -31,18 +31,29 @@ type decoderState struct {
|
|||||||
b *bytes.Buffer
|
b *bytes.Buffer
|
||||||
fieldnum int // the last field number read.
|
fieldnum int // the last field number read.
|
||||||
buf []byte
|
buf []byte
|
||||||
|
next *decoderState // for free list
|
||||||
}
|
}
|
||||||
|
|
||||||
// We pass the bytes.Buffer separately for easier testing of the infrastructure
|
// We pass the bytes.Buffer separately for easier testing of the infrastructure
|
||||||
// without requiring a full Decoder.
|
// without requiring a full Decoder.
|
||||||
func newDecodeState(dec *Decoder, buf *bytes.Buffer) *decoderState {
|
func (dec *Decoder) newDecoderState(buf *bytes.Buffer) *decoderState {
|
||||||
d := new(decoderState)
|
d := dec.freeList
|
||||||
d.dec = dec
|
if d == nil {
|
||||||
|
d = new(decoderState)
|
||||||
|
d.dec = dec
|
||||||
|
} else {
|
||||||
|
dec.freeList = d.next
|
||||||
|
}
|
||||||
d.b = buf
|
d.b = buf
|
||||||
d.buf = make([]byte, uint64Size)
|
d.buf = make([]byte, uint64Size)
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (dec *Decoder) freeDecoderState(d *decoderState) {
|
||||||
|
d.next = dec.freeList
|
||||||
|
dec.freeList = d
|
||||||
|
}
|
||||||
|
|
||||||
func overflow(name string) os.ErrorString {
|
func overflow(name string) os.ErrorString {
|
||||||
return os.ErrorString(`value for "` + name + `" out of range`)
|
return os.ErrorString(`value for "` + name + `" out of range`)
|
||||||
}
|
}
|
||||||
@ -445,7 +456,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, p uintptr)
|
|||||||
indir = int(ut.decIndir)
|
indir = int(ut.decIndir)
|
||||||
}
|
}
|
||||||
p = allocate(ut.base, p, indir)
|
p = allocate(ut.base, p, indir)
|
||||||
state := newDecodeState(dec, &dec.buf)
|
state := dec.newDecoderState(&dec.buf)
|
||||||
state.fieldnum = singletonField
|
state.fieldnum = singletonField
|
||||||
basep := p
|
basep := p
|
||||||
delta := int(state.decodeUint())
|
delta := int(state.decodeUint())
|
||||||
@ -458,6 +469,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, p uintptr)
|
|||||||
ptr = decIndirect(ptr, instr.indir)
|
ptr = decIndirect(ptr, instr.indir)
|
||||||
}
|
}
|
||||||
instr.op(instr, state, ptr)
|
instr.op(instr, state, ptr)
|
||||||
|
dec.freeDecoderState(state)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,7 +480,7 @@ func (dec *Decoder) decodeSingle(engine *decEngine, ut *userTypeInfo, p uintptr)
|
|||||||
// from the user's value, not from the innards of an engine.
|
// from the user's value, not from the innards of an engine.
|
||||||
func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p uintptr, indir int) (err os.Error) {
|
func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p uintptr, indir int) (err os.Error) {
|
||||||
p = allocate(ut.base.(*reflect.StructType), p, indir)
|
p = allocate(ut.base.(*reflect.StructType), p, indir)
|
||||||
state := newDecodeState(dec, &dec.buf)
|
state := dec.newDecoderState(&dec.buf)
|
||||||
state.fieldnum = -1
|
state.fieldnum = -1
|
||||||
basep := p
|
basep := p
|
||||||
for state.b.Len() > 0 {
|
for state.b.Len() > 0 {
|
||||||
@ -492,12 +504,13 @@ func (dec *Decoder) decodeStruct(engine *decEngine, ut *userTypeInfo, p uintptr,
|
|||||||
instr.op(instr, state, p)
|
instr.op(instr, state, p)
|
||||||
state.fieldnum = fieldnum
|
state.fieldnum = fieldnum
|
||||||
}
|
}
|
||||||
|
dec.freeDecoderState(state)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignoreStruct discards the data for a struct with no destination.
|
// ignoreStruct discards the data for a struct with no destination.
|
||||||
func (dec *Decoder) ignoreStruct(engine *decEngine) (err os.Error) {
|
func (dec *Decoder) ignoreStruct(engine *decEngine) (err os.Error) {
|
||||||
state := newDecodeState(dec, &dec.buf)
|
state := dec.newDecoderState(&dec.buf)
|
||||||
state.fieldnum = -1
|
state.fieldnum = -1
|
||||||
for state.b.Len() > 0 {
|
for state.b.Len() > 0 {
|
||||||
delta := int(state.decodeUint())
|
delta := int(state.decodeUint())
|
||||||
@ -515,13 +528,14 @@ func (dec *Decoder) ignoreStruct(engine *decEngine) (err os.Error) {
|
|||||||
instr.op(instr, state, unsafe.Pointer(nil))
|
instr.op(instr, state, unsafe.Pointer(nil))
|
||||||
state.fieldnum = fieldnum
|
state.fieldnum = fieldnum
|
||||||
}
|
}
|
||||||
|
dec.freeDecoderState(state)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignoreSingle discards the data for a top-level non-struct value with no
|
// ignoreSingle discards the data for a top-level non-struct value with no
|
||||||
// destination. It's used when calling Decode with a nil value.
|
// destination. It's used when calling Decode with a nil value.
|
||||||
func (dec *Decoder) ignoreSingle(engine *decEngine) (err os.Error) {
|
func (dec *Decoder) ignoreSingle(engine *decEngine) (err os.Error) {
|
||||||
state := newDecodeState(dec, &dec.buf)
|
state := dec.newDecoderState(&dec.buf)
|
||||||
state.fieldnum = singletonField
|
state.fieldnum = singletonField
|
||||||
delta := int(state.decodeUint())
|
delta := int(state.decodeUint())
|
||||||
if delta != 0 {
|
if delta != 0 {
|
||||||
@ -529,6 +543,7 @@ func (dec *Decoder) ignoreSingle(engine *decEngine) (err os.Error) {
|
|||||||
}
|
}
|
||||||
instr := &engine.instr[singletonField]
|
instr := &engine.instr[singletonField]
|
||||||
instr.op(instr, state, unsafe.Pointer(nil))
|
instr.op(instr, state, unsafe.Pointer(nil))
|
||||||
|
dec.freeDecoderState(state)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ type Decoder struct {
|
|||||||
wireType map[typeId]*wireType // map from remote ID to local description
|
wireType map[typeId]*wireType // map from remote ID to local description
|
||||||
decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
|
decoderCache map[reflect.Type]map[typeId]**decEngine // cache of compiled engines
|
||||||
ignorerCache map[typeId]**decEngine // ditto for ignored objects
|
ignorerCache map[typeId]**decEngine // ditto for ignored objects
|
||||||
countState *decoderState // reads counts from wire
|
freeList *decoderState // list of free decoderStates; avoids reallocation
|
||||||
countBuf []byte // used for decoding integers while parsing messages
|
countBuf []byte // used for decoding integers while parsing messages
|
||||||
tmp []byte // temporary storage for i/o; saves reallocating
|
tmp []byte // temporary storage for i/o; saves reallocating
|
||||||
err os.Error
|
err os.Error
|
||||||
|
@ -25,10 +25,26 @@ type encoderState struct {
|
|||||||
sendZero bool // encoding an array element or map key/value pair; send zero values
|
sendZero bool // encoding an array element or map key/value pair; send zero values
|
||||||
fieldnum int // the last field number written.
|
fieldnum int // the last field number written.
|
||||||
buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation.
|
buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation.
|
||||||
|
next *encoderState // for free list
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEncoderState(enc *Encoder, b *bytes.Buffer) *encoderState {
|
func (enc *Encoder) newEncoderState(b *bytes.Buffer) *encoderState {
|
||||||
return &encoderState{enc: enc, b: b}
|
e := enc.freeList
|
||||||
|
if e == nil {
|
||||||
|
e = new(encoderState)
|
||||||
|
e.enc = enc
|
||||||
|
} else {
|
||||||
|
enc.freeList = e.next
|
||||||
|
}
|
||||||
|
e.sendZero = false
|
||||||
|
e.fieldnum = 0
|
||||||
|
e.b = b
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
|
||||||
|
func (enc *Encoder) freeEncoderState(e *encoderState) {
|
||||||
|
e.next = enc.freeList
|
||||||
|
enc.freeList = e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsigned integers have a two-state encoding. If the number is less
|
// Unsigned integers have a two-state encoding. If the number is less
|
||||||
@ -326,7 +342,7 @@ const singletonField = 0
|
|||||||
|
|
||||||
// encodeSingle encodes a single top-level non-struct value.
|
// encodeSingle encodes a single top-level non-struct value.
|
||||||
func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, basep uintptr) {
|
func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, basep uintptr) {
|
||||||
state := newEncoderState(enc, b)
|
state := enc.newEncoderState(b)
|
||||||
state.fieldnum = singletonField
|
state.fieldnum = singletonField
|
||||||
// There is no surrounding struct to frame the transmission, so we must
|
// There is no surrounding struct to frame the transmission, so we must
|
||||||
// generate data even if the item is zero. To do this, set sendZero.
|
// generate data even if the item is zero. To do this, set sendZero.
|
||||||
@ -339,11 +355,12 @@ func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, basep uintp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
instr.op(instr, state, p)
|
instr.op(instr, state, p)
|
||||||
|
enc.freeEncoderState(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
// encodeStruct encodes a single struct value.
|
// encodeStruct encodes a single struct value.
|
||||||
func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, basep uintptr) {
|
func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, basep uintptr) {
|
||||||
state := newEncoderState(enc, b)
|
state := enc.newEncoderState(b)
|
||||||
state.fieldnum = -1
|
state.fieldnum = -1
|
||||||
for i := 0; i < len(engine.instr); i++ {
|
for i := 0; i < len(engine.instr); i++ {
|
||||||
instr := &engine.instr[i]
|
instr := &engine.instr[i]
|
||||||
@ -355,11 +372,12 @@ func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, basep uintp
|
|||||||
}
|
}
|
||||||
instr.op(instr, state, p)
|
instr.op(instr, state, p)
|
||||||
}
|
}
|
||||||
|
enc.freeEncoderState(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
// encodeArray encodes the array whose 0th element is at p.
|
// encodeArray encodes the array whose 0th element is at p.
|
||||||
func (enc *Encoder) encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndir int, length int) {
|
func (enc *Encoder) encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndir int, length int) {
|
||||||
state := newEncoderState(enc, b)
|
state := enc.newEncoderState(b)
|
||||||
state.fieldnum = -1
|
state.fieldnum = -1
|
||||||
state.sendZero = true
|
state.sendZero = true
|
||||||
state.encodeUint(uint64(length))
|
state.encodeUint(uint64(length))
|
||||||
@ -375,6 +393,7 @@ func (enc *Encoder) encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid ui
|
|||||||
op(nil, state, unsafe.Pointer(elemp))
|
op(nil, state, unsafe.Pointer(elemp))
|
||||||
p += uintptr(elemWid)
|
p += uintptr(elemWid)
|
||||||
}
|
}
|
||||||
|
enc.freeEncoderState(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
// encodeReflectValue is a helper for maps. It encodes the value v.
|
// encodeReflectValue is a helper for maps. It encodes the value v.
|
||||||
@ -392,7 +411,7 @@ func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir in
|
|||||||
// Because map internals are not exposed, we must use reflection rather than
|
// Because map internals are not exposed, we must use reflection rather than
|
||||||
// addresses.
|
// addresses.
|
||||||
func (enc *Encoder) encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elemOp encOp, keyIndir, elemIndir int) {
|
func (enc *Encoder) encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elemOp encOp, keyIndir, elemIndir int) {
|
||||||
state := newEncoderState(enc, b)
|
state := enc.newEncoderState(b)
|
||||||
state.fieldnum = -1
|
state.fieldnum = -1
|
||||||
state.sendZero = true
|
state.sendZero = true
|
||||||
keys := mv.Keys()
|
keys := mv.Keys()
|
||||||
@ -401,6 +420,7 @@ func (enc *Encoder) encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elem
|
|||||||
encodeReflectValue(state, key, keyOp, keyIndir)
|
encodeReflectValue(state, key, keyOp, keyIndir)
|
||||||
encodeReflectValue(state, mv.Elem(key), elemOp, elemIndir)
|
encodeReflectValue(state, mv.Elem(key), elemOp, elemIndir)
|
||||||
}
|
}
|
||||||
|
enc.freeEncoderState(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
// encodeInterface encodes the interface value iv.
|
// encodeInterface encodes the interface value iv.
|
||||||
@ -409,7 +429,7 @@ func (enc *Encoder) encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elem
|
|||||||
// by the concrete value. A nil value gets sent as the empty string for the name,
|
// by the concrete value. A nil value gets sent as the empty string for the name,
|
||||||
// followed by no value.
|
// followed by no value.
|
||||||
func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue) {
|
func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue) {
|
||||||
state := newEncoderState(enc, b)
|
state := enc.newEncoderState(b)
|
||||||
state.fieldnum = -1
|
state.fieldnum = -1
|
||||||
state.sendZero = true
|
state.sendZero = true
|
||||||
if iv.IsNil() {
|
if iv.IsNil() {
|
||||||
@ -445,6 +465,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue)
|
|||||||
if enc.err != nil {
|
if enc.err != nil {
|
||||||
error(err)
|
error(err)
|
||||||
}
|
}
|
||||||
|
enc.freeEncoderState(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
// encGobEncoder encodes a value that implements the GobEncoder interface.
|
// encGobEncoder encodes a value that implements the GobEncoder interface.
|
||||||
@ -456,10 +477,11 @@ func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, v reflect.Value, index int
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
error(err)
|
error(err)
|
||||||
}
|
}
|
||||||
state := newEncoderState(enc, b)
|
state := enc.newEncoderState(b)
|
||||||
state.fieldnum = -1
|
state.fieldnum = -1
|
||||||
state.encodeUint(uint64(len(data)))
|
state.encodeUint(uint64(len(data)))
|
||||||
state.b.Write(data)
|
state.b.Write(data)
|
||||||
|
enc.freeEncoderState(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
var encOpTable = [...]encOp{
|
var encOpTable = [...]encOp{
|
||||||
|
@ -19,6 +19,7 @@ type Encoder struct {
|
|||||||
w []io.Writer // where to send the data
|
w []io.Writer // where to send the data
|
||||||
sent map[reflect.Type]typeId // which types we've already sent
|
sent map[reflect.Type]typeId // which types we've already sent
|
||||||
countState *encoderState // stage for writing counts
|
countState *encoderState // stage for writing counts
|
||||||
|
freeList *encoderState // list of free encoderStates; avoids reallocation
|
||||||
buf []byte // for collecting the output.
|
buf []byte // for collecting the output.
|
||||||
err os.Error
|
err os.Error
|
||||||
}
|
}
|
||||||
@ -28,7 +29,7 @@ func NewEncoder(w io.Writer) *Encoder {
|
|||||||
enc := new(Encoder)
|
enc := new(Encoder)
|
||||||
enc.w = []io.Writer{w}
|
enc.w = []io.Writer{w}
|
||||||
enc.sent = make(map[reflect.Type]typeId)
|
enc.sent = make(map[reflect.Type]typeId)
|
||||||
enc.countState = newEncoderState(enc, new(bytes.Buffer))
|
enc.countState = enc.newEncoderState(new(bytes.Buffer))
|
||||||
return enc
|
return enc
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,7 +219,7 @@ func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enc.err = nil
|
enc.err = nil
|
||||||
state := newEncoderState(enc, new(bytes.Buffer))
|
state := enc.newEncoderState(new(bytes.Buffer))
|
||||||
|
|
||||||
enc.sendTypeDescriptor(enc.writer(), state, ut)
|
enc.sendTypeDescriptor(enc.writer(), state, ut)
|
||||||
enc.sendTypeId(state, ut)
|
enc.sendTypeId(state, ut)
|
||||||
@ -234,5 +235,6 @@ func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
|
|||||||
enc.writeMessage(enc.writer(), state.b)
|
enc.writeMessage(enc.writer(), state.b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enc.freeEncoderState(state)
|
||||||
return enc.err
|
return enc.err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user