1#ifndef ENTT_META_NODE_HPP
2#define ENTT_META_NODE_HPP
9#include "../config/config.h"
10#include "../core/attribute.h"
11#include "../core/bit.hpp"
12#include "../core/enum.hpp"
13#include "../core/fwd.hpp"
14#include "../core/type_info.hpp"
15#include "../core/type_traits.hpp"
16#include "../core/utility.hpp"
18#include "type_traits.hpp"
29enum class meta_traits : std::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>
48[[nodiscard]]
auto meta_to_user_traits(
const meta_traits traits)
noexcept {
49 static_assert(std::is_enum_v<Type>,
"Invalid enum type");
50 constexpr auto shift =
popcount(
static_cast<std::underlying_type_t<meta_traits>
>(meta_traits::_user_defined_traits));
51 return Type{
static_cast<std::underlying_type_t<Type>
>(
static_cast<std::underlying_type_t<meta_traits>
>(traits) >> shift)};
54template<
typename Type>
55[[nodiscard]]
auto user_to_meta_traits(
const Type value)
noexcept {
56 static_assert(std::is_enum_v<Type>,
"Invalid enum type");
57 constexpr auto shift =
popcount(
static_cast<std::underlying_type_t<meta_traits>
>(meta_traits::_user_defined_traits));
58 const auto traits =
static_cast<std::underlying_type_t<internal::meta_traits>
>(
static_cast<std::underlying_type_t<Type>
>(value));
59 ENTT_ASSERT(traits < ((~
static_cast<std::underlying_type_t<meta_traits>
>(meta_traits::_user_defined_traits)) >> shift),
"Invalid traits");
60 return meta_traits{traits << shift};
65struct meta_custom_node {
67 std::shared_ptr<void> value;
70struct meta_base_node {
72 meta_type_node (*resolve)(
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 = std::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_dtor_node {
91 void (*dtor)(
void *){};
94struct meta_data_node {
95 using size_type = std::size_t;
98 meta_traits traits{meta_traits::is_none};
100 meta_type_node (*type)(
const meta_context &)
noexcept {};
101 meta_type (*arg)(
const meta_ctx &,
const size_type)
noexcept {};
102 bool (*set)(meta_handle, meta_any){};
103 meta_any (*get)(meta_handle){};
104 meta_custom_node custom{};
107struct meta_func_node {
108 using size_type = std::size_t;
111 meta_traits traits{meta_traits::is_none};
113 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 std::shared_ptr<meta_func_node> next;
117 meta_custom_node custom{};
120struct meta_template_node {
121 using size_type = std::size_t;
124 meta_type_node (*resolve)(
const meta_context &)
noexcept {};
125 meta_type_node (*arg)(
const meta_context &,
const size_type)
noexcept {};
128struct meta_type_descriptor {
129 std::vector<meta_ctor_node> ctor;
130 std::vector<meta_base_node> base;
131 std::vector<meta_conv_node> conv;
132 std::vector<meta_data_node> data;
133 std::vector<meta_func_node> func;
136struct meta_type_node {
137 using size_type = std::size_t;
139 const type_info *info{};
141 meta_traits traits{meta_traits::is_none};
142 size_type size_of{0u};
143 meta_type_node (*resolve)(
const meta_context &)
noexcept {};
144 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_dtor_node dtor{};
150 meta_custom_node custom{};
151 std::shared_ptr<meta_type_descriptor> details;
154template<auto Member,
typename Type,
typename Value>
155[[nodiscard]]
auto *find_member(Type &from,
const Value value) {
156 for(
auto &&elem: from) {
157 if((elem.*Member) == value) {
162 return static_cast<typename Type::value_type *
>(
nullptr);
165[[nodiscard]]
inline auto *find_overload(meta_func_node *curr, std::remove_pointer_t<
decltype(meta_func_node::invoke)> *
const ref) {
166 while((curr !=
nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); }
171[[nodiscard]]
auto *look_for(
const meta_context &context,
const meta_type_node &node,
const id_type
id) {
172 using value_type =
typename std::remove_reference_t<
decltype((node.details.get()->*Member))>::value_type;
175 if(
auto *member = find_member<&value_type::id>((node.details.get()->*Member),
id); member !=
nullptr) {
179 for(
auto &&curr: node.details->base) {
180 if(
auto *elem = look_for<Member>(context, curr.resolve(context),
id); elem) {
186 return static_cast<value_type *
>(
nullptr);
189template<
typename Type>
190meta_type_node
resolve(
const meta_context &)
noexcept;
192template<
typename... Args>
193[[nodiscard]]
auto meta_arg_node(
const meta_context &context, type_list<Args...>, [[maybe_unused]]
const std::size_t index)
noexcept {
194 meta_type_node (*value)(
const meta_context &)
noexcept =
nullptr;
196 if constexpr(
sizeof...(Args) != 0u) {
198 ((value = (pos++ == index ? &resolve<std::remove_cv_t<std::remove_reference_t<Args>>> : value)), ...);
201 ENTT_ASSERT(value !=
nullptr,
"Out of bounds");
202 return value(context);
205[[nodiscard]]
inline const void *try_cast(
const meta_context &context,
const meta_type_node &from,
const type_info &to,
const void *instance)
noexcept {
206 if((from.info !=
nullptr) && *from.info == to) {
211 for(
auto &&curr: from.details->base) {
212 if(
const void *elem = try_cast(context, curr.resolve(context), to, curr.cast(instance)); elem) {
221template<
typename Func>
222[[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) {
223 if(from.info && *from.info == to) {
224 return func(instance, from);
228 for(
auto &&elem: from.details->conv) {
229 if(elem.type == to.hash()) {
230 return func(instance, elem);
234 for(
auto &&curr: from.details->base) {
235 if(
auto other = try_convert(context, curr.resolve(context), to, arithmetic_or_enum, curr.cast(instance), func); other) {
241 if(from.conversion_helper && arithmetic_or_enum) {
242 return func(instance, from.conversion_helper);
245 return func(instance);
248[[nodiscard]]
inline const meta_type_node *try_resolve(
const meta_context &context,
const type_info &info)
noexcept {
249 const auto it = context.value.find(info.hash());
250 return it != context.value.end() ? &it->second :
nullptr;
253template<
typename Type>
254[[nodiscard]] meta_type_node
resolve(
const meta_context &context)
noexcept {
255 static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>,
"Invalid type");
257 if(
auto *elem = try_resolve(context, type_id<Type>()); elem) {
263 type_id<Type>().hash(),
264 (std::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
265 | (std::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
266 | (std::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
267 | (std::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
268 | (std::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
269 | (std::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
270 | (std::is_pointer_v<Type> ? meta_traits::is_pointer : meta_traits::is_none)
271 | (is_meta_pointer_like_v<Type> ? meta_traits::is_pointer_like : meta_traits::is_none)
272 | (is_complete_v<meta_sequence_container_traits<Type>> ? meta_traits::is_sequence_container : meta_traits::is_none)
273 | (is_complete_v<meta_associative_container_traits<Type>> ? meta_traits::is_associative_container : meta_traits::is_none),
276 &resolve<std::remove_cv_t<std::remove_pointer_t<Type>>>};
278 if constexpr(std::is_default_constructible_v<Type>) {
279 node.default_constructor = +[](
const meta_ctx &ctx) {
280 return meta_any{ctx, std::in_place_type<Type>};
284 if constexpr(std::is_arithmetic_v<Type>) {
285 node.conversion_helper = +[](
void *lhs,
const void *rhs) {
286 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));
288 }
else if constexpr(std::is_enum_v<Type>) {
289 node.conversion_helper = +[](
void *lhs,
const void *rhs) {
290 return lhs ?
static_cast<double>(*
static_cast<Type *
>(lhs) =
static_cast<Type
>(
static_cast<std::underlying_type_t<Type>
>(*
static_cast<const double *
>(rhs)))) : static_cast<double>(*static_cast<const Type *>(rhs));
294 if constexpr(!std::is_void_v<Type> && !std::is_function_v<Type>) {
295 node.from_void = +[](
const meta_ctx &ctx,
void *elem,
const void *celem) {
297 return meta_any{ctx, std::in_place,
static_cast<std::decay_t<Type> *
>(elem)};
301 return meta_any{ctx, std::in_place_type<std::decay_t<Type> &>, *
static_cast<std::decay_t<Type> *
>(elem)};
305 return meta_any{ctx, std::in_place_type<const std::decay_t<Type> &>, *
static_cast<const std::decay_t<Type> *
>(celem)};
309 if constexpr(is_complete_v<meta_template_traits<Type>>) {
310 node.templ = meta_template_node{
311 meta_template_traits<Type>::args_type::size,
312 &resolve<typename meta_template_traits<Type>::class_type>,
313 +[](
const meta_context &area,
const std::size_t index)
noexcept {
return meta_arg_node(area,
typename meta_template_traits<Type>::args_type{}, index); }};
std::uint32_t id_type
Alias declaration for type identifiers.
meta_type resolve(const meta_ctx &ctx) noexcept
Returns the meta type associated with a given type.
constexpr std::enable_if_t< std::is_unsigned_v< Type >, int > popcount(const Type value) noexcept
Returns the number of set bits in a value (waiting for C++20 and std::popcount).