Skip to content

Commit d42d56b

Browse files
apocelipesgopherbot
authored andcommitted
encoding/xml: make use of reflect.TypeAssert
To make the code more readable and improve performance: goos: darwin goarch: arm64 pkg: encoding/xml cpu: Apple M4 │ old │ new │ │ sec/op │ sec/op vs base │ Marshal-10 1.902µ ± 1% 1.496µ ± 1% -21.37% (p=0.000 n=10) Unmarshal-10 3.877µ ± 1% 3.418µ ± 2% -11.84% (p=0.000 n=10) HTMLAutoClose-10 1.314µ ± 3% 1.333µ ± 1% ~ (p=0.270 n=10) geomean 2.132µ 1.896µ -11.07% │ old │ new │ │ B/op │ B/op vs base │ Marshal-10 5.570Ki ± 0% 5.570Ki ± 0% ~ (p=1.000 n=10) ¹ Unmarshal-10 7.586Ki ± 0% 7.555Ki ± 0% -0.41% (p=0.000 n=10) HTMLAutoClose-10 3.496Ki ± 0% 3.496Ki ± 0% ~ (p=1.000 n=10) ¹ geomean 5.286Ki 5.279Ki -0.14% ¹ all samples are equal │ old │ new │ │ allocs/op │ allocs/op vs base │ Marshal-10 23.00 ± 0% 23.00 ± 0% ~ (p=1.000 n=10) ¹ Unmarshal-10 185.0 ± 0% 184.0 ± 0% -0.54% (p=0.000 n=10) HTMLAutoClose-10 93.00 ± 0% 93.00 ± 0% ~ (p=1.000 n=10) ¹ geomean 73.42 73.28 -0.18% ¹ all samples are equal Updates #62121 Change-Id: Ie458e7458d4358c380374571d380ca3b65ca87bb GitHub-Last-Rev: bb6bb30 GitHub-Pull-Request: #75483 Reviewed-on: https://go-review.googlesource.com/c/go/+/704215 LUCI-TryBot-Result: Go LUCI <[email protected]> Auto-Submit: Keith Randall <[email protected]> Reviewed-by: Keith Randall <[email protected]> Reviewed-by: Keith Randall <[email protected]> Reviewed-by: Carlos Amedee <[email protected]>
1 parent 6d51f93 commit d42d56b

File tree

2 files changed

+117
-87
lines changed

2 files changed

+117
-87
lines changed

src/encoding/xml/marshal.go

Lines changed: 71 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -416,12 +416,6 @@ func (p *printer) popPrefix() {
416416
}
417417
}
418418

419-
var (
420-
marshalerType = reflect.TypeFor[Marshaler]()
421-
marshalerAttrType = reflect.TypeFor[MarshalerAttr]()
422-
textMarshalerType = reflect.TypeFor[encoding.TextMarshaler]()
423-
)
424-
425419
// marshalValue writes one or more XML elements representing val.
426420
// If val was obtained from a struct field, finfo must have its details.
427421
func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplate *StartElement) error {
@@ -450,24 +444,32 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
450444
typ := val.Type()
451445

452446
// Check for marshaler.
453-
if val.CanInterface() && typ.Implements(marshalerType) {
454-
return p.marshalInterface(val.Interface().(Marshaler), defaultStart(typ, finfo, startTemplate))
447+
if val.CanInterface() {
448+
if marshaler, ok := reflect.TypeAssert[Marshaler](val); ok {
449+
return p.marshalInterface(marshaler, defaultStart(typ, finfo, startTemplate))
450+
}
455451
}
456452
if val.CanAddr() {
457453
pv := val.Addr()
458-
if pv.CanInterface() && pv.Type().Implements(marshalerType) {
459-
return p.marshalInterface(pv.Interface().(Marshaler), defaultStart(pv.Type(), finfo, startTemplate))
454+
if pv.CanInterface() {
455+
if marshaler, ok := reflect.TypeAssert[Marshaler](pv); ok {
456+
return p.marshalInterface(marshaler, defaultStart(pv.Type(), finfo, startTemplate))
457+
}
460458
}
461459
}
462460

463461
// Check for text marshaler.
464-
if val.CanInterface() && typ.Implements(textMarshalerType) {
465-
return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), defaultStart(typ, finfo, startTemplate))
462+
if val.CanInterface() {
463+
if textMarshaler, ok := reflect.TypeAssert[encoding.TextMarshaler](val); ok {
464+
return p.marshalTextInterface(textMarshaler, defaultStart(typ, finfo, startTemplate))
465+
}
466466
}
467467
if val.CanAddr() {
468468
pv := val.Addr()
469-
if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
470-
return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), defaultStart(pv.Type(), finfo, startTemplate))
469+
if pv.CanInterface() {
470+
if textMarshaler, ok := reflect.TypeAssert[encoding.TextMarshaler](pv); ok {
471+
return p.marshalTextInterface(textMarshaler, defaultStart(pv.Type(), finfo, startTemplate))
472+
}
471473
}
472474
}
473475

