From ecad6333b1e7df6c0c45f527c16dd9ab7fdd9a0f Mon Sep 17 00:00:00 2001 From: joeybloggs Date: Sat, 6 Aug 2016 13:55:36 -0400 Subject: [PATCH] increase dive tag performance. --- cache.go | 15 ++++---- validator.go | 89 ++++++++++++++++++++++++------------------- validator_instance.go | 2 +- 3 files changed, 58 insertions(+), 48 deletions(-) diff --git a/cache.go b/cache.go index f4a2b48..86de914 100644 --- a/cache.go +++ b/cache.go @@ -69,16 +69,17 @@ func (tc *tagCache) Set(key string, value *cTag) { } type cStruct struct { - Name string + name string fields map[int]*cField fn StructLevelFunc } type cField struct { - Idx int - Name string - AltName string - cTags *cTag + idx int + name string + altName string + namesEqual bool + cTags *cTag } type cTag struct { @@ -107,7 +108,7 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr return cs } - cs = &cStruct{Name: sName, fields: make(map[int]*cField), fn: v.structLevelFuncs[typ]} + cs = &cStruct{name: sName, fields: make(map[int]*cField), fn: v.structLevelFuncs[typ]} numFields := current.NumField() @@ -152,7 +153,7 @@ func (v *Validate) extractStructCache(current reflect.Value, sName string) *cStr ctag = new(cTag) } - cs.fields[i] = &cField{Idx: i, Name: fld.Name, AltName: customName, cTags: ctag} + cs.fields[i] = &cField{idx: i, name: fld.Name, altName: customName, cTags: ctag, namesEqual: fld.Name == customName} } v.structCache.Set(typ, cs) diff --git a/validator.go b/validator.go index 7476c76..6806f6e 100644 --- a/validator.go +++ b/validator.go @@ -35,10 +35,10 @@ func (v *validate) validateStruct(parent reflect.Value, current reflect.Value, t if len(ns) == 0 { - ns = append(ns, cs.Name...) + ns = append(ns, cs.name...) ns = append(ns, '.') - structNs = append(structNs, cs.Name...) + structNs = append(structNs, cs.name...) structNs = append(structNs, '.') } @@ -50,14 +50,14 @@ func (v *validate) validateStruct(parent reflect.Value, current reflect.Value, t if v.isPartial { - _, ok = v.includeExclude[string(append(structNs, f.Name...))] + _, ok = v.includeExclude[string(append(structNs, f.name...))] if (ok && v.hasExcludes) || (!ok && !v.hasExcludes) { continue } } - v.traverseField(parent, current.Field(f.Idx), ns, structNs, f, f.cTags) + v.traverseField(parent, current.Field(f.idx), ns, structNs, f, f.cTags) } } @@ -103,10 +103,10 @@ func (v *validate) traverseField(parent reflect.Value, current reflect.Value, ns &fieldError{ tag: ct.aliasTag, actualTag: ct.tag, - ns: string(append(ns, cf.AltName...)), - structNs: string(append(structNs, cf.Name...)), - field: cf.AltName, - structField: cf.Name, + ns: string(append(ns, cf.altName...)), + structNs: string(append(structNs, cf.name...)), + field: cf.altName, + structField: cf.name, param: ct.param, kind: kind, }, @@ -119,10 +119,10 @@ func (v *validate) traverseField(parent reflect.Value, current reflect.Value, ns &fieldError{ tag: ct.aliasTag, actualTag: ct.tag, - ns: string(append(ns, cf.AltName...)), - structNs: string(append(structNs, cf.Name...)), - field: cf.AltName, - structField: cf.Name, + ns: string(append(ns, cf.altName...)), + structNs: string(append(structNs, cf.name...)), + field: cf.altName, + structField: cf.name, value: current.Interface(), param: ct.param, kind: kind, @@ -152,8 +152,8 @@ func (v *validate) traverseField(parent reflect.Value, current reflect.Value, ns // VarWithField - this allows for validating against each field withing the struct against a specific value // pretty handly in certain situations if len(ns) > 0 { - ns = append(append(ns, cf.AltName...), '.') - structNs = append(append(structNs, cf.Name...), '.') + ns = append(append(ns, cf.altName...), '.') + structNs = append(append(structNs, cf.name...), '.') } v.validateStruct(current, current, typ, ns, structNs, ct) @@ -205,19 +205,24 @@ OUTER: i64 = int64(i) - v.misc = append(v.misc[0:0], cf.Name...) + v.misc = append(v.misc[0:0], cf.name...) v.misc = append(v.misc, '[') v.misc = strconv.AppendInt(v.misc, i64, 10) v.misc = append(v.misc, ']') - reusableCF.Name = string(v.misc) + reusableCF.name = string(v.misc) - v.misc = append(v.misc[0:0], cf.AltName...) - v.misc = append(v.misc, '[') - v.misc = strconv.AppendInt(v.misc, i64, 10) - v.misc = append(v.misc, ']') + if cf.namesEqual { + reusableCF.altName = reusableCF.name + } else { + + v.misc = append(v.misc[0:0], cf.altName...) + v.misc = append(v.misc, '[') + v.misc = strconv.AppendInt(v.misc, i64, 10) + v.misc = append(v.misc, ']') - reusableCF.AltName = string(v.misc) + reusableCF.altName = string(v.misc) + } v.traverseField(parent, current.Index(i), ns, structNs, reusableCF, ct) } @@ -231,19 +236,23 @@ OUTER: pv = fmt.Sprintf("%v", key.Interface()) - v.misc = append(v.misc[0:0], cf.Name...) + v.misc = append(v.misc[0:0], cf.name...) v.misc = append(v.misc, '[') v.misc = append(v.misc, pv...) v.misc = append(v.misc, ']') - reusableCF.Name = string(v.misc) + reusableCF.name = string(v.misc) - v.misc = append(v.misc[0:0], cf.AltName...) - v.misc = append(v.misc, '[') - v.misc = append(v.misc, pv...) - v.misc = append(v.misc, ']') + if cf.namesEqual { + reusableCF.altName = reusableCF.name + } else { + v.misc = append(v.misc[0:0], cf.altName...) + v.misc = append(v.misc, '[') + v.misc = append(v.misc, pv...) + v.misc = append(v.misc, ']') - reusableCF.AltName = string(v.misc) + reusableCF.altName = string(v.misc) + } v.traverseField(parent, current.MapIndex(key), ns, structNs, reusableCF, ct) } @@ -296,10 +305,10 @@ OUTER: &fieldError{ tag: ct.aliasTag, actualTag: ct.actualAliasTag, - ns: string(append(ns, cf.AltName...)), - structNs: string(append(structNs, cf.Name...)), - field: cf.AltName, - structField: cf.Name, + ns: string(append(ns, cf.altName...)), + structNs: string(append(structNs, cf.name...)), + field: cf.altName, + structField: cf.name, value: current.Interface(), param: ct.param, kind: kind, @@ -313,10 +322,10 @@ OUTER: &fieldError{ tag: string(v.misc)[1:], actualTag: string(v.misc)[1:], - ns: string(append(ns, cf.AltName...)), - structNs: string(append(structNs, cf.Name...)), - field: cf.AltName, - structField: cf.Name, + ns: string(append(ns, cf.altName...)), + structNs: string(append(structNs, cf.name...)), + field: cf.altName, + structField: cf.name, value: current.Interface(), param: ct.param, kind: kind, @@ -344,10 +353,10 @@ OUTER: &fieldError{ tag: ct.aliasTag, actualTag: ct.tag, - ns: string(append(ns, cf.AltName...)), - structNs: string(append(structNs, cf.Name...)), - field: cf.AltName, - structField: cf.Name, + ns: string(append(ns, cf.altName...)), + structNs: string(append(structNs, cf.name...)), + field: cf.altName, + structField: cf.name, value: current.Interface(), param: ct.param, kind: kind, diff --git a/validator_instance.go b/validator_instance.go index bd98202..d9cc909 100644 --- a/validator_instance.go +++ b/validator_instance.go @@ -31,7 +31,7 @@ const ( var ( timeType = reflect.TypeOf(time.Time{}) - defaultCField = new(cField) + defaultCField = &cField{namesEqual: true} ) // CustomTypeFunc allows for overriding or adding custom field type handler functions