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 > 0 && (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 > 0 && (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 zext 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) {
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) {
104 u8 *base = dst;
105 while (true) {
106 u8 write = value & 0b0111'1111;
107 value >>= 7;
108 if ((value == 0 && (write & 0x40) == 0) ||
109 (value == -1 && (write & 0x40) != 0)) {
110 *dst++ = write;
111 return dst - base;
112 }
113 *dst++ = write | 0b1000'0000;
114 }
115}
116
117template <bool Reverse = false>
118struct BitSetIterator {
119 u64 set;
120
121 struct Iter {
122 u64 set;
123
124 Iter &operator++() {
125 if constexpr (Reverse) {
126 set = set & ~(1ull << (63 - cnt_lz(set)));
127 } else {
128 set = set & (set - 1);
129 }
130 return *this;
131 }
132
133 [[nodiscard]] u64 operator*() const {
134 assert(set != 0);
135 if constexpr (Reverse) {
136 return 63 - cnt_lz(set);
137 } else {
138 return cnt_tz(set);
139 }
140 }
141
142 [[nodiscard]] bool operator!=(const Iter &rhs) const {
143 return rhs.set != set;
144 }
145 };
146
147 explicit BitSetIterator(const u64 set) : set(set) {}
148
149 [[nodiscard]] Iter begin() const { return Iter{.set = set}; }
150
151 [[nodiscard]] Iter end() const { return Iter{.set = 0}; }
152};
153
154} // namespace tpde::util