@@ -503,7 +505,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
503505
start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name
504506
} else {
505507
fv := xmlname.value(val, dontInitNilPointers)
506-
if v, ok := fv.Interface().(Name); ok && v.Local != "" {
508+
if v, ok := reflect.TypeAssert[Name](fv); ok && v.Local != "" {
507509
start.Name = v
508510
}
509511
}
@@ -580,21 +582,9 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
580582

581583
// marshalAttr marshals an attribute with the given name and value, adding to start.Attr.
582584
func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value) error {
583-
if val.CanInterface() && val.Type().Implements(marshalerAttrType) {
584-
attr, err := val.Interface().(MarshalerAttr).MarshalXMLAttr(name)
585-
if err != nil {
586-
return err
587-
}
588-
if attr.Name.Local != "" {
589-
start.Attr = append(start.Attr, attr)
590-
}
591-
return nil
592-
}
593-
594-
if val.CanAddr() {
595-
pv := val.Addr()
596-
if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) {
597-
attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name)
585+
if val.CanInterface() {
586+
if marshaler, ok := reflect.TypeAssert[MarshalerAttr](val); ok {
587+
attr, err := marshaler.MarshalXMLAttr(name)
598588
if err != nil {
599589
return err
600590
}
@@ -605,19 +595,25 @@ func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value)
605595
}
606596
}
607597

