/* SPDX-License-Identifier: BSL-1.0 OR BSD-3-Clause */ #ifndef MPT_BASE_SATURATE_CAST_HPP #define MPT_BASE_SATURATE_CAST_HPP #include "mpt/base/namespace.hpp" #include namespace mpt { inline namespace MPT_INLINE_NS { // Saturate the value of src to the domain of Tdst template constexpr Tdst saturate_cast(Tsrc src) noexcept { // This code tries not only to obviously avoid overflows but also to avoid signed/unsigned comparison warnings and type truncation warnings (which in fact would be safe here) by explicit casting. static_assert(std::numeric_limits::is_integer); static_assert(std::numeric_limits::is_integer); if constexpr (std::numeric_limits::is_signed && std::numeric_limits::is_signed) { if constexpr (sizeof(Tdst) >= sizeof(Tsrc)) { return static_cast(src); } else { return static_cast(std::max(static_cast(std::numeric_limits::min()), std::min(src, static_cast(std::numeric_limits::max())))); } } else if constexpr (!std::numeric_limits::is_signed && !std::numeric_limits::is_signed) { if constexpr (sizeof(Tdst) >= sizeof(Tsrc)) { return static_cast(src); } else { return static_cast(std::min(src, static_cast(std::numeric_limits::max()))); } } else if constexpr (std::numeric_limits::is_signed && !std::numeric_limits::is_signed) { if constexpr (sizeof(Tdst) > sizeof(Tsrc)) { return static_cast(src); } else if constexpr (sizeof(Tdst) == sizeof(Tsrc)) { return static_cast(std::min(src, static_cast(std::numeric_limits::max()))); } else { return static_cast(std::min(src, static_cast(std::numeric_limits::max()))); } } else { // Tdst unsigned, Tsrc signed if constexpr (sizeof(Tdst) >= sizeof(Tsrc)) { return static_cast(std::max(static_cast(0), src)); } else { return static_cast(std::max(static_cast(0), std::min(src, static_cast(std::numeric_limits::max())))); } } } template constexpr Tdst saturate_cast(double src) { if (src >= static_cast(std::numeric_limits::max())) { return std::numeric_limits::max(); } if (src <= static_cast(std::numeric_limits::min())) { return std::numeric_limits::min(); } return static_cast(src); } template constexpr Tdst saturate_cast(float src) { if (src >= static_cast(std::numeric_limits::max())) { return std::numeric_limits::max(); } if (src <= static_cast(std::numeric_limits::min())) { return std::numeric_limits::min(); } return static_cast(src); } } // namespace MPT_INLINE_NS } // namespace mpt #endif // MPT_BASE_SATURATE_CAST_HPP