Adds an Expression pool to reduce allocations.
Description of changes: Allows us to reuse Expression instances, reducing allocations. Please comment if there's a better way to handle the newfound mutable-ness of the data classes in Kotlin.
Note the significant repetition of the pool pattern in PooledExpressionFactory. This is actually not easy to avoid without sacrificing performance (e.g. using lambdas, which require allocations and cut into the benefit).
This doesn't provide a speedup in my benchmarks, but does result in a noticeable reduction in allocations. That's a meaningful metric to drive down, though it means there remain other significant sources of both speedup and allocation improvements.
Speed: 248 ms/op -> 247 ms/op (~0%) Allocations: 189 KB/op -> 175 KB/op (-7.4%)
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
Note the significant repetition of the pool pattern in PooledExpressionFactory. This is actually not easy to avoid without sacrificing performance (e.g. using lambdas, which require allocations and cut into the benefit).
FYI—if you wrote it in Kotlin and used inline functions that accept lambda functions, then you can avoid allocations and other overhead because kotlinc can inline the function at the call site around the functional-typed argument that is passed in.
But absolutely do not take this as a suggestion that you should rewrite it in Kotlin. You already have something that works.
Closing in favor of a different evaluator design.