Skip to content

Commit 94182a2

Browse files
joeybloggsjoeybloggs
authored andcommitted
init struct cache changes
1 parent 638ea8a commit 94182a2

File tree

3 files changed

+123
-37
lines changed

3 files changed

+123
-37
lines changed

cache.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package validator
2+
3+
import "sync"
4+
5+
type cachedField struct {
6+
Idx int
7+
Name string
8+
AltName string
9+
CachedTag *cachedTag
10+
}
11+
12+
type cachedStruct struct {
13+
Name string
14+
fields map[int]cachedField
15+
}
16+
17+
type structCacheMap struct {
18+
lock sync.RWMutex
19+
m map[string]*cachedStruct
20+
}
21+
22+
func (s *structCacheMap) Get(key string) (*cachedStruct, bool) {
23+
s.lock.RLock()
24+
value, ok := s.m[key]
25+
s.lock.RUnlock()
26+
return value, ok
27+
}
28+
29+
func (s *structCacheMap) Set(key string, value *cachedStruct) {
30+
s.lock.Lock()
31+
s.m[key] = value
32+
s.lock.Unlock()
33+
}
34+
35+
type cachedTag struct {
36+
isOmitEmpty bool
37+
isNoStructLevel bool
38+
isStructOnly bool
39+
diveTag string
40+
tags []*tagVals
41+
}
42+
43+
type tagVals struct {
44+
tagVals [][]string
45+
isOrVal bool
46+
isAlias bool
47+
tag string
48+
}
49+
50+
type tagCacheMap struct {
51+
lock sync.RWMutex
52+
m map[string]*cachedTag
53+
}
54+
55+
func (s *tagCacheMap) Get(key string) (*cachedTag, bool) {
56+
s.lock.RLock()
57+
value, ok := s.m[key]
58+
s.lock.RUnlock()
59+
60+
return value, ok
61+
}
62+
63+
func (s *tagCacheMap) Set(key string, value *cachedTag) {
64+
s.lock.Lock()
65+
s.m[key] = value
66+
s.lock.Unlock()
67+
}

util.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,62 @@ func panicIf(err error) {
247247
}
248248
}
249249

250+
func (v *Validate) parseStruct(topStruct reflect.Type, sName string) *cachedStruct {
251+
252+
s := &cachedStruct{Name: sName, fields: map[int]cachedField{}}
253+
254+
numFields := topStruct.NumField()
255+
256+
var fld reflect.StructField
257+
var tag string
258+
var customName string
259+
260+
for i := 0; i < numFields; i++ {
261+
262+
fld = topStruct.Field(i)
263+
264+
if len(fld.PkgPath) != 0 {
265+
continue
266+
}
267+
268+
tag = fld.Tag.Get(v.tagName)
269+
270+
if tag == skipValidationTag {
271+
continue
272+
}
273+
274+
customName = fld.Name
275+
if len(v.fieldNameTag) != 0 {
276+
277+
name := strings.SplitN(fld.Tag.Get(v.fieldNameTag), ",", 2)[0]
278+
279+
// dash check is for json "-" (aka skipValidationTag) means don't output in json
280+
if name != "" && name != skipValidationTag {
281+
customName = name
282+
}
283+
}
284+
285+
cTag, ok := v.tagCache.Get(tag)
286+
if !ok {
287+
cTag = v.parseTags(tag, fld.Name)
288+
}
289+
290+
s.fields[i] = cachedField{Idx: i, Name: fld.Name, AltName: customName, CachedTag: cTag}
291+
}
292+
293+
v.structCache.Set(sName, s)
294+
295+
return s
296+
}
297+
250298
func (v *Validate) parseTags(tag, fieldName string) *cachedTag {
251299

252300
cTag := &cachedTag{}
253301

254302
v.parseTagsRecursive(cTag, tag, fieldName, blank, false)
303+
304+
v.tagCache.Set(tag, cTag)
305+
255306
return cTag
256307
}
257308

validator.go

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -47,39 +47,6 @@ var (
4747
emptyStructPtr = new(struct{})
4848
)
4949

50-
type cachedTag struct {
51-
isOmitEmpty bool
52-
isNoStructLevel bool
53-
isStructOnly bool
54-
diveTag string
55-
tags []*tagVals
56-
}
57-
58-
type tagVals struct {
59-
tagVals [][]string
60-
isOrVal bool
61-
isAlias bool
62-
tag string
63-
}
64-
65-
type tagCacheMap struct {
66-
lock sync.RWMutex
67-
m map[string]*cachedTag
68-
}
69-
70-
func (s *tagCacheMap) Get(key string) (*cachedTag, bool) {
71-
s.lock.RLock()
72-
value, ok := s.m[key]
73-
s.lock.RUnlock()
74-
return value, ok
75-
}
76-
77-
func (s *tagCacheMap) Set(key string, value *cachedTag) {
78-
s.lock.Lock()
79-
s.m[key] = value
80-
s.lock.Unlock()
81-
}
82-
8350
// StructLevel contains all of the information and helper methods
8451
// for reporting errors during struct level validation
8552
type StructLevel struct {
@@ -154,7 +121,8 @@ type Validate struct {
154121
hasCustomFuncs bool
155122
hasAliasValidators bool
156123
hasStructLevelFuncs bool
157-
tagsCache *tagCacheMap
124+
tagCache *tagCacheMap
125+
structCache *structCacheMap
158126
errsPool *sync.Pool
159127
}
160128

@@ -227,7 +195,8 @@ func New(config *Config) *Validate {
227195
v := &Validate{
228196
tagName: config.TagName,
229197
fieldNameTag: config.FieldNameTag,
230-
tagsCache: &tagCacheMap{m: map[string]*cachedTag{}},
198+
tagCache: &tagCacheMap{m: map[string]*cachedTag{}},
199+
structCache: &structCacheMap{m: map[string]*cachedStruct{}},
231200
errsPool: &sync.Pool{New: func() interface{} {
232201
return ValidationErrors{}
233202
}}}
@@ -545,11 +514,10 @@ func (v *Validate) traverseField(topStruct reflect.Value, currentStruct reflect.
545514
return
546515
}
547516

548-
cTag, isCached := v.tagsCache.Get(tag)
517+
cTag, isCached := v.tagCache.Get(tag)
549518

550519
if !isCached {
551520
cTag = v.parseTags(tag, name)
552-
v.tagsCache.Set(tag, cTag)
553521
}
554522

555523
current, kind := v.ExtractType(current)

0 commit comments

Comments
 (0)