TPDE
Loading...
Searching...
No Matches
misc.hpp
1// SPDX-FileCopyrightText: 2025 Contributors to TPDE <https://tpde.org>
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4#pragma once
5
6#include <type_traits>
7
8#include "tpde/base.hpp"
9
10namespace tpde::util {
11
12template <typename T>
13constexpr T align_down(T val, std::type_identity_t<T> align) {
14 // align must be a power of two
15 assert((align & (align - 1)) == 0);
16 return val & ~(align - 1);
17}
18
19template <typename T>
20constexpr T align_up(T val, std::type_identity_t<T> align) {
21 // align must be a power of two
22 assert((align & (align - 1)) == 0);
23 return (val + (align - 1)) & ~(align - 1);
24}
25
26template <typename T>
27T cnt_tz(T) {
28 static_assert(false);
29}
30
31template <>
32constexpr inline u8 cnt_tz<u8>(const u8 val) {
33 return __builtin_ctz(val);
34}
35
36template <>
37constexpr inline u16 cnt_tz<u16>(const u16 val) {
38 return __builtin_ctz(val);
39}
40
41template <>
42constexpr inline u32 cnt_tz<u32>(const u32 val) {
43 return __builtin_ctz(val);
44}
45
46template <>
47constexpr inline u64 cnt_tz<u64>(const u64 val) {
48 return __builtin_ctzll(val);
49}
50
51template <typename T>
52T cnt_lz(T) {
53 static_assert(false);
54}
55
56template <>
57constexpr u8 cnt_lz<u8>(const u8 val) {
58 return __builtin_clz((u32)val) - 24;
59}
60
61template <>
62constexpr u16 cnt_lz<u16>(const u16 val) {
63 return __builtin_clz((u32)val) - 16;
64}
65
66template <>
67constexpr u32 cnt_lz<u32>(const u32 val) {
68 return __builtin_clz(val);
69}
70
71template <>
72constexpr u64 cnt_lz<u64>(const u64 val) {
73 return __builtin_clzll(val);
74}
75
76inline u64 zext(const u64 val, const unsigned bits) {
77 assert(bits > 0 && bits < 64 && "invalid sext bit width");
78 return val & ((u64{1} << bits) - 1);
79}
80
81inline i64 sext(const u64 val, const unsigned bits) {
82 assert(bits > 0 && bits < 64 && "invalid sext bit width");
83 return (i64)(val << (64 - bits)) >> (64 - bits);
84}
85
86constexpr unsigned uleb_len(u64 value) {
87 return value ? (64 - cnt_lz(value) + 6) / 7 : 1;
88}
89
90constexpr unsigned uleb_write(u8 *dst, u64 value) noexcept {
91 u8 *base = dst;
92 while (true) {
93 u8 write = value & 0b0111'1111;
94 value >>= 7;
95 if (value == 0) {
96 *dst++ = write;
97 return dst - base;
98 }
99 *dst++ = write | 0b1000'0000;
100 }
101}
102
103constexpr unsigned sleb_write(u8 *dst, i64 value) noexcept {
104 u8 *base = dst;
105 while (true) {
106 u8 write = value & 0b0111'1111;
107 value >>= 7;
108 if ((value == 0 && (value & 0x40) == 0) || (value == -1 && value & 0x40)) {
109 *dst++ = write;
110 return dst - base;
111 }
112 *dst++ = write | 0b1000'0000;
113 }
114}
115
116template <bool Reverse = false>
117struct BitSetIterator {
118 u64 set;
119
120 struct Iter {
121 u64 set;
122
123 Iter &operator++() noexcept {
124 if constexpr (Reverse) {
125 set = set & ~(1ull << (63 - cnt_lz(set)));
126 } else {
127 set = set & (set - 1);
128 }
129 return *this;
130 }
131
132 [[nodiscard]] u64 operator*() const noexcept {
133 assert(set != 0);
134 if constexpr (Reverse) {
135 return 63 - cnt_lz(set);
136 } else {
137 return cnt_tz(set);
138 }
139 }
140
141 [[nodiscard]] bool operator!=(const Iter &rhs) const noexcept {
142 return rhs.set != set;
143 }
144 };
145
146 explicit BitSetIterator(const u64 set) : set(set) {}
147
148 [[nodiscard]] Iter begin() const noexcept { return Iter{.set = set}; }
149
150 [[nodiscard]] Iter end() const noexcept { return Iter{.set = 0}; }
151};
152
153} // namespace tpde::util