/* * Copyright (c) Atmosphère-NX * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include namespace ams::util { namespace impl { template constexpr ALWAYS_INLINE bool IsIntValueRepresentableImpl(From v) { using ToLimit = std::numeric_limits; using FromLimit = std::numeric_limits; if constexpr (ToLimit::min() <= FromLimit::min() && FromLimit::max() <= ToLimit::max()) { return true; } else { return ToLimit::min() <= v && v <= ToLimit::max(); } } template constexpr ALWAYS_INLINE bool IsIntValueRepresentableImpl(From v) { using ToLimit = std::numeric_limits; using FromLimit = std::numeric_limits; if constexpr (ToLimit::min() <= FromLimit::min() && FromLimit::max() <= ToLimit::max()) { return true; } else { return ToLimit::min() <= v && v <= ToLimit::max(); } } template constexpr ALWAYS_INLINE bool IsIntValueRepresentableImpl(From v) { using UnsignedFrom = typename std::make_unsigned::type; if (v < 0) { return false; } else { return IsIntValueRepresentableImpl(static_cast(v)); } } template constexpr ALWAYS_INLINE bool IsIntValueRepresentableImpl(From v) { using UnsignedTo = typename std::make_unsigned::type; return v <= static_cast(std::numeric_limits::max()); } } template constexpr ALWAYS_INLINE bool IsIntValueRepresentable(From v) { return ::ams::util::impl::IsIntValueRepresentableImpl(v); } template constexpr ALWAYS_INLINE bool CanAddWithoutOverflow(T x, T y) { if constexpr (std::unsigned_integral) { return x <= std::numeric_limits::max() - y; } else { if (y >= 0) { return x <= std::numeric_limits::max() - y; } else { return x >= std::numeric_limits::min() - y; } } } template constexpr ALWAYS_INLINE bool CanSubtractWithoutOverflow(T x, T y) { if constexpr (std::unsigned_integral) { return x >= std::numeric_limits::min() + y; } else { if (y >= 0) { return x >= std::numeric_limits::min() + y; } else { return x <= std::numeric_limits::max() + y; } } } template constexpr ALWAYS_INLINE bool CanMultiplyWithoutOverflow(T x, T y) { if (x == 0 || y == 0) { return true; } if constexpr (std::unsigned_integral) { return y <= std::numeric_limits::max() / x; } else { if (x > 0) { if (y > 0) { return y <= std::numeric_limits::max() / x; } else /*if (y < 0) */ { return y >= std::numeric_limits::min() / x; } } else /* if (x < 0) */ { if (y > 0) { return x >= std::numeric_limits::min() / y; } else /*if (y < 0) */ { return y >= std::numeric_limits::max() / x; } } } } template constexpr inline bool TryAddWithoutOverflow(T *out, T x, T y) { AMS_ASSERT(out != nullptr); if (CanAddWithoutOverflow(x, y)) { *out = x + y; return true; } else { return false; } } template constexpr inline bool TrySubtractWithoutOverflow(T *out, T x, T y) { AMS_ASSERT(out != nullptr); if (CanSubtractWithoutOverflow(x, y)) { *out = x - y; return true; } else { return false; } } template constexpr inline bool TryMultiplyWithoutOverflow(T *out, T x, T y) { AMS_ASSERT(out != nullptr); if (CanMultiplyWithoutOverflow(x, y)) { *out = x * y; return true; } else { return false; } } }