608-
if val.CanInterface() && val.Type().Implements(textMarshalerType) {
609-
text, err := val.Interface().(encoding.TextMarshaler).MarshalText()
610-
if err != nil {
611-
return err
598+
if val.CanAddr() {
599+
pv := val.Addr()
600+
if pv.CanInterface() {
601+
if marshaler, ok := reflect.TypeAssert[MarshalerAttr](pv); ok {
602+
attr, err := marshaler.MarshalXMLAttr(name)
603+
if err != nil {
604+
return err
605+
}
606+
if attr.Name.Local != "" {
607+
start.Attr = append(start.Attr, attr)
608+
}
609+
return nil
610+
}
612611
}
613-
start.Attr = append(start.Attr, Attr{name, string(text)})
614-
return nil
615612
}
616613

617-
if val.CanAddr() {
618-
pv := val.Addr()
619-
if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
620-
text, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
614+
if val.CanInterface() {
615+
if textMarshaler, ok := reflect.TypeAssert[encoding.TextMarshaler](val); ok {
616+
text, err := textMarshaler.MarshalText()
621617
if err != nil {
622618
return err
623619
}
@@ -626,6 +622,20 @@ func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value)
626622
}
627623
}
628624

625+
if val.CanAddr() {
626+
pv := val.Addr()
627+
if pv.CanInterface() {
628+
if textMarshaler, ok := reflect.TypeAssert[encoding.TextMarshaler](pv); ok {
629+
text, err := textMarshaler.MarshalText()
630+
if err != nil {
631+
return err
632+
}
633+
start.Attr = append(start.Attr, Attr{name, string(text)})
634+
return nil
635+
}
636+
}
637+
}
638+
629639
// Dereference or skip nil pointer, interface values.
630640
switch val.Kind() {
631641
case reflect.Pointer, reflect.Interface:
@@ -647,7 +657,8 @@ func (p *printer) marshalAttr(start *StartElement, name Name, val reflect.Value)
647657
}
648658

649659
if val.Type() == attrType {
650-
start.Attr = append(start.Attr, val.Interface().(Attr))
660+
attr, _ := reflect.TypeAssert[Attr](val)
661+
start.Attr = append(start.Attr, attr)
651662
return nil
652663
}
653664

@@ -854,20 +865,9 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
854865
if err := s.trim(finfo.parents); err != nil {
855866
return err
856867
}
857-
if vf.CanInterface() && vf.Type().Implements(textMarshalerType) {
858-
data, err := vf.Interface().(encoding.TextMarshaler).MarshalText()
859-
if err != nil {
860-
return err
861-
}
862-
if err := emit(p, data); err != nil {
863-
return err
864-
}
865-
continue
866-
}
867-
if vf.CanAddr() {
868-
pv := vf.Addr()
869-
if pv.CanInterface() && pv.Type().Implements(textMarshalerType) {
870-
data, err := pv.Interface().(encoding.TextMarshaler).MarshalText()
868+
if vf.CanInterface() {
869+
if textMarshaler, ok := reflect.TypeAssert[encoding.TextMarshaler](vf); ok {
870+
data, err := textMarshaler.MarshalText()
871871
if err != nil {
872872
return err
873873
}
@@ -877,6 +877,21 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
877877
continue
878878
}
879879
}
880+
if vf.CanAddr() {
881+
pv := vf.Addr()
882+
if pv.CanInterface() {
883+
if textMarshaler, ok := reflect.TypeAssert[encoding.TextMarshaler](pv); ok {
884+
data, err := textMarshaler.MarshalText()
885+
if err != nil {
886+
return err
887+
}
888+
if err := emit(p, data); err != nil {
889+
return err
890+
}
891+
continue
892+
}
893+
}
894+
}
880895

881896
var scratch [64]byte
882897
vf = indirect(vf)
@@ -902,7 +917,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
902917
return err
903918
}
904919
case reflect.Slice:
905-
if elem, ok := vf.Interface().([]byte); ok {
920+
if elem, ok := reflect.TypeAssert[[]byte](vf); ok {
906921
if err := emit(p, elem); err != nil {
907922
return err
908923
}

src/encoding/xml/read.go

Lines changed: 46 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -255,28 +255,36 @@ func (d *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
255255
}
256256
val = val.Elem()
257257
}
258-
if val.CanInterface() && val.Type().Implements(unmarshalerAttrType) {
258+
if val.CanInterface() {
259259
// This is an unmarshaler with a non-pointer receiver,
260260
// so it's likely to be incorrect, but we do what we're told.
261-
return val.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr)
261+
if unmarshaler, ok := reflect.TypeAssert[UnmarshalerAttr](val); ok {
262+
return unmarshaler.UnmarshalXMLAttr(attr)
263+
}
262264
}
263265
if val.CanAddr() {
264266
pv := val.Addr()
265-
if pv.CanInterface() && pv.Type().Implements(unmarshalerAttrType) {
266-
return pv.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr)
267+
if pv.CanInterface() {
268+
if unmarshaler, ok := reflect.TypeAssert[UnmarshalerAttr](pv); ok {
269+
return unmarshaler.UnmarshalXMLAttr(attr)
270+
}
267271
}
268272
}
269273

270274
// Not an UnmarshalerAttr; try encoding.TextUnmarshaler.
271-
if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
275+
if val.CanInterface() {
272276
// This is an unmarshaler with a non-pointer receiver,
273277
// so it's likely to be incorrect, but we do what we're told.
274-
return val.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value))
278+
if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](val); ok {
279+
return textUnmarshaler.UnmarshalText([]byte(attr.Value))
280+
}
275281
}
276282
if val.CanAddr() {
277283
pv := val.Addr()
278-
if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
279-
return pv.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value))
284+
if pv.CanInterface() {
285+
if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](pv); ok {
286+
return textUnmarshaler.UnmarshalText([]byte(attr.Value))
287+
}
280288
}
281289
}
282290

