1#ifndef ENTT_META_META_HPP
2#define ENTT_META_META_HPP
10#include "../config/config.h"
11#include "../core/any.hpp"
12#include "../core/fwd.hpp"
13#include "../core/iterator.hpp"
14#include "../core/type_info.hpp"
15#include "../core/type_traits.hpp"
16#include "../core/utility.hpp"
17#include "../locator/locator.hpp"
18#include "adl_pointer.hpp"
23#include "type_traits.hpp"
49 template<
typename Type>
53 value_type_node{&internal::resolve<typename Type::value_type>},
54 const_reference_node{&internal::resolve<std::remove_const_t<std::remove_reference_t<typename Type::const_reference>>>},
55 size_fn{meta_sequence_container_traits<std::remove_const_t<Type>>
::size},
56 clear_fn{meta_sequence_container_traits<std::remove_const_t<Type>>
::clear},
57 reserve_fn{meta_sequence_container_traits<std::remove_const_t<Type>>
::reserve},
58 resize_fn{meta_sequence_container_traits<std::remove_const_t<Type>>
::resize},
59 begin_end_fn{meta_sequence_container_traits<std::remove_const_t<Type>>::iter},
60 insert_fn{meta_sequence_container_traits<std::remove_const_t<Type>>
::insert},
61 erase_fn{meta_sequence_container_traits<std::remove_const_t<Type>>
::erase},
62 const_only{std::is_const_v<Type>} {}
64 [[nodiscard]]
inline meta_type
value_type() const noexcept;
73 [[nodiscard]] inline meta_any operator[](
size_type);
74 [[nodiscard]] inline explicit operator
bool() const noexcept;
77 const meta_ctx *ctx{};
79 const internal::meta_type_node &(*value_type_node)(
const internal::meta_context &){};
80 const internal::meta_type_node &(*const_reference_node)(
const internal::meta_context &){};
82 bool (*clear_fn)(
void *){};
83 bool (*reserve_fn)(
void *,
const size_type){};
84 bool (*resize_fn)(
void *,
const size_type){};
85 iterator (*begin_end_fn)(
const meta_ctx &,
void *,
const void *,
const bool){};
86 iterator (*insert_fn)(
const meta_ctx &,
void *,
const void *,
const void *,
const iterator &){};
110 template<
typename Type>
114 key_type_node{&internal::resolve<typename Type::key_type>},
115 value_type_node{&internal::resolve<typename Type::value_type>},
116 size_fn{&meta_associative_container_traits<std::remove_const_t<Type>>
::size},
117 clear_fn{&meta_associative_container_traits<std::remove_const_t<Type>>
::clear},
118 reserve_fn{&meta_associative_container_traits<std::remove_const_t<Type>>
::reserve},
119 begin_end_fn{&meta_associative_container_traits<std::remove_const_t<Type>>::iter},
120 insert_fn{&meta_associative_container_traits<std::remove_const_t<Type>>
::insert},
121 erase_fn{&meta_associative_container_traits<std::remove_const_t<Type>>
::erase},
122 find_fn{&meta_associative_container_traits<std::remove_const_t<Type>>
::find},
123 const_only{std::is_const_v<Type>} {
124 if constexpr(!meta_associative_container_traits<std::remove_const_t<Type>>::key_only) {
125 mapped_type_node = &internal::resolve<typename Type::mapped_type>;
129 [[nodiscard]]
inline meta_type
key_type() const noexcept;
130 [[nodiscard]] inline meta_type
mapped_type() const noexcept;
131 [[nodiscard]] inline meta_type
value_type() const noexcept;
137 inline
bool insert(meta_any, meta_any);
140 [[nodiscard]] inline explicit operator
bool() const noexcept;
143 const meta_ctx *ctx{};
145 const internal::meta_type_node &(*key_type_node)(
const internal::meta_context &){};
146 const internal::meta_type_node &(*mapped_type_node)(
const internal::meta_context &){};
147 const internal::meta_type_node &(*value_type_node)(
const internal::meta_context &){};
149 bool (*clear_fn)(
void *){};
150 bool (*reserve_fn)(
void *,
const size_type){};
151 iterator (*begin_end_fn)(
const meta_ctx &,
void *,
const void *,
const bool){};
152 bool (*insert_fn)(
void *,
const void *,
const void *){};
153 size_type (*erase_fn)(
void *,
const void *){};
154 iterator (*find_fn)(
const meta_ctx &,
void *,
const void *,
const void *){};
160 using vtable_type = void(
const internal::meta_traits,
const meta_any &,
const void *);
162 template<
typename Type>
163 static void basic_vtable(
const internal::meta_traits req,
const meta_any &value, [[maybe_unused]]
const void *other) {
164 static_assert(std::is_same_v<std::remove_const_t<std::remove_reference_t<Type>>, Type>,
"Invalid type");
166 if(req == internal::meta_traits::is_none) {
167 value.node = &internal::resolve<Type>(internal::meta_context::from(*value.ctx));
171 if(req == internal::meta_traits::is_pointer_like) {
172 if constexpr(std::is_function_v<typename std::pointer_traits<Type>::element_type>) {
173 const_cast<meta_any &
>(value).
emplace<Type>(*
static_cast<const Type *
>(other));
174 }
else if constexpr(!std::is_void_v<std::remove_const_t<typename std::pointer_traits<Type>::element_type>>) {
177 if constexpr(std::is_constructible_v<bool, Type>) {
178 if(
const auto &pointer_like = *
static_cast<const Type *
>(other); pointer_like) {
194 *
static_cast<container_type *
>(
const_cast<void *
>(other)) = container_type{*value.ctx,
any_cast<const Type &>(value.storage)};
197 *
static_cast<container_type *
>(
const_cast<void *
>(other)) = container_type{*value.ctx,
any_cast<Type &>(
const_cast<meta_any &
>(value).storage)};
203 [[nodiscard]]
const auto &fetch_node()
const {
204 if(node ==
nullptr) {
205 ENTT_ASSERT(*
this,
"Invalid vtable function");
206 vtable(internal::meta_traits::is_none, *
this,
nullptr);
209 ENTT_ASSERT(node !=
nullptr,
"Invalid pointer to node");
214 : storage{std::move(elem)},
217 vtable{other.vtable} {}
236 template<
typename Type,
typename... Args>
237 explicit meta_any(std::in_place_type_t<Type>, Args &&...args)
238 : meta_any{
locator<
meta_ctx>::value_or(), std::in_place_type<Type>, std::forward<Args>(args)...} {}
247 template<
typename Type,
typename... Args>
249 : storage{std::in_place_type<Type>, std::forward<Args>(args)...},
251 vtable{&basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>} {}
258 template<
typename Type>
268 template<
typename Type>
272 vtable{storage ? &basic_vtable<Type> : nullptr} {
280 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
282 : meta_any{
locator<
meta_ctx>::value_or(), std::forward<Type>(value)} {}
290 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
292 : meta_any{area, std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)} {}
300 : storage{other.storage},
302 node{(ctx == other.ctx) ? other.node : nullptr},
303 vtable{other.vtable} {}
311 : storage{std::move(other.storage)},
313 node{(ctx == other.ctx) ? std::exchange(other.node, nullptr) : nullptr},
314 vtable{std::exchange(other.vtable, nullptr)} {}
327 : storage{std::move(other.storage)},
329 node{std::exchange(other.node,
nullptr)},
330 vtable{std::exchange(other.vtable,
nullptr)} {}
342 storage = other.storage;
345 vtable = other.vtable;
357 storage = std::move(other.storage);
359 node = std::exchange(other.node,
nullptr);
360 vtable = std::exchange(other.vtable,
nullptr);
370 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
386 template<typename... Args>
390 template<typename... Args>
400 template<typename Type>
418 template<typename Type>
421 return ((elem !=
nullptr) || !*
this) ? elem :
static_cast<const Type *
>(internal::try_cast(internal::meta_context::from(*ctx), fetch_node(),
type_hash<std::remove_const_t<Type>>::value(), storage.data()));
425 template<
typename Type>
427 return ((storage.policy() ==
any_policy::cref) && !std::is_const_v<Type>) ? nullptr :
const_cast<Type *
>(std::as_const(*this).try_cast<std::remove_const_t<Type>>());
435 template<
typename Type>
436 [[nodiscard]] std::remove_const_t<Type>
cast()
const {
438 ENTT_ASSERT(instance,
"Invalid instance");
439 return static_cast<Type
>(*instance);
443 template<
typename Type>
444 [[nodiscard]] std::remove_const_t<Type>
cast() {
447 ENTT_ASSERT(instance,
"Invalid instance");
448 return static_cast<Type
>(*instance);
470 template<
typename Type>
472 if constexpr(!std::is_reference_v<Type> || std::is_const_v<std::remove_reference_t<Type>>) {
473 if(storage.has_value<std::remove_const_t<std::remove_reference_t<Type>>>()) {
476 if constexpr(std::is_arithmetic_v<std::remove_const_t<std::remove_reference_t<Type>>> || std::is_enum_v<std::remove_const_t<std::remove_reference_t<Type>>>) {
477 if(
const auto &from = fetch_node(); from.conversion_helper) {
478 return meta_any{*ctx,
static_cast<Type
>(from.conversion_helper(
nullptr, storage.data()))};
482 if(
const auto &from = fetch_node(); from.details !=
nullptr) {
483 if(
const auto *elem = internal::find_member<&internal::meta_conv_node::type>(from.details->conv,
entt::type_hash<std::remove_const_t<std::remove_reference_t<Type>>>::value()); elem !=
nullptr) {
484 return elem->conv(*ctx, storage.data());
487 for(
auto &&curr: from.details->base) {
488 if(
auto other = curr.resolve(internal::meta_context::from(*ctx)).from_void(*ctx,
nullptr, curr.cast(storage.data())); curr.type ==
entt::type_hash<std::remove_const_t<std::remove_reference_t<Type>>>::value()) {
490 }
else if(
auto from_base = std::as_const(other).
template allow_cast<Type>(); from_base) {
506 template<
typename Type>
508 if constexpr(std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>) {
511 if(storage.has_value<std::remove_const_t<std::remove_reference_t<Type>>>()) {
513 }
else if(
auto other = std::as_const(*this).allow_cast<std::remove_const_t<std::remove_reference_t<Type>>>(); other) {
514 if(other.storage.owner()) {
515 std::swap(*
this, other);
526 template<
typename Type,
typename... Args>
528 storage.emplace<Type>(std::forward<Args>(args)...);
529 auto *prev = std::exchange(vtable, &basic_vtable<std::remove_const_t<std::remove_reference_t<Type>>>);
530 node = (prev == vtable) ? node :
nullptr;
552 if(*
this) { vtable(internal::meta_traits::is_sequence_container, *
this, &proxy); }
559 if(*
this) { vtable(internal::meta_traits::is_sequence_container | internal::meta_traits::is_const, *
this, &proxy); }
569 if(*
this) { vtable(internal::meta_traits::is_associative_container, *
this, &proxy); }
576 if(*
this) { vtable(internal::meta_traits::is_associative_container | internal::meta_traits::is_const, *
this, &proxy); }
587 if(*
this) { vtable(internal::meta_traits::is_pointer_like, ret, storage.data()); }
592 [[nodiscard]]
explicit operator bool() const noexcept {
593 return !(vtable ==
nullptr);
597 [[nodiscard]]
bool operator==(
const meta_any &other)
const noexcept {
598 return (ctx == other.ctx) && (!*
this == !other) && (storage == other.storage);
602 [[nodiscard]]
bool operator!=(
const meta_any &other)
const noexcept {
603 return !(*
this == other);
607 [[nodiscard]] meta_any
as_ref() noexcept {
608 return meta_any{*
this, storage.as_ref()};
612 [[nodiscard]] meta_any
as_ref() const noexcept {
613 return meta_any{*
this, storage.as_ref()};
620 [[nodiscard]]
const any &
base() const noexcept {
635 mutable const internal::meta_type_node *node{};
636 vtable_type *vtable{};
646template<
typename Type>
648 return meta_any{ctx, std::in_place_type<Type &&>, std::forward<Type>(value)};
657template<
typename Type>
664 template<
typename Type,
typename... Args,
typename = std::enable_if_t<std::is_same_v<std::decay_t<Type>,
meta_any>>>
666 : any{std::forward<Args>(args)..., value.as_ref()} {}
668 template<
typename Type,
typename... Args>
670 : any{std::forward<Args>(args)..., std::in_place_type<Type &>, value} {}
682 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_handle>>>
684 : meta_handle{0, value, ctx} {}
691 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_handle>>>
693 : meta_handle{0, value} {}
701 : any{area, std::move(other.any)} {}
728 [[nodiscard]]
explicit operator bool() const noexcept {
729 return static_cast<bool>(any);
765 template<
typename Type>
766 [[nodiscard]]
operator Type *()
const noexcept {
767 return ((node !=
nullptr) && (
type_hash<std::remove_const_t<Type>>::value() == node->type)) ?
static_cast<Type *
>(node->value.get()) :
nullptr;
774 template<
typename Type>
775 [[nodiscard]]
operator Type &()
const noexcept {
776 ENTT_ASSERT(
static_cast<Type *
>(*
this) !=
nullptr,
"Invalid type");
777 return *
static_cast<Type *
>(node->value.get());
781 const internal::meta_custom_node *node{};
786 [[nodiscard]]
auto &node_or_assert()
const noexcept {
787 ENTT_ASSERT(node !=
nullptr,
"Invalid pointer to node");
793 using size_type =
typename internal::meta_data_node::size_type;
811 [[nodiscard]]
const char *
name() const noexcept {
812 return node_or_assert().name;
820 return node_or_assert().arity;
828 return !!(node_or_assert().traits & internal::meta_traits::is_const);
836 return !!(node_or_assert().traits & internal::meta_traits::is_static);
850 template<typename Instance =
meta_handle, typename Type>
852 bool set(Instance &&instance, Type &&value)
const {
853 return node_or_assert().set(
meta_handle{*ctx, std::forward<Instance>(instance)},
meta_any{*ctx, std::forward<Type>(value)});
862 template<
typename Instance = meta_handle>
864 return node_or_assert().
get(
meta_handle{*ctx, std::forward<Instance>(instance)});
879 template<
typename Type>
880 [[nodiscard]] Type
traits() const noexcept {
881 return internal::meta_to_user_traits<Type>(node_or_assert().
traits);
889 return {node_or_assert().custom};
896 [[nodiscard]]
explicit operator bool() const noexcept {
897 return (node !=
nullptr);
906 return (ctx == other.ctx) && (node == other.node);
910 const internal::meta_data_node *node{};
921 return !(lhs == rhs);
926 [[nodiscard]]
auto &node_or_assert()
const noexcept {
927 ENTT_ASSERT(node !=
nullptr,
"Invalid pointer to node");
933 using size_type =
typename internal::meta_func_node::size_type;
951 [[nodiscard]]
const char *
name() const noexcept {
952 return node_or_assert().name;
960 return node_or_assert().arity;
968 return !!(node_or_assert().traits & internal::meta_traits::is_const);
976 return !!(node_or_assert().traits & internal::meta_traits::is_static);
1013 template<
typename Instance =
meta_handle,
typename... Args>
1016 return invoke(std::forward<Instance>(instance), std::array<
meta_any,
sizeof...(Args)>{
meta_any{*ctx, std::forward<Args>(args)}...}.data(),
sizeof...(Args));
1020 template<
typename Type>
1022 return internal::meta_to_user_traits<Type>(node_or_assert().
traits);
1027 return {node_or_assert().custom};
1039 [[nodiscard]]
explicit operator bool() const noexcept {
1040 return (node !=
nullptr);
1045 return (ctx == other.ctx) && (node == other.node);
1049 const internal::meta_func_node *node{};
1055 return !(lhs == rhs);
1060 [[nodiscard]]
const auto &fetch_node()
const {
1061 return (node ==
nullptr) ? internal::resolve<void>(internal::meta_context::from(*ctx)) : *node;
1064 template<
typename Func>
1065 [[nodiscard]]
auto lookup(
meta_any *
const args,
const typename internal::meta_type_node::size_type sz, [[maybe_unused]]
bool constness, Func next)
const {
1066 decltype(next()) candidate =
nullptr;
1070 for(
auto curr = next(); curr; curr = next()) {
1071 if constexpr(std::is_same_v<std::decay_t<
decltype(*curr)>, internal::meta_func_node>) {
1072 if(constness && !(curr->traits & internal::meta_traits::is_const)) {
1077 if(curr->arity == sz) {
1082 for(; pos < sz && args[pos]; ++pos) {
1083 const auto other = curr->arg(*ctx, pos);
1084 const auto type = args[pos].type();
1086 if(
const auto &
info = other.info();
info == type.info()) {
1088 }
else if(!(type.fetch_node().conversion_helper && other.fetch_node().conversion_helper) && !(type.fetch_node().details && (internal::find_member<&internal::meta_base_node::type>(type.fetch_node().details->base,
info.hash()) || internal::find_member<&internal::meta_conv_node::type>(type.fetch_node().details->conv,
info.hash())))) {
1095 if(!candidate || match > same) {
1099 }
else if(match == same) {
1100 if constexpr(std::is_same_v<std::decay_t<
decltype(*curr)>, internal::meta_func_node>) {
1101 if(!!(curr->traits & internal::meta_traits::is_const) != !!(candidate->traits & internal::meta_traits::is_const)) {
1102 candidate = !!(candidate->traits & internal::meta_traits::is_const) ? curr : candidate;
1114 return ambiguous ? nullptr : candidate;
1119 using size_type =
typename internal::meta_type_node::size_type;
1139 :
meta_type{area, curr.resolve(internal::meta_context::from(area))} {}
1146 return *fetch_node().info;
1154 return fetch_node().id;
1161 [[nodiscard]]
const char *
name() const noexcept {
1162 return fetch_node().name;
1170 return fetch_node().size_of;
1179 return !!(fetch_node().traits & internal::meta_traits::is_arithmetic);
1187 return !!(fetch_node().traits & internal::meta_traits::is_integral);
1195 return !!(fetch_node().traits & internal::meta_traits::is_signed);
1203 return !!(fetch_node().traits & internal::meta_traits::is_array);
1211 return !!(fetch_node().traits & internal::meta_traits::is_enum);
1219 return !!(fetch_node().traits & internal::meta_traits::is_class);
1227 return !!(fetch_node().traits & internal::meta_traits::is_pointer);
1236 return meta_type{*ctx, fetch_node().remove_pointer(internal::meta_context::from(*ctx))};
1244 return !!(fetch_node().traits & internal::meta_traits::is_pointer_like);
1252 return !!(fetch_node().traits & internal::meta_traits::is_sequence_container);
1260 return !!(fetch_node().traits & internal::meta_traits::is_associative_container);
1268 return (fetch_node().templ.arity != 0u);
1276 return fetch_node().templ.arity;
1284 return (fetch_node().templ.resolve !=
nullptr) ?
meta_type{*ctx, fetch_node().templ.resolve(internal::meta_context::from(*ctx))} :
meta_type{};
1303 return other && ((*
this == other) || (internal::try_cast(internal::meta_context::from(*ctx), fetch_node(), other.fetch_node().info->hash(),
this) !=
nullptr));
1312 if(
const auto &to = other.info().hash(); (
info().hash() == to) || ((fetch_node().conversion_helper !=
nullptr) && (other.is_arithmetic() || other.is_enum()))) {
1314 }
else if(
const auto &from = fetch_node(); from.details) {
1315 if(
const auto *elem = internal::find_member<&internal::meta_conv_node::type>(from.details->conv, to); elem !=
nullptr) {
1319 for(
auto &&curr: from.details->base) {
1320 if(curr.type == to ||
meta_type{*ctx, curr.resolve(internal::meta_context::from(*ctx))}.can_convert(other)) {
1333 [[nodiscard]]
meta_range<
meta_type,
typename decltype(internal::meta_type_descriptor::base)::const_iterator>
base()
const noexcept {
1334 using range_type =
meta_range<
meta_type,
typename decltype(internal::meta_type_descriptor::base)::const_iterator>;
1335 return fetch_node().details ? range_type{{*ctx, fetch_node().details->base.cbegin()}, {*ctx, fetch_node().details->base.cend()}} : range_type{};
1342 [[nodiscard]]
meta_range<
meta_data,
typename decltype(internal::meta_type_descriptor::data)::const_iterator>
data()
const noexcept {
1343 using range_type =
meta_range<
meta_data,
typename decltype(internal::meta_type_descriptor::data)::const_iterator>;
1344 return fetch_node().details ? range_type{{*ctx, fetch_node().details->data.cbegin()}, {*ctx, fetch_node().details->data.cend()}} : range_type{};
1354 const auto *elem = internal::look_for<&internal::meta_type_descriptor::data>(internal::meta_context::from(*ctx), fetch_node(),
id, recursive);
1362 [[nodiscard]]
meta_range<
meta_func,
typename decltype(internal::meta_type_descriptor::func)::const_iterator>
func()
const noexcept {
1363 using return_type =
meta_range<
meta_func,
typename decltype(internal::meta_type_descriptor::func)::const_iterator>;
1364 return fetch_node().details ? return_type{{*ctx, fetch_node().details->func.cbegin()}, {*ctx, fetch_node().details->func.cend()}} : return_type{};
1374 const auto *elem = internal::look_for<&internal::meta_type_descriptor::func>(internal::meta_context::from(*ctx), fetch_node(),
id, recursive);
1385 if(
const auto &
ref = fetch_node();
ref.details) {
1386 if(
const auto *candidate = lookup(args, sz,
false, [first =
ref.details->ctor.cbegin(), last =
ref.details->ctor.cend()]()
mutable { return first == last ? nullptr : &*(first++); }); candidate) {
1387 return candidate->invoke(*ctx, args);
1391 if(
const auto &
ref = fetch_node(); (sz == 0u) && (
ref.default_constructor !=
nullptr)) {
1392 return ref.default_constructor(*ctx);
1404 template<
typename... Args>
1406 return construct(std::array<
meta_any,
sizeof...(Args)>{
meta_any{*ctx, std::forward<Args>(args)}...}.data(),
sizeof...(Args));
1417 return ((elem !=
nullptr) && (fetch_node().
from_void !=
nullptr)) ? fetch_node().from_void(*ctx, elem, transfer_ownership ? elem :
nullptr) :
meta_any{
meta_ctx_arg, *ctx};
1426 return ((elem !=
nullptr) && (fetch_node().
from_void !=
nullptr)) ? fetch_node().from_void(*ctx,
nullptr, elem) :
meta_any{
meta_ctx_arg, *ctx};
1438 template<
typename Instance = meta_handle>
1441 meta_handle wrapped{*ctx, std::forward<Instance>(instance)};
1443 if(
const auto &
ref = fetch_node();
ref.details) {
1444 if(
auto *elem = internal::find_member<&internal::meta_func_node::id>(
ref.details->func,
id); elem !=
nullptr) {
1445 if(
const auto *candidate = lookup(args, sz, (wrapped->
base().
policy() ==
any_policy::cref), [curr = elem]()
mutable { return (curr != nullptr) ? std::exchange(curr, curr->next.get()) : nullptr; }); candidate) {
1446 return candidate->invoke(std::move(wrapped), args);
1451 for(
auto &&curr:
base()) {
1452 if(
auto elem = curr.second.invoke(
id, *wrapped.operator->(), args, sz); elem) {
1469 template<
typename Instance =
meta_handle,
typename... Args>
1472 return invoke(
id, std::forward<Instance>(instance), std::array<
meta_any,
sizeof...(Args)>{
meta_any{*ctx, std::forward<Args>(args)}...}.data(),
sizeof...(Args));
1484 template<
typename Instance = meta_handle,
typename Type>
1486 bool set(
const id_type id, Instance &&instance, Type &&value)
const {
1487 const auto candidate =
data(
id);
1488 return candidate && candidate.set(std::forward<Instance>(instance), std::forward<Type>(value));
1498 template<
typename Instance = meta_handle>
1500 const auto candidate =
data(
id);
1501 return candidate ? candidate.get(std::forward<Instance>(instance)) :
meta_any{
meta_ctx_arg, *ctx};
1505 template<
typename Type>
1507 return internal::meta_to_user_traits<Type>(fetch_node().
traits);
1512 return fetch_node().custom;
1516 [[nodiscard]]
explicit operator bool() const noexcept {
1517 return (node !=
nullptr);
1522 return (ctx == other.ctx) && (fetch_node().id == other.fetch_node().id);
1526 mutable const internal::meta_type_node *node{};
1532 return !(lhs == rhs);
1539template<
typename... Args>
1542 return type().
invoke(
id, *
this, std::forward<Args>(args)...);
1545template<
typename... Args>
1547 return type().
invoke(
id, *
this, std::forward<Args>(args)...);
1550template<
typename Type>
1552 return type().
set(
id, *
this, std::forward<Type>(value));
1564 if(storage.has_value(
type.info())) {
1567 if(
const auto &from = fetch_node(); (from.conversion_helper !=
nullptr) && (
type.is_arithmetic() ||
type.is_enum())) {
1568 auto other =
type.construct();
1569 const auto value = from.conversion_helper(
nullptr, storage.data());
1570 other.fetch_node().conversion_helper(other.storage.data(), &value);
1574 if(
const auto &from = fetch_node(); from.details) {
1575 if(
const auto *elem = internal::find_member<&internal::meta_conv_node::type>(from.details->conv,
type.info().hash()); elem !=
nullptr) {
1576 return elem->conv(*ctx, storage.data());
1579 for(
auto &&curr: from.details->base) {
1580 if(
auto other = curr.resolve(internal::meta_context::from(*ctx)).from_void(*ctx,
nullptr, curr.cast(storage.data())); curr.type ==
type.info().hash()) {
1582 }
else if(
auto from_base = std::as_const(other).
allow_cast(
type); from_base) {
1593 if(storage.has_value(
type.info())) {
1595 }
else if(
auto other = std::as_const(*this).allow_cast(
type); other) {
1596 if(other.storage.owner()) {
1597 std::swap(*
this, other);
1607 if(!storage.assign(other.storage)) {
1609 return storage.
assign(value.storage);
1616 return storage.
assign(std::move(other.storage)) || storage.assign(std::as_const(other).
allow_cast(
type()).storage);
1620 return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))};
1624 return index <
arity() ? node_or_assert().arg(*ctx, index) :
meta_type{};
1628 return meta_type{*ctx, node_or_assert().ret(internal::meta_context::from(*ctx))};
1632 return index <
arity() ? node_or_assert().arg(*ctx, index) :
meta_type{};
1636class meta_sequence_container::meta_iterator final {
1637 using vtable_type = void(
const void *,
const std::ptrdiff_t,
meta_any *);
1639 template<
typename It>
1640 static void basic_vtable(
const void *value,
const std::ptrdiff_t offset,
meta_any *other) {
1641 const auto &it = *
static_cast<const It *
>(value);
1642 other ? other->
emplace<
decltype(*it)>(*it) : std::advance(
const_cast<It &
>(it), offset);
1646 using value_type = meta_any;
1647 using pointer = input_iterator_pointer<value_type>;
1648 using reference = value_type;
1649 using difference_type = std::ptrdiff_t;
1650 using iterator_category = std::input_iterator_tag;
1651 using iterator_concept = std::bidirectional_iterator_tag;
1653 meta_iterator() =
default;
1655 template<
typename It>
1656 meta_iterator(
const meta_ctx &area, It iter) noexcept
1658 vtable{&basic_vtable<It>},
1661 meta_iterator &operator++() noexcept {
1662 return vtable(
handle.data(), 1,
nullptr), *
this;
1665 meta_iterator operator++(
int value)
noexcept {
1666 meta_iterator orig = *
this;
1667 vtable(
handle.data(), ++value,
nullptr);
1671 meta_iterator &operator--() noexcept {
1672 return vtable(
handle.data(), -1,
nullptr), *
this;
1675 meta_iterator operator--(
int value)
noexcept {
1676 meta_iterator orig = *
this;
1677 vtable(
handle.data(), --value,
nullptr);
1681 [[nodiscard]] reference operator*()
const {
1683 vtable(
handle.data(), 0, &other);
1687 [[nodiscard]] pointer operator->()
const {
1691 [[nodiscard]]
explicit operator bool() const noexcept {
1692 return (vtable !=
nullptr);
1695 [[nodiscard]]
bool operator==(
const meta_iterator &other)
const noexcept {
1696 return handle == other.handle;
1699 [[nodiscard]]
const any &base() const noexcept {
1704 const meta_ctx *ctx{};
1705 vtable_type *vtable{};
1710 return !(lhs == rhs);
1713class meta_associative_container::meta_iterator final {
1714 using vtable_type = void(
const void *, std::pair<meta_any, meta_any> *);
1716 template<
bool KeyOnly,
typename It>
1717 static void basic_vtable(
const void *value, std::pair<meta_any, meta_any> *other) {
1718 if(
const auto &it = *
static_cast<const It *
>(value); other) {
1719 if constexpr(KeyOnly) {
1720 other->first.emplace<
decltype(*it)>(*it);
1722 other->first.emplace<
decltype((it->first))>(it->first);
1723 other->second.emplace<
decltype((it->second))>(it->second);
1726 ++
const_cast<It &
>(it);
1731 using value_type = std::pair<meta_any, meta_any>;
1732 using pointer = input_iterator_pointer<value_type>;
1733 using reference = value_type;
1734 using difference_type = std::ptrdiff_t;
1735 using iterator_category = std::input_iterator_tag;
1736 using iterator_concept = std::forward_iterator_tag;
1738 meta_iterator() =
default;
1740 template<
bool KeyOnly,
typename It>
1741 meta_iterator(
const meta_ctx &area, std::bool_constant<KeyOnly>, It iter) noexcept
1743 vtable{&basic_vtable<KeyOnly, It>},
1746 meta_iterator &operator++() noexcept {
1747 return vtable(
handle.data(),
nullptr), *
this;
1750 meta_iterator operator++(
int)
noexcept {
1751 meta_iterator orig = *
this;
1752 vtable(
handle.data(),
nullptr);
1756 [[nodiscard]] reference operator*()
const {
1758 vtable(
handle.data(), &other);
1762 [[nodiscard]] pointer operator->()
const {
1766 [[nodiscard]]
explicit operator bool() const noexcept {
1767 return (vtable !=
nullptr);
1770 [[nodiscard]]
bool operator==(
const meta_iterator &other)
const noexcept {
1771 return handle == other.handle;
1775 const meta_ctx *ctx{};
1776 vtable_type *vtable{};
1781 return !(lhs == rhs);
1790 return (value_type_node !=
nullptr) ?
meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} :
meta_type{};
1798 return size_fn(data);
1807 return !const_only && resize_fn(
const_cast<void *
>(data), sz);
1815 return !const_only && clear_fn(
const_cast<void *
>(data));
1824 return !const_only && reserve_fn(
const_cast<void *
>(data), sz);
1832 return begin_end_fn(*ctx, const_only ?
nullptr :
const_cast<void *
>(data), data,
false);
1840 return begin_end_fn(*ctx, const_only ?
nullptr :
const_cast<void *
>(data), data,
true);
1851 if(
const auto &vtype = value_type_node(internal::meta_context::from(*ctx)); !const_only && (value.
allow_cast({*ctx, vtype}) || value.
allow_cast({*ctx, const_reference_node(internal::meta_context::from(*ctx))}))) {
1852 const bool is_value_type = (value.
type().info() == *vtype.
info);
1853 return insert_fn(*ctx,
const_cast<void *
>(data), is_value_type ? value.
base().
data() :
nullptr, is_value_type ?
nullptr : value.
base().
data(), it);
1865 return const_only ?
iterator{} : erase_fn(*ctx,
const_cast<void *
>(data), it);
1875 it.operator++(
static_cast<int>(pos) - 1);
1883[[nodiscard]]
inline meta_sequence_container::operator bool() const noexcept {
1884 return (data !=
nullptr);
1892 return (key_type_node !=
nullptr) ?
meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))} :
meta_type{};
1900 return (mapped_type_node !=
nullptr) ?
meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))} :
meta_type{};
1905 return (value_type_node !=
nullptr) ?
meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} :
meta_type{};
1910 return size_fn(data);
1915 return !const_only && clear_fn(
const_cast<void *
>(data));
1920 return !const_only && reserve_fn(
const_cast<void *
>(data), sz);
1925 return begin_end_fn(*ctx, const_only ?
nullptr :
const_cast<void *
>(data), data,
false);
1930 return begin_end_fn(*ctx, const_only ?
nullptr :
const_cast<void *
>(data), data,
true);
1940 return !const_only && key.
allow_cast(
meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})
1941 && ((mapped_type_node ==
nullptr) || value.allow_cast(meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))}))
1942 && insert_fn(
const_cast<void *
>(data), key.
base().
data(), value.base().data());
1951 return (!const_only && key.
allow_cast(
meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})) ? erase_fn(
const_cast<void *
>(data), key.
base().
data()) : 0u;
1960 return key.
allow_cast(
meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) ? find_fn(*ctx, const_only ?
nullptr :
const_cast<void *
>(data), data, key.
base().
data()) :
iterator{};
1967[[nodiscard]]
inline meta_associative_container::operator bool() const noexcept {
1968 return (data !=
nullptr);
const void * data() const noexcept
Returns an opaque pointer to the contained instance.
any_policy policy() const noexcept
Returns the current mode of an any object.
Service locator, nothing more.
static Service & value_or(Args &&...args)
Returns a service if available or sets it from a fallback type.
basic_handle< registry > handle
Alias declaration for the most common use case.
std::remove_const_t< Type > any_cast(const basic_any< Len, Align > &data) noexcept
Performs type-safe access to the contained object.
std::uint32_t id_type
Alias declaration for type identifiers.
basic_any<> any
Alias declaration for the most common use case.
iterable_adaptor< internal::meta_range_iterator< Type, It > > meta_range
Iterable range to use to iterate all types of meta objects.
constexpr bool is_complete_v
Helper variable template.
constexpr get_t< Type... > get
Variable template for lists of observed elements.
constexpr meta_ctx_arg_t meta_ctx_arg
Constant of type meta_context_arg_t used to disambiguate calls.
constexpr auto is_meta_pointer_like_v
Helper variable template.
@ in_place
In-place deletion policy.
meta_any forward_as_meta(const meta_ctx &ctx, Type &&value)
Forwards its argument and avoids copies for lvalue references.
void invoke(Registry ®, const typename Registry::entity_type entt)
Helper to create a listener that directly invokes a member function.
constexpr bool operator!=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
@ ref
Aliasing mode, non-const reference.
@ cref
Const aliasing mode, const reference.
constexpr bool operator==(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
basic_storage< Type > storage
Alias declaration for the most common use case.
Implementation specific information about a type.