#pragma once #include #include #include #include #include namespace stdx { inline namespace v1 { #if __cplusplus >= 202002L #define CONSTEXPR_INVOKE constexpr #else #define CONSTEXPR_INVOKE #endif template CONSTEXPR_INVOKE auto transform_reduce(InputIt first, InputIt last, T init, ROp rop, TOp top, InputItN... first_n) -> T { while (first != last) { init = std::invoke(rop, std::move(init), std::invoke(top, *first, *first_n...)); static_cast(++first), (static_cast(++first_n), ...); } return init; } template CONSTEXPR_INVOKE auto transform_reduce_n(InputIt first, Size n, T init, ROp rop, TOp top, InputItN... first_n) -> T { while (n-- != 0) { init = std::invoke(rop, std::move(init), std::invoke(top, *first, *first_n...)); static_cast(++first), (static_cast(++first_n), ...); } return init; } #undef CONSTEXPR_INVOKE template constexpr auto saturate_cast(From from) -> To { constexpr auto to_min = std::numeric_limits::min(); constexpr auto to_max = std::numeric_limits::max(); if constexpr (sizeof(From) > sizeof(To)) { auto const clamped = std::clamp(from, to_min, to_max); return static_cast(clamped); } if constexpr (sizeof(From) == sizeof(To)) { if constexpr (std::is_unsigned_v and std::is_signed_v) { if (from > to_max) { return to_max; } } if constexpr (std::is_signed_v and std::is_unsigned_v) { if (from < 0) { return static_cast(0); } } } return static_cast(from); } } // namespace v1 } // namespace stdx