summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteven Le Rouzic <steven.lerouzic@gmail.com>2025-04-01 00:39:24 +0200
committerSteven Le Rouzic <steven.lerouzic@gmail.com>2025-04-03 00:34:54 +0200
commit0776012d0942537b1ddfef13cd37f8bfb125f501 (patch)
tree8df94c6ac1e41d8116a196b52852ca29efb76b12
parent4f8cbd442a1b7805decaf4db7226075221655083 (diff)
Add bit library
-rw-r--r--asl/base/BUILD.bazel2
-rw-r--r--asl/base/bit.hpp174
-rw-r--r--asl/base/bit_tests.cpp203
-rw-r--r--asl/base/meta.hpp83
-rw-r--r--asl/base/utility.hpp24
-rw-r--r--asl/containers/buffer.hpp3
-rw-r--r--asl/containers/hash_set.hpp3
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(