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:
parent
47f3944f19
commit
708dabd773
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user