var zeroType = reflect.TypeOf((*types.Zeroer)(nil)).Elem()
+var isZeroCache sync.Map
+
+func implementsIsZero(tp reflect.Type) bool {
+ v, ok := isZeroCache.Load(tp)
+ if ok {
+ return v.(bool)
+ }
+ implements := tp.Implements(zeroType)
+ isZeroCache.Store(tp, implements)
+ return implements
+}
+
// IsTruthfulValue returns whether the given value has a meaningful truth value.
// This is based on template.IsTrue in Go's stdlib, but also considers
// IsZero and any interface value will be unwrapped before it's considered
return
}
- if val.Type().Implements(zeroType) {
+ if implementsIsZero(val.Type()) {
return !val.Interface().(types.Zeroer).IsZero()
}
})
}
-func BenchmarkIsTruthFul(b *testing.B) {
- v := reflect.ValueOf("Hugo")
+func BenchmarkIsTruthFulValue(b *testing.B) {
+ var (
+ stringHugo = reflect.ValueOf("Hugo")
+ stringEmpty = reflect.ValueOf("")
+ zero = reflect.ValueOf(time.Time{})
+ timeNow = reflect.ValueOf(time.Now())
+ boolTrue = reflect.ValueOf(true)
+ boolFalse = reflect.ValueOf(false)
+ nilPointer = reflect.ValueOf((*zeroStruct)(nil))
+ )
b.ResetTimer()
for i := 0; i < b.N; i++ {
- if !IsTruthfulValue(v) {
- b.Fatal("not truthful")
- }
+ IsTruthfulValue(stringHugo)
+ IsTruthfulValue(stringEmpty)
+ IsTruthfulValue(zero)
+ IsTruthfulValue(timeNow)
+ IsTruthfulValue(boolTrue)
+ IsTruthfulValue(boolFalse)
+ IsTruthfulValue(nilPointer)
}
}