10 #include <type_traits> 45 prop(*
const clazz)() noexcept;
50 base_node **
const underlying;
51 type_node *
const parent;
53 type_node *(*
const ref)() noexcept;
54 void *(* const cast)(
void *) noexcept;
55 base(* const clazz)() noexcept;
60 conv_node **
const underlying;
61 type_node *
const parent;
63 type_node *(*
const ref)() noexcept;
64 any(* const convert)(const
void *);
65 conv(* const clazz)() noexcept;
70 using size_type = std::size_t;
71 ctor_node **
const underlying;
72 type_node *
const parent;
76 type_node *(*
const arg)(size_type) noexcept;
77 any(*
const invoke)(any *
const);
78 ctor(*
const clazz)() noexcept;
83 dtor_node **
const underlying;
84 type_node *
const parent;
85 bool(*
const invoke)(handle);
86 dtor(*
const clazz)() noexcept;
91 data_node **
const underlying;
92 std::size_t identifier;
93 type_node *
const parent;
98 type_node *(*
const ref)() noexcept;
99 bool(* const set)(handle, any, any);
100 any(* const get)(handle, any);
101 data(* const clazz)() noexcept;
106 using size_type = std::size_t;
107 func_node **
const underlying;
108 std::size_t identifier;
109 type_node *
const parent;
112 const size_type size;
114 const bool is_static;
115 type_node *(*
const ret)() noexcept;
116 type_node *(* const arg)(size_type) noexcept;
117 any(* const invoke)(handle, any *);
118 func(* const clazz)() noexcept;
123 using size_type = std::size_t;
124 std::size_t identifier;
128 const bool is_integral;
129 const bool is_floating_point;
134 const bool is_pointer;
135 const bool is_function_pointer;
136 const bool is_member_object_pointer;
137 const bool is_member_function_pointer;
138 const size_type extent;
139 bool(*
const compare)(
const void *,
const void *);
140 type(*
const remove_pointer)() noexcept;
141 type(*
const clazz)() noexcept;
142 base_node *base{
nullptr};
143 conv_node *conv{
nullptr};
144 ctor_node *ctor{
nullptr};
145 dtor_node *dtor{
nullptr};
146 data_node *data{
nullptr};
147 func_node *func{
nullptr};
151 template<
typename...>
153 inline static type_node *type =
nullptr;
157 template<
typename Type>
158 struct info_node<Type> {
159 inline static type_node *type =
nullptr;
162 inline static base_node *base =
nullptr;
165 inline static conv_node *conv =
nullptr;
168 inline static ctor_node *ctor =
nullptr;
171 inline static dtor_node *dtor =
nullptr;
174 inline static data_node *data =
nullptr;
177 inline static func_node *func =
nullptr;
179 inline static type_node *
resolve() noexcept;
183 template<typename... Type>
184 struct type_info: info_node<std::remove_cv_t<std::remove_reference_t<Type>>...> {};
187 template<
typename Op,
typename Node>
188 void iterate(Op op,
const Node *curr) noexcept {
196 template<auto Member,
typename Op>
197 void iterate(Op op,
const type_node *node) noexcept {
199 auto *curr = node->base;
200 iterate(op, node->*Member);
203 iterate<Member>(op, curr->ref());
210 template<
typename Op,
typename Node>
211 auto find_if(Op op,
const Node *curr) noexcept {
212 while(curr && !op(curr)) {
220 template<auto Member,
typename Op>
221 auto find_if(Op op,
const type_node *node) noexcept
222 -> decltype(find_if(op, node->*Member)) {
223 decltype(find_if(op, node->*Member)) ret =
nullptr;
226 ret = find_if(op, node->*Member);
227 auto *curr = node->base;
229 while(curr && !ret) {
230 ret = find_if<Member>(op, curr->ref());
239 template<
typename Type>
240 const Type * try_cast(
const type_node *node,
void *instance) noexcept {
241 const auto *type = type_info<Type>::resolve();
247 const auto *base = find_if<&type_node::base>([type](
auto *candidate) {
248 return candidate->ref() == type;
251 ret = base ? base->cast(instance) :
nullptr;
254 return static_cast<const Type *
>(ret);
258 template<auto Member>
259 inline bool can_cast_or_convert(
const type_node *from,
const type_node *to) noexcept {
260 return (from == to) || find_if<Member>([to](
auto *node) {
261 return node->ref() == to;
266 template<
typename... Args, std::size_t... Indexes>
267 inline auto ctor(std::index_sequence<Indexes...>,
const type_node *node) noexcept {
268 return internal::find_if([](
auto *candidate) {
269 return candidate->size ==
sizeof...(Args) &&
270 (([](
auto *from,
auto *to) {
271 return internal::can_cast_or_convert<&internal::type_node::base>(from, to)
272 || internal::can_cast_or_convert<&internal::type_node::conv>(from, to);
273 }(internal::type_info<Args>::resolve(), candidate->arg(Indexes))) && ...);
303 using storage_type = std::aligned_storage_t<sizeof(void *), alignof(void *)>;
304 using copy_fn_type =
void *(storage_type &,
const void *);
305 using destroy_fn_type = void(
void *);
306 using steal_fn_type =
void *(storage_type &,
void *, destroy_fn_type *);
308 template<
typename Type,
typename = std::
void_t<>>
310 template<
typename... Args>
311 static void * instance(storage_type &storage, Args &&... args) {
312 auto instance = std::make_unique<Type>(std::forward<Args>(args)...);
313 new (&storage) Type *{instance.get()};
314 return instance.release();
317 static void destroy(
void *instance) {
318 auto *node = internal::type_info<Type>::resolve();
319 auto *actual =
static_cast<Type *
>(instance);
320 [[maybe_unused]]
const bool destroyed = node->clazz().destroy(*actual);
325 static void * copy(storage_type &storage,
const void *other) {
326 auto instance = std::make_unique<Type>(*
static_cast<const Type *
>(other));
327 new (&storage) Type *{instance.get()};
328 return instance.release();
331 static void * steal(storage_type &to,
void *from, destroy_fn_type *) {
332 auto *instance =
static_cast<Type *
>(from);
333 new (&to) Type *{instance};
338 template<
typename Type>
339 struct type_traits<Type, std::enable_if_t<sizeof(Type) <= sizeof(void *) && std::is_nothrow_move_constructible_v<Type>>> {
340 template<
typename... Args>
341 static void * instance(storage_type &storage, Args &&... args) {
342 return new (&storage) Type{std::forward<Args>(args)...};
345 static void destroy(
void *instance) {
346 auto *node = internal::type_info<Type>::resolve();
347 auto *actual =
static_cast<Type *
>(instance);
348 [[maybe_unused]]
const bool destroyed = node->clazz().destroy(*actual);
353 static void * copy(storage_type &storage,
const void *instance) {
354 return new (&storage) Type{*
static_cast<const Type *
>(instance)};
357 static void * steal(storage_type &to,
void *from, destroy_fn_type *destroy_fn) {
358 void *instance =
new (&to) Type{std::move(*static_cast<Type *>(from))};
381 template<
typename Type,
typename... Args>
382 explicit any(std::in_place_type_t<Type>, [[maybe_unused]] Args &&... args)
385 node = internal::type_info<Type>::resolve();
387 if constexpr(!std::is_void_v<Type>) {
388 using traits_type = type_traits<std::remove_cv_t<std::remove_reference_t<Type>>>;
389 instance = traits_type::instance(storage, std::forward<Args>(args)...);
390 destroy_fn = &traits_type::destroy;
391 copy_fn = &traits_type::copy;
392 steal_fn = &traits_type::steal;
401 template<
typename Type>
402 explicit any(std::reference_wrapper<Type> type)
405 node = internal::type_info<Type>::resolve();
406 instance = &type.get();
413 inline any(handle handle) noexcept;
420 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, any>>>
422 : any{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(type)}
433 instance = other.copy_fn ? other.copy_fn(storage, other.instance) : other.instance;
434 destroy_fn = other.destroy_fn;
435 copy_fn = other.copy_fn;
436 steal_fn = other.steal_fn;
457 destroy_fn(instance);
467 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, any>>>
469 return (*
this = any{std::forward<Type>(type)});
478 return (*
this = any{other});
487 any any{std::move(other)};
502 const void *
data() const noexcept {
508 return const_cast<void *
>(std::as_const(*this).data());
516 template<
typename Type>
518 return internal::try_cast<Type>(node, instance);
522 template<
typename Type>
524 return const_cast<Type *
>(std::as_const(*this).try_cast<Type>());
541 template<
typename Type>
542 const Type &
cast() const noexcept {
543 auto *actual = try_cast<Type>();
549 template<
typename Type>
551 return const_cast<Type &
>(std::as_const(*this).cast<Type>());
560 template<
typename Type>
564 if(
const auto *type = internal::type_info<Type>::resolve(); node == type) {
565 any = *
static_cast<const Type *
>(instance);
567 const auto *conv = internal::find_if<&internal::type_node::conv>([type](
auto *other) {
568 return other->ref() == type;
584 template<
typename Type>
586 bool valid = (node == internal::type_info<Type>::resolve());
589 if(
auto any = std::as_const(*this).convert<Type>(); any) {
605 template<
typename Type,
typename... Args>
607 *
this = any{std::in_place_type_t<Type>{}, std::forward<Args>(args)...};
614 explicit operator bool() const noexcept {
625 return node == other.node && (!node || node->compare(instance, other.instance));
633 friend void swap(any &lhs, any &rhs) noexcept {
634 if(lhs.steal_fn && rhs.steal_fn) {
636 auto *temp = lhs.steal_fn(buffer, lhs.instance, lhs.destroy_fn);
637 lhs.instance = rhs.steal_fn(lhs.storage, rhs.instance, rhs.destroy_fn);
638 rhs.instance = lhs.steal_fn(rhs.storage, temp, lhs.destroy_fn);
639 }
else if(lhs.steal_fn) {
640 lhs.instance = lhs.steal_fn(rhs.storage, lhs.instance, lhs.destroy_fn);
641 std::swap(rhs.instance, lhs.instance);
642 }
else if(rhs.steal_fn) {
643 rhs.instance = rhs.steal_fn(lhs.storage, rhs.instance, rhs.destroy_fn);
644 std::swap(rhs.instance, lhs.instance);
646 std::swap(lhs.instance, rhs.instance);
649 std::swap(lhs.node, rhs.node);
650 std::swap(lhs.destroy_fn, rhs.destroy_fn);
651 std::swap(lhs.copy_fn, rhs.copy_fn);
652 std::swap(lhs.steal_fn, rhs.steal_fn);
656 storage_type storage;
658 const internal::type_node *node;
659 destroy_fn_type *destroy_fn;
660 copy_fn_type *copy_fn;
661 steal_fn_type *steal_fn;
692 instance{any.instance}
700 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, handle>>>
702 : node{internal::type_info<Type>::resolve()},
716 const void *
data() const noexcept {
722 return const_cast<void *
>(std::as_const(*this).data());
729 explicit operator bool() const noexcept {
734 const internal::type_node *node;
745 inline bool operator!=(
const any &lhs,
const any &rhs) noexcept {
746 return !(lhs == rhs);
760 prop(
const internal::prop_node *curr) noexcept
774 any
key() const noexcept {
783 return node->value();
790 explicit operator bool() const noexcept {
801 return node == other.node;
805 const internal::prop_node *node;
815 inline bool operator!=(
const prop &lhs,
const prop &rhs) noexcept {
816 return !(lhs == rhs);
830 base(
const internal::base_node *curr) noexcept
857 void *
cast(
void *instance)
const noexcept {
858 return node->cast(instance);
865 explicit operator bool() const noexcept {
876 return node == other.node;
880 const internal::base_node *node;
890 inline bool operator!=(
const base &lhs,
const base &rhs) noexcept {
891 return !(lhs == rhs);
905 conv(
const internal::conv_node *curr) noexcept
932 any
convert(
const void *instance)
const noexcept {
933 return node->convert(instance);
940 explicit operator bool() const noexcept {
951 return node == other.node;
955 const internal::conv_node *node;
965 inline bool operator!=(
const conv &lhs,
const conv &rhs) noexcept {
966 return !(lhs == rhs);
980 ctor(
const internal::ctor_node *curr) noexcept
986 using size_type =
typename internal::ctor_node::size_type;
1025 template<
typename... Args>
1027 std::array<any,
sizeof...(Args)> arguments{{std::forward<Args>(args)...}};
1030 if(
sizeof...(Args) == size()) {
1031 any = node->invoke(arguments.data());
1042 template<
typename Op>
1043 std::enable_if_t<std::is_invocable_v<Op, meta::prop>,
void>
1045 internal::iterate([op = std::move(op)](
auto *curr) {
1056 template<
typename Key>
1057 std::enable_if_t<!std::is_invocable_v<Key, meta::prop>,
meta::prop>
1059 const auto *curr = internal::find_if([key = any{std::forward<Key>(key)}](
auto *candidate) {
1060 return candidate->key() == key;
1070 explicit operator bool() const noexcept {
1081 return node == other.node;
1085 const internal::ctor_node *node;
1095 inline bool operator!=(
const ctor &lhs,
const ctor &rhs) noexcept {
1096 return !(lhs == rhs);
1110 dtor(
const internal::dtor_node *curr) noexcept
1137 return node->invoke(handle);
1144 explicit operator bool() const noexcept {
1155 return node == other.node;
1159 const internal::dtor_node *node;
1169 inline bool operator!=(
const dtor &lhs,
const dtor &rhs) noexcept {
1170 return !(lhs == rhs);
1184 data(
const internal::data_node *curr) noexcept
1205 return node->is_const;
1217 return node->is_static;
1240 template<
typename Type>
1241 bool set(handle handle, Type &&value)
const {
1242 return node->set(handle, any{}, std::forward<Type>(value));
1260 template<
typename Type>
1261 bool set(handle handle, std::size_t index, Type &&value)
const {
1262 assert(index < node->ref()->extent);
1263 return node->set(handle, index, std::forward<Type>(value));
1275 any
get(handle handle)
const noexcept {
1276 return node->get(handle, any{});
1289 any
get(handle handle, std::size_t index)
const noexcept {
1290 assert(index < node->ref()->extent);
1291 return node->get(handle, index);
1299 template<
typename Op>
1300 std::enable_if_t<std::is_invocable_v<Op, meta::prop>,
void>
1302 internal::iterate([op = std::move(op)](
auto *curr) {
1313 template<
typename Key>
1314 std::enable_if_t<!std::is_invocable_v<Key, meta::prop>,
meta::prop>
1316 const auto *curr = internal::find_if([key = any{std::forward<Key>(key)}](
auto *candidate) {
1317 return candidate->key() == key;
1327 explicit operator bool() const noexcept {
1338 return node == other.node;
1342 const internal::data_node *node;
1352 inline bool operator!=(
const data &lhs,
const data &rhs) noexcept {
1353 return !(lhs == rhs);
1367 func(
const internal::func_node *curr) noexcept
1399 return node->is_const;
1411 return node->is_static;
1442 template<
typename... Args>
1443 any
invoke(handle handle, Args &&... args)
const {
1445 std::array<any,
sizeof...(Args)> arguments{{
meta::handle{args}...}};
1448 if(
sizeof...(Args) == size()) {
1449 any = node->invoke(handle, arguments.
data());
1460 template<
typename Op>
1461 std::enable_if_t<std::is_invocable_v<Op, meta::prop>,
void>
1463 internal::iterate([op = std::move(op)](
auto *curr) {
1474 template<
typename Key>
1475 std::enable_if_t<!std::is_invocable_v<Key, meta::prop>,
meta::prop>
1477 const auto *curr = internal::find_if([key = any{std::forward<Key>(key)}](
auto *candidate) {
1478 return candidate->key() == key;
1488 explicit operator bool() const noexcept {
1499 return node == other.node;
1503 const internal::func_node *node;
1513 inline bool operator!=(
const func &lhs,
const func &rhs) noexcept {
1514 return !(lhs == rhs);
1526 template<
typename...>
friend struct internal::info_node;
1528 type(
const internal::type_node *curr) noexcept
1546 return node->is_void;
1555 return node->is_integral;
1565 return node->is_floating_point;
1574 return node->is_array;
1582 return node->is_enum;
1590 return node->is_union;
1598 return node->is_class;
1606 return node->is_pointer;
1616 return node->is_function_pointer;
1626 return node->is_member_object_pointer;
1636 return node->is_member_function_pointer;
1646 return node->extent;
1666 template<
typename Op>
1667 std::enable_if_t<std::is_invocable_v<Op, meta::base>,
void>
1669 internal::iterate<&internal::type_node::base>([op = std::move(op)](
auto *curr) {
1683 const auto *curr = internal::find_if<&internal::type_node::base>([identifier](
auto *candidate) {
1684 return candidate->ref()->identifier == identifier;
1699 template<
typename Op>
1701 internal::iterate<&internal::type_node::conv>([op = std::move(op)](
auto *curr) {
1716 template<
typename Type>
1718 const auto *curr = internal::find_if<&internal::type_node::conv>([type = internal::type_info<Type>::resolve()](
auto *candidate) {
1719 return candidate->ref() == type;
1730 template<
typename Op>
1732 internal::iterate([op = std::move(op)](
auto *curr) {
1742 template<
typename... Args>
1744 const auto *curr = internal::ctor<Args...>(std::make_index_sequence<
sizeof...(Args)>{}, node);
1753 return node->dtor ? node->dtor->clazz() :
meta::dtor{};
1765 template<
typename Op>
1766 std::enable_if_t<std::is_invocable_v<Op, meta::data>,
void>
1768 internal::iterate<&internal::type_node::data>([op = std::move(op)](
auto *curr) {
1784 const auto *curr = internal::find_if<&internal::type_node::data>([identifier](
auto *candidate) {
1785 return candidate->identifier == identifier;
1801 template<
typename Op>
1802 std::enable_if_t<std::is_invocable_v<Op, meta::func>,
void>
1804 internal::iterate<&internal::type_node::func>([op = std::move(op)](
auto *curr) {
1820 const auto *curr = internal::find_if<&internal::type_node::func>([identifier](
auto *candidate) {
1821 return candidate->identifier == identifier;
1838 template<
typename... Args>
1840 std::array<any,
sizeof...(Args)> arguments{{std::forward<Args>(args)...}};
1843 internal::find_if<&internal::type_node::ctor>([data = arguments.data(), &any](
auto *curr) ->
bool {
1844 if(curr->size ==
sizeof...(args)) {
1845 any = curr->invoke(data);
1848 return static_cast<bool>(any);
1867 return (handle.
type() == node->clazz()) && (!node->dtor || node->dtor->invoke(handle));
1879 template<
typename Op>
1880 std::enable_if_t<std::is_invocable_v<Op, meta::prop>,
void>
1882 internal::iterate<&internal::type_node::prop>([op = std::move(op)](
auto *curr) {
1898 template<
typename Key>
1899 std::enable_if_t<!std::is_invocable_v<Key, meta::prop>,
meta::prop>
1901 const auto *curr = internal::find_if<&internal::type_node::prop>([key = any{std::forward<Key>(key)}](
auto *candidate) {
1902 return candidate->key() == key;
1912 explicit operator bool() const noexcept {
1923 return node == other.node;
1927 const internal::type_node *node;
1937 inline bool operator!=(
const type &lhs,
const type &rhs) noexcept {
1938 return !(lhs == rhs);
1946 instance = handle.instance;
1961 return node->parent->clazz();
1966 return node->ref()->clazz();
1971 return node->parent->clazz();
1976 return node->ref()->clazz();
1981 return node->parent->clazz();
1986 return index < size() ? node->arg(index)->clazz() :
meta::type{};
1991 return node->parent->clazz();
1996 return node->parent->clazz();
2001 return node->ref()->clazz();
2006 return node->parent->clazz();
2011 return node->ret()->clazz();
2016 return index < size() ? node->arg(index)->clazz() :
meta::type{};
2026 namespace internal {
2029 template<
typename Type,
typename = std::enable_if_t<!std::is_
void_v<Type> && !std::is_function_v<Type>>>
2030 static auto compare(
int,
const void *lhs,
const void *rhs)
2031 -> decltype(std::declval<Type>() == std::declval<Type>(),
bool{}) {
2032 return *
static_cast<const Type *
>(lhs) == *static_cast<const Type *>(rhs);
2036 static bool compare(
char,
const void *lhs,
const void *rhs) {
2041 template<
typename Type>
2042 inline type_node * info_node<Type>::resolve() noexcept {
2044 static type_node node{
2048 std::is_void_v<Type>,
2049 std::is_integral_v<Type>,
2050 std::is_floating_point_v<Type>,
2051 std::is_array_v<Type>,
2052 std::is_enum_v<Type>,
2053 std::is_union_v<Type>,
2054 std::is_class_v<Type>,
2055 std::is_pointer_v<Type>,
2056 std::is_pointer_v<Type> && std::is_function_v<std::remove_pointer_t<Type>>,
2057 std::is_member_object_pointer_v<Type>,
2058 std::is_member_function_pointer_v<Type>,
2059 std::extent_v<Type>,
2060 [](
const void *lhs,
const void *rhs) {
2061 return compare<Type>(0, lhs, rhs);
2064 return internal::type_info<std::remove_pointer_t<Type>>
::resolve();
2090 #endif // META_META_HPP