@@ -416,9 +416,9 @@ func (d *decoder) decodeMap(size uint, offset uint, result reflect.Value) (uint,
416
416
}
417
417
418
418
for i := uint (0 ); i < size ; i ++ {
419
- var key string
419
+ var key [] byte
420
420
var err error
421
- key , offset , err = d .decodeKeyString (offset )
421
+ key , offset , err = d .decodeKey (offset )
422
422
423
423
if err != nil {
424
424
return 0 , err
@@ -429,7 +429,7 @@ func (d *decoder) decodeMap(size uint, offset uint, result reflect.Value) (uint,
429
429
if err != nil {
430
430
return 0 , err
431
431
}
432
- result .SetMapIndex (reflect .ValueOf (key ), value .Elem ())
432
+ result .SetMapIndex (reflect .ValueOf (string ( key ) ), value .Elem ())
433
433
}
434
434
return offset , nil
435
435
}
@@ -534,13 +534,15 @@ func (d *decoder) decodeStruct(size uint, offset uint, result reflect.Value) (ui
534
534
for i := uint (0 ); i < size ; i ++ {
535
535
var (
536
536
err error
537
- key string
537
+ key [] byte
538
538
)
539
- key , offset , err = d .decodeStructKey (offset )
539
+ key , offset , err = d .decodeKey (offset )
540
540
if err != nil {
541
541
return 0 , err
542
542
}
543
- j , ok := fields .namedFields [key ]
543
+ // The string() does not create a copy due to this compiler
544
+ // optimization: https://github.com/golang/go/issues/3512
545
+ j , ok := fields .namedFields [string (key )]
544
546
if ! ok {
545
547
offset = d .nextValueOffset (offset , 1 )
546
548
continue
@@ -577,17 +579,22 @@ func uintFromBytes(prefix uint64, uintBytes []byte) uint64 {
577
579
return val
578
580
}
579
581
580
- func (d * decoder ) decodeKeyString (offset uint ) (string , uint , error ) {
581
- typeNum , size , newOffset := d .decodeCtrlData (offset )
582
+ // decodeKey decodes a map key into []byte slice. We use a []byte so that we
583
+ // can take advantage of https://github.com/golang/go/issues/3512 to avoid
584
+ // copying the bytes when decoding a struct. Previously, we achieved this by
585
+ // using unsafe.
586
+ func (d * decoder ) decodeKey (offset uint ) ([]byte , uint , error ) {
587
+ typeNum , size , dataOffset := d .decodeCtrlData (offset )
582
588
if typeNum == _Pointer {
583
- pointer , ptrOffset := d .decodePointer (size , newOffset )
584
- key , _ , err := d .decodeKeyString (pointer )
589
+ pointer , ptrOffset := d .decodePointer (size , dataOffset )
590
+ key , _ , err := d .decodeKey (pointer )
585
591
return key , ptrOffset , err
586
592
}
587
593
if typeNum != _String {
588
- return "" , 0 , newInvalidDatabaseError ("unexpected type when decoding string: %v" , typeNum )
594
+ return nil , 0 , newInvalidDatabaseError ("unexpected type when decoding string: %v" , typeNum )
589
595
}
590
- return d .decodeString (size , newOffset )
596
+ newOffset := dataOffset + size
597
+ return d .buffer [dataOffset :newOffset ], newOffset , nil
591
598
}
592
599
593
600
// This function is used to skip ahead to the next value without decoding
0 commit comments