@@ -91,13 +91,6 @@ func EncodeToReader(val interface{}) (size int, r io.Reader, err error) {
9191 return eb .size (), & encReader {buf : eb }, nil
9292}
9393
94- type encbuf struct {
95- str []byte // string data, contains everything except list headers
96- lheads []listhead // all list headers
97- lhsize int // sum of sizes of all encoded list headers
98- sizebuf []byte // 9-byte auxiliary buffer for uint encoding
99- }
100-
10194type listhead struct {
10295 offset int // index of this header in string data
10396 size int // total size of encoded data (including list headers)
@@ -130,9 +123,20 @@ func puthead(buf []byte, smalltag, largetag byte, size uint64) int {
130123 return sizesize + 1
131124}
132125
126+ type encbuf struct {
127+ str []byte // string data, contains everything except list headers
128+ lheads []listhead // all list headers
129+ lhsize int // sum of sizes of all encoded list headers
130+ sizebuf [9 ]byte // auxiliary buffer for uint encoding
131+ bufvalue reflect.Value // used in writeByteArrayCopy
132+ }
133+
133134// encbufs are pooled.
134135var encbufPool = sync.Pool {
135- New : func () interface {} { return & encbuf {sizebuf : make ([]byte , 9 )} },
136+ New : func () interface {} {
137+ var bytes []byte
138+ return & encbuf {bufvalue : reflect .ValueOf (& bytes ).Elem ()}
139+ },
136140}
137141
138142func (w * encbuf ) reset () {
@@ -160,7 +164,6 @@ func (w *encbuf) encodeStringHeader(size int) {
160164 if size < 56 {
161165 w .str = append (w .str , 0x80 + byte (size ))
162166 } else {
163- // TODO: encode to w.str directly
164167 sizesize := putint (w .sizebuf [1 :], uint64 (size ))
165168 w .sizebuf [0 ] = 0xB7 + byte (sizesize )
166169 w .str = append (w .str , w .sizebuf [:sizesize + 1 ]... )
@@ -177,6 +180,19 @@ func (w *encbuf) encodeString(b []byte) {
177180 }
178181}
179182
183+ func (w * encbuf ) encodeUint (i uint64 ) {
184+ if i == 0 {
185+ w .str = append (w .str , 0x80 )
186+ } else if i < 128 {
187+ // fits single byte
188+ w .str = append (w .str , byte (i ))
189+ } else {
190+ s := putint (w .sizebuf [1 :], i )
191+ w .sizebuf [0 ] = 0x80 + byte (s )
192+ w .str = append (w .str , w .sizebuf [:s + 1 ]... )
193+ }
194+ }
195+
180196// list adds a new list header to the header stack. It returns the index
181197// of the header. The caller must call listEnd with this index after encoding
182198// the content of the list.
@@ -229,7 +245,7 @@ func (w *encbuf) toWriter(out io.Writer) (err error) {
229245 }
230246 }
231247 // write the header
232- enc := head .encode (w .sizebuf )
248+ enc := head .encode (w .sizebuf [:] )
233249 if _ , err = out .Write (enc ); err != nil {
234250 return err
235251 }
@@ -295,7 +311,7 @@ func (r *encReader) next() []byte {
295311 return p
296312 }
297313 r .lhpos ++
298- return head .encode (r .buf .sizebuf )
314+ return head .encode (r .buf .sizebuf [:] )
299315
300316 case r .strpos < len (r .buf .str ):
301317 // String data at the end, after all list headers.
@@ -308,10 +324,7 @@ func (r *encReader) next() []byte {
308324 }
309325}
310326
311- var (
312- encoderInterface = reflect .TypeOf (new (Encoder )).Elem ()
313- big0 = big .NewInt (0 )
314- )
327+ var encoderInterface = reflect .TypeOf (new (Encoder )).Elem ()
315328
316329// makeWriter creates a writer function for the given type.
317330func makeWriter (typ reflect.Type , ts tags ) (writer , error ) {
@@ -336,7 +349,7 @@ func makeWriter(typ reflect.Type, ts tags) (writer, error) {
336349 case kind == reflect .Slice && isByte (typ .Elem ()):
337350 return writeBytes , nil
338351 case kind == reflect .Array && isByte (typ .Elem ()):
339- return writeByteArray , nil
352+ return makeByteArrayWriter ( typ ) , nil
340353 case kind == reflect .Slice || kind == reflect .Array :
341354 return makeSliceWriter (typ , ts )
342355 case kind == reflect .Struct :
@@ -348,28 +361,13 @@ func makeWriter(typ reflect.Type, ts tags) (writer, error) {
348361 }
349362}
350363
351- func isByte (typ reflect.Type ) bool {
352- return typ .Kind () == reflect .Uint8 && ! typ .Implements (encoderInterface )
353- }
354-
355364func writeRawValue (val reflect.Value , w * encbuf ) error {
356365 w .str = append (w .str , val .Bytes ()... )
357366 return nil
358367}
359368
360369func writeUint (val reflect.Value , w * encbuf ) error {
361- i := val .Uint ()
362- if i == 0 {
363- w .str = append (w .str , 0x80 )
364- } else if i < 128 {
365- // fits single byte
366- w .str = append (w .str , byte (i ))
367- } else {
368- // TODO: encode int to w.str directly
369- s := putint (w .sizebuf [1 :], i )
370- w .sizebuf [0 ] = 0x80 + byte (s )
371- w .str = append (w .str , w .sizebuf [:s + 1 ]... )
372- }
370+ w .encodeUint (val .Uint ())
373371 return nil
374372}
375373
@@ -396,13 +394,32 @@ func writeBigIntNoPtr(val reflect.Value, w *encbuf) error {
396394 return writeBigInt (& i , w )
397395}
398396
397+ // wordBytes is the number of bytes in a big.Word
398+ const wordBytes = (32 << (uint64 (^ big .Word (0 )) >> 63 )) / 8
399+
399400func writeBigInt (i * big.Int , w * encbuf ) error {
400- if cmp := i . Cmp ( big0 ); cmp == - 1 {
401+ if i . Sign () == - 1 {
401402 return fmt .Errorf ("rlp: cannot encode negative *big.Int" )
402- } else if cmp == 0 {
403- w .str = append (w .str , 0x80 )
404- } else {
405- w .encodeString (i .Bytes ())
403+ }
404+ bitlen := i .BitLen ()
405+ if bitlen <= 64 {
406+ w .encodeUint (i .Uint64 ())
407+ return nil
408+ }
409+ // Integer is larger than 64 bits, encode from i.Bits().
410+ // The minimal byte length is bitlen rounded up to the next
411+ // multiple of 8, divided by 8.
412+ length := ((bitlen + 7 ) & - 8 ) >> 3
413+ w .encodeStringHeader (length )
414+ w .str = append (w .str , make ([]byte , length )... )
415+ index := length
416+ buf := w .str [len (w .str )- length :]
417+ for _ , d := range i .Bits () {
418+ for j := 0 ; j < wordBytes && index > 0 ; j ++ {
419+ index --
420+ buf [index ] = byte (d )
421+ d >>= 8
422+ }
406423 }
407424 return nil
408425}
@@ -412,7 +429,52 @@ func writeBytes(val reflect.Value, w *encbuf) error {
412429 return nil
413430}
414431
415- func writeByteArray (val reflect.Value , w * encbuf ) error {
432+ var byteType = reflect .TypeOf (byte (0 ))
433+
434+ func makeByteArrayWriter (typ reflect.Type ) writer {
435+ length := typ .Len ()
436+ if length == 0 {
437+ return writeLengthZeroByteArray
438+ } else if length == 1 {
439+ return writeLengthOneByteArray
440+ }
441+ if typ .Elem () != byteType {
442+ return writeNamedByteArray
443+ }
444+ return func (val reflect.Value , w * encbuf ) error {
445+ writeByteArrayCopy (length , val , w )
446+ return nil
447+ }
448+ }
449+
450+ func writeLengthZeroByteArray (val reflect.Value , w * encbuf ) error {
451+ w .str = append (w .str , 0x80 )
452+ return nil
453+ }
454+
455+ func writeLengthOneByteArray (val reflect.Value , w * encbuf ) error {
456+ b := byte (val .Index (0 ).Uint ())
457+ if b <= 0x7f {
458+ w .str = append (w .str , b )
459+ } else {
460+ w .str = append (w .str , 0x81 , b )
461+ }
462+ return nil
463+ }
464+
465+ // writeByteArrayCopy encodes byte arrays using reflect.Copy. This is
466+ // the fast path for [N]byte where N > 1.
467+ func writeByteArrayCopy (length int , val reflect.Value , w * encbuf ) {
468+ w .encodeStringHeader (length )
469+ offset := len (w .str )
470+ w .str = append (w .str , make ([]byte , length )... )
471+ w .bufvalue .SetBytes (w .str [offset :])
472+ reflect .Copy (w .bufvalue , val )
473+ }
474+
475+ // writeNamedByteArray encodes byte arrays with named element type.
476+ // This exists because reflect.Copy can't be used with such types.
477+ func writeNamedByteArray (val reflect.Value , w * encbuf ) error {
416478 if ! val .CanAddr () {
417479 // Slice requires the value to be addressable.
418480 // Make it addressable by copying.
0 commit comments