@@ -303,12 +311,7 @@ func (d *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
303311
return copyValue(val, []byte(attr.Value))
304312
}
305313

306-
var (
307-
attrType = reflect.TypeFor[Attr]()
308-
unmarshalerType = reflect.TypeFor[Unmarshaler]()
309-
unmarshalerAttrType = reflect.TypeFor[UnmarshalerAttr]()
310-
textUnmarshalerType = reflect.TypeFor[encoding.TextUnmarshaler]()
311-
)
314+
var attrType = reflect.TypeFor[Attr]()
312315

313316
const (
314317
maxUnmarshalDepth = 10000
@@ -352,27 +355,35 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement, depth int) e
352355
val = val.Elem()
353356
}
354357

355-
if val.CanInterface() && val.Type().Implements(unmarshalerType) {
358+
if val.CanInterface() {
356359
// This is an unmarshaler with a non-pointer receiver,
357360
// so it's likely to be incorrect, but we do what we're told.
358-
return d.unmarshalInterface(val.Interface().(Unmarshaler), start)
361+
if unmarshaler, ok := reflect.TypeAssert[Unmarshaler](val); ok {
362+
return d.unmarshalInterface(unmarshaler, start)
363+
}
359364
}
360365

361366
if val.CanAddr() {
362367
pv := val.Addr()
363-
if pv.CanInterface() && pv.Type().Implements(unmarshalerType) {
364-
return d.unmarshalInterface(pv.Interface().(Unmarshaler), start)
368+
if pv.CanInterface() {
369+
if unmarshaler, ok := reflect.TypeAssert[Unmarshaler](pv); ok {
370+
return d.unmarshalInterface(unmarshaler, start)
371+
}
365372
}
366373
}
367374

368-
if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
369-
return d.unmarshalTextInterface(val.Interface().(encoding.TextUnmarshaler))
375+
if val.CanInterface() {
376+
if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](val); ok {
377+
return d.unmarshalTextInterface(textUnmarshaler)
378+
}
370379
}
371380

372381
if val.CanAddr() {
373382
pv := val.Addr()
374-
if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
375-
return d.unmarshalTextInterface(pv.Interface().(encoding.TextUnmarshaler))
383+
if pv.CanInterface() {
384+
if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](pv); ok {
385+
return d.unmarshalTextInterface(textUnmarshaler)
386+
}
376387
}
377388
}
378389

@@ -453,7 +464,7 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement, depth int) e
453464
return UnmarshalError(e)
454465
}
455466
fv := finfo.value(sv, initNilPointers)
456-
if _, ok := fv.Interface().(Name); ok {
467+
if _, ok := reflect.TypeAssert[Name](fv); ok {
457468
fv.Set(reflect.ValueOf(start.Name))
458469
}
459470
}
@@ -578,20 +589,24 @@ Loop:
578589
}
579590
}
580591

581-
if saveData.IsValid() && saveData.CanInterface() && saveData.Type().Implements(textUnmarshalerType) {
582-
if err := saveData.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil {
583-
return err
592+
if saveData.IsValid() && saveData.CanInterface() {
593+
if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](saveData); ok {
594+
if err := textUnmarshaler.UnmarshalText(data); err != nil {
595+
return err
596+
}
597+
saveData = reflect.Value{}
584598
}
585-
saveData = reflect.Value{}
586599
}
587600

588601
if saveData.IsValid() && saveData.CanAddr() {
589602
pv := saveData.Addr()
590-
if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
591-
if err := pv.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil {
592-
return err
603+
if pv.CanInterface() {
604+
if textUnmarshaler, ok := reflect.TypeAssert[encoding.TextUnmarshaler](pv); ok {
605+
if err := textUnmarshaler.UnmarshalText(data); err != nil {
606+
return err
607+
}
608+
saveData = reflect.Value{}
593609
}
594-
saveData = reflect.Value{}
595610
}
596611
}
597612

0 commit comments

Comments
 (0)