Thorin 1.9.0
The Higher ORder INtermediate representation
Loading...
Searching...
No Matches
util.h
Go to the documentation of this file.
1#pragma once
2
3#include <optional>
4#include <queue>
5#include <stack>
6#include <type_traits>
7
8#include <absl/container/flat_hash_map.h>
9#include <absl/container/flat_hash_set.h>
10#include <absl/container/node_hash_map.h>
11#include <absl/container/node_hash_set.h>
12#include <fe/assert.h>
13
14#include "thorin/util/hash.h"
15
16namespace thorin {
17
18/// @name Utility Functions
19///@{
20
21template<class This, class T> inline T& lazy_init(const This* self, std::unique_ptr<T>& ptr) {
22 return *(ptr ? ptr : ptr = std::make_unique<T>(*self));
23}
24
25/// A bitcast from @p src of type @p S to @p D.
26template<class D, class S> inline D bitcast(const S& src) {
27 D dst;
28 auto s = reinterpret_cast<const void*>(&src);
29 auto d = reinterpret_cast<void*>(&dst);
30
31 if constexpr (sizeof(D) == sizeof(S)) std::memcpy(d, s, sizeof(D));
32 if constexpr (sizeof(D) < sizeof(S)) std::memcpy(d, s, sizeof(D));
33 if constexpr (sizeof(D) > sizeof(S)) {
34 std::memset(d, 0, sizeof(D));
35 std::memcpy(d, s, sizeof(S));
36 }
37 return dst;
38}
39
40template<class T> bool get_sign(T val) {
41 static_assert(std::is_integral<T>(), "get_sign only supported for signed and unsigned integer types");
42 if constexpr (std::is_signed<T>())
43 return val < 0;
44 else
45 return val >> (T(sizeof(val)) * T(8) - T(1));
46}
47
48// TODO I guess we can do that with C++20 <bit>
49inline u64 pad(u64 offset, u64 align) {
50 auto mod = offset % align;
51 if (mod != 0) offset += align - mod;
52 return offset;
53}
54///@}
55
56/// @name Algorithms
57///@{
58template<class I, class T, class Cmp> I binary_find(I begin, I end, T val, Cmp cmp) {
59 auto i = std::lower_bound(begin, end, val, cmp);
60 return (i != end && !(cmp(val, *i))) ? i : end;
61}
62
63/// Like `std::string::substr`, but works on `std::string_view` instead.
64inline std::string_view subview(std::string_view s, size_t i, size_t n = std::string_view::npos) {
65 n = std::min(n, s.size());
66 return {s.data() + i, n - i};
67}
68
69/// Replaces all occurrences of @p what with @p repl.
70inline void find_and_replace(std::string& str, std::string_view what, std::string_view repl) {
71 for (size_t pos = str.find(what); pos != std::string::npos; pos = str.find(what, pos + repl.size()))
72 str.replace(pos, what.size(), repl);
73}
74///@}
75
76/// @name Helpers for Containers
77///@{
78template<class S> auto pop(S& s) -> decltype(s.top(), typename S::value_type()) {
79 auto val = s.top();
80 s.pop();
81 return val;
82}
83
84template<class Q> auto pop(Q& q) -> decltype(q.front(), typename Q::value_type()) {
85 auto val = q.front();
86 q.pop();
87 return val;
88}
89
90/// Yields pointer to element (or the element itself if it is already a pointer), if found and `nullptr` otherwise.
91/// @warning If the element is **not** already a pointer, this lookup will simply take the address of this element.
92/// This means that, e.g., a rehash of an `absl::flat_hash_map` will invalidate this pointer.
93template<class C, class K> auto lookup(const C& container, const K& key) {
94 auto i = container.find(key);
95 if constexpr (std::is_pointer_v<typename C::mapped_type>)
96 return i != container.end() ? i->second : nullptr;
97 else
98 return i != container.end() ? &i->second : nullptr;
99}
100
101/// Invokes `emplace` on @p container, asserts that insertion actually happened, and returns the iterator.
102template<class C, class... Args> auto assert_emplace(C& container, Args&&... args) {
103 auto [i, ins] = container.emplace(std::forward<Args&&>(args)...);
104 assert_unused(ins);
105 return i;
106}
107///@}
108
109template<class Set> class unique_stack {
110public:
111 using T = typename std::remove_reference_t<Set>::value_type;
112
113 bool push(T val) {
114 if (done_.emplace(val).second) {
115 stack_.emplace(val);
116 return true;
117 }
118 return false;
119 }
120
121 bool empty() const { return stack_.empty(); }
122 const T& top() { return stack_.top(); }
123 T pop() { return thorin::pop(stack_); }
124 void clear() {
125 done_.clear();
126 stack_ = {};
127 }
128
129private:
130 Set done_;
131 std::stack<T> stack_;
132};
133
134template<class Set> class unique_queue {
135public:
136 using T = typename std::remove_reference_t<Set>::value_type;
137
138 unique_queue() = default;
140 : done_(set) {}
141
142 bool push(T val) {
143 if (done_.emplace(val).second) {
144 queue_.emplace(val);
145 return true;
146 }
147 return false;
148 }
149
150 bool empty() const { return queue_.empty(); }
151 T pop() { return thorin::pop(queue_); }
152 T& front() { return queue_.front(); }
153 T& back() { return queue_.back(); }
154 void clear() {
155 done_.clear();
156 queue_ = {};
157 }
158
159private:
160 Set done_;
161 std::queue<T> queue_;
162};
163
164template<class T> struct GIDHash {
165 size_t operator()(T p) const { return murmur3(p->gid()); }
166};
167
168template<class T> struct GIDEq {
169 bool operator()(T a, T b) const { return a->gid() == b->gid(); }
170};
171
172template<class T> struct GIDLt {
173 bool operator()(T a, T b) const { return a->gid() < b->gid(); }
174};
175
176// clang-format off
177/// @name GID
178///@{
179template<class K, class V> using GIDMap = absl::flat_hash_map<K, V, GIDHash<K>, GIDEq<K>>;
180template<class K> using GIDSet = absl::flat_hash_set<K, GIDHash<K>, GIDEq<K>>;
181template<class K, class V> using GIDNodeMap = absl::node_hash_map<K, V, GIDHash<K>, GIDEq<K>>;
182template<class K> using GIDNodeSet = absl::node_hash_set<K, GIDHash<K>, GIDEq<K>>;
183///@}
184
185/// Use this to declare all kind of bit and comparison operators for an `enum` @p E.
186/// Note that the bit operators return @p E's underlying type and not the original `enum` @p E.
187/// This is because the result may not be a valid `enum` value.
188/// For the same reason, it doesn't make sense to declare operators such as `&=`.
189#define THORIN_ENUM_OPERATORS(E) \
190 constexpr auto operator&( E x, E y) { return std::underlying_type_t<E>(x) & std::underlying_type_t<E>(y); } \
191 constexpr auto operator&(std::underlying_type_t<E> x, E y) { return x & std::underlying_type_t<E>(y); } \
192 constexpr auto operator&( E x, std::underlying_type_t<E> y) { return std::underlying_type_t<E>(x) & y ; } \
193 constexpr auto operator|( E x, E y) { return std::underlying_type_t<E>(x) | std::underlying_type_t<E>(y); } \
194 constexpr auto operator|(std::underlying_type_t<E> x, E y) { return x | std::underlying_type_t<E>(y); } \
195 constexpr auto operator|( E x, std::underlying_type_t<E> y) { return std::underlying_type_t<E>(x) | y ; } \
196 constexpr auto operator^( E x, E y) { return std::underlying_type_t<E>(x) ^ std::underlying_type_t<E>(y); } \
197 constexpr auto operator^(std::underlying_type_t<E> x, E y) { return x ^ std::underlying_type_t<E>(y); } \
198 constexpr auto operator^( E x, std::underlying_type_t<E> y) { return std::underlying_type_t<E>(x) ^ y ; } \
199 constexpr std::strong_ordering operator<=>(std::underlying_type_t<E> x, E y) { return x <=> std::underlying_type_t<E>(y); } \
200 constexpr std::strong_ordering operator<=>(E x, std::underlying_type_t<E> y) { return std::underlying_type_t<E>(x) <=> y; } \
201 constexpr bool operator==(std::underlying_type_t<E> x, E y) { return x == std::underlying_type_t<E>(y); } \
202 constexpr bool operator==(E x, std::underlying_type_t<E> y) { return std::underlying_type_t<E>(x) == y; }
203// clang-format on
204
205} // namespace thorin
bool empty() const
Definition util.h:150
unique_queue(Set set)
Definition util.h:139
bool push(T val)
Definition util.h:142
typename std::remove_reference_t< Set >::value_type T
Definition util.h:136
bool push(T val)
Definition util.h:113
typename std::remove_reference_t< Set >::value_type T
Definition util.h:111
const T & top()
Definition util.h:122
bool empty() const
Definition util.h:121
Definition cfg.h:11
std::string_view subview(std::string_view s, size_t i, size_t n=std::string_view::npos)
Like std::string::substr, but works on std::string_view instead.
Definition util.h:64
uint64_t u64
Definition types.h:35
D bitcast(const S &src)
A bitcast from src of type S to D.
Definition util.h:26
auto lookup(const C &container, const K &key)
Yields pointer to element (or the element itself if it is already a pointer), if found and nullptr ot...
Definition util.h:93
I binary_find(I begin, I end, T val, Cmp cmp)
Definition util.h:58
absl::node_hash_set< K, GIDHash< K >, GIDEq< K > > GIDNodeSet
Definition util.h:182
absl::flat_hash_map< K, V, GIDHash< K >, GIDEq< K > > GIDMap
Definition util.h:179
hash_t murmur3(hash_t h, uint32_t key)
Definition hash.h:22
auto assert_emplace(C &container, Args &&... args)
Invokes emplace on container, asserts that insertion actually happened, and returns the iterator.
Definition util.h:102
auto pop(S &s) -> decltype(s.top(), typename S::value_type())
Definition util.h:78
absl::node_hash_map< K, V, GIDHash< K >, GIDEq< K > > GIDNodeMap
Definition util.h:181
u64 pad(u64 offset, u64 align)
Definition util.h:49
bool get_sign(T val)
Definition util.h:40
absl::flat_hash_set< K, GIDHash< K >, GIDEq< K > > GIDSet
Definition util.h:180
void find_and_replace(std::string &str, std::string_view what, std::string_view repl)
Replaces all occurrences of what with repl.
Definition util.h:70
T & lazy_init(const This *self, std::unique_ptr< T > &ptr)
Definition util.h:21
bool operator()(T a, T b) const
Definition util.h:169
size_t operator()(T p) const
Definition util.h:165
bool operator()(T a, T b) const
Definition util.h:173