@@ -91,13 +91,6 @@ func EncodeToReader(val interface{}) (size int, r io.Reader, err error) {
91
91
return eb .size (), & encReader {buf : eb }, nil
92
92
}
93
93
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
-
101
94
type listhead struct {
102
95
offset int // index of this header in string data
103
96
size int // total size of encoded data (including list headers)
@@ -130,9 +123,20 @@ func puthead(buf []byte, smalltag, largetag byte, size uint64) int {
130
123
return sizesize + 1
131
124
}
132
125
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
+
133
134
// encbufs are pooled.
134
135
var 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
+ },
136
140
}
137
141
138
142
func (w * encbuf ) reset () {
@@ -160,7 +164,6 @@ func (w *encbuf) encodeStringHeader(size int) {
160
164
if size < 56 {
161
165
w .str = append (w .str , 0x80 + byte (size ))
162
166
} else {
163
- // TODO: encode to w.str directly
164
167
sizesize := putint (w .sizebuf [1 :], uint64 (size ))
165
168
w .sizebuf [0 ] = 0xB7 + byte (sizesize )
166
169
w .str = append (w .str , w .sizebuf [:sizesize + 1 ]... )
@@ -177,6 +180,19 @@ func (w *encbuf) encodeString(b []byte) {
177
180
}
178
181
}
179
182
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
+
180
196
// list adds a new list header to the header stack. It returns the index
181
197
// of the header. The caller must call listEnd with this index after encoding
182
198
// the content of the list.
@@ -229,7 +245,7 @@ func (w *encbuf) toWriter(out io.Writer) (err error) {
229
245
}
230
246
}
231
247
// write the header
232
- enc := head .encode (w .sizebuf )
248
+ enc := head .encode (w .sizebuf [:] )
233
249
if _ , err = out .Write (enc ); err != nil {
234
250
return err
235
251
}
@@ -295,7 +311,7 @@ func (r *encReader) next() []byte {
295
311
return p
296
312
}
297
313
r .lhpos ++
298
- return head .encode (r .buf .sizebuf )
314
+ return head .encode (r .buf .sizebuf [:] )
299
315
300
316
case r .strpos < len (r .buf .str ):
301
317
// String data at the end, after all list headers.
@@ -308,10 +324,7 @@ func (r *encReader) next() []byte {
308
324
}
309
325
}
310
326
311
- var (
312
- encoderInterface = reflect .TypeOf (new (Encoder )).Elem ()
313
- big0 = big .NewInt (0 )
314
- )
327
+ var encoderInterface = reflect .TypeOf (new (Encoder )).Elem ()
315
328
316
329
// makeWriter creates a writer function for the given type.
317
330
func makeWriter (typ reflect.Type , ts tags ) (writer , error ) {
@@ -336,7 +349,7 @@ func makeWriter(typ reflect.Type, ts tags) (writer, error) {
336
349
case kind == reflect .Slice && isByte (typ .Elem ()):
337
350
return writeBytes , nil
338
351
case kind == reflect .Array && isByte (typ .Elem ()):
339
- return writeByteArray , nil
352
+ return makeByteArrayWriter ( typ ) , nil
340
353
case kind == reflect .Slice || kind == reflect .Array :
341
354
return makeSliceWriter (typ , ts )
342
355
case kind == reflect .Struct :
@@ -348,28 +361,13 @@ func makeWriter(typ reflect.Type, ts tags) (writer, error) {
348
361
}
349
362
}
350
363
351
- func isByte (typ reflect.Type ) bool {
352
- return typ .Kind () == reflect .Uint8 && ! typ .Implements (encoderInterface )
353
- }
354
-
355
364
func writeRawValue (val reflect.Value , w * encbuf ) error {
356
365
w .str = append (w .str , val .Bytes ()... )
357
366
return nil
358
367
}
359
368
360
369
func 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 ())
373
371
return nil
374
372
}
375
373
@@ -396,13 +394,32 @@ func writeBigIntNoPtr(val reflect.Value, w *encbuf) error {
396
394
return writeBigInt (& i , w )
397
395
}
398
396
397
+ // wordBytes is the number of bytes in a big.Word
398
+ const wordBytes = (32 << (uint64 (^ big .Word (0 )) >> 63 )) / 8
399
+
399
400
func writeBigInt (i * big.Int , w * encbuf ) error {
400
- if cmp := i . Cmp ( big0 ); cmp == - 1 {
401
+ if i . Sign () == - 1 {
401
402
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
+ }
406
423
}
407
424
return nil
408
425
}
@@ -412,7 +429,52 @@ func writeBytes(val reflect.Value, w *encbuf) error {
412
429
return nil
413
430
}
414
431
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 {
416
478
if ! val .CanAddr () {
417
479
// Slice requires the value to be addressable.
418
480
// Make it addressable by copying.
0 commit comments