init struct cache changes

pull/217/head
joeybloggs 9 years ago
parent 638ea8a3f8
commit 94182a2199
  1. 67
      cache.go
  2. 51
      util.go
  3. 42
      validator.go

@ -0,0 +1,67 @@
package validator
import "sync"
type cachedField struct {
Idx int
Name string
AltName string
CachedTag *cachedTag
}
type cachedStruct struct {
Name string
fields map[int]cachedField
}
type structCacheMap struct {
lock sync.RWMutex
m map[string]*cachedStruct
}
func (s *structCacheMap) Get(key string) (*cachedStruct, bool) {
s.lock.RLock()
value, ok := s.m[key]
s.lock.RUnlock()
return value, ok
}
func (s *structCacheMap) Set(key string, value *cachedStruct) {
s.lock.Lock()
s.m[key] = value
s.lock.Unlock()
}
type cachedTag struct {
isOmitEmpty bool
isNoStructLevel bool
isStructOnly bool
diveTag string
tags []*tagVals
}
type tagVals struct {
tagVals [][]string
isOrVal bool
isAlias bool
tag string
}
type tagCacheMap struct {
lock sync.RWMutex
m map[string]*cachedTag
}
func (s *tagCacheMap) Get(key string) (*cachedTag, bool) {
s.lock.RLock()
value, ok := s.m[key]
s.lock.RUnlock()
return value, ok
}
func (s *tagCacheMap) Set(key string, value *cachedTag) {
s.lock.Lock()
s.m[key] = value
s.lock.Unlock()
}

@ -247,11 +247,62 @@ func panicIf(err error) {
}
}
func (v *Validate) parseStruct(topStruct reflect.Type, sName string) *cachedStruct {
s := &cachedStruct{Name: sName, fields: map[int]cachedField{}}
numFields := topStruct.NumField()
var fld reflect.StructField
var tag string
var customName string
for i := 0; i < numFields; i++ {
fld = topStruct.Field(i)
if len(fld.PkgPath) != 0 {
continue
}
tag = fld.Tag.Get(v.tagName)
if tag == skipValidationTag {
continue
}
customName = fld.Name
if len(v.fieldNameTag) != 0 {
name := strings.SplitN(fld.Tag.Get(v.fieldNameTag), ",", 2)[0]
// dash check is for json "-" (aka skipValidationTag) means don't output in json
if name != "" && name != skipValidationTag {
customName = name
}
}
cTag, ok := v.tagCache.Get(tag)
if !ok {
cTag = v.parseTags(tag, fld.Name)
}
s.fields[i] = cachedField{Idx: i, Name: fld.Name, AltName: customName, CachedTag: cTag}
}
v.structCache.Set(sName, s)
return s
}
func (v *Validate) parseTags(tag, fieldName string) *cachedTag {
cTag := &cachedTag{}
v.parseTagsRecursive(cTag, tag, fieldName, blank, false)
v.tagCache.Set(tag, cTag)
return cTag
}

@ -47,39 +47,6 @@ var (
emptyStructPtr = new(struct{})
)
type cachedTag struct {
isOmitEmpty bool
isNoStructLevel bool
isStructOnly bool
diveTag string
tags []*tagVals
}
type tagVals struct {
tagVals [][]string
isOrVal bool
isAlias bool
tag string
}
type tagCacheMap struct {
lock sync.RWMutex
m map[string]*cachedTag
}
func (s *tagCacheMap) Get(key string) (*cachedTag, bool) {
s.lock.RLock()
value, ok := s.m[key]
s.lock.RUnlock()
return value, ok
}
func (s *tagCacheMap) Set(key string, value *cachedTag) {
s.lock.Lock()
s.m[key] = value
s.lock.Unlock()
}
// StructLevel contains all of the information and helper methods
// for reporting errors during struct level validation
type StructLevel struct {
@ -154,7 +121,8 @@ type Validate struct {
hasCustomFuncs bool
hasAliasValidators bool
hasStructLevelFuncs bool
tagsCache *tagCacheMap
tagCache *tagCacheMap
structCache *structCacheMap
errsPool *sync.Pool
}
@ -227,7 +195,8 @@ func New(config *Config) *Validate {
v := &Validate{
tagName: config.TagName,
fieldNameTag: config.FieldNameTag,
tagsCache: &tagCacheMap{m: map[string]*cachedTag{}},
tagCache: &tagCacheMap{m: map[string]*cachedTag{}},
structCache: &structCacheMap{m: map[string]*cachedStruct{}},
errsPool: &sync.Pool{New: func() interface{} {
return ValidationErrors{}
}}}
@ -545,11 +514,10 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.
return
}
cTag, isCached := v.tagsCache.Get(tag)
cTag, isCached := v.tagCache.Get(tag)
if !isCached {
cTag = v.parseTags(tag, name)
v.tagsCache.Set(tag, cTag)
}
current, kind := v.ExtractType(current)

Loading…
Cancel
Save