From 4ce4d1cd712e5f719e1b90b1aeb2079022a19abe Mon Sep 17 00:00:00 2001 From: joeybloggs Date: Mon, 11 Jul 2016 13:54:33 -0400 Subject: [PATCH] gain another 5% on average by changing tag type from bool's to enum ``` benchmark old ns/op new ns/op delta BenchmarkFieldSuccess-4 117 116 -0.85% BenchmarkFieldFailure-4 675 651 -3.56% BenchmarkFieldDiveSuccess-4 2518 2418 -3.97% BenchmarkFieldDiveFailure-4 3096 3011 -2.75% BenchmarkFieldCustomTypeSuccess-4 319 297 -6.90% BenchmarkFieldCustomTypeFailure-4 688 680 -1.16% BenchmarkFieldOrTagSuccess-4 1251 1176 -6.00% BenchmarkFieldOrTagFailure-4 1090 1073 -1.56% BenchmarkStructLevelValidationSuccess-4 558 567 +1.61% BenchmarkStructLevelValidationFailure-4 608 562 -7.57% BenchmarkStructSimpleCustomTypeSuccess-4 702 636 -9.40% BenchmarkStructSimpleCustomTypeFailure-4 1380 1295 -6.16% BenchmarkStructPartialSuccess-4 1139 1058 -7.11% BenchmarkStructPartialFailure-4 1760 1648 -6.36% BenchmarkStructExceptSuccess-4 951 917 -3.58% BenchmarkStructExceptFailure-4 1147 1085 -5.41% BenchmarkStructSimpleCrossFieldSuccess-4 873 783 -10.31% BenchmarkStructSimpleCrossFieldFailure-4 1478 1384 -6.36% BenchmarkStructSimpleCrossStructCrossFieldSuccess-4 1328 1273 -4.14% BenchmarkStructSimpleCrossStructCrossFieldFailure-4 1949 1896 -2.72% BenchmarkStructSimpleSuccess-4 559 523 -6.44% BenchmarkStructSimpleFailure-4 1334 1311 -1.72% BenchmarkStructSimpleSuccessParallel-4 148 137 -7.43% BenchmarkStructSimpleFailureParallel-4 631 591 -6.34% BenchmarkStructComplexSuccess-4 3476 3500 +0.69% BenchmarkStructComplexFailure-4 8467 8406 -0.72% BenchmarkStructComplexSuccessParallel-4 1098 1012 -7.83% BenchmarkStructComplexFailureParallel-4 3113 3121 +0.26% benchmark old allocs new allocs delta BenchmarkFieldSuccess-4 0 0 +0.00% BenchmarkFieldFailure-4 4 4 +0.00% BenchmarkFieldDiveSuccess-4 28 28 +0.00% BenchmarkFieldDiveFailure-4 32 32 +0.00% BenchmarkFieldCustomTypeSuccess-4 2 2 +0.00% BenchmarkFieldCustomTypeFailure-4 4 4 +0.00% BenchmarkFieldOrTagSuccess-4 1 1 +0.00% BenchmarkFieldOrTagFailure-4 6 6 +0.00% BenchmarkStructLevelValidationSuccess-4 5 5 +0.00% BenchmarkStructLevelValidationFailure-4 5 5 +0.00% BenchmarkStructSimpleCustomTypeSuccess-4 3 3 +0.00% BenchmarkStructSimpleCustomTypeFailure-4 9 9 +0.00% BenchmarkStructPartialSuccess-4 9 9 +0.00% BenchmarkStructPartialFailure-4 14 14 +0.00% BenchmarkStructExceptSuccess-4 7 7 +0.00% BenchmarkStructExceptFailure-4 9 9 +0.00% BenchmarkStructSimpleCrossFieldSuccess-4 4 4 +0.00% BenchmarkStructSimpleCrossFieldFailure-4 9 9 +0.00% BenchmarkStructSimpleCrossStructCrossFieldSuccess-4 7 7 +0.00% BenchmarkStructSimpleCrossStructCrossFieldFailure-4 12 12 +0.00% BenchmarkStructSimpleSuccess-4 1 1 +0.00% BenchmarkStructSimpleFailure-4 9 9 +0.00% BenchmarkStructSimpleSuccessParallel-4 1 1 +0.00% BenchmarkStructSimpleFailureParallel-4 9 9 +0.00% BenchmarkStructComplexSuccess-4 15 15 +0.00% BenchmarkStructComplexFailure-4 60 60 +0.00% BenchmarkStructComplexSuccessParallel-4 15 15 +0.00% BenchmarkStructComplexFailureParallel-4 60 60 +0.00% benchmark old bytes new bytes delta BenchmarkFieldSuccess-4 0 0 +0.00% BenchmarkFieldFailure-4 432 432 +0.00% BenchmarkFieldDiveSuccess-4 464 464 +0.00% BenchmarkFieldDiveFailure-4 896 896 +0.00% BenchmarkFieldCustomTypeSuccess-4 32 32 +0.00% BenchmarkFieldCustomTypeFailure-4 432 432 +0.00% BenchmarkFieldOrTagSuccess-4 4 4 +0.00% BenchmarkFieldOrTagFailure-4 448 448 +0.00% BenchmarkStructLevelValidationSuccess-4 160 160 +0.00% BenchmarkStructLevelValidationFailure-4 160 160 +0.00% BenchmarkStructSimpleCustomTypeSuccess-4 36 36 +0.00% BenchmarkStructSimpleCustomTypeFailure-4 640 640 +0.00% BenchmarkStructPartialSuccess-4 336 336 +0.00% BenchmarkStructPartialFailure-4 794 794 +0.00% BenchmarkStructExceptSuccess-4 314 314 +0.00% BenchmarkStructExceptFailure-4 336 336 +0.00% BenchmarkStructSimpleCrossFieldSuccess-4 80 80 +0.00% BenchmarkStructSimpleCrossFieldFailure-4 536 536 +0.00% BenchmarkStructSimpleCrossStructCrossFieldSuccess-4 112 112 +0.00% BenchmarkStructSimpleCrossStructCrossFieldFailure-4 576 576 +0.00% BenchmarkStructSimpleSuccess-4 4 4 +0.00% BenchmarkStructSimpleFailure-4 640 640 +0.00% BenchmarkStructSimpleSuccessParallel-4 4 4 +0.00% BenchmarkStructSimpleFailureParallel-4 640 640 +0.00% BenchmarkStructComplexSuccess-4 244 244 +0.00% BenchmarkStructComplexFailure-4 3608 3608 +0.00% BenchmarkStructComplexSuccessParallel-4 244 244 +0.00% BenchmarkStructComplexFailureParallel-4 3608 3608 +0.00% ``` --- cache.go | 49 ++++++++++++++++++++++++++------------------ validator.go | 58 ++++++++++++++++++++++++++-------------------------- 2 files changed, 58 insertions(+), 49 deletions(-) diff --git a/cache.go b/cache.go index 6445b78..400dd45 100644 --- a/cache.go +++ b/cache.go @@ -8,6 +8,18 @@ import ( "sync/atomic" ) +type tagType uint8 + +const ( + typeDefault tagType = iota + typeOmitEmpty + typeNoStructLevel + typeStructOnly + typeDive + typeOr + typeExists +) + type structCache struct { lock sync.Mutex m atomic.Value // map[reflect.Type]*cStruct @@ -68,20 +80,15 @@ type cField struct { // TODO: investigate using enum instead of so many booleans, may be faster // but let's get the new cache system working first type cTag struct { - tag string - aliasTag string - actualAliasTag string - param string - hasAlias bool - isOmitEmpty bool - isNoStructLevel bool - isStructOnly bool - isDive bool - isOrVal bool - exists bool - hasTag bool - fn Func - next *cTag + tag string + aliasTag string + actualAliasTag string + param string + hasAlias bool + typeof tagType + hasTag bool + fn Func + next *cTag } // TODO: eliminate get and set functions from cache, they are pure overhead for nicer syntax. @@ -198,23 +205,23 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s switch t { case diveTag: - current.isDive = true + current.typeof = typeDive continue case omitempty: - current.isOmitEmpty = true + current.typeof = typeOmitEmpty continue case structOnlyTag: - current.isStructOnly = true + current.typeof = typeStructOnly continue case noStructLevelTag: - current.isNoStructLevel = true + current.typeof = typeNoStructLevel continue case existsTag: - current.exists = true + current.typeof = typeExists continue default: @@ -247,7 +254,9 @@ func (v *Validate) parseFieldTagsRecursive(tag string, fieldName string, alias s panic(strings.TrimSpace(fmt.Sprintf(undefinedValidation, fieldName))) } - current.isOrVal = len(orVals) > 1 + if len(orVals) > 1 { + current.typeof = typeOr + } if len(vals) > 1 { current.param = strings.Replace(strings.Replace(vals[1], utf8HexComma, ",", -1), utf8Pipe, "|", -1) diff --git a/validator.go b/validator.go index 2ab85a3..fe3019e 100644 --- a/validator.go +++ b/validator.go @@ -548,7 +548,7 @@ func (v *Validate) tranverseStruct(topStruct reflect.Value, currentStruct reflec // structonly tag present don't tranverseFields // but must still check and run below struct level validation // if present - if first || ct == nil || !ct.isStructOnly { + if first || ct == nil || ct.typeof != typeStructOnly { for _, f := range cs.fields { @@ -584,7 +584,7 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. return } - if ct.isOmitEmpty { + if ct.typeof == typeOmitEmpty { return } @@ -631,7 +631,7 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect. ct = ct.next } - if ct != nil && ct.isNoStructLevel { + if ct != nil && ct.typeof == typeNoStructLevel { return } @@ -652,12 +652,13 @@ OUTER: return } - if ct.exists { + switch ct.typeof { + + case typeExists: ct = ct.next continue - } - if ct.isOmitEmpty { + case typeOmitEmpty: if !HasValue(v, topStruct, currentStruct, current, typ, kind, blank) { return @@ -665,9 +666,8 @@ OUTER: ct = ct.next continue - } - if ct.isDive { + case typeDive: ct = ct.next @@ -692,9 +692,8 @@ OUTER: } return - } - if ct.isOrVal { + case typeOr: errTag := blank @@ -711,7 +710,7 @@ OUTER: return } - if !ct.isOrVal { + if ct.typeof != typeOr { continue OUTER } } @@ -755,29 +754,30 @@ OUTER: ct = ct.next } - } - if !ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) { + default: + if !ct.fn(v, topStruct, currentStruct, current, typ, kind, ct.param) { - ns := errPrefix + cf.Name + ns := errPrefix + cf.Name - errs[ns] = &FieldError{ - FieldNamespace: ns, - NameNamespace: nsPrefix + cf.AltName, - Name: cf.AltName, - Field: cf.Name, - Tag: ct.aliasTag, - ActualTag: ct.tag, - Value: current.Interface(), - Param: ct.param, - Type: typ, - Kind: kind, - } + errs[ns] = &FieldError{ + FieldNamespace: ns, + NameNamespace: nsPrefix + cf.AltName, + Name: cf.AltName, + Field: cf.Name, + Tag: ct.aliasTag, + ActualTag: ct.tag, + Value: current.Interface(), + Param: ct.param, + Type: typ, + Kind: kind, + } - return + return - } + } - ct = ct.next + ct = ct.next + } } }