3 #include <initializer_list>
11 void move_vector(std::pmr::vector<T>& from, std::pmr::vector<T>& to) {
12 to.reserve(from.size());
14 std::make_move_iterator(from.begin()),
15 std::make_move_iterator(from.end()));
20 using remove_ptr_or_ref_t = std::conditional_t<
22 std::remove_pointer_t<T>,
23 std::remove_reference_t<T>>;
26 template <
typename To,
typename From>
27 using transfer_const_t = std::conditional_t<
28 std::is_const_v<From>,
29 std::add_const_t<To>, To>;
32 template <
typename To,
typename From>
33 using transfer_volatile_t = std::conditional_t<
34 std::is_volatile_v<From>,
35 std::add_volatile_t<To>, To>;
38 template <
typename To,
typename From>
39 using transfer_cv_t = transfer_volatile_t<transfer_const_t<To, From>, From>;
42 template <
typename U,
typename V>
43 using union_cv_t = transfer_cv_t<transfer_cv_t<U, V>, U>;
46 template <
typename To,
typename From>
47 using transfer_ptr_or_ref_t = std::conditional_t<
48 std::is_pointer_v<From>,
49 std::add_pointer_t<To>,
51 std::is_reference_v<From>,
52 std::add_lvalue_reference_t<To>,
56 template <
typename To,
typename From>
57 consteval bool is_valid_type_cast_f() {
58 constexpr bool c1 = std::is_class_v<remove_ptr_or_ref_t<To>>;
59 static_assert(c1,
"To must be a class or a pointer to a class");
60 constexpr bool c2 = std::is_class_v<remove_ptr_or_ref_t<From>>;
61 static_assert(c2,
"From must be a class or a pointer to a class");
62 constexpr bool c3 = std::is_pointer_v<From> || std::is_reference_v<From>;
63 static_assert(c3,
"From must be a pointer or a reference");
64 constexpr bool c4 = !(std::is_pointer_v<From> && std::is_reference_v<To>);
65 static_assert(c4,
"From* -> To& is illegal");
66 constexpr bool c5 = !(std::is_reference_v<From> && std::is_pointer_v<To>);
67 static_assert(c5,
"From& -> To* is illegal");
68 constexpr bool c6 = !std::is_reference_v<To>;
69 static_assert(c6,
"Casting to a reference is illegal");
70 return c1 && c2 && c3 && c4 && c5 && c6;
80 template <
typename To,
typename From>
81 using canonicalize_t = utils::union_cv_t<utils::remove_ptr_or_ref_t<To>,
82 utils::remove_ptr_or_ref_t<From>>;
91 template <
typename To,
typename From>
92 std::enable_if_t<std::is_pointer_v<From>, canonicalize_t<To, From>*>
94 if constexpr(utils::is_valid_type_cast_f<To, From>()) {
95 assert(from &&
"Tried to cast a nullptr");
96 auto ptr =
dynamic_cast<canonicalize_t<To, From>*>(from);
97 assert(ptr &&
"Invalid cast");
110 template <
typename To,
typename From>
111 std::enable_if_t<!std::is_pointer_v<From>, canonicalize_t<To, From>*>
113 return cast<To>(&from);
124 template <
typename To,
typename From>
125 std::enable_if_t<std::is_pointer_v<From>, canonicalize_t<To, From>*>
126 dyn_cast(From from) {
127 if constexpr(utils::is_valid_type_cast_f<To, From>()) {
128 assert(from &&
"Tried to dyn_cast a nullptr");
129 return dynamic_cast<canonicalize_t<To, From>*>(from);
141 template <
typename To,
typename From>
142 std::enable_if_t<!std::is_pointer_v<From>, canonicalize_t<To, From>*>
143 dyn_cast(From& from) {
144 return dyn_cast<To>(&from);
153 template <
typename To,
typename From>
154 std::enable_if_t<std::is_pointer_v<From>, canonicalize_t<To, From>*>
155 dyn_cast_or_null(From from) {
156 if constexpr(utils::is_valid_type_cast_f<To, From>()) {
157 return dynamic_cast<canonicalize_t<To, From>*>(from);
167 namespace utils::details {
169 template <
typename...>
172 template <
class T,
class R =
void,
class =
void>
176 struct is_callable<T,
void, void_t<std::result_of_t<T>>> : std::true_type {};
178 template <
class T,
class R>
180 : std::is_convertible<std::result_of_t<T>, R> {};
182 template <
typename TSignature>
183 struct signature_helper;
185 template <
typename TReturn,
typename... TArgs>
186 struct signature_helper<TReturn(TArgs...)> {
187 using fn_ptr_type = TReturn (*)(TArgs...);
190 template <
typename TSignature>
191 using fn_ptr =
typename signature_helper<TSignature>::fn_ptr_type;
193 template <
typename T>
196 template <
typename TSignature>
199 template <
typename TReturn,
typename... TArgs>
200 class function_ref<TReturn(TArgs...)>
final {
202 using signature_type = TReturn(
void*, TArgs...);
204 TReturn (*_erased_fn)(
void*, TArgs...);
207 template <
typename T,
typename = std::enable_if_t<
209 !std::is_same<std::decay_t<T>, function_ref>{}>>
210 function_ref(T&& x)
noexcept : _ptr{(
void*)std::addressof(x)} {
211 _erased_fn = [](
void* ptr, TArgs... xs) -> TReturn {
212 return (*
reinterpret_cast<std::add_pointer_t<T>>(ptr))(
213 std::forward<TArgs>(xs)...);
216 decltype(
auto) operator()(TArgs... xs)
const
217 noexcept(
noexcept(_erased_fn(_ptr, std::forward<TArgs>(xs)...))) {
218 return _erased_fn(_ptr, std::forward<TArgs>(xs)...);
232 template <
typename T>
241 template<
typename U,
class Tp>
242 requires std::convertible_to<U, T>
243 range_ref(std::vector<U, Tp>& vec) {
244 range_ =
const_cast<
void*>(
static_cast<
void const*>(&vec));
245 foreach_ = [](
void* r, details::function_ref<
void(T)> callback) {
246 for(
auto&& v : *
reinterpret_cast<
decltype(&vec)>(r)) callback(v);
251 template<std::ranges::view R>
252 requires std::convertible_to<std::ranges::range_value_t<R>, T>
253 range_ref(R&& range) {
254 range_ =
const_cast<
void*>(
static_cast<
void const*>(&range));
255 foreach_ = [](
void* r, details::function_ref<
void(T)> callback) {
256 for(
auto&& v : *
reinterpret_cast<
decltype(&range)>(r)) callback(v);
258 sz_ = std::ranges::size(range);
262 requires std::convertible_to<U, T>
263 range_ref(std::initializer_list<U>&& list) {
264 range_ =
const_cast<
void*>(
static_cast<
void const*>(&list));
265 foreach_ = [](
void* r, details::function_ref<
void(T)> callback) {
266 for(
auto&& v : *
reinterpret_cast<
decltype(&list)>(r)) callback(v);
271 inline void for_each(details::function_ref<
void(T)> callback) {
272 if(foreach_) foreach_(range_, callback);
275 inline std::size_t size()
const {
280 using range_fun_t =
void (*)(
void*, details::function_ref<
void(T)>);
281 void* range_ =
nullptr;
282 range_fun_t foreach_ =
nullptr;