1#ifndef ENTT_META_NODE_HPP
2#define ENTT_META_NODE_HPP
10#include "../config/config.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 const 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_data_node {
91 using size_type = std::size_t;
95 meta_traits traits{meta_traits::is_none};
97 const meta_type_node &(*type)(
const meta_context &)
noexcept {};
98 meta_type (*arg)(
const meta_ctx &,
const size_type)
noexcept {};
99 bool (*set)(meta_handle, meta_any){};
100 meta_any (*get)(meta_handle){};
101 meta_custom_node custom{};
104struct meta_func_node {
105 using size_type = std::size_t;
109 meta_traits traits{meta_traits::is_none};
111 const meta_type_node &(*ret)(
const meta_context &)
noexcept {};
112 meta_type (*arg)(
const meta_ctx &,
const size_type)
noexcept {};
113 meta_any (*invoke)(meta_handle, meta_any *
const){};
114 std::unique_ptr<meta_func_node> next;
115 meta_custom_node custom{};
118struct meta_template_node {
119 using size_type = std::size_t;
122 const meta_type_node &(*resolve)(
const meta_context &)
noexcept {};
123 const meta_type_node &(*arg)(
const meta_context &,
const size_type)
noexcept {};
126struct meta_type_descriptor {
127 std::vector<meta_ctor_node> ctor{};
128 std::vector<meta_base_node> base{};
129 std::vector<meta_conv_node> conv{};
130 std::vector<meta_data_node> data{};
131 std::vector<meta_func_node> func{};
134struct meta_type_node {
135 using size_type = std::size_t;
137 const type_info *info{};
140 meta_traits traits{meta_traits::is_none};
141 size_type size_of{0u};
142 const meta_type_node &(*remove_pointer)(
const meta_context &)
noexcept {};
143 meta_any (*default_constructor)(
const meta_ctx &){};
144 double (*conversion_helper)(
void *,
const void *){};
145 meta_any (*from_void)(
const meta_ctx &,
void *,
const void *){};
146 meta_template_node templ{};
147 meta_custom_node custom{};
148 std::unique_ptr<meta_type_descriptor> details{};
151template<auto Member,
typename Type,
typename Value>
152[[nodiscard]]
auto *find_member(Type &from,
const Value value) {
153 for(
auto &&elem: from) {
154 if((elem.*Member) == value) {
159 return static_cast<typename Type::value_type *
>(
nullptr);
162[[nodiscard]]
inline auto *find_overload(meta_func_node *curr, std::remove_pointer_t<
decltype(meta_func_node::invoke)> *
const ref) {
163 while((curr !=
nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); }
168[[nodiscard]]
auto *look_for(
const meta_context &context,
const meta_type_node &node,
const id_type
id,
bool recursive) {
169 using value_type =
typename std::remove_reference_t<
decltype((node.details.get()->*Member))>::value_type;
172 if(
auto *member = find_member<&value_type::id>((node.details.get()->*Member),
id); member !=
nullptr) {
177 for(
auto &&curr: node.details->base) {
178 if(
auto *elem = look_for<Member>(context, curr.resolve(context),
id, recursive); elem) {
185 return static_cast<value_type *
>(
nullptr);
188template<
typename Type>
189const meta_type_node &
resolve(
const meta_context &)
noexcept;
191template<
typename... Args>
192[[nodiscard]]
const meta_type_node &meta_arg_node(
const meta_context &context, type_list<Args...>,
const std::size_t index)
noexcept {
193 using resolve_type =
const meta_type_node &(*)(
const meta_context &)
noexcept;
194 constexpr std::array<resolve_type,
sizeof...(Args)> list{&resolve<std::remove_const_t<std::remove_reference_t<Args>>>...};
195 ENTT_ASSERT(index <
sizeof...(Args),
"Out of bounds");
196 return list[index](context);
199[[nodiscard]]
inline const void *try_cast(
const meta_context &context,
const meta_type_node &from,
const id_type to,
const void *instance)
noexcept {
201 for(
auto &&curr: from.details->base) {
202 if(
const void *other = curr.cast(instance); curr.type == to) {
204 }
else if(
const void *elem = try_cast(context, curr.resolve(context), to, other); elem) {
213template<
typename Type>
214auto setup_node_for() noexcept {
217 type_id<Type>().hash(),
219 (std::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
220 | (std::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
221 | (std::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
222 | (std::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
223 | (std::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
224 | (std::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
225 | (std::is_pointer_v<Type> ? meta_traits::is_pointer : meta_traits::is_none)
226 | (is_meta_pointer_like_v<Type> ? meta_traits::is_pointer_like : meta_traits::is_none)
227 | (is_complete_v<meta_sequence_container_traits<Type>> ? meta_traits::is_sequence_container : meta_traits::is_none)
228 | (is_complete_v<meta_associative_container_traits<Type>> ? meta_traits::is_associative_container : meta_traits::is_none),
230 &resolve<std::remove_const_t<std::remove_pointer_t<Type>>>};
232 if constexpr(std::is_default_constructible_v<Type>) {
233 node.default_constructor = +[](
const meta_ctx &ctx) {
234 return meta_any{ctx, std::in_place_type<Type>};
238 if constexpr(std::is_arithmetic_v<Type>) {
239 node.conversion_helper = +[](
void *lhs,
const void *rhs) {
240 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));
242 }
else if constexpr(std::is_enum_v<Type>) {
243 node.conversion_helper = +[](
void *lhs,
const void *rhs) {
244 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));
248 if constexpr(!std::is_void_v<Type> && !std::is_function_v<Type>) {
249 node.from_void = +[](
const meta_ctx &ctx,
void *elem,
const void *celem) {
251 return meta_any{ctx, std::in_place,
static_cast<std::decay_t<Type> *
>(elem)};
255 return meta_any{ctx, std::in_place_type<std::decay_t<Type> &>, *
static_cast<std::decay_t<Type> *
>(elem)};
259 return meta_any{ctx, std::in_place_type<const std::decay_t<Type> &>, *
static_cast<const std::decay_t<Type> *
>(celem)};
263 if constexpr(is_complete_v<meta_template_traits<Type>>) {
264 node.templ = meta_template_node{
265 meta_template_traits<Type>::args_type::size,
266 &resolve<typename meta_template_traits<Type>::class_type>,
267 +[](
const meta_context &area,
const std::size_t index)
noexcept ->
decltype(
auto) {
return meta_arg_node(area,
typename meta_template_traits<Type>::args_type{}, index); }};
273[[nodiscard]]
inline const meta_type_node *try_resolve(
const meta_context &context,
const type_info &info)
noexcept {
274 const auto it = context.value.find(info.hash());
275 return (it != context.value.end()) ? it->second.get() :
nullptr;
278template<
typename Type>
279[[nodiscard]]
const meta_type_node &
resolve(
const meta_context &context)
noexcept {
280 static_assert(std::is_same_v<Type, std::remove_const_t<std::remove_reference_t<Type>>>,
"Invalid type");
281 static const meta_type_node node = setup_node_for<Type>();
282 const auto *elem = try_resolve(context, *node.info);
283 return (elem ==
nullptr) ? node : *elem;
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).