1#ifndef ENTT_META_NODE_HPP
2#define ENTT_META_NODE_HPP
4#include "../config/config.h"
5#include "../core/bit.hpp"
6#include "../core/concepts.hpp"
7#include "../core/enum.hpp"
8#include "../core/fwd.hpp"
9#include "../core/type_info.hpp"
10#include "../core/type_traits.hpp"
11#include "../core/utility.hpp"
12#include "../stl/array.hpp"
13#include "../stl/bit.hpp"
14#include "../stl/cstddef.hpp"
15#include "../stl/cstdint.hpp"
16#include "../stl/memory.hpp"
17#include "../stl/type_traits.hpp"
18#include "../stl/utility.hpp"
19#include "../stl/vector.hpp"
22#include "type_traits.hpp"
29enum class meta_traits : stl::uint32_t {
33 is_arithmetic = 0x0004,
40 is_pointer_like = 0x0200,
41 is_sequence_container = 0x0400,
42 is_associative_container = 0x0800,
43 _user_defined_traits = 0xFFFF,
44 _entt_enum_as_bitmask = 0xFFFF
47template<
typename Type>
48requires stl::is_enum_v<Type>
49[[nodiscard]]
auto meta_to_user_traits(
const meta_traits traits)
noexcept {
50 constexpr auto shift = stl::popcount(
static_cast<stl::underlying_type_t<meta_traits>
>(meta_traits::_user_defined_traits));
51 return Type{
static_cast<stl::underlying_type_t<Type>
>(
static_cast<stl::underlying_type_t<meta_traits>
>(traits) >> shift)};
54template<
typename Type>
55requires stl::is_enum_v<Type>
56[[nodiscard]]
auto user_to_meta_traits(
const Type value)
noexcept {
57 constexpr auto shift = stl::popcount(
static_cast<stl::underlying_type_t<meta_traits>
>(meta_traits::_user_defined_traits));
58 const auto traits =
static_cast<stl::underlying_type_t<internal::meta_traits>
>(
static_cast<stl::underlying_type_t<Type>
>(value));
59 ENTT_ASSERT(traits < ((~
static_cast<stl::underlying_type_t<meta_traits>
>(meta_traits::_user_defined_traits)) >> shift),
"Invalid traits");
60 return meta_traits{traits << shift};
65struct meta_custom_node {
67 stl::shared_ptr<void> value{};
70struct meta_base_node {
72 const meta_type_node &(*type)(
const meta_context &)
noexcept {};
73 const void *(*cast)(
const void *)
noexcept {};
76struct meta_conv_node {
78 meta_any (*conv)(
const meta_ctx &,
const void *){};
81struct meta_ctor_node {
82 using size_type = stl::size_t;
86 meta_type (*arg)(
const meta_ctx &,
const size_type)
noexcept {};
87 meta_any (*invoke)(
const meta_ctx &, meta_any *
const){};
90struct meta_data_node {
91 using size_type = stl::size_t;
95 meta_traits traits{meta_traits::is_none};
96 size_type set_arity{0u};
97 size_type get_arity{0u};
98 meta_type (*set_arg)(
const meta_ctx &,
const size_type)
noexcept {};
99 meta_type (*get_arg)(
const meta_ctx &,
const size_type)
noexcept {};
100 const meta_type_node &(*type)(
const meta_context &)
noexcept {};
101 bool (*set)(meta_handle, meta_any *
const){};
102 meta_any (*get)(meta_handle, meta_any *
const){};
103 meta_custom_node custom{};
106struct meta_func_node {
107 using size_type = stl::size_t;
111 meta_traits traits{meta_traits::is_none};
113 const meta_type_node &(*ret)(
const meta_context &)
noexcept {};
114 meta_type (*arg)(
const meta_ctx &,
const size_type)
noexcept {};
115 meta_any (*invoke)(meta_handle, meta_any *
const){};
116 stl::unique_ptr<meta_func_node> next;
117 meta_custom_node custom{};
120struct meta_template_node {
121 using size_type = stl::size_t;
124 const meta_type_node &(*resolve)(
const meta_context &)
noexcept {};
125 const meta_type_node &(*arg)(
const meta_context &,
const size_type)
noexcept {};
128struct meta_type_descriptor {
129 stl::vector<meta_ctor_node> ctor{};
130 stl::vector<meta_base_node> base{};
131 stl::vector<meta_conv_node> conv{};
132 stl::vector<meta_data_node> data{};
133 stl::vector<meta_func_node> func{};
136struct meta_type_node {
137 using size_type = stl::size_t;
139 const type_info *info{};
142 meta_traits traits{meta_traits::is_none};
143 size_type size_of{0u};
144 const meta_type_node &(*remove_pointer)(
const meta_context &)
noexcept {};
145 meta_any (*default_constructor)(
const meta_ctx &){};
146 double (*conversion_helper)(
void *,
const void *){};
147 meta_any (*from_void)(
const meta_ctx &,
void *,
const void *){};
148 meta_template_node templ{};
149 meta_custom_node custom{};
150 stl::unique_ptr<meta_type_descriptor> details{};
153template<
typename Type,
typename Value>
154[[nodiscard]]
auto *find_member(Type &from,
const Value value) {
155 for(
auto &&elem: from) {
156 if(elem.id == value) {
161 return static_cast<Type::value_type *
>(
nullptr);
164[[nodiscard]]
inline auto *find_overload(meta_func_node *curr, stl::remove_pointer_t<
decltype(meta_func_node::invoke)> *
const ref) {
165 while((curr !=
nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); }
170[[nodiscard]]
auto *look_for(
const meta_context &context,
const meta_type_node &node,
const id_type
id,
bool recursive) {
171 using value_type = stl::remove_reference_t<
decltype((node.details.get()->*Member))>::value_type;
174 if(
auto *member = find_member((node.details.get()->*Member),
id); member !=
nullptr) {
179 for(
auto &&curr: node.details->base) {
180 if(
auto *elem = look_for<Member>(context, curr.type(context),
id, recursive); elem) {
187 return static_cast<value_type *
>(
nullptr);
190template<cvref_unqualified Type>
191const meta_type_node &
resolve(
const meta_context &)
noexcept;
193template<
typename... Args>
194[[nodiscard]]
const meta_type_node &meta_arg_node(
const meta_context &context, type_list<Args...>,
const stl::size_t index)
noexcept {
195 using resolve_type =
const meta_type_node &(*)(
const meta_context &)
noexcept;
196 constexpr stl::array<resolve_type,
sizeof...(Args)> list{&resolve<stl::remove_cvref_t<Args>>...};
197 ENTT_ASSERT(index <
sizeof...(Args),
"Out of bounds");
198 return list[index](context);
201[[nodiscard]]
inline const void *try_cast(
const meta_context &context,
const meta_type_node &from,
const id_type to,
const void *instance)
noexcept {
203 for(
auto &&curr: from.details->base) {
204 if(
const void *other = curr.cast(instance); curr.id == to) {
206 }
else if(
const void *elem = try_cast(context, curr.type(context), to, other); elem) {
215template<
typename Type>
216auto setup_node_for() noexcept {
219 type_id<Type>().hash(),
221 (stl::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
222 | (stl::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
223 | (stl::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
224 | (stl::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
225 | (stl::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
226 | (stl::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
227 | (stl::is_pointer_v<Type> ? meta_traits::is_pointer : meta_traits::is_none)
228 | (is_meta_pointer_like_v<Type> ? meta_traits::is_pointer_like : meta_traits::is_none)
229 | (is_complete_v<meta_sequence_container_traits<Type>> ? meta_traits::is_sequence_container : meta_traits::is_none)
230 | (is_complete_v<meta_associative_container_traits<Type>> ? meta_traits::is_associative_container : meta_traits::is_none),
232 &resolve<stl::remove_const_t<stl::remove_pointer_t<Type>>>};
234 if constexpr(stl::is_default_constructible_v<Type>) {
235 node.default_constructor = +[](
const meta_ctx &ctx) {
236 return meta_any{ctx, stl::in_place_type<Type>};
240 if constexpr(stl::is_arithmetic_v<Type>) {
241 node.conversion_helper = +[](
void *lhs,
const void *rhs) {
242 return lhs ?
static_cast<double>(*
static_cast<Type *
>(lhs) =
static_cast<Type
>(*
static_cast<const double *
>(rhs))) : static_cast<double>(*static_cast<const Type *>(rhs));
244 }
else if constexpr(stl::is_enum_v<Type>) {
245 node.conversion_helper = +[](
void *lhs,
const void *rhs) {
246 return lhs ?
static_cast<double>(*
static_cast<Type *
>(lhs) =
static_cast<Type
>(
static_cast<stl::underlying_type_t<Type>
>(*
static_cast<const double *
>(rhs)))) : static_cast<double>(*static_cast<const Type *>(rhs));
250 if constexpr(!stl::is_void_v<Type> && !stl::is_function_v<Type>) {
251 node.from_void = +[](
const meta_ctx &ctx,
void *elem,
const void *celem) {
253 return meta_any{ctx, stl::in_place,
static_cast<stl::decay_t<Type> *
>(elem)};
257 return meta_any{ctx, stl::in_place_type<stl::decay_t<Type> &>, *
static_cast<stl::decay_t<Type> *
>(elem)};
261 return meta_any{ctx, stl::in_place_type<const stl::decay_t<Type> &>, *
static_cast<const stl::decay_t<Type> *
>(celem)};
265 if constexpr(is_complete_v<meta_template_traits<Type>>) {
266 node.templ = meta_template_node{
267 meta_template_traits<Type>::args_type::size,
268 &resolve<typename meta_template_traits<Type>::class_type>,
269 +[](
const meta_context &area,
const stl::size_t index)
noexcept ->
decltype(
auto) {
return meta_arg_node(area,
typename meta_template_traits<Type>::args_type{}, index); }};
275template<cvref_unqualified Type>
276[[nodiscard]]
const meta_type_node &
resolve(
const meta_context &context)
noexcept {
277 static const meta_type_node node = setup_node_for<Type>();
278 const auto it = context.bucket.find(node.info->hash());
279 return (it == context.bucket.cend()) ? node : *it->second;
meta_type resolve(const meta_ctx &ctx) noexcept
Returns the meta type associated with a given type.
stl::uint32_t id_type
Alias declaration for type identifiers.