MXS-1632: Add statistics functions

The statistic.hh header defines a set of functions that complement the
standard library numeric functions. They differ from the standard library
functions in that they take a container reference and a pointer-to-member
as parameters and calculate the statistic based on the pointed-to member.
This commit is contained in:
Markus Mäkelä 2018-09-02 03:03:31 +03:00
parent 47f3944f19
commit 708dabd773
No known key found for this signature in database
GPG Key ID: 72D48FCE664F7B19

View File

@ -14,10 +14,174 @@
#include <maxscale/ccdefs.hh>
enum ts_stats_type
#include <algorithm>
#include <functional>
#include <numeric>
/**
* Helper functions for calculating statistics over STL containers of classes. Containers of
* fundamental types aren't supported as the standard library functions already implement it.
*/
namespace maxscale
{
TS_STATS_MAX, /**< Maximum value */
TS_STATS_MIX, /**< Minimum value */
TS_STATS_SUM, /**< Sum of all value */
TS_STATS_AVG /**< Average of all values */
};
template <typename T>
using value_type = typename T::value_type;
/**
* Calculate sum of members
*
* @param values Container of values
* @param member Member of T::value_type to use
*
* @return Sum of member values
*/
template <typename T, typename R>
R sum(const T& values, R value_type<T>::*member)
{
return std::accumulate(values.begin(), values.end(), R {}, [&](R r, value_type<T> t){
return r + t.*member;
});
}
/**
* Calculate average of members
*
* @param values Container of values
* @param member Member of T::value_type to use
*
* @return Average of member values
*/
template <typename T, typename R>
R avg(const T& values, R value_type<T>::*member)
{
return values.empty() ? R{} : sum(values, member) / static_cast<R>(values.size());
}
/**
* Get minimum member value
*
* @param values Container of values
* @param member Member of T::value_type to use
*
* @return The minimum value of T::*member in `values`
*/
template <typename T, typename R>
R min(const T& values, R value_type<T>::*member)
{
auto it = std::min_element(values.begin(), values.end(), [&](value_type<T> a, value_type<T> b) {
return a.*member < b.*member;
});
return it != values.end() ? (*it).*member : R{};
}
/**
* Get maximum member value
*
* @param values Container of values
* @param member Member of T::value_type to use
*
* @return The maximum value of T::*member in `values`
*/
template <typename T, typename R>
R max(const T& values, R value_type<T>::*member)
{
auto it = std::max_element(values.begin(), values.end(), [&](value_type<T> a, value_type<T> b) {
return a.*member < b.*member;
});
return it != values.end() ? (*it).*member : R{};
}
/**
* Helper function for accumulating container-like member values
*
* This function accumulates the values element-wise with `accum` and returns the resulting container.
*
* @param values Container of values
* @param member Member of T::value_type to use
* @param accum Accumulator function
*
* @return Accumulated container
*/
template <typename T, typename R, typename Accum>
R accumulate(const T& values, R value_type<T>::*member, Accum accum)
{
return std::accumulate(values.begin(), values.end(), R {}, [&](R r, const value_type<T>& t){
std::transform(r.begin(), r.end(), (t.*member).begin(), r.begin(), [&](value_type<R> a, value_type<R> b){
return accum(a, b);
});
return r;
});
}
/**
* Calculate sum of member container values
*
* @param values Container of values
* @param member Member of T::value_type to use
*
* @return Sum of members
*/
template <typename T, typename R>
R sum_element(const T& values, R value_type<T>::*member)
{
return accumulate(values, member, std::plus<value_type<R>>());
}
/**
* Calculate average of member container values
*
* @param values Container of values
* @param member Member of T::value_type to use
*
* @return Average of members
*/
template <typename T, typename R>
R avg_element(const T& values, R value_type<T>::*member)
{
auto result = sum_element(values, member);
for (auto&& a : result)
{
a /= static_cast<value_type<R>>(values.size());
}
return result;
}
/**
* Calculate minimum of member container values
*
* @param values Container of values
* @param member Member of T::value_type to use
*
* @return Minimum of members
*/
template <typename T, typename R>
R min_element(const T& values, R value_type<T>::*member)
{
return accumulate(values, member, [](const value_type<R>& a, const value_type<R>& b){
return std::min(a, b);
});
}
/**
* Calculate maximum of member container values
*
* @param values Container of values
* @param member Member of T::value_type to use
*
* @return Maximum of members
*/
template <typename T, typename R>
R max_element(const T& values, R value_type<T>::*member)
{
return accumulate(values, member, [](const value_type<R>& a, const value_type<R>& b){
return std::max(a, b);
});
}
}