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_meta_pointer_like = 0x0200,
41 is_meta_sequence_container = 0x0400,
42 is_meta_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_prop_node {
72 meta_type_node (*type)(
const meta_context &)
noexcept {};
73 std::shared_ptr<void> value{};
76struct meta_base_node {
78 meta_type_node (*resolve)(
const meta_context &)
noexcept {};
79 const void *(*cast)(
const void *)
noexcept {};
82struct meta_conv_node {
84 meta_any (*conv)(
const meta_ctx &,
const void *){};
87struct meta_ctor_node {
88 using size_type = std::size_t;
92 meta_type (*arg)(
const meta_ctx &,
const size_type)
noexcept {};
93 meta_any (*invoke)(
const meta_ctx &, meta_any *
const){};
96struct meta_dtor_node {
97 void (*dtor)(
void *){};
100struct meta_data_node {
101 using size_type = std::size_t;
104 meta_traits traits{meta_traits::is_none};
106 meta_type_node (*type)(
const meta_context &)
noexcept {};
107 meta_type (*arg)(
const meta_ctx &,
const size_type)
noexcept {};
108 bool (*set)(meta_handle, meta_any){};
109 meta_any (*get)(
const meta_ctx &, meta_handle){};
110 meta_custom_node custom{};
111 std::vector<meta_prop_node> prop{};
114struct meta_func_node {
115 using size_type = std::size_t;
118 meta_traits traits{meta_traits::is_none};
120 meta_type_node (*ret)(
const meta_context &)
noexcept {};
121 meta_type (*arg)(
const meta_ctx &,
const size_type)
noexcept {};
122 meta_any (*invoke)(
const meta_ctx &, meta_handle, meta_any *
const){};
123 std::shared_ptr<meta_func_node> next{};
124 meta_custom_node custom{};
125 std::vector<meta_prop_node> prop{};
128struct meta_template_node {
129 using size_type = std::size_t;
132 meta_type_node (*resolve)(
const meta_context &)
noexcept {};
133 meta_type_node (*arg)(
const meta_context &,
const size_type)
noexcept {};
136struct meta_type_descriptor {
137 std::vector<meta_ctor_node> ctor{};
138 std::vector<meta_base_node> base{};
139 std::vector<meta_conv_node> conv{};
140 std::vector<meta_data_node> data{};
141 std::vector<meta_func_node> func{};
142 std::vector<meta_prop_node> prop{};
145struct meta_type_node {
146 using size_type = std::size_t;
148 const type_info *info{};
150 meta_traits traits{meta_traits::is_none};
151 size_type size_of{0u};
152 meta_type_node (*resolve)(
const meta_context &)
noexcept {};
153 meta_type_node (*remove_pointer)(
const meta_context &)
noexcept {};
154 meta_any (*default_constructor)(
const meta_ctx &){};
155 double (*conversion_helper)(
void *,
const void *){};
156 meta_any (*from_void)(
const meta_ctx &,
void *,
const void *){};
157 meta_template_node templ{};
158 meta_dtor_node dtor{};
159 meta_custom_node custom{};
160 std::shared_ptr<meta_type_descriptor> details{};
163template<auto Member,
typename Type,
typename Value>
164[[nodiscard]]
auto *find_member(Type &from,
const Value value) {
165 for(
auto &&elem: from) {
166 if((elem.*Member) == value) {
171 return static_cast<typename Type::value_type *
>(
nullptr);
174[[nodiscard]]
inline auto *find_overload(meta_func_node *curr, std::remove_pointer_t<
decltype(meta_func_node::invoke)> *
const ref) {
175 while((curr !=
nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); }
180[[nodiscard]]
auto *look_for(
const meta_context &context,
const meta_type_node &node,
const id_type
id) {
181 using value_type =
typename std::remove_reference_t<
decltype((node.details.get()->*Member))>::value_type;
184 if(
auto *member = find_member<&value_type::id>((node.details.get()->*Member), id); member !=
nullptr) {
188 for(
auto &&curr: node.details->base) {
189 if(
auto *elem = look_for<Member>(context, curr.resolve(context),
id); elem) {
195 return static_cast<value_type *
>(
nullptr);
198template<
typename Type>
199meta_type_node
resolve(
const meta_context &)
noexcept;
201template<
typename... Args>
202[[nodiscard]]
auto meta_arg_node(
const meta_context &context, type_list<Args...>, [[maybe_unused]]
const std::size_t index)
noexcept {
203 [[maybe_unused]] std::size_t pos{};
204 meta_type_node (*value)(
const meta_context &)
noexcept =
nullptr;
205 ((value = (pos++ == index ? &resolve<std::remove_cv_t<std::remove_reference_t<Args>>> : value)), ...);
206 ENTT_ASSERT(value !=
nullptr,
"Out of bounds");
207 return value(context);
210[[nodiscard]]
inline const void *try_cast(
const meta_context &context,
const meta_type_node &from,
const meta_type_node &to,
const void *instance)
noexcept {
211 if((from.info !=
nullptr) && (to.info !=
nullptr) && *from.info == *to.info) {
216 for(
auto &&curr: from.details->base) {
217 if(
const void *elem = try_cast(context, curr.resolve(context), to, curr.cast(instance)); elem) {
226template<
typename Func>
227[[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) {
228 if(from.info && *from.info == to) {
229 return func(instance, from);
233 for(
auto &&elem: from.details->conv) {
234 if(elem.type == to.hash()) {
235 return func(instance, elem);
239 for(
auto &&curr: from.details->base) {
240 if(
auto other = try_convert(context, curr.resolve(context), to, arithmetic_or_enum, curr.cast(instance), func); other) {
246 if(from.conversion_helper && arithmetic_or_enum) {
247 return func(instance, from.conversion_helper);
250 return func(instance);
253[[nodiscard]]
inline const meta_type_node *try_resolve(
const meta_context &context,
const type_info &info)
noexcept {
254 const auto it = context.value.find(info.hash());
255 return it != context.value.end() ? &it->second :
nullptr;
258template<
typename Type>
259[[nodiscard]] meta_type_node
resolve(
const meta_context &context)
noexcept {
260 static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>,
"Invalid type");
262 if(
auto *elem = try_resolve(context, type_id<Type>()); elem) {
268 type_id<Type>().hash(),
269 (std::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
270 | (std::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
271 | (std::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
272 | (std::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
273 | (std::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
274 | (std::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
275 | (std::is_pointer_v<Type> ? meta_traits::is_pointer : meta_traits::is_none)
277 | (
is_complete_v<meta_sequence_container_traits<Type>> ? meta_traits::is_meta_sequence_container : meta_traits::is_none)
278 | (
is_complete_v<meta_associative_container_traits<Type>> ? meta_traits::is_meta_associative_container : meta_traits::is_none),
281 &
resolve<std::remove_cv_t<std::remove_pointer_t<Type>>>};
283 if constexpr(std::is_default_constructible_v<Type>) {
284 node.default_constructor = +[](
const meta_ctx &ctx) {
285 return meta_any{ctx, std::in_place_type<Type>};
289 if constexpr(std::is_arithmetic_v<Type>) {
290 node.conversion_helper = +[](
void *lhs,
const void *rhs) {
291 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));
293 }
else if constexpr(std::is_enum_v<Type>) {
294 node.conversion_helper = +[](
void *lhs,
const void *rhs) {
295 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));
299 if constexpr(!std::is_void_v<Type> && !std::is_function_v<Type>) {
300 node.from_void = +[](
const meta_ctx &ctx,
void *elem,
const void *celem) {
302 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); }};
constexpr std::size_t size_of_v
Helper variable template.
std::uint32_t id_type
Alias declaration for type identifiers.
constexpr bool is_complete_v
Helper variable template.
constexpr auto is_meta_pointer_like_v
Helper variable template.
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).