@@ -566,6 +566,151 @@ func (e *Encoder) structField(fieldCode *structFieldCode, valueCode *opcode, tag
566
566
}
567
567
return code
568
568
}
569
+
570
+ func (e * Encoder ) isNotExistsField (head * structFieldCode ) bool {
571
+ if head == nil {
572
+ return false
573
+ }
574
+ if head .op != opStructFieldAnonymousHead {
575
+ return false
576
+ }
577
+ if head .next == nil {
578
+ return false
579
+ }
580
+ if head .nextField == nil {
581
+ return false
582
+ }
583
+ if head .nextField .op != opStructAnonymousEnd {
584
+ return false
585
+ }
586
+ if head .next .op == opStructAnonymousEnd {
587
+ return true
588
+ }
589
+ if head .next .op .codeType () != codeStructField {
590
+ return false
591
+ }
592
+ return e .isNotExistsField (head .next .toStructFieldCode ())
593
+ }
594
+
595
+ func (e * Encoder ) optimizeAnonymousFields (head * structFieldCode ) {
596
+ code := head
597
+ var prev * structFieldCode
598
+ for {
599
+ if code .op == opStructEnd || code .op == opStructEndIndent {
600
+ break
601
+ }
602
+ if code .op == opStructField || code .op == opStructFieldIndent {
603
+ codeType := code .next .op .codeType ()
604
+ if codeType == codeStructField {
605
+ if e .isNotExistsField (code .next .toStructFieldCode ()) {
606
+ code .next = code .nextField
607
+ linkPrevToNextField (prev , code )
608
+ code = prev
609
+ }
610
+ }
611
+ }
612
+ prev = code
613
+ code = code .nextField .toStructFieldCode ()
614
+ }
615
+ }
616
+
617
+ type structFieldPair struct {
618
+ prevField * structFieldCode
619
+ curField * structFieldCode
620
+ isTaggedKey bool
621
+ linked bool
622
+ }
623
+
624
+ func (e * Encoder ) anonymousStructFieldPairMap (typ * rtype , tags structTags , valueCode * structFieldCode ) map [string ][]structFieldPair {
625
+ //fmt.Println("type = ", typ, "valueCode = ", valueCode.dump())
626
+ anonymousFields := map [string ][]structFieldPair {}
627
+ f := valueCode
628
+ var prevAnonymousField * structFieldCode
629
+ for {
630
+ existsKey := tags .existsKey (f .displayKey )
631
+ op := f .op .headToAnonymousHead ()
632
+ if op != f .op {
633
+ if existsKey {
634
+ f .op = opStructFieldAnonymousHead
635
+ } else {
636
+ f .op = op
637
+ }
638
+ } else if f .op == opStructEnd {
639
+ f .op = opStructAnonymousEnd
640
+ } else if existsKey {
641
+ linkPrevToNextField (prevAnonymousField , f )
642
+ }
643
+
644
+ if f .displayKey == "" {
645
+ if f .nextField == nil {
646
+ break
647
+ }
648
+ prevAnonymousField = f
649
+ f = f .nextField .toStructFieldCode ()
650
+ continue
651
+ }
652
+
653
+ anonymousFields [f .displayKey ] = append (anonymousFields [f .displayKey ], structFieldPair {
654
+ prevField : prevAnonymousField ,
655
+ curField : f ,
656
+ isTaggedKey : f .isTaggedKey ,
657
+ })
658
+ if f .next != nil && f .nextField != f .next && f .next .op .codeType () == codeStructField {
659
+ for k , v := range e .anonymousStructFieldPairMap (typ , tags , f .next .toStructFieldCode ()) {
660
+ anonymousFields [k ] = append (anonymousFields [k ], v ... )
661
+ }
662
+ }
663
+ if f .nextField == nil {
664
+ break
665
+ }
666
+ prevAnonymousField = f
667
+ f = f .nextField .toStructFieldCode ()
668
+ }
669
+ return anonymousFields
670
+ }
671
+
672
+ func (e * Encoder ) optimizeConflictAnonymousFields (anonymousFields map [string ][]structFieldPair ) {
673
+ for _ , fieldPairs := range anonymousFields {
674
+ if len (fieldPairs ) == 1 {
675
+ continue
676
+ }
677
+ // conflict anonymous fields
678
+ taggedPairs := []structFieldPair {}
679
+ for _ , fieldPair := range fieldPairs {
680
+ if fieldPair .isTaggedKey {
681
+ taggedPairs = append (taggedPairs , fieldPair )
682
+ } else {
683
+ if ! fieldPair .linked {
684
+ if fieldPair .prevField == nil {
685
+ // head operation
686
+ fieldPair .curField .op = opStructFieldAnonymousHead
687
+ } else {
688
+ linkPrevToNextField (fieldPair .prevField , fieldPair .curField )
689
+ }
690
+ fieldPair .linked = true
691
+ }
692
+ }
693
+ }
694
+ if len (taggedPairs ) > 1 {
695
+ for _ , fieldPair := range taggedPairs {
696
+ if ! fieldPair .linked {
697
+ if fieldPair .prevField == nil {
698
+ // head operation
699
+ fieldPair .curField .op = opStructFieldAnonymousHead
700
+ } else {
701
+ linkPrevToNextField (fieldPair .prevField , fieldPair .curField )
702
+ }
703
+ fieldPair .linked = true
704
+ }
705
+ }
706
+ } else {
707
+ for _ , fieldPair := range taggedPairs {
708
+ fieldPair .curField .isTaggedKey = false
709
+ }
710
+ }
711
+ }
712
+ }
713
+
569
714
func (e * Encoder ) compileStruct (typ * rtype , isPtr , root , withIndent bool ) (* opcode , error ) {
570
715
if code := e .compiledCode (typ , withIndent ); code != nil {
571
716
return code , nil
@@ -588,12 +733,17 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
588
733
prevField * structFieldCode
589
734
)
590
735
e .indent ++
736
+ tags := structTags {}
737
+ anonymousFields := map [string ][]structFieldPair {}
591
738
for i := 0 ; i < fieldNum ; i ++ {
592
739
field := typ .Field (i )
593
740
if isIgnoredStructField (field ) {
594
741
continue
595
742
}
596
- tag := structTagFromField (field )
743
+ tags = append (tags , structTagFromField (field ))
744
+ }
745
+ for i , tag := range tags {
746
+ field := tag .field
597
747
fieldType := type2rtype (field .Type )
598
748
if isPtr && i == 0 {
599
749
// head field of pointer structure at top level
@@ -609,16 +759,8 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
609
759
return nil , err
610
760
}
611
761
if field .Anonymous {
612
- f := valueCode .toStructFieldCode ()
613
- for {
614
- f .op = f .op .headToAnonymousHead ()
615
- if f .op == opStructEnd {
616
- f .op = opStructAnonymousEnd
617
- }
618
- if f .nextField == nil {
619
- break
620
- }
621
- f = f .nextField .toStructFieldCode ()
762
+ for k , v := range e .anonymousStructFieldPairMap (typ , tags , valueCode .toStructFieldCode ()) {
763
+ anonymousFields [k ] = append (anonymousFields [k ], v ... )
622
764
}
623
765
}
624
766
if fieldNum == 1 && valueCode .op == opPtr {
@@ -640,6 +782,8 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
640
782
},
641
783
anonymousKey : field .Anonymous ,
642
784
key : []byte (key ),
785
+ isTaggedKey : tag .isTaggedKey ,
786
+ displayKey : tag .key ,
643
787
offset : field .Offset ,
644
788
}
645
789
if fieldIdx == 0 {
@@ -690,6 +834,10 @@ func (e *Encoder) compileStruct(typ *rtype, isPtr, root, withIndent bool) (*opco
690
834
}
691
835
head .end = structEndCode
692
836
code .next = structEndCode
837
+
838
+ e .optimizeConflictAnonymousFields (anonymousFields )
839
+ e .optimizeAnonymousFields (head )
840
+
693
841
ret := (* opcode )(unsafe .Pointer (head ))
694
842
compiled .code = ret
695
843
0 commit comments