meta  1.4.9
meta.hpp
1 #ifndef META_META_HPP
2 #define META_META_HPP
3 
4 
5 #include <array>
6 #include <memory>
7 #include <cstring>
8 #include <cstddef>
9 #include <utility>
10 #include <type_traits>
11 #include <cassert>
12 
13 
14 namespace meta {
15 
16 
17 class any;
18 class handle;
19 class prop;
20 class base;
21 class conv;
22 class ctor;
23 class dtor;
24 class data;
25 class func;
26 class type;
27 
28 
35 namespace internal {
36 
37 
38 struct type_node;
39 
40 
41 struct prop_node {
42  prop_node * next;
43  any(* const key)();
44  any(* const value)();
45  prop(* const clazz)() noexcept;
46 };
47 
48 
49 struct base_node {
50  base_node ** const underlying;
51  type_node * const parent;
52  base_node * next;
53  type_node *(* const ref)() noexcept;
54  void *(* const cast)(void *) noexcept;
55  base(* const clazz)() noexcept;
56 };
57 
58 
59 struct conv_node {
60  conv_node ** const underlying;
61  type_node * const parent;
62  conv_node * next;
63  type_node *(* const ref)() noexcept;
64  any(* const convert)(const void *);
65  conv(* const clazz)() noexcept;
66 };
67 
68 
69 struct ctor_node {
70  using size_type = std::size_t;
71  ctor_node ** const underlying;
72  type_node * const parent;
73  ctor_node * next;
74  prop_node * prop;
75  const size_type size;
76  type_node *(* const arg)(size_type) noexcept;
77  any(* const invoke)(any * const);
78  ctor(* const clazz)() noexcept;
79 };
80 
81 
82 struct dtor_node {
83  dtor_node ** const underlying;
84  type_node * const parent;
85  bool(* const invoke)(handle);
86  dtor(* const clazz)() noexcept;
87 };
88 
89 
90 struct data_node {
91  data_node ** const underlying;
92  std::size_t identifier;
93  type_node * const parent;
94  data_node * next;
95  prop_node * prop;
96  const bool is_const;
97  const bool is_static;
98  type_node *(* const ref)() noexcept;
99  bool(* const set)(handle, any, any);
100  any(* const get)(handle, any);
101  data(* const clazz)() noexcept;
102 };
103 
104 
105 struct func_node {
106  using size_type = std::size_t;
107  func_node ** const underlying;
108  std::size_t identifier;
109  type_node * const parent;
110  func_node * next;
111  prop_node * prop;
112  const size_type size;
113  const bool is_const;
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;
119 };
120 
121 
122 struct type_node {
123  using size_type = std::size_t;
124  std::size_t identifier;
125  type_node * next;
126  prop_node * prop;
127  const bool is_void;
128  const bool is_integral;
129  const bool is_floating_point;
130  const bool is_array;
131  const bool is_enum;
132  const bool is_union;
133  const bool is_class;
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};
148 };
149 
150 
151 template<typename...>
152 struct info_node {
153  inline static type_node *type = nullptr;
154 };
155 
156 
157 template<typename Type>
158 struct info_node<Type> {
159  inline static type_node *type = nullptr;
160 
161  template<typename>
162  inline static base_node *base = nullptr;
163 
164  template<typename>
165  inline static conv_node *conv = nullptr;
166 
167  template<typename>
168  inline static ctor_node *ctor = nullptr;
169 
170  template<auto>
171  inline static dtor_node *dtor = nullptr;
172 
173  template<auto...>
174  inline static data_node *data = nullptr;
175 
176  template<auto>
177  inline static func_node *func = nullptr;
178 
179  inline static type_node * resolve() noexcept;
180 };
181 
182 
183 template<typename... Type>
184 struct type_info: info_node<std::remove_cv_t<std::remove_reference_t<Type>>...> {};
185 
186 
187 template<typename Op, typename Node>
188 void iterate(Op op, const Node *curr) noexcept {
189  while(curr) {
190  op(curr);
191  curr = curr->next;
192  }
193 }
194 
195 
196 template<auto Member, typename Op>
197 void iterate(Op op, const type_node *node) noexcept {
198  if(node) {
199  auto *curr = node->base;
200  iterate(op, node->*Member);
201 
202  while(curr) {
203  iterate<Member>(op, curr->ref());
204  curr = curr->next;
205  }
206  }
207 }
208 
209 
210 template<typename Op, typename Node>
211 auto find_if(Op op, const Node *curr) noexcept {
212  while(curr && !op(curr)) {
213  curr = curr->next;
214  }
215 
216  return curr;
217 }
218 
219 
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;
224 
225  if(node) {
226  ret = find_if(op, node->*Member);
227  auto *curr = node->base;
228 
229  while(curr && !ret) {
230  ret = find_if<Member>(op, curr->ref());
231  curr = curr->next;
232  }
233  }
234 
235  return ret;
236 }
237 
238 
239 template<typename Type>
240 const Type * try_cast(const type_node *node, void *instance) noexcept {
241  const auto *type = type_info<Type>::resolve();
242  void *ret = nullptr;
243 
244  if(node == type) {
245  ret = instance;
246  } else {
247  const auto *base = find_if<&type_node::base>([type](auto *candidate) {
248  return candidate->ref() == type;
249  }, node);
250 
251  ret = base ? base->cast(instance) : nullptr;
252  }
253 
254  return static_cast<const Type *>(ret);
255 }
256 
257 
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;
262  }, from);
263 }
264 
265 
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))) && ...);
274  }, node->ctor);
275 }
276 
277 
278 }
279 
280 
299 class any {
301  friend class handle;
302 
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 *);
307 
308  template<typename Type, typename = std::void_t<>>
309  struct type_traits {
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();
315  }
316 
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);
321  assert(destroyed);
322  delete actual;
323  }
324 
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();
329  }
330 
331  static void * steal(storage_type &to, void *from, destroy_fn_type *) {
332  auto *instance = static_cast<Type *>(from);
333  new (&to) Type *{instance};
334  return instance;
335  }
336  };
337 
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)...};
343  }
344 
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);
349  assert(destroyed);
350  actual->~Type();
351  }
352 
353  static void * copy(storage_type &storage, const void *instance) {
354  return new (&storage) Type{*static_cast<const Type *>(instance)};
355  }
356 
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))};
359  destroy_fn(from);
360  return instance;
361  }
362  };
363 
364 public:
366  any() noexcept
367  : storage{},
368  instance{nullptr},
369  node{nullptr},
370  destroy_fn{nullptr},
371  copy_fn{nullptr},
372  steal_fn{nullptr}
373  {}
374 
381  template<typename Type, typename... Args>
382  explicit any(std::in_place_type_t<Type>, [[maybe_unused]] Args &&... args)
383  : any{}
384  {
385  node = internal::type_info<Type>::resolve();
386 
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;
393  }
394  }
395 
401  template<typename Type>
402  explicit any(std::reference_wrapper<Type> type)
403  : any{}
404  {
405  node = internal::type_info<Type>::resolve();
406  instance = &type.get();
407  }
408 
413  inline any(handle handle) noexcept;
414 
420  template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, any>>>
421  any(Type &&type)
422  : any{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(type)}
423  {}
424 
429  any(const any &other)
430  : any{}
431  {
432  node = other.node;
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;
437  }
438 
448  any(any &&other) noexcept
449  : any{}
450  {
451  swap(*this, other);
452  }
453 
455  ~any() {
456  if(destroy_fn) {
457  destroy_fn(instance);
458  }
459  }
460 
467  template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, any>>>
468  any & operator=(Type &&type) {
469  return (*this = any{std::forward<Type>(type)});
470  }
471 
477  any & operator=(const any &other) {
478  return (*this = any{other});
479  }
480 
486  any & operator=(any &&other) noexcept {
487  any any{std::move(other)};
488  swap(any, *this);
489  return *this;
490  }
491 
496  inline meta::type type() const noexcept;
497 
502  const void * data() const noexcept {
503  return instance;
504  }
505 
507  void * data() noexcept {
508  return const_cast<void *>(std::as_const(*this).data());
509  }
510 
516  template<typename Type>
517  const Type * try_cast() const noexcept {
518  return internal::try_cast<Type>(node, instance);
519  }
520 
522  template<typename Type>
523  Type * try_cast() noexcept {
524  return const_cast<Type *>(std::as_const(*this).try_cast<Type>());
525  }
526 
541  template<typename Type>
542  const Type & cast() const noexcept {
543  auto *actual = try_cast<Type>();
544  assert(actual);
545  return *actual;
546  }
547 
549  template<typename Type>
550  Type & cast() noexcept {
551  return const_cast<Type &>(std::as_const(*this).cast<Type>());
552  }
553 
560  template<typename Type>
561  any convert() const {
562  any any{};
563 
564  if(const auto *type = internal::type_info<Type>::resolve(); node == type) {
565  any = *static_cast<const Type *>(instance);
566  } else {
567  const auto *conv = internal::find_if<&internal::type_node::conv>([type](auto *other) {
568  return other->ref() == type;
569  }, node);
570 
571  if(conv) {
572  any = conv->convert(instance);
573  }
574  }
575 
576  return any;
577  }
578 
584  template<typename Type>
585  bool convert() {
586  bool valid = (node == internal::type_info<Type>::resolve());
587 
588  if(!valid) {
589  if(auto any = std::as_const(*this).convert<Type>(); any) {
590  swap(any, *this);
591  valid = true;
592  }
593  }
594 
595  return valid;
596  }
597 
605  template<typename Type, typename... Args>
606  void emplace(Args&& ... args) {
607  *this = any{std::in_place_type_t<Type>{}, std::forward<Args>(args)...};
608  }
609 
614  explicit operator bool() const noexcept {
615  return node;
616  }
617 
624  bool operator==(const any &other) const noexcept {
625  return node == other.node && (!node || node->compare(instance, other.instance));
626  }
627 
633  friend void swap(any &lhs, any &rhs) noexcept {
634  if(lhs.steal_fn && rhs.steal_fn) {
635  storage_type buffer;
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);
645  } else {
646  std::swap(lhs.instance, rhs.instance);
647  }
648 
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);
653  }
654 
655 private:
656  storage_type storage;
657  void *instance;
658  const internal::type_node *node;
659  destroy_fn_type *destroy_fn;
660  copy_fn_type *copy_fn;
661  steal_fn_type *steal_fn;
662 };
663 
664 
675 class handle {
677  friend class any;
678 
679 public:
681  handle() noexcept
682  : node{nullptr},
683  instance{nullptr}
684  {}
685 
690  handle(any &any) noexcept
691  : node{any.node},
692  instance{any.instance}
693  {}
694 
700  template<typename Type, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, handle>>>
701  handle(Type &obj) noexcept
702  : node{internal::type_info<Type>::resolve()},
703  instance{&obj}
704  {}
705 
710  inline meta::type type() const noexcept;
711 
716  const void * data() const noexcept {
717  return instance;
718  }
719 
721  void * data() noexcept {
722  return const_cast<void *>(std::as_const(*this).data());
723  }
724 
729  explicit operator bool() const noexcept {
730  return instance;
731  }
732 
733 private:
734  const internal::type_node *node;
735  void *instance;
736 };
737 
738 
745 inline bool operator!=(const any &lhs, const any &rhs) noexcept {
746  return !(lhs == rhs);
747 }
748 
749 
756 class prop {
758  template<typename> friend class factory;
759 
760  prop(const internal::prop_node *curr) noexcept
761  : node{curr}
762  {}
763 
764 public:
766  prop() noexcept
767  : node{nullptr}
768  {}
769 
774  any key() const noexcept {
775  return node->key();
776  }
777 
782  any value() const noexcept {
783  return node->value();
784  }
785 
790  explicit operator bool() const noexcept {
791  return node;
792  }
793 
800  bool operator==(const prop &other) const noexcept {
801  return node == other.node;
802  }
803 
804 private:
805  const internal::prop_node *node;
806 };
807 
808 
815 inline bool operator!=(const prop &lhs, const prop &rhs) noexcept {
816  return !(lhs == rhs);
817 }
818 
819 
826 class base {
828  template<typename> friend class factory;
829 
830  base(const internal::base_node *curr) noexcept
831  : node{curr}
832  {}
833 
834 public:
836  base() noexcept
837  : node{nullptr}
838  {}
839 
844  inline meta::type parent() const noexcept;
845 
850  inline meta::type type() const noexcept;
851 
857  void * cast(void *instance) const noexcept {
858  return node->cast(instance);
859  }
860 
865  explicit operator bool() const noexcept {
866  return node;
867  }
868 
875  bool operator==(const base &other) const noexcept {
876  return node == other.node;
877  }
878 
879 private:
880  const internal::base_node *node;
881 };
882 
883 
890 inline bool operator!=(const base &lhs, const base &rhs) noexcept {
891  return !(lhs == rhs);
892 }
893 
894 
901 class conv {
903  template<typename> friend class factory;
904 
905  conv(const internal::conv_node *curr) noexcept
906  : node{curr}
907  {}
908 
909 public:
911  conv() noexcept
912  : node{nullptr}
913  {}
914 
919  inline meta::type parent() const noexcept;
920 
925  inline meta::type type() const noexcept;
926 
932  any convert(const void *instance) const noexcept {
933  return node->convert(instance);
934  }
935 
940  explicit operator bool() const noexcept {
941  return node;
942  }
943 
950  bool operator==(const conv &other) const noexcept {
951  return node == other.node;
952  }
953 
954 private:
955  const internal::conv_node *node;
956 };
957 
958 
965 inline bool operator!=(const conv &lhs, const conv &rhs) noexcept {
966  return !(lhs == rhs);
967 }
968 
969 
976 class ctor {
978  template<typename> friend class factory;
979 
980  ctor(const internal::ctor_node *curr) noexcept
981  : node{curr}
982  {}
983 
984 public:
986  using size_type = typename internal::ctor_node::size_type;
987 
989  ctor() noexcept
990  : node{nullptr}
991  {}
992 
997  inline meta::type parent() const noexcept;
998 
1003  size_type size() const noexcept {
1004  return node->size;
1005  }
1006 
1012  meta::type arg(size_type index) const noexcept;
1013 
1025  template<typename... Args>
1026  any invoke(Args &&... args) const {
1027  std::array<any, sizeof...(Args)> arguments{{std::forward<Args>(args)...}};
1028  any any{};
1029 
1030  if(sizeof...(Args) == size()) {
1031  any = node->invoke(arguments.data());
1032  }
1033 
1034  return any;
1035  }
1036 
1042  template<typename Op>
1043  std::enable_if_t<std::is_invocable_v<Op, meta::prop>, void>
1044  prop(Op op) const noexcept {
1045  internal::iterate([op = std::move(op)](auto *curr) {
1046  op(curr->clazz());
1047  }, node->prop);
1048  }
1049 
1056  template<typename Key>
1057  std::enable_if_t<!std::is_invocable_v<Key, meta::prop>, meta::prop>
1058  prop(Key &&key) const noexcept {
1059  const auto *curr = internal::find_if([key = any{std::forward<Key>(key)}](auto *candidate) {
1060  return candidate->key() == key;
1061  }, node->prop);
1062 
1063  return curr ? curr->clazz() : meta::prop{};
1064  }
1065 
1070  explicit operator bool() const noexcept {
1071  return node;
1072  }
1073 
1080  bool operator==(const ctor &other) const noexcept {
1081  return node == other.node;
1082  }
1083 
1084 private:
1085  const internal::ctor_node *node;
1086 };
1087 
1088 
1095 inline bool operator!=(const ctor &lhs, const ctor &rhs) noexcept {
1096  return !(lhs == rhs);
1097 }
1098 
1099 
1106 class dtor {
1108  template<typename> friend class factory;
1109 
1110  dtor(const internal::dtor_node *curr) noexcept
1111  : node{curr}
1112  {}
1113 
1114 public:
1116  dtor() noexcept
1117  : node{nullptr}
1118  {}
1119 
1124  inline meta::type parent() const noexcept;
1125 
1136  bool invoke(handle handle) const {
1137  return node->invoke(handle);
1138  }
1139 
1144  explicit operator bool() const noexcept {
1145  return node;
1146  }
1147 
1154  bool operator==(const dtor &other) const noexcept {
1155  return node == other.node;
1156  }
1157 
1158 private:
1159  const internal::dtor_node *node;
1160 };
1161 
1162 
1169 inline bool operator!=(const dtor &lhs, const dtor &rhs) noexcept {
1170  return !(lhs == rhs);
1171 }
1172 
1173 
1180 class data {
1182  template<typename> friend class factory;
1183 
1184  data(const internal::data_node *curr) noexcept
1185  : node{curr}
1186  {}
1187 
1188 public:
1190  data() noexcept
1191  : node{nullptr}
1192  {}
1193 
1198  inline meta::type parent() const noexcept;
1199 
1204  bool is_const() const noexcept {
1205  return node->is_const;
1206  }
1207 
1216  bool is_static() const noexcept {
1217  return node->is_static;
1218  }
1219 
1224  inline meta::type type() const noexcept;
1225 
1240  template<typename Type>
1241  bool set(handle handle, Type &&value) const {
1242  return node->set(handle, any{}, std::forward<Type>(value));
1243  }
1244 
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));
1264  }
1265 
1275  any get(handle handle) const noexcept {
1276  return node->get(handle, any{});
1277  }
1278 
1289  any get(handle handle, std::size_t index) const noexcept {
1290  assert(index < node->ref()->extent);
1291  return node->get(handle, index);
1292  }
1293 
1299  template<typename Op>
1300  std::enable_if_t<std::is_invocable_v<Op, meta::prop>, void>
1301  prop(Op op) const noexcept {
1302  internal::iterate([op = std::move(op)](auto *curr) {
1303  op(curr->clazz());
1304  }, node->prop);
1305  }
1306 
1313  template<typename Key>
1314  std::enable_if_t<!std::is_invocable_v<Key, meta::prop>, meta::prop>
1315  prop(Key &&key) const noexcept {
1316  const auto *curr = internal::find_if([key = any{std::forward<Key>(key)}](auto *candidate) {
1317  return candidate->key() == key;
1318  }, node->prop);
1319 
1320  return curr ? curr->clazz() : meta::prop{};
1321  }
1322 
1327  explicit operator bool() const noexcept {
1328  return node;
1329  }
1330 
1337  bool operator==(const data &other) const noexcept {
1338  return node == other.node;
1339  }
1340 
1341 private:
1342  const internal::data_node *node;
1343 };
1344 
1345 
1352 inline bool operator!=(const data &lhs, const data &rhs) noexcept {
1353  return !(lhs == rhs);
1354 }
1355 
1356 
1363 class func {
1365  template<typename> friend class factory;
1366 
1367  func(const internal::func_node *curr) noexcept
1368  : node{curr}
1369  {}
1370 
1371 public:
1373  using size_type = typename internal::func_node::size_type;
1374 
1376  func() noexcept
1377  : node{nullptr}
1378  {}
1379 
1384  inline meta::type parent() const noexcept;
1385 
1390  size_type size() const noexcept {
1391  return node->size;
1392  }
1393 
1398  bool is_const() const noexcept {
1399  return node->is_const;
1400  }
1401 
1410  bool is_static() const noexcept {
1411  return node->is_static;
1412  }
1413 
1418  inline meta::type ret() const noexcept;
1419 
1425  inline meta::type arg(size_type index) const noexcept;
1426 
1442  template<typename... Args>
1443  any invoke(handle handle, Args &&... args) const {
1444  // makes aliasing on the values and passes forward references if any
1445  std::array<any, sizeof...(Args)> arguments{{meta::handle{args}...}};
1446  any any{};
1447 
1448  if(sizeof...(Args) == size()) {
1449  any = node->invoke(handle, arguments.data());
1450  }
1451 
1452  return any;
1453  }
1454 
1460  template<typename Op>
1461  std::enable_if_t<std::is_invocable_v<Op, meta::prop>, void>
1462  prop(Op op) const noexcept {
1463  internal::iterate([op = std::move(op)](auto *curr) {
1464  op(curr->clazz());
1465  }, node->prop);
1466  }
1467 
1474  template<typename Key>
1475  std::enable_if_t<!std::is_invocable_v<Key, meta::prop>, meta::prop>
1476  prop(Key &&key) const noexcept {
1477  const auto *curr = internal::find_if([key = any{std::forward<Key>(key)}](auto *candidate) {
1478  return candidate->key() == key;
1479  }, node->prop);
1480 
1481  return curr ? curr->clazz() : meta::prop{};
1482  }
1483 
1488  explicit operator bool() const noexcept {
1489  return node;
1490  }
1491 
1498  bool operator==(const func &other) const noexcept {
1499  return node == other.node;
1500  }
1501 
1502 private:
1503  const internal::func_node *node;
1504 };
1505 
1506 
1513 inline bool operator!=(const func &lhs, const func &rhs) noexcept {
1514  return !(lhs == rhs);
1515 }
1516 
1517 
1524 class type {
1526  template<typename...> friend struct internal::info_node;
1527 
1528  type(const internal::type_node *curr) noexcept
1529  : node{curr}
1530  {}
1531 
1532 public:
1534  using size_type = typename internal::type_node::size_type;
1535 
1537  type() noexcept
1538  : node{nullptr}
1539  {}
1540 
1545  bool is_void() const noexcept {
1546  return node->is_void;
1547  }
1548 
1554  bool is_integral() const noexcept {
1555  return node->is_integral;
1556  }
1557 
1564  bool is_floating_point() const noexcept {
1565  return node->is_floating_point;
1566  }
1567 
1573  bool is_array() const noexcept {
1574  return node->is_array;
1575  }
1576 
1581  bool is_enum() const noexcept {
1582  return node->is_enum;
1583  }
1584 
1589  bool is_union() const noexcept {
1590  return node->is_union;
1591  }
1592 
1597  bool is_class() const noexcept {
1598  return node->is_class;
1599  }
1600 
1605  bool is_pointer() const noexcept {
1606  return node->is_pointer;
1607  }
1608 
1615  bool is_function_pointer() const noexcept {
1616  return node->is_function_pointer;
1617  }
1618 
1625  bool is_member_object_pointer() const noexcept {
1626  return node->is_member_object_pointer;
1627  }
1628 
1635  bool is_member_function_pointer() const noexcept {
1636  return node->is_member_function_pointer;
1637  }
1638 
1645  size_type extent() const noexcept {
1646  return node->extent;
1647  }
1648 
1654  meta::type remove_pointer() const noexcept {
1655  return node->remove_pointer();
1656  }
1657 
1666  template<typename Op>
1667  std::enable_if_t<std::is_invocable_v<Op, meta::base>, void>
1668  base(Op op) const noexcept {
1669  internal::iterate<&internal::type_node::base>([op = std::move(op)](auto *curr) {
1670  op(curr->clazz());
1671  }, node);
1672  }
1673 
1682  meta::base base(const std::size_t identifier) const noexcept {
1683  const auto *curr = internal::find_if<&internal::type_node::base>([identifier](auto *candidate) {
1684  return candidate->ref()->identifier == identifier;
1685  }, node);
1686 
1687  return curr ? curr->clazz() : meta::base{};
1688  }
1689 
1699  template<typename Op>
1700  void conv(Op op) const noexcept {
1701  internal::iterate<&internal::type_node::conv>([op = std::move(op)](auto *curr) {
1702  op(curr->clazz());
1703  }, node);
1704  }
1705 
1716  template<typename Type>
1717  meta::conv conv() const noexcept {
1718  const auto *curr = internal::find_if<&internal::type_node::conv>([type = internal::type_info<Type>::resolve()](auto *candidate) {
1719  return candidate->ref() == type;
1720  }, node);
1721 
1722  return curr ? curr->clazz() : meta::conv{};
1723  }
1724 
1730  template<typename Op>
1731  void ctor(Op op) const noexcept {
1732  internal::iterate([op = std::move(op)](auto *curr) {
1733  op(curr->clazz());
1734  }, node->ctor);
1735  }
1736 
1742  template<typename... Args>
1743  meta::ctor ctor() const noexcept {
1744  const auto *curr = internal::ctor<Args...>(std::make_index_sequence<sizeof...(Args)>{}, node);
1745  return curr ? curr->clazz() : meta::ctor{};
1746  }
1747 
1752  meta::dtor dtor() const noexcept {
1753  return node->dtor ? node->dtor->clazz() : meta::dtor{};
1754  }
1755 
1765  template<typename Op>
1766  std::enable_if_t<std::is_invocable_v<Op, meta::data>, void>
1767  data(Op op) const noexcept {
1768  internal::iterate<&internal::type_node::data>([op = std::move(op)](auto *curr) {
1769  op(curr->clazz());
1770  }, node);
1771  }
1772 
1783  meta::data data(const std::size_t identifier) const noexcept {
1784  const auto *curr = internal::find_if<&internal::type_node::data>([identifier](auto *candidate) {
1785  return candidate->identifier == identifier;
1786  }, node);
1787 
1788  return curr ? curr->clazz() : meta::data{};
1789  }
1790 
1801  template<typename Op>
1802  std::enable_if_t<std::is_invocable_v<Op, meta::func>, void>
1803  func(Op op) const noexcept {
1804  internal::iterate<&internal::type_node::func>([op = std::move(op)](auto *curr) {
1805  op(curr->clazz());
1806  }, node);
1807  }
1808 
1819  meta::func func(const std::size_t identifier) const noexcept {
1820  const auto *curr = internal::find_if<&internal::type_node::func>([identifier](auto *candidate) {
1821  return candidate->identifier == identifier;
1822  }, node);
1823 
1824  return curr ? curr->clazz() : meta::func{};
1825  }
1826 
1838  template<typename... Args>
1839  any construct(Args &&... args) const {
1840  std::array<any, sizeof...(Args)> arguments{{std::forward<Args>(args)...}};
1841  any any{};
1842 
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);
1846  }
1847 
1848  return static_cast<bool>(any);
1849  }, node);
1850 
1851  return any;
1852  }
1853 
1866  bool destroy(handle handle) const {
1867  return (handle.type() == node->clazz()) && (!node->dtor || node->dtor->invoke(handle));
1868  }
1869 
1879  template<typename Op>
1880  std::enable_if_t<std::is_invocable_v<Op, meta::prop>, void>
1881  prop(Op op) const noexcept {
1882  internal::iterate<&internal::type_node::prop>([op = std::move(op)](auto *curr) {
1883  op(curr->clazz());
1884  }, node);
1885  }
1886 
1898  template<typename Key>
1899  std::enable_if_t<!std::is_invocable_v<Key, meta::prop>, meta::prop>
1900  prop(Key &&key) const noexcept {
1901  const auto *curr = internal::find_if<&internal::type_node::prop>([key = any{std::forward<Key>(key)}](auto *candidate) {
1902  return candidate->key() == key;
1903  }, node);
1904 
1905  return curr ? curr->clazz() : meta::prop{};
1906  }
1907 
1912  explicit operator bool() const noexcept {
1913  return node;
1914  }
1915 
1922  bool operator==(const type &other) const noexcept {
1923  return node == other.node;
1924  }
1925 
1926 private:
1927  const internal::type_node *node;
1928 };
1929 
1930 
1937 inline bool operator!=(const type &lhs, const type &rhs) noexcept {
1938  return !(lhs == rhs);
1939 }
1940 
1941 
1942 inline any::any(handle handle) noexcept
1943  : any{}
1944 {
1945  node = handle.node;
1946  instance = handle.instance;
1947 }
1948 
1949 
1950 inline meta::type any::type() const noexcept {
1951  return node ? node->clazz() : meta::type{};
1952 }
1953 
1954 
1955 inline meta::type handle::type() const noexcept {
1956  return node ? node->clazz() : meta::type{};
1957 }
1958 
1959 
1960 inline meta::type base::parent() const noexcept {
1961  return node->parent->clazz();
1962 }
1963 
1964 
1965 inline meta::type base::type() const noexcept {
1966  return node->ref()->clazz();
1967 }
1968 
1969 
1970 inline meta::type conv::parent() const noexcept {
1971  return node->parent->clazz();
1972 }
1973 
1974 
1975 inline meta::type conv::type() const noexcept {
1976  return node->ref()->clazz();
1977 }
1978 
1979 
1980 inline meta::type ctor::parent() const noexcept {
1981  return node->parent->clazz();
1982 }
1983 
1984 
1985 inline meta::type ctor::arg(size_type index) const noexcept {
1986  return index < size() ? node->arg(index)->clazz() : meta::type{};
1987 }
1988 
1989 
1990 inline meta::type dtor::parent() const noexcept {
1991  return node->parent->clazz();
1992 }
1993 
1994 
1995 inline meta::type data::parent() const noexcept {
1996  return node->parent->clazz();
1997 }
1998 
1999 
2000 inline meta::type data::type() const noexcept {
2001  return node->ref()->clazz();
2002 }
2003 
2004 
2005 inline meta::type func::parent() const noexcept {
2006  return node->parent->clazz();
2007 }
2008 
2009 
2010 inline meta::type func::ret() const noexcept {
2011  return node->ret()->clazz();
2012 }
2013 
2014 
2015 inline meta::type func::arg(size_type index) const noexcept {
2016  return index < size() ? node->arg(index)->clazz() : meta::type{};
2017 }
2018 
2019 
2026 namespace internal {
2027 
2028 
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);
2033 }
2034 
2035 template<typename>
2036 static bool compare(char, const void *lhs, const void *rhs) {
2037  return lhs == rhs;
2038 }
2039 
2040 
2041 template<typename Type>
2042 inline type_node * info_node<Type>::resolve() noexcept {
2043  if(!type) {
2044  static type_node node{
2045  {},
2046  nullptr,
2047  nullptr,
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);
2062  },
2063  []() noexcept -> meta::type {
2064  return internal::type_info<std::remove_pointer_t<Type>>::resolve();
2065  },
2066  []() noexcept -> meta::type {
2067  return &node;
2068  }
2069  };
2070 
2071  type = &node;
2072  }
2073 
2074  return type;
2075 }
2076 
2077 
2078 }
2079 
2080 
2087 }
2088 
2089 
2090 #endif // META_META_HPP
bool is_union() const noexcept
Indicates whether a given meta type refers to an union or not.
Definition: meta.hpp:1589
any invoke(Args &&... args) const
Creates an instance of the underlying type, if possible.
Definition: meta.hpp:1026
bool is_array() const noexcept
Indicates whether a given meta type refers to an array type or not.
Definition: meta.hpp:1573
type resolve() noexcept
Returns the meta type associated with a given type.
Definition: factory.hpp:897
std::enable_if_t< std::is_invocable_v< Op, meta::prop >, void > prop(Op op) const noexcept
Iterates all the properties assigned to a meta type.
Definition: meta.hpp:1881
const void * data() const noexcept
Returns an opaque pointer to the contained instance.
Definition: meta.hpp:502
any & operator=(const any &other)
Copy assignment operator.
Definition: meta.hpp:477
std::enable_if_t< std::is_invocable_v< Op, meta::base >, void > base(Op op) const noexcept
Iterates all the meta base of a meta type.
Definition: meta.hpp:1668
typename internal::ctor_node::size_type size_type
Unsigned integer type.
Definition: meta.hpp:986
data() noexcept
Default constructor.
Definition: meta.hpp:1190
std::enable_if_t< std::is_invocable_v< Op, meta::prop >, void > prop(Op op) const noexcept
Iterates all the properties assigned to a meta function.
Definition: meta.hpp:1462
bool is_floating_point() const noexcept
Indicates whether a given meta type refers to a floating-point type or not.
Definition: meta.hpp:1564
std::enable_if_t< std::is_invocable_v< Op, meta::func >, void > func(Op op) const noexcept
Iterates all the meta functions of a meta type.
Definition: meta.hpp:1803
size_type size() const noexcept
Returns the number of arguments accepted by a meta constructor.
Definition: meta.hpp:1003
handle() noexcept
Default constructor.
Definition: meta.hpp:681
any(any &&other) noexcept
Move constructor.
Definition: meta.hpp:448
bool is_class() const noexcept
Indicates whether a given meta type refers to a class or not.
Definition: meta.hpp:1597
Type & cast() noexcept
Tries to cast an instance to a given type.
Definition: meta.hpp:550
std::enable_if_t< std::is_invocable_v< Op, meta::prop >, void > prop(Op op) const noexcept
Iterates all the properties assigned to a meta constructor.
Definition: meta.hpp:1044
type() noexcept
Default constructor.
Definition: meta.hpp:1537
any value() const noexcept
Returns the stored value.
Definition: meta.hpp:782
any(std::reference_wrapper< Type > type)
Constructs a meta any that holds an unmanaged object.
Definition: meta.hpp:402
friend void swap(any &lhs, any &rhs) noexcept
Swaps two meta any objects.
Definition: meta.hpp:633
prop() noexcept
Default constructor.
Definition: meta.hpp:766
bool operator!=(const any &lhs, const any &rhs) noexcept
Checks if two containers differ in their content.
Definition: meta.hpp:745
void conv(Op op) const noexcept
Iterates all the meta conversion functions of a meta type.
Definition: meta.hpp:1700
bool operator==(const prop &other) const noexcept
Checks if two meta objects refer to the same node.
Definition: meta.hpp:800
bool operator==(const data &other) const noexcept
Checks if two meta objects refer to the same node.
Definition: meta.hpp:1337
ctor() noexcept
Default constructor.
Definition: meta.hpp:989
bool convert()
Tries to convert an instance to a given type.
Definition: meta.hpp:585
void ctor(Op op) const noexcept
Iterates all the meta constructors of a meta type.
Definition: meta.hpp:1731
bool destroy(handle handle) const
Destroys an instance of the underlying type.
Definition: meta.hpp:1866
const Type & cast() const noexcept
Tries to cast an instance to a given type.
Definition: meta.hpp:542
std::enable_if_t< std::is_invocable_v< Op, meta::prop >, void > prop(Op op) const noexcept
Iterates all the properties assigned to a meta data.
Definition: meta.hpp:1301
typename internal::type_node::size_type size_type
Unsigned integer type.
Definition: meta.hpp:1534
handle(Type &obj) noexcept
Constructs a meta handle from a given instance.
Definition: meta.hpp:701
meta::type type() const noexcept
Returns the meta type of the underlying object.
Definition: meta.hpp:1955
bool operator==(const func &other) const noexcept
Checks if two meta objects refer to the same node.
Definition: meta.hpp:1498
meta::type remove_pointer() const noexcept
Provides the meta type for which the pointer is defined.
Definition: meta.hpp:1654
std::enable_if_t<!std::is_invocable_v< Key, meta::prop >, meta::prop > prop(Key &&key) const noexcept
Returns the property associated with a given key.
Definition: meta.hpp:1476
base() noexcept
Default constructor.
Definition: meta.hpp:836
dtor() noexcept
Default constructor.
Definition: meta.hpp:1116
meta::type ret() const noexcept
Returns the meta type of the return type of a meta function.
Definition: meta.hpp:2010
Meta constructor object.
Definition: meta.hpp:976
std::enable_if_t<!std::is_invocable_v< Key, meta::prop >, meta::prop > prop(Key &&key) const noexcept
Returns the property associated with a given key.
Definition: meta.hpp:1058
Meta destructor object.
Definition: meta.hpp:1106
meta::dtor dtor() const noexcept
Returns the meta destructor associated with a given type.
Definition: meta.hpp:1752
Meta property object.
Definition: meta.hpp:756
~any()
Frees the internal storage, whatever it means.
Definition: meta.hpp:455
any convert() const
Tries to convert an instance to a given type and returns it.
Definition: meta.hpp:561
meta::type arg(size_type index) const noexcept
Returns the meta type of the i-th argument of a meta constructor.
Definition: meta.hpp:1985
meta::func func(const std::size_t identifier) const noexcept
Returns the meta function associated with a given identifier.
Definition: meta.hpp:1819
bool operator==(const base &other) const noexcept
Checks if two meta objects refer to the same node.
Definition: meta.hpp:875
void * data() noexcept
Returns an opaque pointer to the contained instance.
Definition: meta.hpp:721
Meta handle object.
Definition: meta.hpp:675
std::enable_if_t< std::is_invocable_v< Op, meta::data >, void > data(Op op) const noexcept
Iterates all the meta data of a meta type.
Definition: meta.hpp:1767
meta::ctor ctor() const noexcept
Returns the meta constructor that accepts a given list of types of arguments.
Definition: meta.hpp:1743
std::enable_if_t<!std::is_invocable_v< Key, meta::prop >, meta::prop > prop(Key &&key) const noexcept
Returns the property associated with a given key.
Definition: meta.hpp:1900
bool operator==(const type &other) const noexcept
Checks if two meta objects refer to the same node.
Definition: meta.hpp:1922
Type * try_cast() noexcept
Tries to cast an instance to a given type.
Definition: meta.hpp:523
bool operator==(const conv &other) const noexcept
Checks if two meta objects refer to the same node.
Definition: meta.hpp:950
any & operator=(Type &&type)
Assignment operator.
Definition: meta.hpp:468
Meta function object.
Definition: meta.hpp:1363
meta default namespace.
Definition: factory.hpp:16
A meta factory to be used for reflection purposes.
Definition: factory.hpp:249
meta::type parent() const noexcept
Returns the meta type to which a meta conversion function belongs.
Definition: meta.hpp:1970
const void * data() const noexcept
Returns an opaque pointer to the contained instance.
Definition: meta.hpp:716
any(Type &&type)
Constructs a meta any from a given value.
Definition: meta.hpp:421
any convert(const void *instance) const noexcept
Converts an instance to a given type.
Definition: meta.hpp:932
bool is_function_pointer() const noexcept
Indicates whether a given meta type refers to a function pointer or not.
Definition: meta.hpp:1615
any(std::in_place_type_t< Type >, [[maybe_unused]] Args &&... args)
Constructs a meta any by directly initializing the new object.
Definition: meta.hpp:382
bool is_static() const noexcept
Indicates whether a given meta function is static or not.
Definition: meta.hpp:1410
void * cast(void *instance) const noexcept
Casts an instance from a parent type to a base type.
Definition: meta.hpp:857
Meta data object.
Definition: meta.hpp:1180
std::enable_if_t<!std::is_invocable_v< Key, meta::prop >, meta::prop > prop(Key &&key) const noexcept
Returns the property associated with a given key.
Definition: meta.hpp:1315
bool operator==(const dtor &other) const noexcept
Checks if two meta objects refer to the same node.
Definition: meta.hpp:1154
typename internal::func_node::size_type size_type
Unsigned integer type.
Definition: meta.hpp:1373
bool invoke(handle handle) const
Destroys an instance of the underlying type.
Definition: meta.hpp:1136
meta::type type() const noexcept
Returns the meta type of the underlying object.
Definition: meta.hpp:1950
bool is_const() const noexcept
Indicates whether a given meta data is constant or not.
Definition: meta.hpp:1204
bool is_enum() const noexcept
Indicates whether a given meta type refers to an enum or not.
Definition: meta.hpp:1581
meta::type parent() const noexcept
Returns the meta type to which a meta function belongs.
Definition: meta.hpp:2005
meta::base base(const std::size_t identifier) const noexcept
Returns the meta base associated with a given identifier.
Definition: meta.hpp:1682
meta::type parent() const noexcept
Returns the meta type to which a meta base belongs.
Definition: meta.hpp:1960
meta::conv conv() const noexcept
Returns the meta conversion function associated with a given type.
Definition: meta.hpp:1717
Meta conversion function object.
Definition: meta.hpp:901
bool operator==(const ctor &other) const noexcept
Checks if two meta objects refer to the same node.
Definition: meta.hpp:1080
func() noexcept
Default constructor.
Definition: meta.hpp:1376
bool is_pointer() const noexcept
Indicates whether a given meta type refers to a pointer or not.
Definition: meta.hpp:1605
bool operator==(const any &other) const noexcept
Checks if two containers differ in their content.
Definition: meta.hpp:624
meta::type type() const noexcept
Returns the meta type of a given meta base.
Definition: meta.hpp:1965
bool is_void() const noexcept
Indicates whether a given meta type refers to void or not.
Definition: meta.hpp:1545
size_type extent() const noexcept
If a given meta type refers to an array type, provides the number of elements of the array...
Definition: meta.hpp:1645
meta::type parent() const noexcept
Returns the meta type to which a meta constructor belongs.
Definition: meta.hpp:1980
meta::data data(const std::size_t identifier) const noexcept
Returns the meta data associated with a given identifier.
Definition: meta.hpp:1783
bool is_member_function_pointer() const noexcept
Indicates whether a given meta type refers to a pointer to member function or not.
Definition: meta.hpp:1635
any() noexcept
Default constructor.
Definition: meta.hpp:366
handle(any &any) noexcept
Constructs a meta handle from a meta any object.
Definition: meta.hpp:690
meta::type arg(size_type index) const noexcept
Returns the meta type of the i-th argument of a meta function.
Definition: meta.hpp:2015
any(const any &other)
Copy constructor.
Definition: meta.hpp:429
any & operator=(any &&other) noexcept
Move assignment operator.
Definition: meta.hpp:486
const Type * try_cast() const noexcept
Tries to cast an instance to a given type.
Definition: meta.hpp:517
Meta type object.
Definition: meta.hpp:1524
bool is_member_object_pointer() const noexcept
Indicates whether a given meta type refers to a pointer to data member or not.
Definition: meta.hpp:1625
any key() const noexcept
Returns the stored key.
Definition: meta.hpp:774
any construct(Args &&... args) const
Creates an instance of the underlying type, if possible.
Definition: meta.hpp:1839
meta::type parent() const noexcept
Returns the meta type to which a meta data belongs.
Definition: meta.hpp:1995
size_type size() const noexcept
Returns the number of arguments accepted by a meta function.
Definition: meta.hpp:1390
any invoke(handle handle, Args &&... args) const
Invokes the underlying function, if possible.
Definition: meta.hpp:1443
bool is_static() const noexcept
Indicates whether a given meta data is static or not.
Definition: meta.hpp:1216
Meta base object.
Definition: meta.hpp:826
conv() noexcept
Default constructor.
Definition: meta.hpp:911
void * data() noexcept
Returns an opaque pointer to the contained instance.
Definition: meta.hpp:507
void emplace(Args &&... args)
Replaces the contained object by initializing a new instance directly.
Definition: meta.hpp:606
meta::type type() const noexcept
Returns the meta type of a given meta conversion function.
Definition: meta.hpp:1975
bool is_integral() const noexcept
Indicates whether a given meta type refers to an integral type or not.
Definition: meta.hpp:1554
meta::type type() const noexcept
Returns the meta type of a given meta data.
Definition: meta.hpp:2000
bool is_const() const noexcept
Indicates whether a given meta function is constant or not.
Definition: meta.hpp:1398
meta::type parent() const noexcept
Returns the meta type to which a meta destructor belongs.
Definition: meta.hpp:1990