summaryrefslogtreecommitdiff
path: root/asl/base/bit.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'asl/base/bit.hpp')
-rw-r--r--asl/base/bit.hpp174
1 files changed, 174 insertions, 0 deletions
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
+