@@ -416,9 +416,9 @@ func (d *decoder) decodeMap(size uint, offset uint, result reflect.Value) (uint,
416416 }
417417
418418 for i := uint (0 ); i < size ; i ++ {
419- var key string
419+ var key [] byte
420420 var err error
421- key , offset , err = d .decodeKeyString (offset )
421+ key , offset , err = d .decodeKey (offset )
422422
423423 if err != nil {
424424 return 0 , err
@@ -429,7 +429,7 @@ func (d *decoder) decodeMap(size uint, offset uint, result reflect.Value) (uint,
429429 if err != nil {
430430 return 0 , err
431431 }
432- result .SetMapIndex (reflect .ValueOf (key ), value .Elem ())
432+ result .SetMapIndex (reflect .ValueOf (string ( key ) ), value .Elem ())
433433 }
434434 return offset , nil
435435}
@@ -534,13 +534,15 @@ func (d *decoder) decodeStruct(size uint, offset uint, result reflect.Value) (ui
534534 for i := uint (0 ); i < size ; i ++ {
535535 var (
536536 err error
537- key string
537+ key [] byte
538538 )
539- key , offset , err = d .decodeStructKey (offset )
539+ key , offset , err = d .decodeKey (offset )
540540 if err != nil {
541541 return 0 , err
542542 }
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 )]
544546 if ! ok {
545547 offset = d .nextValueOffset (offset , 1 )
546548 continue
@@ -577,17 +579,22 @@ func uintFromBytes(prefix uint64, uintBytes []byte) uint64 {
577579 return val
578580}
579581
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 )
582588 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 )
585591 return key , ptrOffset , err
586592 }
587593 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 )
589595 }
590- return d .decodeString (size , newOffset )
596+ newOffset := dataOffset + size
597+ return d .buffer [dataOffset :newOffset ], newOffset , nil
591598}
592599
593600// This function is used to skip ahead to the next value without decoding
0 commit comments