Skip to content

Commit 4d13035

Browse files
committed
common/hreflect: Speed up IsTrutfulValue
By caching the calculation of whether a type implements `IsZero`: ``` IsTruthFulVAlue-10 467.95n ± ∞ ¹ 79.13n ± ∞ ¹ -83.09% (p=0.029 n=4) ```
1 parent 9943c1b commit 4d13035

File tree

2 files changed

+30
-6
lines changed

2 files changed

+30
-6
lines changed

‎common/hreflect/helpers.go‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,18 @@ func IsSlice(v any) bool {
8686

8787
var zeroType = reflect.TypeOf((*types.Zeroer)(nil)).Elem()
8888

89+
var isZeroCache sync.Map
90+
91+
func implementsIsZero(tp reflect.Type) bool {
92+
v, ok := isZeroCache.Load(tp)
93+
if ok {
94+
return v.(bool)
95+
}
96+
implements := tp.Implements(zeroType)
97+
isZeroCache.Store(tp, implements)
98+
return implements
99+
}
100+
89101
// IsTruthfulValue returns whether the given value has a meaningful truth value.
90102
// This is based on template.IsTrue in Go's stdlib, but also considers
91103
// IsZero and any interface value will be unwrapped before it's considered
@@ -105,7 +117,7 @@ func IsTruthfulValue(val reflect.Value) (truth bool) {
105117
return
106118
}
107119

108-
if val.Type().Implements(zeroType) {
120+
if implementsIsZero(val.Type()) {
109121
return !val.Interface().(types.Zeroer).IsZero()
110122
}
111123

‎common/hreflect/helpers_test.go‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,26 @@ func BenchmarkIsContextType(b *testing.B) {
106106
})
107107
}
108108

109-
func BenchmarkIsTruthFul(b *testing.B) {
110-
v := reflect.ValueOf("Hugo")
109+
func BenchmarkIsTruthFulValue(b *testing.B) {
110+
var (
111+
stringHugo = reflect.ValueOf("Hugo")
112+
stringEmpty = reflect.ValueOf("")
113+
zero = reflect.ValueOf(time.Time{})
114+
timeNow = reflect.ValueOf(time.Now())
115+
boolTrue = reflect.ValueOf(true)
116+
boolFalse = reflect.ValueOf(false)
117+
nilPointer = reflect.ValueOf((*zeroStruct)(nil))
118+
)
111119

112120
b.ResetTimer()
113121
for i := 0; i < b.N; i++ {
114-
if !IsTruthfulValue(v) {
115-
b.Fatal("not truthful")
116-
}
122+
IsTruthfulValue(stringHugo)
123+
IsTruthfulValue(stringEmpty)
124+
IsTruthfulValue(zero)
125+
IsTruthfulValue(timeNow)
126+
IsTruthfulValue(boolTrue)
127+
IsTruthfulValue(boolFalse)
128+
IsTruthfulValue(nilPointer)
117129
}
118130
}
119131

0 commit comments

Comments
 (0)