#ifndef CHAOS_SERVICE_BRANCHLESS_HPP #define CHAOS_SERVICE_BRANCHLESS_HPP #include #include #include namespace Chaos::Service { struct Branchless { template static constexpr OutUInt MsbMask(InUInt in) noexcept { static_assert(std::is_unsigned_v && std::is_unsigned_v); constexpr uint8_t shift = (sizeof(InUInt) * CHAR_BIT) - 1; return static_cast(0) - (in >> shift); } template static constexpr OutUInt Lt(InUInt lhs, InUInt rhs) noexcept { static_assert(std::is_unsigned_v && std::is_unsigned_v); static_assert(sizeof(InUInt) <= sizeof(uint64_t)); const uint64_t lhsEx = lhs; const uint64_t rhsEx = rhs; return MsbMask(lhsEx ^ ((lhsEx ^ rhsEx) | ((lhsEx - rhsEx) ^ lhsEx))); } template static constexpr OutUInt IsZero(InUInt in) noexcept { static_assert(std::is_unsigned_v && std::is_unsigned_v); static_assert(sizeof(InUInt) <= sizeof(uint64_t)); const uint64_t inEx = in; return MsbMask(~inEx & (inEx - 1U)); } template static constexpr OutUInt Eq(InUInt lhs, InUInt rhs) noexcept { static_assert(std::is_unsigned_v && std::is_unsigned_v); return IsZero(lhs ^ rhs); } template static constexpr OutUInt Ge(InUInt lhs, InUInt rhs) noexcept { static_assert(std::is_unsigned_v && std::is_unsigned_v); return ~Lt(lhs, rhs); } template static constexpr OutUInt Gt(InUInt lhs, InUInt rhs) noexcept { static_assert(std::is_unsigned_v && std::is_unsigned_v); return Lt(rhs, lhs); } template static constexpr UInt Sel(UInt mask, UInt onTrue, UInt onFalse) noexcept { static_assert(std::is_unsigned_v); return (mask & onTrue) | (~mask & onFalse); } }; } // namespace Chaos::Service #endif // CHAOS_SERVICE_BRANCHLESS_HPP