/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_UTILITY_HPP #define MPT_BASE_UTILITY_HPP #include "mpt/base/detect_compiler.hpp" #include "mpt/base/namespace.hpp" #if MPT_CXX_BEFORE(20) #include "mpt/base/saturate_cast.hpp" #endif #include #include #include namespace mpt { inline namespace MPT_INLINE_NS { #if MPT_CXX_AT_LEAST(20) && !MPT_CLANG_BEFORE(13, 0, 0) using std::in_range; #else // Returns true iff Tdst can represent the value val. // Use as if(mpt::in_range(-1)). template constexpr bool in_range(Tsrc val) { return (static_cast(mpt::saturate_cast(val)) == val); } #endif #if MPT_CXX_AT_LEAST(23) using std::to_underlying; #else template constexpr std::underlying_type_t to_underlying(T value) noexcept { return static_cast::type>(value); } #endif template struct value_initializer { inline void operator()(T & x) { x = T{}; } }; template struct value_initializer { inline void operator()(T (&a)[N]) { for (auto & e : a) { value_initializer{}(e); } } }; template inline void reset(T & x) { value_initializer{}(x); } #if MPT_CXX_AT_LEAST(20) && !MPT_CLANG_BEFORE(13, 0, 0) using std::cmp_equal; using std::cmp_greater; using std::cmp_greater_equal; using std::cmp_less; using std::cmp_less_equal; using std::cmp_not_equal; #else template constexpr bool cmp_equal(Ta a, Tb b) noexcept { using UTa = typename std::make_unsigned::type; using UTb = typename std::make_unsigned::type; if constexpr (std::is_signed::value == std::is_signed::value) { return a == b; } else if constexpr (std::is_signed::value) { return (a < 0) ? false : static_cast(a) == b; } else { return (b < 0) ? false : a == static_cast(b); } } template constexpr bool cmp_not_equal(Ta a, Tb b) noexcept { using UTa = typename std::make_unsigned::type; using UTb = typename std::make_unsigned::type; if constexpr (std::is_signed::value == std::is_signed::value) { return a != b; } else if constexpr (std::is_signed::value) { return (a < 0) ? true : static_cast(a) != b; } else { return (b < 0) ? true : a != static_cast(b); } } template constexpr bool cmp_less(Ta a, Tb b) noexcept { using UTa = typename std::make_unsigned::type; using UTb = typename std::make_unsigned::type; if constexpr (std::is_signed::value == std::is_signed::value) { return a < b; } else if constexpr (std::is_signed::value) { return (a < 0) ? true : static_cast(a) < b; } else { return (b < 0) ? false : a < static_cast(b); } } template constexpr bool cmp_greater(Ta a, Tb b) noexcept { using UTa = typename std::make_unsigned::type; using UTb = typename std::make_unsigned::type; if constexpr (std::is_signed::value == std::is_signed::value) { return a > b; } else if constexpr (std::is_signed::value) { return (a < 0) ? false : static_cast(a) > b; } else { return (b < 0) ? true : a > static_cast(b); } } template constexpr bool cmp_less_equal(Ta a, Tb b) noexcept { using UTa = typename std::make_unsigned::type; using UTb = typename std::make_unsigned::type; if constexpr (std::is_signed::value == std::is_signed::value) { return a <= b; } else if constexpr (std::is_signed::value) { return (a < 0) ? true : static_cast(a) <= b; } else { return (b < 0) ? false : a <= static_cast(b); } } template constexpr bool cmp_greater_equal(Ta a, Tb b) noexcept { using UTa = typename std::make_unsigned::type; using UTb = typename std::make_unsigned::type; if constexpr (std::is_signed::value == std::is_signed::value) { return a >= b; } else if constexpr (std::is_signed::value) { return (a < 0) ? false : static_cast(a) >= b; } else { return (b < 0) ? true : a >= static_cast(b); } } #endif } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_UTILITY_HPP