factory.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. #ifndef ENTT_META_FACTORY_HPP
  2. #define ENTT_META_FACTORY_HPP
  3. #include <cstddef>
  4. #include <functional>
  5. #include <memory>
  6. #include <tuple>
  7. #include <type_traits>
  8. #include <utility>
  9. #include "../config/config.h"
  10. #include "../core/fwd.hpp"
  11. #include "../core/type_info.hpp"
  12. #include "../core/type_traits.hpp"
  13. #include "../locator/locator.hpp"
  14. #include "context.hpp"
  15. #include "meta.hpp"
  16. #include "node.hpp"
  17. #include "policy.hpp"
  18. #include "range.hpp"
  19. #include "resolve.hpp"
  20. #include "utility.hpp"
  21. namespace entt {
  22. /**
  23. * @cond TURN_OFF_DOXYGEN
  24. * Internal details not to be documented.
  25. */
  26. namespace internal {
  27. [[nodiscard]] inline decltype(auto) owner(meta_ctx &ctx, const type_info &info) {
  28. auto &&context = internal::meta_context::from(ctx);
  29. ENTT_ASSERT(context.value.contains(info.hash()), "Type not available");
  30. return context.value[info.hash()];
  31. }
  32. inline meta_data_node &meta_extend(internal::meta_type_node &parent, const id_type id, meta_data_node node) {
  33. return parent.details->data.insert_or_assign(id, std::move(node)).first->second;
  34. }
  35. inline meta_func_node &meta_extend(internal::meta_type_node &parent, const id_type id, meta_func_node node) {
  36. if(auto it = parent.details->func.find(id); it != parent.details->func.end()) {
  37. for(auto *curr = &it->second; curr; curr = curr->next.get()) {
  38. if(curr->invoke == node.invoke) {
  39. node.next = std::move(curr->next);
  40. *curr = std::move(node);
  41. return *curr;
  42. }
  43. }
  44. // locally overloaded function
  45. node.next = std::make_shared<meta_func_node>(std::move(parent.details->func[id]));
  46. }
  47. return parent.details->func.insert_or_assign(id, std::move(node)).first->second;
  48. }
  49. } // namespace internal
  50. /**
  51. * Internal details not to be documented.
  52. * @endcond
  53. */
  54. /**
  55. * @brief Basic meta factory to be used for reflection purposes.
  56. * @tparam Type Reflected type for which the factory was created.
  57. */
  58. template<typename Type>
  59. class meta_factory {
  60. template<typename Setter, auto Getter, typename Policy, std::size_t... Index>
  61. void data(const id_type id, std::index_sequence<Index...>) noexcept {
  62. using data_type = std::invoke_result_t<decltype(Getter), Type &>;
  63. using args_type = type_list<typename meta_function_helper_t<Type, decltype(value_list_element_v<Index, Setter>)>::args_type...>;
  64. static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
  65. auto &&elem = internal::meta_extend(
  66. internal::owner(*ctx, *info),
  67. id,
  68. internal::meta_data_node{
  69. /* this is never static */
  70. (std::is_member_object_pointer_v<decltype(value_list_element_v<Index, Setter>)> && ... && std::is_const_v<std::remove_reference_t<data_type>>) ? internal::meta_traits::is_const : internal::meta_traits::is_none,
  71. Setter::size,
  72. &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
  73. &meta_arg<type_list<type_list_element_t<type_list_element_t<Index, args_type>::size != 1u, type_list_element_t<Index, args_type>>...>>,
  74. +[](meta_handle instance, meta_any value) { return (meta_setter<Type, value_list_element_v<Index, Setter>>(*instance.operator->(), value.as_ref()) || ...); },
  75. &meta_getter<Type, Getter, Policy>});
  76. bucket = &elem.prop;
  77. }
  78. public:
  79. /*! @brief Default constructor. */
  80. meta_factory() noexcept
  81. : meta_factory{locator<meta_ctx>::value_or()} {}
  82. /**
  83. * @brief Context aware constructor.
  84. * @param area The context into which to construct meta types.
  85. */
  86. meta_factory(meta_ctx &area) noexcept
  87. : ctx{&area},
  88. bucket{},
  89. info{&type_id<Type>()} {
  90. auto &&elem = internal::owner(*ctx, *info);
  91. if(!elem.details) {
  92. elem.details = std::make_shared<internal::meta_type_descriptor>();
  93. }
  94. bucket = &elem.details->prop;
  95. }
  96. /**
  97. * @brief Assigns a custom unique identifier to a meta type.
  98. * @param id A custom unique identifier.
  99. * @return A meta factory for the given type.
  100. */
  101. auto type(const id_type id) noexcept {
  102. auto &&elem = internal::owner(*ctx, *info);
  103. ENTT_ASSERT(elem.id == id || !resolve(*ctx, id), "Duplicate identifier");
  104. bucket = &elem.details->prop;
  105. elem.id = id;
  106. return *this;
  107. }
  108. /**
  109. * @brief Assigns a meta base to a meta type.
  110. *
  111. * A reflected base class must be a real base class of the reflected type.
  112. *
  113. * @tparam Base Type of the base class to assign to the meta type.
  114. * @return A meta factory for the parent type.
  115. */
  116. template<typename Base>
  117. auto base() noexcept {
  118. static_assert(!std::is_same_v<Type, Base> && std::is_base_of_v<Base, Type>, "Invalid base type");
  119. auto *const op = +[](const void *instance) noexcept { return static_cast<const void *>(static_cast<const Base *>(static_cast<const Type *>(instance))); };
  120. internal::owner(*ctx, *info).details->base.insert_or_assign(type_id<Base>().hash(), internal::meta_base_node{&internal::resolve<Base>, op});
  121. bucket = nullptr;
  122. return *this;
  123. }
  124. /**
  125. * @brief Assigns a meta conversion function to a meta type.
  126. *
  127. * Conversion functions can be either free functions or member
  128. * functions.<br/>
  129. * In case of free functions, they must accept a const reference to an
  130. * instance of the parent type as an argument. In case of member functions,
  131. * they should have no arguments at all.
  132. *
  133. * @tparam Candidate The actual function to use for the conversion.
  134. * @return A meta factory for the parent type.
  135. */
  136. template<auto Candidate>
  137. auto conv() noexcept {
  138. using conv_type = std::remove_cv_t<std::remove_reference_t<std::invoke_result_t<decltype(Candidate), Type &>>>;
  139. auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, std::invoke(Candidate, *static_cast<const Type *>(instance))); };
  140. internal::owner(*ctx, *info).details->conv.insert_or_assign(type_id<conv_type>().hash(), internal::meta_conv_node{op});
  141. bucket = nullptr;
  142. return *this;
  143. }
  144. /**
  145. * @brief Assigns a meta conversion function to a meta type.
  146. *
  147. * The given type must be such that an instance of the reflected type can be
  148. * converted to it.
  149. *
  150. * @tparam To Type of the conversion function to assign to the meta type.
  151. * @return A meta factory for the parent type.
  152. */
  153. template<typename To>
  154. auto conv() noexcept {
  155. using conv_type = std::remove_cv_t<std::remove_reference_t<To>>;
  156. auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast<To>(*static_cast<const Type *>(instance))); };
  157. internal::owner(*ctx, *info).details->conv.insert_or_assign(type_id<conv_type>().hash(), internal::meta_conv_node{op});
  158. bucket = nullptr;
  159. return *this;
  160. }
  161. /**
  162. * @brief Assigns a meta constructor to a meta type.
  163. *
  164. * Both member functions and free function can be assigned to meta types in
  165. * the role of constructors. All that is required is that they return an
  166. * instance of the underlying type.<br/>
  167. * From a client's point of view, nothing changes if a constructor of a meta
  168. * type is a built-in one or not.
  169. *
  170. * @tparam Candidate The actual function to use as a constructor.
  171. * @tparam Policy Optional policy (no policy set by default).
  172. * @return A meta factory for the parent type.
  173. */
  174. template<auto Candidate, typename Policy = as_is_t>
  175. auto ctor() noexcept {
  176. using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
  177. static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
  178. static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>, Type>, "The function doesn't return an object of the required type");
  179. internal::owner(*ctx, *info).details->ctor.insert_or_assign(type_id<typename descriptor::args_type>().hash(), internal::meta_ctor_node{descriptor::args_type::size, &meta_arg<typename descriptor::args_type>, &meta_construct<Type, Candidate, Policy>});
  180. bucket = nullptr;
  181. return *this;
  182. }
  183. /**
  184. * @brief Assigns a meta constructor to a meta type.
  185. *
  186. * A meta constructor is uniquely identified by the types of its arguments
  187. * and is such that there exists an actual constructor of the underlying
  188. * type that can be invoked with parameters whose types are those given.
  189. *
  190. * @tparam Args Types of arguments to use to construct an instance.
  191. * @return A meta factory for the parent type.
  192. */
  193. template<typename... Args>
  194. auto ctor() noexcept {
  195. // default constructor is already implicitly generated, no need for redundancy
  196. if constexpr(sizeof...(Args) != 0u) {
  197. using descriptor = meta_function_helper_t<Type, Type (*)(Args...)>;
  198. internal::owner(*ctx, *info).details->ctor.insert_or_assign(type_id<typename descriptor::args_type>().hash(), internal::meta_ctor_node{descriptor::args_type::size, &meta_arg<typename descriptor::args_type>, &meta_construct<Type, Args...>});
  199. }
  200. bucket = nullptr;
  201. return *this;
  202. }
  203. /**
  204. * @brief Assigns a meta destructor to a meta type.
  205. *
  206. * Both free functions and member functions can be assigned to meta types in
  207. * the role of destructors.<br/>
  208. * The signature of a free function should be identical to the following:
  209. *
  210. * @code{.cpp}
  211. * void(Type &);
  212. * @endcode
  213. *
  214. * Member functions should not take arguments instead.<br/>
  215. * The purpose is to give users the ability to free up resources that
  216. * require special treatment before an object is actually destroyed.
  217. *
  218. * @tparam Func The actual function to use as a destructor.
  219. * @return A meta factory for the parent type.
  220. */
  221. template<auto Func>
  222. auto dtor() noexcept {
  223. static_assert(std::is_invocable_v<decltype(Func), Type &>, "The function doesn't accept an object of the type provided");
  224. auto *const op = +[](void *instance) { std::invoke(Func, *static_cast<Type *>(instance)); };
  225. internal::owner(*ctx, *info).dtor = internal::meta_dtor_node{op};
  226. bucket = nullptr;
  227. return *this;
  228. }
  229. /**
  230. * @brief Assigns a meta data to a meta type.
  231. *
  232. * Both data members and static and global variables, as well as constants
  233. * of any kind, can be assigned to a meta type.<br/>
  234. * From a client's point of view, all the variables associated with the
  235. * reflected object will appear as if they were part of the type itself.
  236. *
  237. * @tparam Data The actual variable to attach to the meta type.
  238. * @tparam Policy Optional policy (no policy set by default).
  239. * @param id Unique identifier.
  240. * @return A meta factory for the parent type.
  241. */
  242. template<auto Data, typename Policy = as_is_t>
  243. auto data(const id_type id) noexcept {
  244. if constexpr(std::is_member_object_pointer_v<decltype(Data)>) {
  245. using data_type = std::invoke_result_t<decltype(Data), Type &>;
  246. static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
  247. auto &&elem = internal::meta_extend(
  248. internal::owner(*ctx, *info),
  249. id,
  250. internal::meta_data_node{
  251. /* this is never static */
  252. std::is_const_v<std::remove_reference_t<data_type>> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
  253. 1u,
  254. &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
  255. &meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
  256. &meta_setter<Type, Data>,
  257. &meta_getter<Type, Data, Policy>});
  258. bucket = &elem.prop;
  259. } else {
  260. using data_type = std::remove_pointer_t<decltype(Data)>;
  261. if constexpr(std::is_pointer_v<decltype(Data)>) {
  262. static_assert(Policy::template value<decltype(*Data)>, "Invalid return type for the given policy");
  263. } else {
  264. static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
  265. }
  266. auto &&elem = internal::meta_extend(
  267. internal::owner(*ctx, *info),
  268. id,
  269. internal::meta_data_node{
  270. ((std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<data_type>>> || std::is_const_v<std::remove_reference_t<data_type>>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
  271. 1u,
  272. &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
  273. &meta_arg<type_list<std::remove_cv_t<std::remove_reference_t<data_type>>>>,
  274. &meta_setter<Type, Data>,
  275. &meta_getter<Type, Data, Policy>});
  276. bucket = &elem.prop;
  277. }
  278. return *this;
  279. }
  280. /**
  281. * @brief Assigns a meta data to a meta type by means of its setter and
  282. * getter.
  283. *
  284. * Setters and getters can be either free functions, member functions or a
  285. * mix of them.<br/>
  286. * In case of free functions, setters and getters must accept a reference to
  287. * an instance of the parent type as their first argument. A setter has then
  288. * an extra argument of a type convertible to that of the parameter to
  289. * set.<br/>
  290. * In case of member functions, getters have no arguments at all, while
  291. * setters has an argument of a type convertible to that of the parameter to
  292. * set.
  293. *
  294. * @tparam Setter The actual function to use as a setter.
  295. * @tparam Getter The actual function to use as a getter.
  296. * @tparam Policy Optional policy (no policy set by default).
  297. * @param id Unique identifier.
  298. * @return A meta factory for the parent type.
  299. */
  300. template<auto Setter, auto Getter, typename Policy = as_is_t>
  301. auto data(const id_type id) noexcept {
  302. using data_type = std::invoke_result_t<decltype(Getter), Type &>;
  303. static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
  304. if constexpr(std::is_same_v<decltype(Setter), std::nullptr_t>) {
  305. auto &&elem = internal::meta_extend(
  306. internal::owner(*ctx, *info),
  307. id,
  308. internal::meta_data_node{
  309. /* this is never static */
  310. internal::meta_traits::is_const,
  311. 0u,
  312. &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
  313. &meta_arg<type_list<>>,
  314. &meta_setter<Type, Setter>,
  315. &meta_getter<Type, Getter, Policy>});
  316. bucket = &elem.prop;
  317. } else {
  318. using args_type = typename meta_function_helper_t<Type, decltype(Setter)>::args_type;
  319. auto &&elem = internal::meta_extend(
  320. internal::owner(*ctx, *info),
  321. id,
  322. internal::meta_data_node{
  323. /* this is never static nor const */
  324. internal::meta_traits::is_none,
  325. 1u,
  326. &internal::resolve<std::remove_cv_t<std::remove_reference_t<data_type>>>,
  327. &meta_arg<type_list<type_list_element_t<args_type::size != 1u, args_type>>>,
  328. &meta_setter<Type, Setter>,
  329. &meta_getter<Type, Getter, Policy>});
  330. bucket = &elem.prop;
  331. }
  332. return *this;
  333. }
  334. /**
  335. * @brief Assigns a meta data to a meta type by means of its setters and
  336. * getter.
  337. *
  338. * Multi-setter support for meta data members. All setters are tried in the
  339. * order of definition before returning to the caller.<br/>
  340. * Setters can be either free functions, member functions or a mix of them
  341. * and are provided via a `value_list` type.
  342. *
  343. * @sa data
  344. *
  345. * @tparam Setter The actual functions to use as setters.
  346. * @tparam Getter The actual getter function.
  347. * @tparam Policy Optional policy (no policy set by default).
  348. * @param id Unique identifier.
  349. * @return A meta factory for the parent type.
  350. */
  351. template<typename Setter, auto Getter, typename Policy = as_is_t>
  352. auto data(const id_type id) noexcept {
  353. data<Setter, Getter, Policy>(id, std::make_index_sequence<Setter::size>{});
  354. return *this;
  355. }
  356. /**
  357. * @brief Assigns a meta function to a meta type.
  358. *
  359. * Both member functions and free functions can be assigned to a meta
  360. * type.<br/>
  361. * From a client's point of view, all the functions associated with the
  362. * reflected object will appear as if they were part of the type itself.
  363. *
  364. * @tparam Candidate The actual function to attach to the meta type.
  365. * @tparam Policy Optional policy (no policy set by default).
  366. * @param id Unique identifier.
  367. * @return A meta factory for the parent type.
  368. */
  369. template<auto Candidate, typename Policy = as_is_t>
  370. auto func(const id_type id) noexcept {
  371. using descriptor = meta_function_helper_t<Type, decltype(Candidate)>;
  372. static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
  373. auto &&elem = internal::meta_extend(
  374. internal::owner(*ctx, *info),
  375. id,
  376. internal::meta_func_node{
  377. (descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none),
  378. descriptor::args_type::size,
  379. &internal::resolve<std::conditional_t<std::is_same_v<Policy, as_void_t>, void, std::remove_cv_t<std::remove_reference_t<typename descriptor::return_type>>>>,
  380. &meta_arg<typename descriptor::args_type>,
  381. &meta_invoke<Type, Candidate, Policy>});
  382. bucket = &elem.prop;
  383. return *this;
  384. }
  385. /**
  386. * @brief Assigns a property to the last meta object created.
  387. *
  388. * Both the key and the value (if any) must be at least copy constructible.
  389. *
  390. * @tparam Value Optional type of the property value.
  391. * @param id Property key.
  392. * @param value Optional property value.
  393. * @return A meta factory for the parent type.
  394. */
  395. template<typename... Value>
  396. meta_factory prop(id_type id, [[maybe_unused]] Value &&...value) {
  397. ENTT_ASSERT(bucket != nullptr, "Meta object does not support properties");
  398. if constexpr(sizeof...(Value) == 0u) {
  399. (*bucket)[id] = internal::meta_prop_node{&internal::resolve<void>};
  400. } else {
  401. (*bucket)[id] = internal::meta_prop_node{
  402. &internal::resolve<std::decay_t<Value>>...,
  403. std::make_shared<std::decay_t<Value>>(std::forward<Value>(value))...};
  404. }
  405. return *this;
  406. }
  407. private:
  408. meta_ctx *ctx;
  409. dense_map<id_type, internal::meta_prop_node, identity> *bucket;
  410. const type_info *info;
  411. };
  412. /**
  413. * @brief Utility function to use for reflection.
  414. *
  415. * This is the point from which everything starts.<br/>
  416. * By invoking this function with a type that is not yet reflected, a meta type
  417. * is created to which it will be possible to attach meta objects through a
  418. * dedicated factory.
  419. *
  420. * @tparam Type Type to reflect.
  421. * @param ctx The context into which to construct meta types.
  422. * @return A meta factory for the given type.
  423. */
  424. template<typename Type>
  425. [[nodiscard]] auto meta(meta_ctx &ctx) noexcept {
  426. auto &&context = internal::meta_context::from(ctx);
  427. // make sure the type exists in the context before returning a factory
  428. context.value.try_emplace(type_id<Type>().hash(), internal::resolve<Type>(context));
  429. return meta_factory<Type>{ctx};
  430. }
  431. /**
  432. * @brief Utility function to use for reflection.
  433. *
  434. * This is the point from which everything starts.<br/>
  435. * By invoking this function with a type that is not yet reflected, a meta type
  436. * is created to which it will be possible to attach meta objects through a
  437. * dedicated factory.
  438. *
  439. * @tparam Type Type to reflect.
  440. * @return A meta factory for the given type.
  441. */
  442. template<typename Type>
  443. [[nodiscard]] auto meta() noexcept {
  444. return meta<Type>(locator<meta_ctx>::value_or());
  445. }
  446. /**
  447. * @brief Resets a type and all its parts.
  448. *
  449. * Resets a type and all its data members, member functions and properties, as
  450. * well as its constructors, destructors and conversion functions if any.<br/>
  451. * Base classes aren't reset but the link between the two types is removed.
  452. *
  453. * The type is also removed from the set of searchable types.
  454. *
  455. * @param id Unique identifier.
  456. * @param ctx The context from which to reset meta types.
  457. */
  458. inline void meta_reset(meta_ctx &ctx, const id_type id) noexcept {
  459. auto &&context = internal::meta_context::from(ctx);
  460. for(auto it = context.value.begin(); it != context.value.end();) {
  461. if(it->second.id == id) {
  462. it = context.value.erase(it);
  463. } else {
  464. ++it;
  465. }
  466. }
  467. }
  468. /**
  469. * @brief Resets a type and all its parts.
  470. *
  471. * Resets a type and all its data members, member functions and properties, as
  472. * well as its constructors, destructors and conversion functions if any.<br/>
  473. * Base classes aren't reset but the link between the two types is removed.
  474. *
  475. * The type is also removed from the set of searchable types.
  476. *
  477. * @param id Unique identifier.
  478. */
  479. inline void meta_reset(const id_type id) noexcept {
  480. meta_reset(locator<meta_ctx>::value_or(), id);
  481. }
  482. /**
  483. * @brief Resets a type and all its parts.
  484. *
  485. * @sa meta_reset
  486. *
  487. * @tparam Type Type to reset.
  488. * @param ctx The context from which to reset meta types.
  489. */
  490. template<typename Type>
  491. void meta_reset(meta_ctx &ctx) noexcept {
  492. internal::meta_context::from(ctx).value.erase(type_id<Type>().hash());
  493. }
  494. /**
  495. * @brief Resets a type and all its parts.
  496. *
  497. * @sa meta_reset
  498. *
  499. * @tparam Type Type to reset.
  500. */
  501. template<typename Type>
  502. void meta_reset() noexcept {
  503. meta_reset<Type>(locator<meta_ctx>::value_or());
  504. }
  505. /**
  506. * @brief Resets all meta types.
  507. *
  508. * @sa meta_reset
  509. *
  510. * @param ctx The context from which to reset meta types.
  511. */
  512. inline void meta_reset(meta_ctx &ctx) noexcept {
  513. internal::meta_context::from(ctx).value.clear();
  514. }
  515. /**
  516. * @brief Resets all meta types.
  517. *
  518. * @sa meta_reset
  519. */
  520. inline void meta_reset() noexcept {
  521. meta_reset(locator<meta_ctx>::value_or());
  522. }
  523. } // namespace entt
  524. #endif