1#ifndef ENTT_META_META_HPP
2#define ENTT_META_META_HPP
9#include "../config/config.h"
10#include "../core/any.hpp"
11#include "../core/fwd.hpp"
12#include "../core/iterator.hpp"
13#include "../core/type_info.hpp"
14#include "../core/type_traits.hpp"
15#include "../core/utility.hpp"
16#include "../locator/locator.hpp"
17#include "adl_pointer.hpp"
22#include "type_traits.hpp"
55 template<
typename Type>
56 void rebind(Type &instance)
noexcept {
57 value_type_node = &internal::resolve<typename Type::value_type>;
58 const_reference_node = &internal::resolve<std::remove_const_t<std::remove_reference_t<typename Type::const_reference>>>;
67 const_only = std::is_const_v<Type>;
85 internal::meta_type_node (*value_type_node)(
const internal::meta_context &){};
86 internal::meta_type_node (*const_reference_node)(
const internal::meta_context &){};
88 bool (*clear_fn)(
void *){};
91 iterator (*begin_fn)(
const meta_ctx &,
void *,
const void *){};
92 iterator (*end_fn)(
const meta_ctx &,
void *,
const void *){};
93 iterator (*insert_fn)(
const meta_ctx &,
void *,
const void *,
const void *,
const iterator &){};
125 template<
typename Type>
127 key_type_node = &internal::resolve<typename Type::key_type>;
128 value_type_node = &internal::resolve<typename Type::value_type>;
131 mapped_type_node = &internal::resolve<typename Type::mapped_type>;
142 const_only = std::is_const_v<Type>;
162 internal::meta_type_node (*key_type_node)(
const internal::meta_context &){};
163 internal::meta_type_node (*mapped_type_node)(
const internal::meta_context &){};
164 internal::meta_type_node (*value_type_node)(
const internal::meta_context &){};
166 bool (*clear_fn)(
void *){};
168 iterator (*begin_fn)(
const meta_ctx &,
void *,
const void *){};
169 iterator (*end_fn)(
const meta_ctx &,
void *,
const void *){};
170 bool (*insert_fn)(
void *,
const void *,
const void *){};
171 size_type (*erase_fn)(
void *,
const void *){};
172 iterator (*find_fn)(
const meta_ctx &,
void *,
const void *,
const void *){};
182 using vtable_type =
void(
const internal::meta_traits
op,
const bool,
const void *,
void *);
184 template<
typename Type>
187 if(
req == internal::meta_traits::is_meta_pointer_like) {
188 if constexpr(std::is_function_v<typename std::pointer_traits<Type>::element_type>) {
190 }
else if constexpr(!std::is_void_v<std::remove_const_t<typename std::pointer_traits<Type>::element_type>>) {
193 if constexpr(std::is_constructible_v<bool, Type>) {
205 if(
req == internal::meta_traits::is_meta_sequence_container) {
211 if(
req == internal::meta_traits::is_meta_associative_container) {
226 node{
storage ?
other.node : internal::meta_type_node{}},
250 template<
typename Type,
typename...
Args>
261 template<
typename Type,
typename...
Args>
273 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
283 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
295 node = node.resolve ? node.resolve(internal::meta_context::from(*ctx)) : node;
306 node = node.resolve ? node.resolve(internal::meta_context::from(*ctx)) : node;
322 node{std::exchange(
other.node, internal::meta_type_node{})},
340 vtable =
other.vtable;
353 node = std::exchange(
other.node, internal::meta_type_node{});
364 template<
typename Type>
391 template<
typename...
Args>
395 template<
typename...
Args>
405 template<
typename Type>
423 template<
typename Type>
425 const auto other = internal::resolve<std::remove_cv_t<Type>>(internal::meta_context::from(*ctx));
426 return static_cast<const Type *
>(internal::try_cast(internal::meta_context::from(*ctx), node,
other,
data()));
430 template<
typename Type>
432 if constexpr(std::is_const_v<Type>) {
433 return std::as_const(*this).try_cast<std::remove_const_t<Type>>();
435 const auto other = internal::resolve<std::remove_cv_t<Type>>(internal::meta_context::from(*ctx));
436 return static_cast<Type *
>(
const_cast<void *
>(internal::try_cast(internal::meta_context::from(*ctx), node,
other,
data())));
445 template<
typename Type>
448 ENTT_ASSERT(instance,
"Invalid instance");
449 return static_cast<Type
>(*instance);
453 template<
typename Type>
457 ENTT_ASSERT(instance,
"Invalid instance");
458 return static_cast<Type
>(*instance);
477 std::swap(*
this,
other);
492 template<
typename Type>
494 if constexpr(std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>) {
497 auto other = internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(internal::meta_context::from(*ctx));
507 template<
typename Type>
509 auto other = internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(internal::meta_context::from(*ctx));
514 template<
typename Type,
typename...
Args>
518 node = internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(internal::meta_context::from(*ctx));
549 vtable(internal::meta_traits::is_meta_sequence_container,
true,
data(), &
proxy);
566 vtable(internal::meta_traits::is_meta_associative_container,
true,
data(), &
proxy);
577 vtable(internal::meta_traits::is_meta_pointer_like,
true,
storage.
data(), &ret);
586 return !(node.info ==
nullptr);
591 return (ctx ==
other.ctx) && ((!node.info && !
other.node.info) || (node.info &&
other.node.info && *node.info == *
other.node.info &&
storage ==
other.storage));
596 return !(*
this ==
other);
625 internal::meta_type_node node;
636template<
typename Type>
638 return meta_any{ctx, std::in_place_type<Type &&>, std::forward<Type>(value)};
647template<
typename Type>
690 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_handle>>>
692 :
any{ctx, std::in_place_type<Type &>, value} {}
699 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_handle>>>
742 return static_cast<bool>(
any);
752 return !(*
this ==
other);
793 return node->value ? node->type(internal::meta_context::from(*ctx)).from_void(*ctx,
nullptr, node->value.get()) :
meta_any{
meta_ctx_arg, *ctx};
801 return node->value ? node->type(internal::meta_context::from(*ctx)).from_void(*ctx, node->value.get(),
nullptr) :
meta_any{
meta_ctx_arg, *ctx};
809 return (node !=
nullptr);
818 return (ctx ==
other.ctx && node ==
other.node);
822 const internal::meta_prop_node *node;
839 using size_type =
typename internal::meta_data_node::size_type;
868 return static_cast<bool>(node->traits & internal::meta_traits::is_const);
876 return static_cast<bool>(node->traits & internal::meta_traits::is_static);
891 return node->set && node->set(
meta_handle{*ctx, std::move(instance)},
meta_any{*ctx, std::forward<Type>(value)});
900 return node->get(*ctx,
meta_handle{*ctx, std::move(instance)});
915 return {{*ctx, node->prop.cbegin()}, {*ctx, node->prop.cend()}};
924 const auto it = node->prop.find(
key);
933 return (node !=
nullptr);
938 return (ctx ==
other.ctx && node ==
other.node);
942 const internal::meta_data_node *node;
959 using size_type =
typename internal::meta_func_node::size_type;
988 return static_cast<bool>(node->traits & internal::meta_traits::is_const);
996 return static_cast<bool>(node->traits & internal::meta_traits::is_static);
1034 template<
typename...
Args>
1042 return {{*ctx, node->prop.cbegin()}, {*ctx, node->prop.cend()}};
1051 const auto it = node->prop.find(
key);
1068 return (node !=
nullptr);
1073 return (ctx ==
other.ctx && node ==
other.node);
1077 const internal::meta_func_node *node;
1093 template<
typename Func>
1100 if constexpr(std::is_same_v<std::decay_t<
decltype(*curr)>, internal::meta_func_node>) {
1101 if(
constness && !
static_cast<bool>(
curr->traits & internal::meta_traits::is_const)) {
1112 const auto type =
args[
pos].type();
1116 }
else if(!((type.node.details && (type.node.details->base.contains(
info.
hash()) || type.node.details->conv.contains(
info.
hash()))) || (type.node.conversion_helper &&
other.node.conversion_helper))) {
1127 if constexpr(std::is_same_v<std::decay_t<
decltype(*curr)>, internal::meta_func_node>) {
1128 if(
static_cast<bool>(
curr->traits & internal::meta_traits::is_const) !=
static_cast<bool>(
candidate->traits & internal::meta_traits::is_const)) {
1146 using size_type =
typename internal::meta_type_node::size_type;
1191 return node.size_of;
1200 return static_cast<bool>(node.traits & internal::meta_traits::is_arithmetic);
1208 return static_cast<bool>(node.traits & internal::meta_traits::is_integral);
1216 return static_cast<bool>(node.traits & internal::meta_traits::is_signed);
1224 return static_cast<bool>(node.traits & internal::meta_traits::is_array);
1232 return static_cast<bool>(node.traits & internal::meta_traits::is_enum);
1240 return static_cast<bool>(node.traits & internal::meta_traits::is_class);
1257 return {*ctx, node.remove_pointer(internal::meta_context::from(*ctx))};
1265 return static_cast<bool>(node.traits & internal::meta_traits::is_meta_pointer_like);
1273 return static_cast<bool>(node.traits & internal::meta_traits::is_meta_sequence_container);
1281 return static_cast<bool>(node.traits & internal::meta_traits::is_meta_associative_container);
1291 return (node.templ.arity != 0
u);
1299 return node.templ.arity;
1307 return node.templ.type ?
meta_type{*ctx, node.templ.type(internal::meta_context::from(*ctx))} :
meta_type{};
1326 return (internal::try_cast(internal::meta_context::from(*ctx), node,
other.node,
this) !=
nullptr);
1335 return (internal::try_convert(internal::meta_context::from(*ctx), node,
other.info(),
other.is_arithmetic() ||
other.is_enum(),
nullptr, [](
const void *,
auto &&...args) { return ((static_cast<void>(args), 1) + ... + 0u); }) != 0
u);
1344 return node.details ?
range_type{{*ctx, node.details->base.cbegin()}, {*ctx, node.details->base.cend()}} :
range_type{};
1353 return node.details ?
range_type{{*ctx, node.details->data.cbegin()}, {*ctx, node.details->data.cend()}} :
range_type{};
1362 const auto *
elem = internal::look_for<&internal::meta_type_descriptor::data>(internal::meta_context::from(*ctx), node,
id);
1371 using return_type =
meta_range<
meta_func,
typename decltype(internal::meta_type_descriptor::func)::const_iterator>;
1372 return node.details ? return_type{{*ctx, node.details->func.cbegin()}, {*ctx, node.details->func.cend()}} : return_type{};
1384 const auto *
elem = internal::look_for<&internal::meta_type_descriptor::func>(internal::meta_context::from(*ctx), node,
id);
1400 if(
const auto *
candidate = lookup(
args,
sz,
false, [first = node.details->ctor.cbegin(), last = node.details->ctor.cend()]()
mutable { return first == last ? nullptr : &(first++)->second; });
candidate) {
1405 if(
sz == 0
u && node.default_constructor) {
1406 return node.default_constructor(*ctx);
1418 template<
typename...
Args>
1452 if(
auto it = node.details->func.find(
id);
it != node.details->func.cend()) {
1453 if(
const auto *
candidate = lookup(
args,
sz, instance && (instance->
data() ==
nullptr), [
curr = &
it->second]()
mutable { return curr ? std::exchange(curr, curr->next.get()) : nullptr; });
candidate) {
1476 template<
typename...
Args>
1490 template<
typename Type>
1513 return node.details ?
range_type{{*ctx, node.details->prop.cbegin()}, {*ctx, node.details->prop.cend()}} :
range_type{};
1522 const auto *
elem = internal::look_for<&internal::meta_type_descriptor::prop>(internal::meta_context::from(*ctx), node,
key);
1531 return !(ctx ==
nullptr);
1536 return (ctx ==
other.ctx) && ((!node.info && !
other.node.info) || (node.info &&
other.node.info && *node.info == *
other.node.info));
1540 internal::meta_type_node node;
1558template<
typename...
Args>
1563template<
typename...
Args>
1568template<
typename Type>
1570 return type().
set(
id, *
this, std::forward<Type>(value));
1583 if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<
decltype(
args)>>, internal::meta_type_node> || ...)) {
1584 return (
args.from_void(*ctx,
nullptr, instance), ...);
1585 }
else if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<
decltype(
args)>>, internal::meta_conv_node> || ...)) {
1586 return (
args.conv(*ctx, instance), ...);
1587 }
else if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<
decltype(
args)>>,
decltype(internal::meta_type_node::conversion_helper)> || ...)) {
1590 const auto value = (
args(
nullptr, instance), ...);
1591 other.node.conversion_helper(
other.data(), &value);
1601 auto value =
other.allow_cast({*ctx, node});
1602 return value &&
storage.assign(value.storage);
1606 if(*node.info == *
other.node.info) {
1614 return meta_type{*ctx, node->type(internal::meta_context::from(*ctx))};
1618 return index < arity() ? node->arg(*ctx, index) :
meta_type{};
1622 return meta_type{*ctx, node->ret(internal::meta_context::from(*ctx))};
1626 return index < arity() ? node->arg(*ctx, index) :
meta_type{};
1630class meta_sequence_container::meta_iterator
final {
1631 using vtable_type = void(
const void *,
const std::ptrdiff_t,
meta_any *);
1633 template<
typename It>
1634 static void basic_vtable(
const void *value,
const std::ptrdiff_t offset,
meta_any *other) {
1635 const auto &it = *
static_cast<const It *
>(value);
1636 other ? other->
emplace<
decltype(*it)>(*it) : std::advance(
const_cast<It &
>(it), offset);
1640 using difference_type = std::ptrdiff_t;
1641 using value_type = meta_any;
1642 using pointer = input_iterator_pointer<value_type>;
1643 using reference = value_type;
1644 using iterator_category = std::input_iterator_tag;
1645 using iterator_concept = std::bidirectional_iterator_tag;
1647 meta_iterator() noexcept
1648 : meta_iterator{locator<meta_ctx>::value_or()} {}
1650 meta_iterator(
const meta_ctx &area) noexcept
1653 template<
typename It>
1654 meta_iterator(
const meta_ctx &area, It iter) noexcept
1656 vtable{&basic_vtable<It>},
1659 meta_iterator &operator++() noexcept {
1660 vtable(
handle.data(), 1,
nullptr);
1664 meta_iterator operator++(
int value)
noexcept {
1665 meta_iterator orig = *
this;
1666 vtable(
handle.data(), ++value,
nullptr);
1670 meta_iterator &operator--() noexcept {
1671 vtable(
handle.data(), -1,
nullptr);
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 static_cast<bool>(
handle);
1695 [[nodiscard]]
bool operator==(
const meta_iterator &other)
const noexcept {
1696 return handle == other.handle;
1699 [[nodiscard]]
bool operator!=(
const meta_iterator &other)
const noexcept {
1700 return !(*
this == other);
1703 [[nodiscard]]
const any &base() const noexcept {
1708 const meta_ctx *ctx{};
1709 vtable_type *vtable{};
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 difference_type = std::ptrdiff_t;
1732 using value_type = std::pair<meta_any, meta_any>;
1733 using pointer = input_iterator_pointer<value_type>;
1734 using reference = value_type;
1735 using iterator_category = std::input_iterator_tag;
1736 using iterator_concept = std::forward_iterator_tag;
1738 meta_iterator() noexcept
1739 : meta_iterator{locator<meta_ctx>::value_or()} {}
1741 meta_iterator(
const meta_ctx &area) noexcept
1744 template<
bool KeyOnly,
typename It>
1745 meta_iterator(
const meta_ctx &area, std::bool_constant<KeyOnly>, It iter) noexcept
1747 vtable{&basic_vtable<KeyOnly, It>},
1750 meta_iterator &operator++() noexcept {
1751 vtable(
handle.data(),
nullptr);
1755 meta_iterator operator++(
int)
noexcept {
1756 meta_iterator orig = *
this;
1757 vtable(
handle.data(),
nullptr);
1761 [[nodiscard]] reference operator*()
const {
1763 vtable(
handle.data(), &other);
1767 [[nodiscard]] pointer operator->()
const {
1771 [[nodiscard]]
explicit operator bool() const noexcept {
1772 return static_cast<bool>(
handle);
1775 [[nodiscard]]
bool operator==(
const meta_iterator &other)
const noexcept {
1776 return handle == other.handle;
1779 [[nodiscard]]
bool operator!=(
const meta_iterator &other)
const noexcept {
1780 return !(*
this == other);
1784 const meta_ctx *ctx{};
1785 vtable_type *vtable{};
1795 return value_type_node ?
meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} :
meta_type{};
1803 return size_fn(data);
1812 return !const_only && resize_fn(
const_cast<void *
>(data),
sz);
1820 return !const_only && clear_fn(
const_cast<void *
>(data));
1829 return !const_only && reserve_fn(
const_cast<void *
>(data),
sz);
1837 return begin_fn(*ctx, const_only ?
nullptr :
const_cast<void *
>(data), data);
1845 return end_fn(*ctx, const_only ?
nullptr :
const_cast<void *
>(data), data);
1856 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))}))) {
1870 return const_only ?
iterator{*ctx} : erase_fn(*ctx,
const_cast<void *
>(data),
it);
1881 it.operator++(
static_cast<int>(
pos) - 1);
1890 return (data !=
nullptr);
1898 return (mapped_type_node ==
nullptr);
1906 return key_type_node ?
meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))} :
meta_type{};
1914 return mapped_type_node ?
meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))} :
meta_type{};
1919 return value_type_node ?
meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} :
meta_type{};
1924 return size_fn(data);
1929 return !const_only && clear_fn(
const_cast<void *
>(data));
1934 return !const_only && reserve_fn(
const_cast<void *
>(data),
sz);
1939 return begin_fn(*ctx, const_only ?
nullptr :
const_cast<void *
>(data), data);
1944 return end_fn(*ctx, const_only ?
nullptr :
const_cast<void *
>(data), data);
1954 return !const_only &&
key.allow_cast(
meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})
1955 && (!mapped_type_node || value.allow_cast(meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))}))
1956 && insert_fn(
const_cast<void *
>(data), std::as_const(
key).data(), std::as_const(value).data());
1965 return (!const_only &&
key.allow_cast(
meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})) ? erase_fn(
const_cast<void *
>(data), std::as_const(
key).data()) : 0
u;
1974 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, std::as_const(
key).data()) :
iterator{*ctx};
1982 return (data !=
nullptr);
basic_any as_ref() noexcept
Aliasing constructor.
pointer data() const noexcept
Direct access to the internal packed array.
deletion_policy policy() const noexcept
Returns the deletion policy of a sparse set.
Basic storage implementation.
value_type & emplace(const entity_type entt, Args &&...args)
Assigns an entity to a storage and constructs its object.
Service locator, nothing more.
static Service & value_or(Args &&...args)
Returns a service if available or sets it from a fallback type.
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
basic_handle< registry > handle
Alias declaration for the most common use case.
basic_any<> any
Alias declaration for the most common use case.
std::uint32_t id_type
Alias declaration for type identifiers.
constexpr get_t< Type... > get
Variable template for lists of observed components.
meta_type resolve() noexcept
Returns the meta type associated with a given type.
constexpr meta_ctx_arg_t meta_ctx_arg
Constant of type meta_context_arg_t used to disambiguate calls.
meta_any forward_as_meta(const meta_ctx &ctx, Type &&value)
Forwards its argument and avoids copies for lvalue references.
constexpr bool operator!=(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
any_policy
Possible modes of an any object.
@ ref
Aliasing mode, the object points to a non-const element.
@ cref
Const aliasing mode, the object points to a const element.
@ owner
Default mode, the object owns the contained element.
constexpr bool operator==(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs) noexcept
Compares two hashed strings.
Utility class to create an iterable object from a pair of iterators.
Implementation specific information about a type.
constexpr id_type hash() const noexcept
Type hash.