node.hpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. #ifndef ENTT_META_NODE_HPP
  2. #define ENTT_META_NODE_HPP
  3. #include <cstddef>
  4. #include <memory>
  5. #include <type_traits>
  6. #include <utility>
  7. #include "../config/config.h"
  8. #include "../container/dense_map.hpp"
  9. #include "../core/attribute.h"
  10. #include "../core/enum.hpp"
  11. #include "../core/fwd.hpp"
  12. #include "../core/type_info.hpp"
  13. #include "../core/type_traits.hpp"
  14. #include "../core/utility.hpp"
  15. #include "context.hpp"
  16. #include "type_traits.hpp"
  17. namespace entt {
  18. class meta_any;
  19. class meta_type;
  20. struct meta_handle;
  21. /**
  22. * @cond TURN_OFF_DOXYGEN
  23. * Internal details not to be documented.
  24. */
  25. namespace internal {
  26. enum class meta_traits : std::uint32_t {
  27. is_none = 0x0000,
  28. is_const = 0x0001,
  29. is_static = 0x0002,
  30. is_arithmetic = 0x0004,
  31. is_integral = 0x0008,
  32. is_signed = 0x0010,
  33. is_array = 0x0020,
  34. is_enum = 0x0040,
  35. is_class = 0x0080,
  36. is_meta_pointer_like = 0x0100,
  37. is_meta_sequence_container = 0x0200,
  38. is_meta_associative_container = 0x0400,
  39. _entt_enum_as_bitmask
  40. };
  41. struct meta_type_node;
  42. struct meta_prop_node {
  43. meta_type_node (*type)(const meta_context &) noexcept {};
  44. std::shared_ptr<void> value{};
  45. };
  46. struct meta_base_node {
  47. meta_type_node (*type)(const meta_context &) noexcept {};
  48. const void *(*cast)(const void *) noexcept {};
  49. };
  50. struct meta_conv_node {
  51. meta_any (*conv)(const meta_ctx &, const void *){};
  52. };
  53. struct meta_ctor_node {
  54. using size_type = std::size_t;
  55. size_type arity{0u};
  56. meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
  57. meta_any (*invoke)(const meta_ctx &, meta_any *const){};
  58. };
  59. struct meta_dtor_node {
  60. void (*dtor)(void *){};
  61. };
  62. struct meta_data_node {
  63. using size_type = std::size_t;
  64. meta_traits traits{meta_traits::is_none};
  65. size_type arity{0u};
  66. meta_type_node (*type)(const meta_context &) noexcept {};
  67. meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
  68. bool (*set)(meta_handle, meta_any){};
  69. meta_any (*get)(const meta_ctx &, meta_handle){};
  70. dense_map<id_type, meta_prop_node, identity> prop{};
  71. };
  72. struct meta_func_node {
  73. using size_type = std::size_t;
  74. meta_traits traits{meta_traits::is_none};
  75. size_type arity{0u};
  76. meta_type_node (*ret)(const meta_context &) noexcept {};
  77. meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
  78. meta_any (*invoke)(const meta_ctx &, meta_handle, meta_any *const){};
  79. std::shared_ptr<meta_func_node> next{};
  80. dense_map<id_type, meta_prop_node, identity> prop{};
  81. };
  82. struct meta_template_node {
  83. using size_type = std::size_t;
  84. size_type arity{0u};
  85. meta_type_node (*type)(const meta_context &) noexcept {};
  86. meta_type_node (*arg)(const meta_context &, const size_type) noexcept {};
  87. };
  88. struct meta_type_descriptor {
  89. dense_map<id_type, meta_ctor_node, identity> ctor{};
  90. dense_map<id_type, meta_base_node, identity> base{};
  91. dense_map<id_type, meta_conv_node, identity> conv{};
  92. dense_map<id_type, meta_data_node, identity> data{};
  93. dense_map<id_type, meta_func_node, identity> func{};
  94. dense_map<id_type, meta_prop_node, identity> prop{};
  95. };
  96. struct meta_type_node {
  97. using size_type = std::size_t;
  98. const type_info *info{};
  99. id_type id{};
  100. meta_traits traits{meta_traits::is_none};
  101. size_type size_of{0u};
  102. meta_type_node (*resolve)(const meta_context &) noexcept {};
  103. meta_type_node (*remove_pointer)(const meta_context &) noexcept {};
  104. meta_any (*default_constructor)(const meta_ctx &){};
  105. double (*conversion_helper)(void *, const void *){};
  106. meta_any (*from_void)(const meta_ctx &, void *, const void *){};
  107. meta_template_node templ{};
  108. meta_dtor_node dtor{};
  109. std::shared_ptr<meta_type_descriptor> details{};
  110. };
  111. template<auto Member>
  112. auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id) {
  113. if(node.details) {
  114. if(const auto it = (node.details.get()->*Member).find(id); it != (node.details.get()->*Member).cend()) {
  115. return &it->second;
  116. }
  117. for(auto &&curr: node.details->base) {
  118. if(auto *elem = look_for<Member>(context, curr.second.type(context), id); elem) {
  119. return elem;
  120. }
  121. }
  122. }
  123. return static_cast<typename std::remove_reference_t<decltype(node.details.get()->*Member)>::mapped_type *>(nullptr);
  124. }
  125. template<typename Type>
  126. meta_type_node resolve(const meta_context &) noexcept;
  127. template<typename... Args>
  128. [[nodiscard]] auto meta_arg_node(const meta_context &context, type_list<Args...>, [[maybe_unused]] const std::size_t index) noexcept {
  129. [[maybe_unused]] std::size_t pos{};
  130. meta_type_node (*value)(const meta_context &) noexcept = nullptr;
  131. ((value = (pos++ == index ? &resolve<std::remove_cv_t<std::remove_reference_t<Args>>> : value)), ...);
  132. ENTT_ASSERT(value != nullptr, "Out of bounds");
  133. return value(context);
  134. }
  135. [[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const meta_type_node &to, const void *instance) noexcept {
  136. if(from.info && to.info && *from.info == *to.info) {
  137. return instance;
  138. }
  139. if(from.details) {
  140. for(auto &&curr: from.details->base) {
  141. if(const void *elem = try_cast(context, curr.second.type(context), to, curr.second.cast(instance)); elem) {
  142. return elem;
  143. }
  144. }
  145. }
  146. return nullptr;
  147. }
  148. template<typename Func>
  149. [[nodiscard]] inline auto try_convert(const meta_context &context, const meta_type_node &from, const type_info &to, const bool arithmetic_or_enum, const void *instance, Func func) {
  150. if(from.info && *from.info == to) {
  151. return func(instance, from);
  152. }
  153. if(from.details) {
  154. if(auto it = from.details->conv.find(to.hash()); it != from.details->conv.cend()) {
  155. return func(instance, it->second);
  156. }
  157. for(auto &&curr: from.details->base) {
  158. if(auto other = try_convert(context, curr.second.type(context), to, arithmetic_or_enum, curr.second.cast(instance), func); other) {
  159. return other;
  160. }
  161. }
  162. }
  163. if(from.conversion_helper && arithmetic_or_enum) {
  164. return func(instance, from.conversion_helper);
  165. }
  166. return func(instance);
  167. }
  168. [[nodiscard]] inline const meta_type_node *try_resolve(const meta_context &context, const type_info &info) noexcept {
  169. const auto it = context.value.find(info.hash());
  170. return it != context.value.end() ? &it->second : nullptr;
  171. }
  172. template<typename Type>
  173. [[nodiscard]] meta_type_node resolve(const meta_context &context) noexcept {
  174. static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>, "Invalid type");
  175. if(auto *elem = try_resolve(context, type_id<Type>()); elem) {
  176. return *elem;
  177. }
  178. meta_type_node node{
  179. &type_id<Type>(),
  180. type_id<Type>().hash(),
  181. (std::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
  182. | (std::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
  183. | (std::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
  184. | (std::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
  185. | (std::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
  186. | (std::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
  187. | (is_meta_pointer_like_v<Type> ? meta_traits::is_meta_pointer_like : meta_traits::is_none)
  188. | (is_complete_v<meta_sequence_container_traits<Type>> ? meta_traits::is_meta_sequence_container : meta_traits::is_none)
  189. | (is_complete_v<meta_associative_container_traits<Type>> ? meta_traits::is_meta_associative_container : meta_traits::is_none),
  190. size_of_v<Type>,
  191. &resolve<Type>,
  192. &resolve<std::remove_cv_t<std::remove_pointer_t<Type>>>};
  193. if constexpr(std::is_default_constructible_v<Type>) {
  194. node.default_constructor = +[](const meta_ctx &ctx) {
  195. return meta_any{ctx, std::in_place_type<Type>};
  196. };
  197. }
  198. if constexpr(std::is_arithmetic_v<Type>) {
  199. node.conversion_helper = +[](void *bin, const void *value) {
  200. return bin ? static_cast<double>(*static_cast<Type *>(bin) = static_cast<Type>(*static_cast<const double *>(value))) : static_cast<double>(*static_cast<const Type *>(value));
  201. };
  202. } else if constexpr(std::is_enum_v<Type>) {
  203. node.conversion_helper = +[](void *bin, const void *value) {
  204. return bin ? static_cast<double>(*static_cast<Type *>(bin) = static_cast<Type>(static_cast<std::underlying_type_t<Type>>(*static_cast<const double *>(value)))) : static_cast<double>(*static_cast<const Type *>(value));
  205. };
  206. }
  207. if constexpr(!std::is_void_v<Type> && !std::is_function_v<Type>) {
  208. node.from_void = +[](const meta_ctx &ctx, void *element, const void *as_const) {
  209. if(element) {
  210. return meta_any{ctx, std::in_place_type<std::decay_t<Type> &>, *static_cast<std::decay_t<Type> *>(element)};
  211. }
  212. return meta_any{ctx, std::in_place_type<const std::decay_t<Type> &>, *static_cast<const std::decay_t<Type> *>(as_const)};
  213. };
  214. }
  215. if constexpr(is_complete_v<meta_template_traits<Type>>) {
  216. node.templ = meta_template_node{
  217. meta_template_traits<Type>::args_type::size,
  218. &resolve<typename meta_template_traits<Type>::class_type>,
  219. +[](const meta_context &area, const std::size_t index) noexcept { return meta_arg_node(area, typename meta_template_traits<Type>::args_type{}, index); }};
  220. }
  221. return node;
  222. }
  223. } // namespace internal
  224. /**
  225. * Internal details not to be documented.
  226. * @endcond
  227. */
  228. } // namespace entt
  229. #endif