nngn
Loading...
Searching...
No Matches
utils.h
Go to the documentation of this file.
1#ifndef NNGN_UTILS_UTILS_H
2#define NNGN_UTILS_UTILS_H
3
4#include <bit>
5#include <cassert>
6#include <cstring>
7#include <functional>
8#include <span>
9#include <string>
10#include <string_view>
11#include <type_traits>
12#include <utility>
13#include <vector>
14
15#include "concepts.h"
17
18#define FWD(...) std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__)
19
20#define NNGN_DEFAULT_CONSTRUCT(x) \
21 x() = default; \
22 x(const x&) = default; \
23 x &operator=(const x&) = default; \
24 x(x&&) noexcept = default; \
25 x &operator=(x&&) noexcept = default; \
26
27#define NNGN_VIRTUAL(x) \
28 NNGN_DEFAULT_CONSTRUCT(x) \
29 virtual ~x() = default;
30
31#define NNGN_PURE_VIRTUAL(x) \
32 NNGN_DEFAULT_CONSTRUCT(x) \
33 virtual ~x() = 0;
34
35#define NNGN_NO_COPY(x) \
36 x(const x&) = delete; \
37 x &operator=(const x&) = delete;
38
39#define NNGN_MOVE_ONLY(x) \
40 NNGN_NO_COPY(x) \
41 x(x&&) noexcept = default; \
42 x &operator=(x&&) noexcept = default;
43
44#define NNGN_NO_MOVE(x) \
45 x(const x&) = delete; \
46 x &operator=(const x&) = delete; \
47 x(x&&) noexcept = delete; \
48 x &operator=(x&&) noexcept = delete;
49
50#define NNGN_ANON_IMPL1(l) nngn_anon_ ## l
51#define NNGN_ANON_IMPL0(l) NNGN_ANON_IMPL1(l)
52#define NNGN_ANON() NNGN_ANON_IMPL0(__LINE__)
53#define NNGN_ANON_DECL(...) \
54 [[maybe_unused]] const auto NNGN_ANON() = __VA_ARGS__;
55
56#define NNGN_CONTAINER_OF(t, n, p) \
57 (nngn::byte_cast<t*>(nngn::byte_cast<char*>(p) - offsetof(t, n)))
58
59#define NNGN_BIND_MEM_FN(x, f) \
60 std::bind_front([] { \
61 constexpr auto nngn_ret = \
62 &std::remove_pointer_t<std::decay_t<decltype(x)>>::f; \
63 static_assert(std::is_member_function_pointer_v<decltype(nngn_ret)>); \
64 return nngn_ret; \
65 }(), (x))
66
67#define NNGN_EXPOSE_ITERATOR(n, m) \
68 NNGN_EXPOSE_ITERATOR0(n, m, cbegin) \
69 NNGN_EXPOSE_ITERATOR0(n, m, cend) \
70 NNGN_EXPOSE_ITERATOR0(n, m, begin) \
71 NNGN_EXPOSE_ITERATOR0(n, m, end)
72#define NNGN_EXPOSE_ITERATOR0(n, m, i) \
73 auto n##i(void) const { using std::i; return i(this->m); } \
74 auto n##i(void) { using std::i; return i(this->m); }
75
76namespace nngn {
77
78namespace detail {
79
80template<typename T>
81struct chain_cast {
82 constexpr decltype(auto) operator<<(auto &&x) {
83 return static_cast<T>(FWD(x));
84 }
85};
86
87}
88
89enum class empty {};
90
92template<typename ...Ts>
93constexpr decltype(auto) chain_cast(auto &&x) {
94 return (detail::chain_cast<Ts>{} << ... << FWD(x));
95}
96
98template<typename To, typename From>
99To narrow(const From &x) {
100 To ret = static_cast<To>(x);
101 assert(static_cast<From>(ret) == x);
102 return ret;
103}
104
106template<typename T, typename U>
107constexpr decltype(auto) cast(U &&x) {
108 if constexpr(requires { const_cast<T>(FWD(x)); })
109 return const_cast<T>(FWD(x));
110 else if constexpr(requires { static_cast<T>(FWD(x)); })
111 return static_cast<T>(FWD(x));
112 else
113 return reinterpret_cast<T>(FWD(x));
114}
115
117template<typename To, typename From>
118requires byte_pointer<To> || byte_pointer<From>
119constexpr To byte_cast(From p) {
120 constexpr bool is_const = std::is_const_v<std::remove_pointer_t<From>>;
121 using V = std::conditional_t<is_const, const void*, void*>;
122 return chain_cast<To, V>(p);
123}
124
126template<typename To, typename From>
127requires
128 byte_type<To> || char_type<To>
129 || byte_type<From> || char_type<From>
130std::span<To> byte_cast(std::span<From> s) {
131 assert(!(s.size() % sizeof(To)));
132 return {byte_cast<To*>(s.data()), s.size() / sizeof(To)};
133}
134
135template<enum_ T>
136inline constexpr auto to_underlying(T t) {
137 return static_cast<std::underlying_type_t<T>>(t);
138}
139
141inline constexpr auto ptr_diff(const auto *lhs, const auto *rhs) {
142 return byte_cast<const char*>(lhs) - byte_cast<const char*>(rhs);
143}
144
146inline constexpr bool ptr_cmp(const auto *p0, const auto *p1)
147 { return static_cast<const void*>(p0) == static_cast<const void*>(p1); }
148
150template<standard_layout T>
151std::size_t offsetof_ptr(auto T::*p) {
152 T t = {};
153 return static_cast<std::size_t>(ptr_diff(&(t.*p), &t));
154}
155
156inline auto as_bytes(const void *p) { return static_cast<const std::byte*>(p); }
157inline auto as_bytes(void *p) { return static_cast<std::byte*>(p); }
158
159inline std::span<const std::byte> as_byte_span(const auto *x)
160 { return {as_bytes(x), sizeof(*x)}; }
161inline std::span<std::byte> as_byte_span(auto *x)
162 { return {as_bytes(x), sizeof(*x)}; }
163
164inline constexpr bool str_less(const char *lhs, const char *rhs) {
165 if(!std::is_constant_evaluated())
166 return std::strcmp(lhs, rhs) < 0;
167 while(*lhs && *rhs && *lhs == *rhs)
168 ++lhs, ++rhs;
169 return *rhs && (!*lhs || *lhs < *rhs);
170}
171
172template<typename To, typename From>
173requires (
174 sizeof(To) == sizeof(From)
175 && std::is_trivially_copyable_v<To>
176 && std::is_trivially_copyable_v<From>)
177constexpr auto bit_cast(const From &from) {
178 static_assert(std::is_trivially_constructible_v<To>);
179 To ret = {};
180 std::memcpy(&ret, &from, sizeof(To));
181 return ret;
182}
183
184template<typename T>
185constexpr auto set_bit(T t, T mask, bool value) {
186 assert(std::popcount(mask) == 1);
187 return t ^ ((t ^ -T{value}) & mask);
188}
189
195template<typename> struct member_obj_type;
196
197template<typename T, typename O>
198struct member_obj_type<O(T::*)> : std::type_identity<T> {};
199
200template<typename T, typename R, typename ...Args>
201struct member_obj_type<R(T::*)(Args...)> : std::type_identity<T> {};
202
204template<typename T>
206
207template<member_pointer auto p>
208struct mem_obj {
209 template<typename T>
210 requires requires (T t) { {t.*p}; }
211 constexpr decltype(auto) operator()(const T &t)
212 { return t.*p; }
213};
214
215template<member_pointer auto p>
217 template<typename T>
218 requires requires (T t) { {t.*p}; }
219 constexpr bool operator()(const T &lhs, const T &rhs)
220 { return lhs.*p < rhs.*p; }
221};
222
227constexpr decltype(auto) rptr(auto &&r) { return &r; }
228
229bool read_file(std::string_view filename, std::string *ret);
230bool read_file(std::string_view filename, std::vector<std::byte> *ret);
231
232}
233
234#endif
assert
Definition: debug.lua:3
Definition: debug.h:45
constexpr auto bit_cast(const From &from)
Definition: utils.h:177
constexpr To byte_cast(From p)
reinterpret_cast restricted to conversions from/to char/uchar.
Definition: utils.h:119
bool read_file(std::string_view filename, std::string *ret)
Definition: utils.cpp:30
constexpr auto to_underlying(T t)
Definition: utils.h:136
constexpr chain_cast(auto &&x)
Performs successive static_casts, right to left.
Definition: utils.h:93
constexpr rptr(auto &&r)
Allows passing an rvalue pointer to a function.
Definition: utils.h:227
constexpr auto set_bit(T t, T mask, bool value)
Definition: utils.h:185
constexpr bool str_less(const char *lhs, const char *rhs)
Definition: utils.h:164
constexpr cast(U &&x)
Cast value to T with the strictest cast operator.
Definition: utils.h:107
typename member_obj_type< T >::type member_obj_type_t
Definition: utils.h:205
constexpr bool ptr_cmp(const auto *p0, const auto *p1)
Compares the address of two pointers.
Definition: utils.h:146
To narrow(const From &x)
Casts x to a narrower type, asserting that the value is preserved.
Definition: utils.h:99
std::size_t offsetof_ptr(auto T::*p)
Similar to the stdlib's offsetof, but using member data pointers.
Definition: utils.h:151
std::span< const std::byte > as_byte_span(const auto *x)
Definition: utils.h:159
empty
Definition: utils.h:89
constexpr auto ptr_diff(const auto *lhs, const auto *rhs)
Signed distance in bytes between pointers.
Definition: utils.h:141
auto as_bytes(const void *p)
Definition: utils.h:156
Definition: utils.h:81
Definition: utils.h:208
Definition: utils.h:216
constexpr bool operator()(const T &lhs, const T &rhs)
Definition: utils.h:219
Type associated with a member object/function pointer.
Definition: utils.h:195
std::chrono::seconds s
Definition: timing.cpp:6
#define FWD(...)
Definition: utils.h:18