Phase 1 optimization complete, Phase 2 ( Warm liquid goo phase ) commencing
Still looking good
```
benchmark old ns/op new ns/op delta
BenchmarkFieldSuccess-4 167 119 -28.74%
BenchmarkFieldFailure-4 701 653 -6.85%
BenchmarkFieldDiveSuccess-4 2937 2488 -15.29%
BenchmarkFieldDiveFailure-4 3536 3059 -13.49%
BenchmarkFieldCustomTypeSuccess-4 341 292 -14.37%
BenchmarkFieldCustomTypeFailure-4 679 679 +0.00%
BenchmarkFieldOrTagSuccess-4 1157 1146 -0.95%
BenchmarkFieldOrTagFailure-4 1109 1063 -4.15%
BenchmarkStructLevelValidationSuccess-4 694 559 -19.45%
BenchmarkStructLevelValidationFailure-4 1311 551 -57.97%
BenchmarkStructSimpleCustomTypeSuccess-4 894 641 -28.30%
BenchmarkStructSimpleCustomTypeFailure-4 1496 1302 -12.97%
BenchmarkStructPartialSuccess-4 1229 1071 -12.86%
BenchmarkStructPartialFailure-4 1838 1685 -8.32%
BenchmarkStructExceptSuccess-4 961 927 -3.54%
BenchmarkStructExceptFailure-4 1218 1068 -12.32%
BenchmarkStructSimpleCrossFieldSuccess-4 954 779 -18.34%
BenchmarkStructSimpleCrossFieldFailure-4 1569 1405 -10.45%
BenchmarkStructSimpleCrossStructCrossFieldSuccess-4 1588 1299 -18.20%
BenchmarkStructSimpleCrossStructCrossFieldFailure-4 2217 1917 -13.53%
BenchmarkStructSimpleSuccess-4 925 519 -43.89%
BenchmarkStructSimpleFailure-4 1650 1323 -19.82%
BenchmarkStructSimpleSuccessParallel-4 261 149 -42.91%
BenchmarkStructSimpleFailureParallel-4 758 543 -28.36%
BenchmarkStructComplexSuccess-4 5868 3387 -42.28%
BenchmarkStructComplexFailure-4 10767 8498 -21.07%
BenchmarkStructComplexSuccessParallel-4 1559 1114 -28.54%
BenchmarkStructComplexFailureParallel-4 3747 3163 -15.59%
```
joeybloggs
7 years ago
621 | 621 |
return
|
622 | 622 |
}
|
623 | 623 |
|
624 | |
// if we get here tag length is zero and we can leave
|
625 | |
if kind == reflect.Invalid {
|
626 | |
return
|
627 | |
}
|
628 | |
|
629 | 624 |
case reflect.Struct:
|
630 | 625 |
typ = current.Type()
|
631 | 626 |
|
|
704 | 699 |
|
705 | 700 |
for {
|
706 | 701 |
|
707 | |
if !ct.isOrVal {
|
708 | |
// if we get here, no valid 'or' value, but more tags
|
|
702 |
if ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) {
|
|
703 |
|
|
704 |
// drain rest of the 'or' values, then continue or leave
|
|
705 |
for {
|
|
706 |
|
|
707 |
ct = ct.next
|
|
708 |
|
|
709 |
if ct == nil {
|
|
710 |
return
|
|
711 |
}
|
|
712 |
|
|
713 |
if !ct.isOrVal {
|
|
714 |
continue OUTER
|
|
715 |
}
|
|
716 |
}
|
|
717 |
}
|
|
718 |
|
|
719 |
errTag += orSeparator + ct.tag
|
|
720 |
|
|
721 |
if ct.next == nil {
|
|
722 |
// if we get here, no valid 'or' value and no more tags
|
709 | 723 |
|
710 | 724 |
ns := errPrefix + cf.Name
|
711 | 725 |
|
|
735 | 749 |
}
|
736 | 750 |
}
|
737 | 751 |
|
738 | |
continue OUTER
|
739 | |
}
|
740 | |
|
741 | |
if ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) {
|
742 | |
|
743 | |
// drain rest of the 'or' values, then continue or leave
|
744 | |
for {
|
745 | |
|
746 | |
ct = ct.next
|
747 | |
|
748 | |
if ct == nil {
|
749 | |
return
|
750 | |
}
|
751 | |
|
752 | |
if !ct.isOrVal {
|
753 | |
continue OUTER
|
754 | |
}
|
755 | |
}
|
756 | |
}
|
757 | |
|
758 | |
errTag += orSeparator + ct.tag
|
759 | |
|
760 | |
if ct.next == nil {
|
761 | |
// if we get here, no valid 'or' value and no more tags
|
762 | |
|
763 | |
ns := errPrefix + cf.Name
|
764 | |
|
765 | |
if ct.hasAlias {
|
766 | |
errs[ns] = &FieldError{
|
767 | |
FieldNamespace: ns,
|
768 | |
NameNamespace: nsPrefix + cf.AltName,
|
769 | |
Name: cf.AltName,
|
770 | |
Field: cf.Name,
|
771 | |
Tag: ct.aliasTag,
|
772 | |
ActualTag: ct.actualAliasTag,
|
773 | |
Value: current.Interface(),
|
774 | |
Type: typ,
|
775 | |
Kind: kind,
|
776 | |
}
|
777 | |
} else {
|
778 | |
errs[errPrefix+cf.Name] = &FieldError{
|
779 | |
FieldNamespace: ns,
|
780 | |
NameNamespace: nsPrefix + cf.AltName,
|
781 | |
Name: cf.AltName,
|
782 | |
Field: cf.Name,
|
783 | |
Tag: errTag[1:],
|
784 | |
ActualTag: errTag[1:],
|
785 | |
Value: current.Interface(),
|
786 | |
Type: typ,
|
787 | |
Kind: kind,
|
788 | |
}
|
789 | |
}
|
790 | |
|
791 | 752 |
return
|
792 | 753 |
}
|
793 | 754 |
|
2367 | 2367 |
Equal(t, errs, nil)
|
2368 | 2368 |
|
2369 | 2369 |
errs = validate.Field(iface, "")
|
|
2370 |
Equal(t, errs, nil)
|
|
2371 |
|
|
2372 |
errs = validate.FieldWithValue(nil, iface, "")
|
2370 | 2373 |
Equal(t, errs, nil)
|
2371 | 2374 |
|
2372 | 2375 |
var f func(string)
|
|
5786 | 5789 |
Equal(t, errs["A.D"].Name, "D")
|
5787 | 5790 |
Equal(t, errs["A.E"].Name, "E")
|
5788 | 5791 |
}
|
|
5792 |
|
|
5793 |
func TestMutipleRecursiveExtractStructCache(t *testing.T) {
|
|
5794 |
|
|
5795 |
type Recursive struct {
|
|
5796 |
Field *string `validate:"exists,required,len=5,ne=string"`
|
|
5797 |
}
|
|
5798 |
|
|
5799 |
var test Recursive
|
|
5800 |
|
|
5801 |
current := reflect.ValueOf(test)
|
|
5802 |
name := "Recursive"
|
|
5803 |
proceed := make(chan struct{})
|
|
5804 |
|
|
5805 |
sc := validate.extractStructCache(current, name)
|
|
5806 |
ptr := fmt.Sprintf("%p", sc)
|
|
5807 |
|
|
5808 |
for i := 0; i < 100; i++ {
|
|
5809 |
|
|
5810 |
go func() {
|
|
5811 |
<-proceed
|
|
5812 |
sc := validate.extractStructCache(current, name)
|
|
5813 |
Equal(t, ptr, fmt.Sprintf("%p", sc))
|
|
5814 |
}()
|
|
5815 |
}
|
|
5816 |
|
|
5817 |
close(proceed)
|
|
5818 |
}
|