// Test basic encode/decode routines for unsigned integers
func TestUintCodec(t *testing.T) {
defer testError(t)
- b := new(bytes.Buffer)
+ b := new(encBuffer)
encState := newEncoderState(b)
for _, tt := range encodeT {
b.Reset()
t.Errorf("encodeUint: %#x encode: expected % x got % x", tt.x, tt.b, b.Bytes())
}
}
- decState := newDecodeState(b)
for u := uint64(0); ; u = (u + 1) * 7 {
b.Reset()
encState.encodeUint(u)
+ decState := newDecodeState(bytes.NewBuffer(b.Bytes()))
v := decState.decodeUint()
if u != v {
t.Errorf("Encode/Decode: sent %#x received %#x", u, v)
func verifyInt(i int64, t *testing.T) {
defer testError(t)
- var b = new(bytes.Buffer)
+ var b = new(encBuffer)
encState := newEncoderState(b)
encState.encodeInt(i)
- decState := newDecodeState(b)
+ decState := newDecodeState(bytes.NewBuffer(b.Bytes()))
decState.buf = make([]byte, 8)
j := decState.decodeInt()
if i != j {
return d
}
-func newEncoderState(b *bytes.Buffer) *encoderState {
+func newEncoderState(b *encBuffer) *encoderState {
b.Reset()
state := &encoderState{enc: nil, b: b}
state.fieldnum = -1
// Test instruction execution for encoding.
// Do not run the machine yet; instead do individual instructions crafted by hand.
func TestScalarEncInstructions(t *testing.T) {
- var b = new(bytes.Buffer)
+ var b = new(encBuffer)
// bool
{
package gob
import (
- "bytes"
"encoding"
"math"
"reflect"
// 0 terminates the structure.
type encoderState struct {
enc *Encoder
- b *bytes.Buffer
+ b *encBuffer
sendZero bool // encoding an array element or map key/value pair; send zero values
fieldnum int // the last field number written.
buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation.
next *encoderState // for free list
}
-func (enc *Encoder) newEncoderState(b *bytes.Buffer) *encoderState {
+// encBuffer is an extremely simple, fast implementation of a write-only byte buffer.
+// It never returns a non-nil error, but Write returns an error value so it matches io.Writer.
+type encBuffer struct {
+ data []byte
+ scratch [64]byte
+}
+
+func (e *encBuffer) WriteByte(c byte) {
+ e.data = append(e.data, c)
+}
+
+func (e *encBuffer) Write(p []byte) (int, error) {
+ e.data = append(e.data, p...)
+ return len(p), nil
+}
+
+func (e *encBuffer) WriteString(s string) {
+ e.data = append(e.data, s...)
+}
+
+func (e *encBuffer) Len() int {
+ return len(e.data)
+}
+
+func (e *encBuffer) Bytes() []byte {
+ return e.data
+}
+
+func (e *encBuffer) Reset() {
+ e.data = e.data[0:0]
+}
+
+func (enc *Encoder) newEncoderState(b *encBuffer) *encoderState {
e := enc.freeList
if e == nil {
e = new(encoderState)
e.sendZero = false
e.fieldnum = 0
e.b = b
+ if len(b.data) == 0 {
+ b.data = b.scratch[0:0]
+ }
return e
}
// encodeUint writes an encoded unsigned integer to state.b.
func (state *encoderState) encodeUint(x uint64) {
if x <= 0x7F {
- err := state.b.WriteByte(uint8(x))
- if err != nil {
- error_(err)
- }
+ state.b.WriteByte(uint8(x))
return
}
i := uint64Size
i--
}
state.buf[i] = uint8(i - uint64Size) // = loop count, negated
- _, err := state.b.Write(state.buf[i : uint64Size+1])
- if err != nil {
- error_(err)
- }
+ state.b.Write(state.buf[i : uint64Size+1])
}
// encodeInt writes an encoded signed integer to state.w.
}
// encodeSingle encodes a single top-level non-struct value.
-func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, value reflect.Value) {
+func (enc *Encoder) encodeSingle(b *encBuffer, engine *encEngine, value reflect.Value) {
state := enc.newEncoderState(b)
defer enc.freeEncoderState(state)
state.fieldnum = singletonField
}
// encodeStruct encodes a single struct value.
-func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, value reflect.Value) {
+func (enc *Encoder) encodeStruct(b *encBuffer, engine *encEngine, value reflect.Value) {
if !valid(value) {
return
}
}
// encodeArray encodes an array.
-func (enc *Encoder) encodeArray(b *bytes.Buffer, value reflect.Value, op encOp, elemIndir int, length int, helper encHelper) {
+func (enc *Encoder) encodeArray(b *encBuffer, value reflect.Value, op encOp, elemIndir int, length int, helper encHelper) {
state := enc.newEncoderState(b)
defer enc.freeEncoderState(state)
state.fieldnum = -1
}
// encodeMap encodes a map as unsigned count followed by key:value pairs.
-func (enc *Encoder) encodeMap(b *bytes.Buffer, mv reflect.Value, keyOp, elemOp encOp, keyIndir, elemIndir int) {
+func (enc *Encoder) encodeMap(b *encBuffer, mv reflect.Value, keyOp, elemOp encOp, keyIndir, elemIndir int) {
state := enc.newEncoderState(b)
state.fieldnum = -1
state.sendZero = true
// by the type identifier (which might require defining that type right now), followed
// by the concrete value. A nil value gets sent as the empty string for the name,
// followed by no value.
-func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv reflect.Value) {
+func (enc *Encoder) encodeInterface(b *encBuffer, iv reflect.Value) {
// Gobs can encode nil interface values but not typed interface
// values holding nil pointers, since nil pointers point to no value.
elem := iv.Elem()
}
// Send the name.
state.encodeUint(uint64(len(name)))
- _, err := state.b.WriteString(name)
- if err != nil {
- error_(err)
- }
+ state.b.WriteString(name)
// Define the type id if necessary.
enc.sendTypeDescriptor(enc.writer(), state, ut)
// Send the type id.
// Encode the value into a new buffer. Any nested type definitions
// should be written to b, before the encoded value.
enc.pushWriter(b)
- data := new(bytes.Buffer)
+ data := new(encBuffer)
data.Write(spaceForLength)
enc.encode(data, elem, ut)
if enc.err != nil {
enc.popWriter()
enc.writeMessage(b, data)
if enc.err != nil {
- error_(err)
+ error_(enc.err)
}
enc.freeEncoderState(state)
}
// encGobEncoder encodes a value that implements the GobEncoder interface.
// The data is sent as a byte array.
-func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, ut *userTypeInfo, v reflect.Value) {
+func (enc *Encoder) encodeGobEncoder(b *encBuffer, ut *userTypeInfo, v reflect.Value) {
// TODO: should we catch panics from the called method?
var data []byte
return enc
}
-func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value, ut *userTypeInfo) {
+func (enc *Encoder) encode(b *encBuffer, value reflect.Value, ut *userTypeInfo) {
defer catchError(&enc.err)
engine := getEncEngine(ut, nil)
indir := ut.indir