feat(utils/misc): added a number of misc things (e.g. float roundoff compensated summation class)

This commit is contained in:
2026-11-09 13:44:41 -05:00
parent 585d6e3bf8
commit 9f3a2fca44
5 changed files with 30 additions and 38 deletions

View File

@@ -0,0 +1,21 @@
#pragma once
#include <cmath>
namespace serif::utils {
/// Neumaier summation retains small terms when a scalar reduction contains cancellation.
class CompensatedSum final {
public:
void add(const double value) {
const double next = m_sum + value;
m_correction += std::abs(m_sum) >= std::abs(value) ? (m_sum - next) + value : (value - next) + m_sum;
m_sum = next;
}
[[nodiscard]] double value() const { return m_sum + m_correction; }
private:
double m_sum{0.0};
double m_correction{0.0};
};
}

View File

@@ -1,18 +0,0 @@
#pragma once
#include "serif/utils/misc/concepts/concat.hpp"
#include "serif/utils/types/type_list.hpp"
namespace serif::utils::misc::concepts {
// Might make sense to rename these to FlatMap or some such
template <typename TypeList, template <typename> typename Descriptor>
struct EnumerateTypes;
template <template <typename> typename Descriptor, typename... TypeTs>
struct EnumerateTypes<types::TypeList<TypeTs...>, Descriptor> {
using Type = ConcatT<Descriptor<TypeTs>...>;
};
template <typename TypeList, template <typename> typename Descriptor>
using EnumerateTypesT = EnumerateTypes<TypeList, Descriptor>::Type;
}

View File

@@ -1,15 +1,10 @@
#pragma once
#include <exception>
#include <type_traits>
#include <string>
#include "serif/utils/misc/concepts/numeric.hpp"
namespace serif::utils::misc::concepts {
template <typename ExceptionCandidate>
concept IsException = std::is_base_of_v<std::exception, ExceptionCandidate>;
template <typename ExceptionCandidate, typename ErrorCode>
concept IsExceptionWithErrorCode = IsException<ExceptionCandidate> &&
std::constructible_from<ExceptionCandidate, ErrorCode, std::string>;
}

View File

@@ -7,9 +7,6 @@ namespace serif::utils::misc::concepts {
template <typename T>
concept IsNumeric = std::integral<T> || std::floating_point<T>;
template <typename T>
concept IsOrderable = std::totally_ordered<T>;
template <typename T>
concept IsComparableToNumeric = std::totally_ordered_with<T, float> ||
std::totally_ordered_with<T, double> ||
@@ -20,7 +17,4 @@ namespace serif::utils::misc::concepts {
template <typename...Ts>
concept SetOfOneOrTwo = (sizeof...(Ts) == 1) || (sizeof...(Ts) == 2);
template <typename EnumCandidate>
concept IsEnum = std::is_enum_v<EnumCandidate>;
}

View File

@@ -1,19 +1,19 @@
#pragma once
#include <array>
#include "serif/utils/misc/std_helper/cleaning.hpp"
namespace serif::utils::misc::traits {
template <typename... Ts>
constexpr bool all_unique_types_v = true;
// This can be a bit confusing. Whats going on here is that !SameType<First, Rest> && ...
// is preforming variadic folding. That is we check if First is the same as all types in
// the rest type list. If First is the same as any of those this will eval to true and then be negated to false.
// The only way for the first term (!SameType<First, Rest> && ...) to be true is if First is not the same as any of the types in Rest.
// Then we recursively call all_unique_types_v<Rest...> to check the rest. This ensures that this is only true if
// every single type in the type list is unique.
/** @brief Compare each head with the remaining exact types without a pack-sized Boolean fold. */
template <typename First, typename... Rest>
constexpr bool all_unique_types_v<First, Rest...> = (!std_helper::SameType<First, Rest> && ...) && all_unique_types_v<Rest...>;
constexpr bool all_unique_types_v<First, Rest...> = [] {
constexpr std::array<bool, sizeof...(Rest)> duplicates{std_helper::SameType<First, Rest>...};
for (const bool duplicate : duplicates) {
if (duplicate) { return false; }
}
return all_unique_types_v<Rest...>;
}();
}