/* * Copyright (c) 2018 MariaDB Corporation Ab * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file and at www.mariadb.com/bsl11. * * Change Date: 2024-10-14 * * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2 or later of the General * Public License. */ #pragma once #include #include #include #include /** * 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 { template using ValueType = 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 R sum(const T& values, R ValueType::* member) { return std::accumulate(values.begin(), values.end(), R {}, [&](R r, ValueType 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 R avg(const T& values, R ValueType::* member) { return values.empty() ? R {} : sum(values, member) / static_cast(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 R min(const T& values, R ValueType::* member) { auto it = std::min_element(values.begin(), values.end(), [&](ValueType a, ValueType 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 R max(const T& values, R ValueType::* member) { auto it = std::max_element(values.begin(), values.end(), [&](ValueType a, ValueType 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 R accumulate(const T& values, R ValueType::* member, Accum accum) { return std::accumulate(values.begin(), values.end(), R {}, [&](R r, const ValueType& t) { std::transform(r.begin(), r.end(), (t.*member).begin(), r.begin(), [&](ValueType a, ValueType 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 R sum_element(const T& values, R ValueType::* member) { return accumulate(values, member, std::plus>()); } /** * 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 R avg_element(const T& values, R ValueType::* member) { auto result = sum_element(values, member); for (auto&& a : result) { // Using C-style cast to work around an uncrustify bug a /= (ValueType)(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 R min_element(const T& values, R ValueType::* member) { return accumulate(values, member, [](const ValueType& a, const ValueType& 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 R max_element(const T& values, R ValueType::* member) { return accumulate(values, member, [](const ValueType& a, const ValueType& b) { return std::max(a, b); }); } }