diff --git a/libs/utils/include/utils/algorithm.h b/libs/utils/include/utils/algorithm.h index a719d463d9..8d99b3fb14 100644 --- a/libs/utils/include/utils/algorithm.h +++ b/libs/utils/include/utils/algorithm.h @@ -19,7 +19,8 @@ #include -#include +#include // for std::less +#include // for std::enable_if #include #include @@ -27,46 +28,51 @@ namespace utils { namespace details { + template constexpr inline T popcount(T v) noexcept { - static_assert(sizeof(T) * 8 <= 128, "details::popcount() only support up to 128 bits"); + static_assert(sizeof(T) * CHAR_BIT <= 128, "details::popcount() only support up to 128 bits"); constexpr T ONES = ~T(0); - v = v - ((v >> 1) & ONES / 3); - v = (v & ONES / 15 * 3) + ((v >> 2) & ONES / 15 * 3); - v = (v + (v >> 4)) & ONES / 255 * 15; + v = v - ((v >> 1u) & ONES / 3); + v = (v & ONES / 15 * 3) + ((v >> 2u) & ONES / 15 * 3); + v = (v + (v >> 4u)) & ONES / 255 * 15; return (T) (v * (ONES / 255)) >> (sizeof(T) - 1) * CHAR_BIT; } -template +template::value>> constexpr inline T clz(T x) noexcept { - static_assert(sizeof(T) <= sizeof(uint64_t), "details::clz() only support up to 64 bits"); - x |= (x >> 1); - x |= (x >> 2); - x |= (x >> 4); - x |= (x >> 8); - x |= (x >> 16); - if (sizeof(T) * 8 > 32) { // if() only needed to quash compiler warnings - x |= (x >> 32); + static_assert(sizeof(T) * CHAR_BIT <= 128, "details::clz() only support up to 128 bits"); + x |= (x >> 1u); + x |= (x >> 2u); + x |= (x >> 4u); + x |= (x >> 8u); + x |= (x >> 16u); + if (sizeof(T) * CHAR_BIT >= 64) { // just to silence compiler warning + x |= (x >> 32u); } - return (sizeof(T) * CHAR_BIT) - details::popcount(x); + if (sizeof(T) * CHAR_BIT >= 128) { // just to silence compiler warning + x |= (x >> 64u); + } + return T(sizeof(T) * CHAR_BIT) - details::popcount(x); } -template +template::value>> constexpr inline T ctz(T x) noexcept { - static_assert(sizeof(T) <= sizeof(uint64_t), "details::ctz() only support up to 64 bits"); - T c = sizeof(T) * 8; - x &= -signed(x); + static_assert(sizeof(T) * CHAR_BIT <= 64, "details::ctz() only support up to 64 bits"); + T c = sizeof(T) * CHAR_BIT; + x &= -x; // equivalent to x & (~x + 1) if (x) c--; - if (sizeof(T) * 8 > 32) { // if() only needed to quash compiler warnings - if (x & 0x00000000FFFFFFFF) c -= 32; + if (sizeof(T) * CHAR_BIT >= 64) { + if (x & T(0x00000000FFFFFFFF)) c -= 32; } - if (x & 0x0000FFFF) c -= 16; - if (x & 0x00FF00FF) c -= 8; - if (x & 0x0F0F0F0F) c -= 4; - if (x & 0x33333333) c -= 2; - if (x & 0x55555555) c -= 1; + if (x & T(0x0000FFFF0000FFFF)) c -= 16; + if (x & T(0x00FF00FF00FF00FF)) c -= 8; + if (x & T(0x0F0F0F0F0F0F0F0F)) c -= 4; + if (x & T(0x3333333333333333)) c -= 2; + if (x & T(0x5555555555555555)) c -= 1; return c; } + } // namespace details constexpr inline UTILS_PUBLIC UTILS_PURE @@ -249,8 +255,8 @@ RandomAccessIterator partition_point( // The number of repetitions here doesn't affect the result. We manually unroll the loop // twice, to guarantee we have at least two iterations without branches (for the case // where the size is not known at compile time - first += pred(first[len>>=1]) ? len : 0; - first += pred(first[len>>=1]) ? len : 0; + first += pred(first[len>>=1u]) ? len : 0; + first += pred(first[len>>=1u]) ? len : 0; } first += pred(*first); return first; diff --git a/libs/utils/test/test_algorithm.cpp b/libs/utils/test/test_algorithm.cpp index 2cd7be1ff0..97f4401ad8 100644 --- a/libs/utils/test/test_algorithm.cpp +++ b/libs/utils/test/test_algorithm.cpp @@ -33,25 +33,25 @@ static inline T count_trailing_zeros(T v) noexcept { } TEST(AlgorithmTest, details_clz) { - for (uint64_t i = 1, j = 63; i < 64; i *= 2, j--) { + for (uint64_t i = 1, j = 63; j < 64; i *= 2, j--) { EXPECT_EQ(j, details::clz(i)); EXPECT_EQ(j, details::clz(i|1)); } - for (uint32_t i = 1, j = 31; i < 32; i *= 2, j--) { + for (uint32_t i = 1, j = 31; j < 32; i *= 2, j--) { EXPECT_EQ(j, details::clz(i)); EXPECT_EQ(j, details::clz(i|1)); } } TEST(AlgorithmTest, clz) { - for (uint64_t i = 1, j = 63; i < 64; i *= 2, j--) { + for (uint64_t i = 1, j = 63; j < 64; i *= 2, j--) { EXPECT_EQ(j, clz(i)); EXPECT_EQ(j, clz(i|1)); EXPECT_EQ(j, details::clz(i)); EXPECT_EQ(j, details::clz(i|1)); EXPECT_EQ(j, count_leading_zeros(i)); } - for (uint32_t i = 1, j = 31; i < 32; i *= 2, j--) { + for (uint32_t i = 1, j = 31; j < 32; i *= 2, j--) { EXPECT_EQ(j, clz(i)); EXPECT_EQ(j, clz(i|1)); EXPECT_EQ(j, details::clz(i)); @@ -61,21 +61,21 @@ TEST(AlgorithmTest, clz) { } TEST(AlgorithmTest, details_ctz) { - for (uint64_t i = 1, j = 0; i < 64; i *= 2, j++) { + for (uint64_t i = 1, j = 0; j < 64; i *= 2, j++) { EXPECT_EQ(j, details::ctz(i)); } - for (uint32_t i = 1, j = 0; i < 32; i *= 2, j++) { + for (uint32_t i = 1, j = 0; j < 32; i *= 2, j++) { EXPECT_EQ(j, details::ctz(i)); } } TEST(AlgorithmTest, ctz) { - for (uint64_t i = 1, j = 0; i < 64; i *= 2, j++) { + for (uint64_t i = 1, j = 0; j < 64; i *= 2, j++) { EXPECT_EQ(j, ctz(i)); EXPECT_EQ(j, details::ctz(i)); EXPECT_EQ(j, count_trailing_zeros(i)); } - for (uint32_t i = 1, j = 0; i < 32; i *= 2, j++) { + for (uint32_t i = 1, j = 0; j < 32; i *= 2, j++) { EXPECT_EQ(j, ctz(i)); EXPECT_EQ(j, details::ctz(i)); EXPECT_EQ(j, count_trailing_zeros(i)); @@ -99,13 +99,13 @@ TEST(AlgorithmTest, details_popcount) { EXPECT_EQ(16, details::popcount(uint32_t(0x55555555))); EXPECT_EQ(32, details::popcount(uint64_t(0x5555555555555555))); - for (uint64_t i = 1, j = 63; i < 64; i *= 2, j--) { + for (uint64_t i = 1, j = 63; j < 64; i *= 2, j--) { EXPECT_EQ(1, details::popcount(i)); } - for (uint32_t i = 1, j = 31; i < 32; i *= 2, j--) { + for (uint32_t i = 1, j = 31; j < 32; i *= 2, j--) { EXPECT_EQ(1, details::popcount(i)); } - for (uint8_t i = 1, j = 7; i < 8; i *= 2, j--) { + for (uint8_t i = 1, j = 7; j < 8; i *= 2, j--) { EXPECT_EQ(1, details::popcount(i)); } } @@ -130,10 +130,10 @@ TEST(AlgorithmTest, popcount) { for (uint64_t i = 1, j = 63; i < 64; i *= 2, j--) { EXPECT_EQ(1, popcount(i)); } - for (uint32_t i = 1, j = 31; i < 32; i *= 2, j--) { + for (uint32_t i = 1, j = 31; j < 32; i *= 2, j--) { EXPECT_EQ(1, popcount(i)); } - for (uint8_t i = 1, j = 7; i < 8; i *= 2, j--) { + for (uint8_t i = 1, j = 7; j < 8; i *= 2, j--) { EXPECT_EQ(1, popcount(i)); } }