From 7209809e296f0f57b0be923f1a7866abfa886fc9 Mon Sep 17 00:00:00 2001 From: Nikita Mikhaylov Date: Mon, 24 Aug 2020 14:54:04 +0300 Subject: [PATCH] get rid of virtual call --- src/AggregateFunctions/QuantileExact.h | 61 +++++++++++++++++--------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/src/AggregateFunctions/QuantileExact.h b/src/AggregateFunctions/QuantileExact.h index 5a427b07feb..da0f644721b 100644 --- a/src/AggregateFunctions/QuantileExact.h +++ b/src/AggregateFunctions/QuantileExact.h @@ -17,17 +17,10 @@ namespace ErrorCodes extern const int BAD_ARGUMENTS; } -/** Calculates quantile by collecting all values into array - * and applying n-th element (introselect) algorithm for the resulting array. - * - * It uses O(N) memory and it is very inefficient in case of high amount of identical values. - * But it is very CPU efficient for not large datasets. - */ -template -struct QuantileExact -{ - virtual ~QuantileExact() = default; +template +struct QuantileExactBase +{ /// The memory will be allocated to several elements at once, so that the state occupies 64 bytes. static constexpr size_t bytes_in_arena = 64 - sizeof(PODArray); using Array = PODArrayWithStackMemory; @@ -46,7 +39,7 @@ struct QuantileExact throw Exception("Method add with weight is not implemented for QuantileExact", ErrorCodes::NOT_IMPLEMENTED); } - void merge(const QuantileExact & rhs) { array.insert(rhs.array.begin(), rhs.array.end()); } + void merge(const QuantileExactBase & rhs) { array.insert(rhs.array.begin(), rhs.array.end()); } void serialize(WriteBuffer & buf) const { @@ -63,8 +56,32 @@ struct QuantileExact buf.read(reinterpret_cast(array.data()), size * sizeof(array[0])); } + Value get(Float64 level) + { + auto derived = static_cast(this); + return derived->getImpl(level); + } + + void getMany(const Float64 * levels, const size_t * indices, size_t size, Value * result) + { + auto derived = static_cast(this); + return derived->getManyImpl(levels, indices, size, result); + } +}; + +/** Calculates quantile by collecting all values into array + * and applying n-th element (introselect) algorithm for the resulting array. + * + * It uses O(N) memory and it is very inefficient in case of high amount of identical values. + * But it is very CPU efficient for not large datasets. + */ +template +struct QuantileExact : QuantileExactBase> +{ + using QuantileExactBase>::array; + // Get the value of the `level` quantile. The level must be between 0 and 1. - virtual Value get(Float64 level) + Value getImpl(Float64 level) { if (!array.empty()) { @@ -79,7 +96,7 @@ struct QuantileExact /// Get the `size` values of `levels` quantiles. Write `size` results starting with `result` address. /// indices - an array of index levels such that the corresponding elements will go in ascending order. - virtual void getMany(const Float64 * levels, const size_t * indices, size_t size, Value * result) + void getManyImpl(const Float64 * levels, const size_t * indices, size_t size, Value * result) { if (!array.empty()) { @@ -106,6 +123,7 @@ struct QuantileExact /// QuantileExactExclusive is equivalent to Excel PERCENTILE.EXC, R-6, SAS-4, SciPy-(0,0) template +/// There is no virtual-like functions. So we don't inherit from QuantileExactBase. struct QuantileExactExclusive : public QuantileExact { using QuantileExact::array; @@ -173,6 +191,7 @@ struct QuantileExactExclusive : public QuantileExact /// QuantileExactInclusive is equivalent to Excel PERCENTILE and PERCENTILE.INC, R-7, SciPy-(1,1) template +/// There is no virtual-like functions. So we don't inherit from QuantileExactBase. struct QuantileExactInclusive : public QuantileExact { using QuantileExact::array; @@ -237,11 +256,11 @@ struct QuantileExactInclusive : public QuantileExact // Implementation is as per "medium_low" function from python: // https://docs.python.org/3/library/statistics.html#statistics.median_low template -struct QuantileExactLow : public QuantileExact +struct QuantileExactLow : public QuantileExactBase> { - using QuantileExact::array; + using QuantileExactBase>::array; - Value get(Float64 level) override + Value getImpl(Float64 level) { if (!array.empty()) { @@ -270,7 +289,7 @@ struct QuantileExactLow : public QuantileExact return std::numeric_limits::quiet_NaN(); } - void getMany(const Float64 * levels, const size_t * indices, size_t size, Value * result) override + void getManyImpl(const Float64 * levels, const size_t * indices, size_t size, Value * result) { if (!array.empty()) { @@ -311,11 +330,11 @@ struct QuantileExactLow : public QuantileExact // Implementation is as per "medium_high function from python: // https://docs.python.org/3/library/statistics.html#statistics.median_high template -struct QuantileExactHigh : public QuantileExact +struct QuantileExactHigh : public QuantileExactBase> { - using QuantileExact::array; + using QuantileExactBase>::array; - Value get(Float64 level) override + Value getImpl(Float64 level) { if (!array.empty()) { @@ -336,7 +355,7 @@ struct QuantileExactHigh : public QuantileExact return std::numeric_limits::quiet_NaN(); } - void getMany(const Float64 * levels, const size_t * indices, size_t size, Value * result) override + void getManyImpl(const Float64 * levels, const size_t * indices, size_t size, Value * result) { if (!array.empty()) {