#pragma once #include // Safe comparisons betweeen types that may contain mixture between signed and unsigned types. // Based on https://www.sandordargo.com/blog/2023/10/11/cpp20-intcmp-utilities namespace cmp { namespace detail { template struct eq_impl; template struct eq_impl { static constexpr bool call(T t, U u) noexcept { return t == u; } }; template struct eq_impl { static constexpr bool call(T t, U u) noexcept { if (std::is_signed::value) { return t >= 0 && static_cast::type>(t) == u; } else { return u >= 0 && static_cast::type>(u) == t; } } }; } template constexpr bool eq(T t, U u) noexcept { return detail::eq_impl::value == std::is_signed::value>::call(t, u); } template constexpr bool ne(T t, U u) noexcept { return !eq(t, u); } namespace detail { template struct lt_impl; template struct lt_impl { static constexpr bool call(T t, U u) noexcept { return t < u; } }; template struct lt_impl { static constexpr bool call(T t, U u) noexcept { if (std::is_signed::value) { return t < 0 || static_cast::type>(t) < u; } else { return u >= 0 && t < static_cast::type>(u); } } }; } template constexpr bool lt(T t, U u) noexcept { return detail::lt_impl::value == std::is_signed::value>::call(t, u); } template constexpr bool gt(T t, U u) noexcept { return lt(u, t); } template constexpr bool le(T t, U u) noexcept { return !lt(u, t); } template constexpr bool ge(T t, U u) noexcept { return !lt(t, u); } } // namespace cmp