faster Run for known types
This is an alternative to PRs #160 and #165. It's essentially the same as PR #165 except that it uses generics to reduce the amount of duplicated code.
Instead of just amortizing the checking of the type, when the argument type of the function passed to Run is known, it bypasses the reflect-based code altogether.
We don't bother implementing the optimization on pre-generics Go versions because those are end-of-lifetime anyway.
I've added an implementation-independent benchmark.
goos: linux
goarch: amd64
pkg: github.com/frankban/quicktest
cpu: Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
│ base │ thisPR │
│ sec/op │ sec/op vs base │
CNewAndRunWithCustomType-8 1077.5n ± 5% 136.8n ± 6% -87.30% (p=0.002 n=6)
CRunWithCustomType-8 1035.00n ± 11% 66.43n ± 3% -93.58% (p=0.002 n=6)
geomean 1.056µ 95.33n -90.97%
The commit message claims:
It's essentially the same as PR #165 except that it uses generics to reduce the amount of duplicated code.
Well. To remove 7 lines which, in #165, are duplicated just once 10 lines below (and not exact duplicate as this allows to call testing.T.Helper()), this implementation uses a succession of wrappers which add lines of code. Also the use of generics in a project where we aim to maintain compatibility with pre-generics versions of Go implies to isolate that clever implementation with build tags and bumping the Go version in go.mod (with a warning comment) which adds even more code.
Is it really worth it?
I don't think so. This is just a bad use case for generics.
Note: CI is failing on Go 1.13.
@rogpeppe @frankban In #165 I have just added a commit that factorizes the code which here is wrapped in fastRun1. In fact I've gone further as my factorization is also used in the reflect version.