diff options
author | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2025-04-01 00:39:24 +0200 |
---|---|---|
committer | Steven Le Rouzic <steven.lerouzic@gmail.com> | 2025-04-03 00:34:54 +0200 |
commit | 0776012d0942537b1ddfef13cd37f8bfb125f501 (patch) | |
tree | 8df94c6ac1e41d8116a196b52852ca29efb76b12 | |
parent | 4f8cbd442a1b7805decaf4db7226075221655083 (diff) |
Add bit library
-rw-r--r-- | asl/base/BUILD.bazel | 2 | ||||
-rw-r--r-- | asl/base/bit.hpp | 174 | ||||
-rw-r--r-- | asl/base/bit_tests.cpp | 203 | ||||
-rw-r--r-- | asl/base/meta.hpp | 83 | ||||
-rw-r--r-- | asl/base/utility.hpp | 24 | ||||
-rw-r--r-- | asl/containers/buffer.hpp | 3 | ||||
-rw-r--r-- | asl/containers/hash_set.hpp | 3 |
7 files changed, 455 insertions, 37 deletions
diff --git a/asl/base/BUILD.bazel b/asl/base/BUILD.bazel index 32ea47f..9157ad0 100644 --- a/asl/base/BUILD.bazel +++ b/asl/base/BUILD.bazel @@ -11,6 +11,7 @@ cc_library( hdrs = [ "annotations.hpp", "assert.hpp", + "bit.hpp", "config.hpp", "defer.hpp", "float.hpp", @@ -37,6 +38,7 @@ cc_library( "//asl/types:box", ], ) for name in [ + "bit", "defer", "float", "functional", diff --git a/asl/base/bit.hpp b/asl/base/bit.hpp new file mode 100644 index 0000000..f2e3f61 --- /dev/null +++ b/asl/base/bit.hpp @@ -0,0 +1,174 @@ +// Copyright 2025 Steven Le Rouzic +// +// SPDX-License-Identifier: BSD-3-Clause + +#pragma once + +#include "asl/base/integers.hpp" +#include "asl/base/meta.hpp" + +namespace asl +{ + +constexpr bool has_single_bit(is_unsigned_integer auto x) +{ + return x != 0 && ((x - 1) & x) == 0; +} + +// @Todo Move this to numeric library +template<is_integer T> +constexpr bool is_pow2(T x) +{ + using unsigned_type = select_t<is_unsigned_integer<T>, T, as_unsigned_integer<T>>; + return x > 0 && has_single_bit(static_cast<unsigned_type>(x)); +} + +constexpr int popcount(uint8_t v) +{ + v = v - ((v >> 1) & 0x55); + v = (v & 0x33) + ((v >> 2) & 0x33); + return (v + (v >> 4)) & 0x0F; +} + +constexpr int popcount(uint16_t v) +{ + v = v - ((v >> 1) & 0x5555); + v = (v & 0x3333) + ((v >> 2) & 0x3333); + return static_cast<uint16_t>((v + (v >> 4) & 0x0F0F) * uint16_t{0x0101}) >> 8; +} + +constexpr int popcount(uint32_t v) +{ + v = v - ((v >> 1) & 0x5555'5555); + v = (v & 0x3333'3333) + ((v >> 2) & 0x3333'3333); + return static_cast<int>(((v + (v >> 4) & 0x0F0F'0F0F) * 0x0101'0101) >> 24); +} + +constexpr int popcount(uint64_t v) +{ + v = v - ((v >> 1) & 0x5555'5555'5555'5555); + v = (v & 0x3333'3333'3333'3333) + ((v >> 2) & 0x3333'3333'3333'3333); + return static_cast<int>(((v + (v >> 4) & 0x0F0F'0F0F'0F0F'0F0F) * 0x0101'0101'0101'0101) >> 56); +} + +constexpr uint8_t propagate_right_one(uint8_t v) +{ + v = v | (v >> 1); + v = v | (v >> 2); + v = v | (v >> 4); + return v; +} + +constexpr uint16_t propagate_right_one(uint16_t v) +{ + v = v | (v >> 1); + v = v | (v >> 2); + v = v | (v >> 4); + v = v | (v >> 8); + return v; +} + +constexpr uint32_t propagate_right_one(uint32_t v) +{ + v = v | (v >> 1); + v = v | (v >> 2); + v = v | (v >> 4); + v = v | (v >> 8); + v = v | (v >> 16); + return v; +} + +constexpr uint64_t propagate_right_one(uint64_t v) +{ + v = v | (v >> 1); + v = v | (v >> 2); + v = v | (v >> 4); + v = v | (v >> 8); + v = v | (v >> 16); + v = v | (v >> 32); + return v; +} + +constexpr int countr_zero(is_unsigned_integer auto v) +{ + v = ~v & (v - 1); + return popcount(v); +} + +constexpr int countr_one(is_unsigned_integer auto v) +{ + v = v & (~v - 1); + return popcount(v); +} + +constexpr int countl_zero(is_unsigned_integer auto v) +{ + v = ~propagate_right_one(v); + return popcount(v); +} + +constexpr int countl_one(is_unsigned_integer auto v) +{ + v = ~v; + v = ~propagate_right_one(v); + return popcount(v); +} + +template<is_unsigned_integer T> +constexpr T rotr(T v, int s); + +template<is_unsigned_integer T> +constexpr T rotl(T v, int s) // NOLINT(*-no-recursion) +{ + static constexpr int N = sizeof(decltype(v)) * 8; + s = s % N; + return (s >= 0) ? (v << s) | (v >> (N - s)) : rotr(v, -s); +} + +template<is_unsigned_integer T> +constexpr T rotr(T v, int s) // NOLINT(*-no-recursion) +{ + static constexpr int N = sizeof(decltype(v)) * 8; + s = s % N; + return (s >= 0) ? (v >> s) | (v << (N - s)) : rotl(v, -s); +} + +constexpr uint16_t byteswap(uint16_t v) +{ + return static_cast<uint16_t>((v << 8U) | (v >> 8U)); +} + +constexpr uint32_t byteswap(uint32_t v) +{ + return rotr(v & 0x00ff'00ff, 8) | rotl(v & 0xff00'ff00, 8); +} + +constexpr uint64_t byteswap(uint64_t v) +{ + return (uint64_t{byteswap(static_cast<uint32_t>(v))} << 32) + | uint64_t{byteswap(static_cast<uint32_t>(v >> 32))}; +} + +constexpr auto bit_ceil(is_unsigned_integer auto v) +{ + v -= 1; + v = propagate_right_one(v); + v += 1; + return v; +} + +constexpr auto bit_floor(is_unsigned_integer auto v) +{ + v = propagate_right_one(v); + v = v - (v >> 1); + return v; +} + +constexpr int bit_width(is_unsigned_integer auto v) +{ + static constexpr int N = sizeof(decltype(v)) * 8; + return N - countl_zero(v); +} + +} // namespace asl + diff --git a/asl/base/bit_tests.cpp b/asl/base/bit_tests.cpp new file mode 100644 index 0000000..3b95c2f --- /dev/null +++ b/asl/base/bit_tests.cpp @@ -0,0 +1,203 @@ +// Copyright 2025 Steven Le Rouzic +// +// SPDX-License-Identifier: BSD-3-Clause + +#include "asl/base/bit.hpp" + +#include "asl/testing/testing.hpp" + +ASL_TEST(has_single_bit) +{ + ASL_TEST_EXPECT(asl::has_single_bit(4U)); + ASL_TEST_EXPECT(asl::has_single_bit(1024U)); + ASL_TEST_EXPECT(asl::has_single_bit(0x8000'0000U)); + ASL_TEST_EXPECT(asl::has_single_bit(0x0000'8000'0000'0000ULL)); + ASL_TEST_EXPECT(!asl::has_single_bit(0U)); + ASL_TEST_EXPECT(!asl::has_single_bit(3U)); + ASL_TEST_EXPECT(!asl::has_single_bit(341U)); +} + +ASL_TEST(is_pow2) +{ + ASL_TEST_EXPECT(asl::is_pow2(4)); + ASL_TEST_EXPECT(asl::is_pow2(65536)); + ASL_TEST_EXPECT(!asl::is_pow2(6)); + ASL_TEST_EXPECT(!asl::is_pow2(1978)); + ASL_TEST_EXPECT(!asl::is_pow2(0)); +} + +ASL_TEST(popcount) // NOLINT(*-cognitive-complexity) +{ + ASL_TEST_EXPECT(asl::popcount(uint8_t{0}) == 0); + ASL_TEST_EXPECT(asl::popcount(uint8_t{255}) == 8); + ASL_TEST_EXPECT(asl::popcount(uint8_t{46}) == 4); + ASL_TEST_EXPECT(asl::popcount(uint16_t{0}) == 0); + ASL_TEST_EXPECT(asl::popcount(uint16_t{255}) == 8); + ASL_TEST_EXPECT(asl::popcount(uint16_t{65535}) == 16); + ASL_TEST_EXPECT(asl::popcount(uint16_t{46}) == 4); + ASL_TEST_EXPECT(asl::popcount(uint32_t{0}) == 0); + ASL_TEST_EXPECT(asl::popcount(uint32_t{255}) == 8); + ASL_TEST_EXPECT(asl::popcount(uint32_t{65535}) == 16); + ASL_TEST_EXPECT(asl::popcount(uint32_t{65536}) == 1); + ASL_TEST_EXPECT(asl::popcount(uint32_t{46}) == 4); + ASL_TEST_EXPECT(asl::popcount(uint32_t{0xffff'ffff}) == 32); + ASL_TEST_EXPECT(asl::popcount(0x8421'1248'8421'1248) == 16); + ASL_TEST_EXPECT(asl::popcount(0xffff'ffff'ffff'ffff) == 64); +} + +ASL_TEST(countr_zero) +{ + ASL_TEST_EXPECT(asl::countr_zero(uint8_t{0}) == 8); + ASL_TEST_EXPECT(asl::countr_zero(uint8_t{255}) == 0); + ASL_TEST_EXPECT(asl::countr_zero(uint8_t{0b00011100}) == 2); + ASL_TEST_EXPECT(asl::countr_zero(uint8_t{0b10101010}) == 1); + ASL_TEST_EXPECT(asl::countr_zero(uint8_t{0b10101001}) == 0); +} + +ASL_TEST(countr_one) +{ + ASL_TEST_EXPECT(asl::countr_one(uint8_t{0}) == 0); + ASL_TEST_EXPECT(asl::countr_one(uint8_t{255}) == 8); + ASL_TEST_EXPECT(asl::countr_one(uint8_t{0b00011100}) == 0); + ASL_TEST_EXPECT(asl::countr_one(uint8_t{0b10101011}) == 2); + ASL_TEST_EXPECT(asl::countr_one(uint8_t{0b10101001}) == 1); +} + +ASL_TEST(countl_zero) +{ + ASL_TEST_EXPECT(asl::countl_zero(uint8_t{0}) == 8); + ASL_TEST_EXPECT(asl::countl_zero(uint8_t{255}) == 0); + ASL_TEST_EXPECT(asl::countl_zero(uint8_t{0b00011100}) == 3); + ASL_TEST_EXPECT(asl::countl_zero(uint8_t{0b10101010}) == 0); + ASL_TEST_EXPECT(asl::countl_zero(uint8_t{0b00001001}) == 4); +} + +ASL_TEST(countl_one) +{ + ASL_TEST_EXPECT(asl::countl_one(uint8_t{0}) == 0); + ASL_TEST_EXPECT(asl::countl_one(uint8_t{255}) == 8); + ASL_TEST_EXPECT(asl::countl_one(uint8_t{0b00011100}) == 0); + ASL_TEST_EXPECT(asl::countl_one(uint8_t{0b10101010}) == 1); + ASL_TEST_EXPECT(asl::countl_one(uint8_t{0b11101001}) == 3); +} + +ASL_TEST(rotl) +{ + ASL_TEST_EXPECT(asl::rotl(uint32_t{0x4000'0100}, 1) == 0x8000'0200); + ASL_TEST_EXPECT(asl::rotl(uint32_t{0x4000'0100}, 3) == 0x0000'0802); + ASL_TEST_EXPECT(asl::rotl(uint32_t{0x4000'0100}, 0) == 0x4000'0100); + ASL_TEST_EXPECT(asl::rotl(uint32_t{0x4000'0100}, -1) == 0x2000'0080); + ASL_TEST_EXPECT(asl::rotl(uint32_t{0x4000'0100}, -12) == 0x1004'0000); +} + +ASL_TEST(rotr) +{ + ASL_TEST_EXPECT(asl::rotr(uint32_t{0x4000'0100}, -1) == 0x8000'0200); + ASL_TEST_EXPECT(asl::rotr(uint32_t{0x4000'0100}, -3) == 0x0000'0802); + ASL_TEST_EXPECT(asl::rotr(uint32_t{0x4000'0100}, 0) == 0x4000'0100); + ASL_TEST_EXPECT(asl::rotr(uint32_t{0x4000'0100}, 1) == 0x2000'0080); + ASL_TEST_EXPECT(asl::rotr(uint32_t{0x4000'0100}, 12) == 0x1004'0000); +} + +ASL_TEST(byteswap) +{ + ASL_TEST_EXPECT(asl::byteswap(uint32_t{0x1234'5678}) == 0x7856'3412); + ASL_TEST_EXPECT(asl::byteswap(uint16_t{0x1234}) == 0x3412); + ASL_TEST_EXPECT(asl::byteswap(uint64_t{0x0123'4567'89ab'cdef}) == 0xefcd'ab89'6745'2301); +} + +ASL_TEST(bit_ceil) // NOLINT(*-cognitive-complexity) +{ + ASL_TEST_EXPECT(asl::bit_ceil(uint8_t{0}) == 0); + ASL_TEST_EXPECT(asl::bit_ceil(uint8_t{1}) == 1); + ASL_TEST_EXPECT(asl::bit_ceil(uint8_t{2}) == 2); + ASL_TEST_EXPECT(asl::bit_ceil(uint8_t{3}) == 4); + ASL_TEST_EXPECT(asl::bit_ceil(uint8_t{4}) == 4); + ASL_TEST_EXPECT(asl::bit_ceil(uint8_t{5}) == 8); + ASL_TEST_EXPECT(asl::bit_ceil(uint8_t{6}) == 8); + ASL_TEST_EXPECT(asl::bit_ceil(uint8_t{127}) == 128); + ASL_TEST_EXPECT(asl::bit_ceil(uint8_t{128}) == 128); + ASL_TEST_EXPECT(asl::bit_ceil(uint8_t{254}) == 0); + ASL_TEST_EXPECT(asl::bit_ceil(uint8_t{255}) == 0); + + ASL_TEST_EXPECT(asl::bit_ceil(uint16_t{0}) == 0); + ASL_TEST_EXPECT(asl::bit_ceil(uint16_t{1}) == 1); + ASL_TEST_EXPECT(asl::bit_ceil(uint16_t{2}) == 2); + ASL_TEST_EXPECT(asl::bit_ceil(uint16_t{3}) == 4); + ASL_TEST_EXPECT(asl::bit_ceil(uint16_t{4}) == 4); + ASL_TEST_EXPECT(asl::bit_ceil(uint16_t{5}) == 8); + ASL_TEST_EXPECT(asl::bit_ceil(uint16_t{6}) == 8); + ASL_TEST_EXPECT(asl::bit_ceil(uint16_t{32000}) == 32768); + ASL_TEST_EXPECT(asl::bit_ceil(uint16_t{32768}) == 32768); + ASL_TEST_EXPECT(asl::bit_ceil(uint16_t{35000}) == 0); + ASL_TEST_EXPECT(asl::bit_ceil(uint16_t{65535}) == 0); +} + +ASL_TEST(bit_floor) // NOLINT(*-cognitive-complexity) +{ + ASL_TEST_EXPECT(asl::bit_floor(uint8_t{0}) == 0); + ASL_TEST_EXPECT(asl::bit_floor(uint8_t{1}) == 1); + ASL_TEST_EXPECT(asl::bit_floor(uint8_t{2}) == 2); + ASL_TEST_EXPECT(asl::bit_floor(uint8_t{3}) == 2); + ASL_TEST_EXPECT(asl::bit_floor(uint8_t{4}) == 4); + ASL_TEST_EXPECT(asl::bit_floor(uint8_t{5}) == 4); + ASL_TEST_EXPECT(asl::bit_floor(uint8_t{6}) == 4); + ASL_TEST_EXPECT(asl::bit_floor(uint8_t{127}) == 64); + ASL_TEST_EXPECT(asl::bit_floor(uint8_t{128}) == 128); + ASL_TEST_EXPECT(asl::bit_floor(uint8_t{254}) == 128); + ASL_TEST_EXPECT(asl::bit_floor(uint8_t{255}) == 128); + + ASL_TEST_EXPECT(asl::bit_floor(uint16_t{0}) == 0); + ASL_TEST_EXPECT(asl::bit_floor(uint16_t{1}) == 1); + ASL_TEST_EXPECT(asl::bit_floor(uint16_t{2}) == 2); + ASL_TEST_EXPECT(asl::bit_floor(uint16_t{3}) == 2); + ASL_TEST_EXPECT(asl::bit_floor(uint16_t{4}) == 4); + ASL_TEST_EXPECT(asl::bit_floor(uint16_t{5}) == 4); + ASL_TEST_EXPECT(asl::bit_floor(uint16_t{6}) == 4); + ASL_TEST_EXPECT(asl::bit_floor(uint16_t{32000}) == 16384); + ASL_TEST_EXPECT(asl::bit_floor(uint16_t{32768}) == 32768); + ASL_TEST_EXPECT(asl::bit_floor(uint16_t{35000}) == 32768); + ASL_TEST_EXPECT(asl::bit_floor(uint16_t{65535}) == 32768); +} + +ASL_TEST(bit_width) // NOLINT(*-cognitive-complexity) +{ + ASL_TEST_EXPECT(asl::bit_width(uint8_t{0}) == 0); + ASL_TEST_EXPECT(asl::bit_width(uint8_t{1}) == 1); + ASL_TEST_EXPECT(asl::bit_width(uint8_t{2}) == 2); + ASL_TEST_EXPECT(asl::bit_width(uint8_t{3}) == 2); + ASL_TEST_EXPECT(asl::bit_width(uint8_t{4}) == 3); + ASL_TEST_EXPECT(asl::bit_width(uint8_t{5}) == 3); + ASL_TEST_EXPECT(asl::bit_width(uint8_t{6}) == 3); + + ASL_TEST_EXPECT(asl::bit_width(uint16_t{0}) == 0); + ASL_TEST_EXPECT(asl::bit_width(uint16_t{1}) == 1); + ASL_TEST_EXPECT(asl::bit_width(uint16_t{2}) == 2); + ASL_TEST_EXPECT(asl::bit_width(uint16_t{3}) == 2); + ASL_TEST_EXPECT(asl::bit_width(uint16_t{4}) == 3); + ASL_TEST_EXPECT(asl::bit_width(uint16_t{5}) == 3); + ASL_TEST_EXPECT(asl::bit_width(uint16_t{6}) == 3); + ASL_TEST_EXPECT(asl::bit_width(uint16_t{65535}) == 16); + + ASL_TEST_EXPECT(asl::bit_width(uint32_t{0}) == 0); + ASL_TEST_EXPECT(asl::bit_width(uint32_t{1}) == 1); + ASL_TEST_EXPECT(asl::bit_width(uint32_t{2}) == 2); + ASL_TEST_EXPECT(asl::bit_width(uint32_t{3}) == 2); + ASL_TEST_EXPECT(asl::bit_width(uint32_t{4}) == 3); + ASL_TEST_EXPECT(asl::bit_width(uint32_t{5}) == 3); + ASL_TEST_EXPECT(asl::bit_width(uint32_t{6}) == 3); + ASL_TEST_EXPECT(asl::bit_width(uint32_t{65535}) == 16); + ASL_TEST_EXPECT(asl::bit_width(uint32_t{65536}) == 17); + ASL_TEST_EXPECT(asl::bit_width(uint32_t{0xffff'ffff}) == 32); + + ASL_TEST_EXPECT(asl::bit_width(uint64_t{0}) == 0); + ASL_TEST_EXPECT(asl::bit_width(uint64_t{1}) == 1); + ASL_TEST_EXPECT(asl::bit_width(uint64_t{2}) == 2); + ASL_TEST_EXPECT(asl::bit_width(uint64_t{3}) == 2); + ASL_TEST_EXPECT(asl::bit_width(uint64_t{4}) == 3); + ASL_TEST_EXPECT(asl::bit_width(uint64_t{5}) == 3); + ASL_TEST_EXPECT(asl::bit_width(uint64_t{6}) == 3); + ASL_TEST_EXPECT(asl::bit_width(uint64_t{65535}) == 16); + ASL_TEST_EXPECT(asl::bit_width(uint64_t{65536}) == 17); + ASL_TEST_EXPECT(asl::bit_width(uint64_t{0xffff'ffff}) == 32); +} diff --git a/asl/base/meta.hpp b/asl/base/meta.hpp index 1d57367..c13439a 100644 --- a/asl/base/meta.hpp +++ b/asl/base/meta.hpp @@ -25,6 +25,9 @@ struct empty {}; template<typename T> struct id { using type = T; }; +struct in_place_t {}; +static constexpr in_place_t in_place{}; + template<typename... Args> static constexpr isize_t types_count = sizeof...(Args); template<typename T, T kValue> struct integral_constant { static constexpr T value = kValue; }; @@ -234,17 +237,75 @@ template<> struct _is_floating_point_helper<double> : true_type {}; template<typename T> concept is_floating_point = _is_floating_point_helper<un_cv_t<T>>::value; -template<typename T> struct _is_integer_helper : false_type {}; -template<> struct _is_integer_helper<int8_t> : true_type {}; -template<> struct _is_integer_helper<int16_t> : true_type {}; -template<> struct _is_integer_helper<int32_t> : true_type {}; -template<> struct _is_integer_helper<int64_t> : true_type {}; -template<> struct _is_integer_helper<uint8_t> : true_type {}; -template<> struct _is_integer_helper<uint16_t> : true_type {}; -template<> struct _is_integer_helper<uint32_t> : true_type {}; -template<> struct _is_integer_helper<uint64_t> : true_type {}; - -template<typename T> concept is_integer = _is_integer_helper<un_cv_t<T>>::value; +template<typename T> struct _integer_traits +{ + static constexpr bool kSigned = false; + static constexpr bool kUnsigned = false; +}; + +template<> struct _integer_traits<uint8_t> +{ + static constexpr bool kSigned = false; + static constexpr bool kUnsigned = true; + using as_signed = int8_t; +}; + +template<> struct _integer_traits<uint16_t> +{ + static constexpr bool kSigned = false; + static constexpr bool kUnsigned = true; + using as_signed = int16_t; +}; + +template<> struct _integer_traits<uint32_t> +{ + static constexpr bool kSigned = false; + static constexpr bool kUnsigned = true; + using as_signed = int32_t; +}; + +template<> struct _integer_traits<uint64_t> +{ + static constexpr bool kSigned = false; + static constexpr bool kUnsigned = true; + using as_signed = int64_t; +}; + +template<> struct _integer_traits<int8_t> +{ + static constexpr bool kSigned = true; + static constexpr bool kUnsigned = false; + using as_unsigned = uint8_t; +}; + +template<> struct _integer_traits<int16_t> +{ + static constexpr bool kSigned = true; + static constexpr bool kUnsigned = false; + using as_unsigned = uint16_t; +}; + +template<> struct _integer_traits<int32_t> +{ + static constexpr bool kSigned = true; + static constexpr bool kUnsigned = false; + using as_unsigned = uint32_t; +}; + +template<> struct _integer_traits<int64_t> +{ + static constexpr bool kSigned = true; + static constexpr bool kUnsigned = false; + using as_unsigned = uint64_t; +}; + +template<typename T> concept is_signed_integer = _integer_traits<T>::kSigned; +template<typename T> concept is_unsigned_integer = _integer_traits<T>::kUnsigned; + +template<typename T> concept is_integer = is_signed_integer<T> || is_unsigned_integer<T>; + +template<is_signed_integer T> using as_unsigned_integer = _integer_traits<T>::as_unsigned; +template<is_unsigned_integer T> using as_signed_integer = _integer_traits<T>::as_signed; template<typename T> concept is_enum = __is_enum(T); diff --git a/asl/base/utility.hpp b/asl/base/utility.hpp index 85c873d..77ccc6b 100644 --- a/asl/base/utility.hpp +++ b/asl/base/utility.hpp @@ -47,9 +47,6 @@ template<typename T> namespace asl { -struct in_place_t {}; -static constexpr in_place_t in_place{}; - template<moveable T> constexpr void swap(T& a, T& b) { @@ -84,27 +81,6 @@ constexpr T max(T a, T b) return (a >= b) ? a : b; } -constexpr uint64_t round_up_pow2(uint64_t v) -{ - ASL_ASSERT(v <= 0x8000'0000'0000'0000); - - v -= 1; - - v |= v >> 1U; - v |= v >> 2U; - v |= v >> 4U; - v |= v >> 8U; - v |= v >> 16U; - v |= v >> 32U; - - return v + 1; -} - -constexpr bool is_pow2(isize_t v) -{ - return v > 0 && ((v - 1) & v) == 0; // NOLINT -} - // NOLINTBEGIN(*-macro-parentheses) #define ASL_DELETE_COPY(T) \ T(const T&) = delete; \ diff --git a/asl/containers/buffer.hpp b/asl/containers/buffer.hpp index f684808..d61abf9 100644 --- a/asl/containers/buffer.hpp +++ b/asl/containers/buffer.hpp @@ -9,6 +9,7 @@ #include "asl/memory/memory.hpp" #include "asl/base/annotations.hpp" #include "asl/base/assert.hpp" +#include "asl/base/bit.hpp" #include "asl/types/span.hpp" #include "asl/hashing/hash.hpp" @@ -320,7 +321,7 @@ public: if (new_capacity <= capacity()) { return; } ASL_ASSERT(new_capacity > kInlineCapacity); - new_capacity = static_cast<isize_t>(round_up_pow2(static_cast<uint64_t>(new_capacity))); + new_capacity = static_cast<isize_t>(bit_ceil(static_cast<uint64_t>(new_capacity))); T* old_data = data(); const isize_t old_capacity = capacity(); diff --git a/asl/containers/hash_set.hpp b/asl/containers/hash_set.hpp index 6e6f851..809b402 100644 --- a/asl/containers/hash_set.hpp +++ b/asl/containers/hash_set.hpp @@ -7,6 +7,7 @@ #include "asl/base/annotations.hpp" #include "asl/base/utility.hpp" #include "asl/base/meta.hpp" +#include "asl/base/bit.hpp" #include "asl/memory/allocator.hpp" #include "asl/memory/memory.hpp" #include "asl/types/maybe_uninit.hpp" @@ -83,7 +84,7 @@ protected: ASL_ASSERT(size > 0); return max<isize_t>( kMinCapacity, - static_cast<isize_t>(round_up_pow2((static_cast<uint64_t>(size) * 4 + 2) / 3))); + static_cast<isize_t>(bit_ceil((static_cast<uint64_t>(size) * 4 + 2) / 3))); } static void insert_inner( |