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"
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 &){};
124 template<
typename Type>
126 key_type_node = &internal::resolve<typename Type::key_type>;
127 value_type_node = &internal::resolve<typename Type::value_type>;
130 mapped_type_node = &internal::resolve<typename Type::mapped_type>;
141 const_only = std::is_const_v<Type>;
160 internal::meta_type_node (*key_type_node)(
const internal::meta_context &){};
161 internal::meta_type_node (*mapped_type_node)(
const internal::meta_context &){};
162 internal::meta_type_node (*value_type_node)(
const internal::meta_context &){};
164 bool (*clear_fn)(
void *){};
166 iterator (*begin_fn)(
const meta_ctx &,
void *,
const void *){};
167 iterator (*end_fn)(
const meta_ctx &,
void *,
const void *){};
168 bool (*insert_fn)(
void *,
const void *,
const void *){};
169 size_type (*erase_fn)(
void *,
const void *){};
170 iterator (*find_fn)(
const meta_ctx &,
void *,
const void *,
const void *){};
180 using vtable_type =
void(
const internal::meta_traits
op,
const bool,
const void *,
void *);
182 template<
typename Type>
185 if(
req == internal::meta_traits::is_meta_pointer_like) {
186 if constexpr(std::is_function_v<typename std::pointer_traits<Type>::element_type>) {
188 }
else if constexpr(!std::is_void_v<std::remove_const_t<typename std::pointer_traits<Type>::element_type>>) {
191 if constexpr(std::is_constructible_v<bool, Type>) {
203 if(
req == internal::meta_traits::is_meta_sequence_container) {
209 if(
req == internal::meta_traits::is_meta_associative_container) {
224 node{
storage ?
other.node : internal::meta_type_node{}},
244 template<
typename Type,
typename...
Args>
255 template<
typename Type,
typename...
Args>
267 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
277 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
290 vtable{
other.vtable} {}
316 node{std::exchange(
other.node, internal::meta_type_node{})},
335 vtable =
other.vtable;
347 ENTT_ASSERT(
this != &
other,
"Self move assignment");
352 node = std::exchange(
other.node, internal::meta_type_node{});
363 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
389 template<
typename...
Args>
393 template<
typename...
Args>
403 template<
typename Type>
421 template<
typename Type>
423 const auto other = internal::resolve<std::remove_cv_t<Type>>(internal::meta_context::from(*ctx));
424 return static_cast<const Type *
>(internal::try_cast(internal::meta_context::from(*ctx), node,
other,
data()));
428 template<
typename Type>
430 if constexpr(std::is_const_v<Type>) {
431 return std::as_const(*this).try_cast<std::remove_const_t<Type>>();
433 const auto other = internal::resolve<std::remove_cv_t<Type>>(internal::meta_context::from(*ctx));
434 return static_cast<Type *
>(
const_cast<void *
>(internal::try_cast(internal::meta_context::from(*ctx), node,
other,
data())));
443 template<
typename Type>
446 ENTT_ASSERT(instance,
"Invalid instance");
447 return static_cast<Type
>(*instance);
451 template<
typename Type>
455 ENTT_ASSERT(instance,
"Invalid instance");
456 return static_cast<Type
>(*instance);
475 std::swap(*
this,
other);
490 template<
typename Type>
492 if constexpr(std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>) {
495 auto other = internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(internal::meta_context::from(*ctx));
505 template<
typename Type>
507 auto other = internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(internal::meta_context::from(*ctx));
512 template<
typename Type,
typename...
Args>
516 node = internal::resolve<std::remove_cv_t<std::remove_reference_t<Type>>>(internal::meta_context::from(*ctx));
547 vtable(internal::meta_traits::is_meta_sequence_container,
true,
data(), &
proxy);
564 vtable(internal::meta_traits::is_meta_associative_container,
true,
data(), &
proxy);
575 vtable(internal::meta_traits::is_meta_pointer_like,
true,
storage.
data(), &ret);
584 return !(node.info ==
nullptr);
589 return (ctx ==
other.ctx) && (((node.info ==
nullptr) && (
other.node.info ==
nullptr)) || ((node.info !=
nullptr) && (
other.node.info !=
nullptr) && *node.info == *
other.node.info &&
storage ==
other.storage));
594 return !(*
this ==
other);
618 internal::meta_type_node node{};
629template<
typename Type>
631 return meta_any{ctx, std::in_place_type<Type &&>, std::forward<Type>(value)};
640template<
typename Type>
667 :
any{value.as_ref()} {}
674 :
any{value.as_ref()} {}
682 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_handle>>>
691 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_handle>>>
737 return static_cast<bool>(
any);
747 return !(*
this ==
other);
778 : node{std::move(
curr)},
786 return node.value ? node.type(internal::meta_context::from(*ctx)).from_void(*ctx,
nullptr, node.value.get()) :
meta_any{
meta_ctx_arg, *ctx};
794 return node.value ? node.type(internal::meta_context::from(*ctx)).from_void(*ctx, node.value.get(),
nullptr) :
meta_any{
meta_ctx_arg, *ctx};
802 return static_cast<bool>(node.type);
811 return (ctx ==
other.ctx && node.value ==
other.node.value);
815 internal::meta_prop_node node{};
816 const meta_ctx *ctx{};
839 : node{std::move(
curr)} {}
845 template<
typename Type>
847 return (
type_id<Type>().hash() == node.type) ? std::static_pointer_cast<Type>(node.value).get() :
nullptr;
854 template<
typename Type>
856 ENTT_ASSERT(
type_id<Type>().hash() == node.type,
"Invalid type");
857 return *std::static_pointer_cast<Type>(node.value);
861 internal::meta_custom_node node{};
867 using size_type =
typename internal::meta_data_node::size_type;
894 return static_cast<bool>(node->traits & internal::meta_traits::is_const);
902 return static_cast<bool>(node->traits & internal::meta_traits::is_static);
918 return node->set && node->set(
meta_handle{*ctx, std::move(instance)},
meta_any{*ctx, std::forward<Type>(value)});
927 return node->get(*ctx,
meta_handle{*ctx, std::move(instance)});
942 return {{*ctx, node->prop.cbegin()}, {*ctx, node->prop.cend()}};
951 for(
auto &&
elem: node->prop) {
965 template<
typename Type>
967 return internal::meta_to_user_traits<Type>(node->traits);
975 return {node->custom};
983 return (node !=
nullptr);
988 return (ctx ==
other.ctx && node ==
other.node);
992 const internal::meta_data_node *node{};
993 const meta_ctx *ctx{};
1009 using size_type =
typename internal::meta_func_node::size_type;
1036 return static_cast<bool>(node->traits & internal::meta_traits::is_const);
1044 return static_cast<bool>(node->traits & internal::meta_traits::is_static);
1078 template<
typename...
Args>
1082 return invoke(std::move(instance),
arguments.data(),
sizeof...(Args));
1087 return {{*ctx, node->prop.cbegin()}, {*ctx, node->prop.cend()}};
1096 for(
auto &&
elem: node->prop) {
1106 template<
typename Type>
1108 return internal::meta_to_user_traits<Type>(node->traits);
1113 return {node->custom};
1129 return (node !=
nullptr);
1134 return (ctx ==
other.ctx && node ==
other.node);
1138 const internal::meta_func_node *node{};
1139 const meta_ctx *ctx{};
1154 template<
typename Func>
1161 if constexpr(std::is_same_v<std::decay_t<
decltype(*curr)>, internal::meta_func_node>) {
1162 if(
constness && !
static_cast<bool>(
curr->traits & internal::meta_traits::is_const)) {
1174 const auto type =
args[
pos].type();
1178 }
else if(!(type.node.conversion_helper &&
other.node.conversion_helper) && !(type.node.details && (internal::find_member<&internal::meta_base_node::type>(type.node.details->base,
info.
hash()) || internal::find_member<&internal::meta_conv_node::type>(type.node.details->conv,
info.
hash())))) {
1190 if constexpr(std::is_same_v<std::decay_t<
decltype(*curr)>, internal::meta_func_node>) {
1191 if(
static_cast<bool>(
curr->traits & internal::meta_traits::is_const) !=
static_cast<bool>(
candidate->traits & internal::meta_traits::is_const)) {
1209 using size_type =
typename internal::meta_type_node::size_type;
1220 : node{std::move(
curr)},
1252 return node.size_of;
1261 return static_cast<bool>(node.traits & internal::meta_traits::is_arithmetic);
1269 return static_cast<bool>(node.traits & internal::meta_traits::is_integral);
1277 return static_cast<bool>(node.traits & internal::meta_traits::is_signed);
1285 return static_cast<bool>(node.traits & internal::meta_traits::is_array);
1293 return static_cast<bool>(node.traits & internal::meta_traits::is_enum);
1301 return static_cast<bool>(node.traits & internal::meta_traits::is_class);
1309 return static_cast<bool>(node.traits & internal::meta_traits::is_pointer);
1318 return {*ctx, node.remove_pointer(internal::meta_context::from(*ctx))};
1326 return static_cast<bool>(node.traits & internal::meta_traits::is_meta_pointer_like);
1334 return static_cast<bool>(node.traits & internal::meta_traits::is_meta_sequence_container);
1342 return static_cast<bool>(node.traits & internal::meta_traits::is_meta_associative_container);
1352 return (node.templ.arity != 0
u);
1360 return node.templ.arity;
1368 return (node.templ.resolve !=
nullptr) ?
meta_type{*ctx, node.templ.resolve(internal::meta_context::from(*ctx))} :
meta_type{};
1387 return (internal::try_cast(internal::meta_context::from(*ctx), node,
other.node,
this) !=
nullptr);
1396 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);
1405 return node.details ?
range_type{{*ctx, node.details->base.cbegin()}, {*ctx, node.details->base.cend()}} :
range_type{};
1414 return node.details ?
range_type{{*ctx, node.details->data.cbegin()}, {*ctx, node.details->data.cend()}} :
range_type{};
1423 const auto *
elem = internal::look_for<&internal::meta_type_descriptor::data>(internal::meta_context::from(*ctx), node,
id);
1432 using return_type =
meta_range<
meta_func,
typename decltype(internal::meta_type_descriptor::func)::const_iterator>;
1433 return node.details ? return_type{{*ctx, node.details->func.cbegin()}, {*ctx, node.details->func.cend()}} : return_type{};
1445 const auto *
elem = internal::look_for<&internal::meta_type_descriptor::func>(internal::meta_context::from(*ctx), node,
id);
1457 if(
const auto *
candidate = lookup(
args,
sz,
false, [first = node.details->ctor.cbegin(), last = node.details->ctor.cend()]()
mutable { return first == last ? nullptr : &*(first++); });
candidate) {
1462 if(
sz == 0
u && (node.default_constructor !=
nullptr)) {
1463 return node.default_constructor(*ctx);
1475 template<
typename...
Args>
1505 if(
auto *
elem = internal::find_member<&internal::meta_func_node::id>(node.details->func,
id);
elem !=
nullptr) {
1506 if(
const auto *
candidate = lookup(
args,
sz, instance && (instance->
data() ==
nullptr), [
curr =
elem]()
mutable { return (curr != nullptr) ? std::exchange(curr, curr->next.get()) : nullptr; });
candidate) {
1529 template<
typename...
Args>
1533 return invoke(
id, std::move(instance),
arguments.data(),
sizeof...(Args));
1544 template<
typename Type>
1567 return node.details ?
range_type{{*ctx, node.details->prop.cbegin()}, {*ctx, node.details->prop.cend()}} :
range_type{};
1576 const auto *
elem = internal::look_for<&internal::meta_type_descriptor::prop>(internal::meta_context::from(*ctx), node,
key);
1581 template<
typename Type>
1583 return internal::meta_to_user_traits<Type>(node.traits);
1588 return {node.custom};
1596 return !(ctx ==
nullptr);
1601 return (ctx ==
other.ctx) && (((node.info ==
nullptr) && (
other.node.info ==
nullptr)) || ((node.info !=
nullptr) && (
other.node.info !=
nullptr) && *node.info == *
other.node.info));
1605 internal::meta_type_node node{};
1606 const meta_ctx *ctx{};
1623template<
typename...
Args>
1629template<
typename...
Args>
1634template<
typename Type>
1636 return type().
set(
id, *
this, std::forward<Type>(value));
1649 if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<
decltype(
args)>>, internal::meta_type_node> || ...)) {
1650 return (
args.from_void(*ctx,
nullptr, instance), ...);
1651 }
else if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<
decltype(
args)>>, internal::meta_conv_node> || ...)) {
1652 return (
args.conv(*ctx, instance), ...);
1653 }
else if constexpr((std::is_same_v<std::remove_const_t<std::remove_reference_t<
decltype(
args)>>,
decltype(internal::meta_type_node::conversion_helper)> || ...)) {
1656 const auto value = (
args(
nullptr, instance), ...);
1657 other.node.conversion_helper(
other.data(), &value);
1667 auto value =
other.allow_cast({*ctx, node});
1668 return value &&
storage.assign(value.storage);
1672 if(*node.info == *
other.node.info) {
1680 return meta_type{*ctx, node->type(internal::meta_context::from(*ctx))};
1684 return index < arity() ? node->arg(*ctx, index) :
meta_type{};
1688 return meta_type{*ctx, node->ret(internal::meta_context::from(*ctx))};
1692 return index < arity() ? node->arg(*ctx, index) :
meta_type{};
1696class meta_sequence_container::meta_iterator
final {
1697 using vtable_type = void(
const void *,
const std::ptrdiff_t,
meta_any *);
1699 template<
typename It>
1700 static void basic_vtable(
const void *value,
const std::ptrdiff_t offset,
meta_any *other) {
1701 const auto &it = *
static_cast<const It *
>(value);
1702 other ? other->
emplace<
decltype(*it)>(*it) : std::advance(
const_cast<It &
>(it), offset);
1706 using value_type = meta_any;
1707 using pointer = input_iterator_pointer<value_type>;
1708 using reference = value_type;
1709 using difference_type = std::ptrdiff_t;
1710 using iterator_category = std::input_iterator_tag;
1711 using iterator_concept = std::bidirectional_iterator_tag;
1713 meta_iterator() =
default;
1715 template<
typename It>
1716 meta_iterator(
const meta_ctx &area, It iter) noexcept
1718 vtable{&basic_vtable<It>},
1721 meta_iterator &operator++() noexcept {
1722 vtable(
handle.data(), 1,
nullptr);
1726 meta_iterator operator++(
int value)
noexcept {
1727 meta_iterator orig = *
this;
1728 vtable(
handle.data(), ++value,
nullptr);
1732 meta_iterator &operator--() noexcept {
1733 vtable(
handle.data(), -1,
nullptr);
1737 meta_iterator operator--(
int value)
noexcept {
1738 meta_iterator orig = *
this;
1739 vtable(
handle.data(), --value,
nullptr);
1743 [[nodiscard]] reference operator*()
const {
1745 vtable(
handle.data(), 0, &other);
1749 [[nodiscard]] pointer operator->()
const {
1753 [[nodiscard]]
explicit operator bool() const noexcept {
1754 return static_cast<bool>(
handle);
1757 [[nodiscard]]
bool operator==(
const meta_iterator &other)
const noexcept {
1758 return handle == other.handle;
1761 [[nodiscard]]
bool operator!=(
const meta_iterator &other)
const noexcept {
1762 return !(*
this == other);
1765 [[nodiscard]]
const any &base() const noexcept {
1770 const meta_ctx *ctx{&locator<meta_ctx>::value_or()};
1771 vtable_type *vtable{};
1775class meta_associative_container::meta_iterator
final {
1776 using vtable_type = void(
const void *, std::pair<meta_any, meta_any> *);
1778 template<
bool KeyOnly,
typename It>
1779 static void basic_vtable(
const void *value, std::pair<meta_any, meta_any> *other) {
1780 if(
const auto &it = *
static_cast<const It *
>(value); other) {
1781 if constexpr(KeyOnly) {
1782 other->first.emplace<
decltype(*it)>(*it);
1784 other->first.emplace<
decltype((it->first))>(it->first);
1785 other->second.emplace<
decltype((it->second))>(it->second);
1788 ++
const_cast<It &
>(it);
1793 using value_type = std::pair<meta_any, meta_any>;
1794 using pointer = input_iterator_pointer<value_type>;
1795 using reference = value_type;
1796 using difference_type = std::ptrdiff_t;
1797 using iterator_category = std::input_iterator_tag;
1798 using iterator_concept = std::forward_iterator_tag;
1800 meta_iterator() =
default;
1802 template<
bool KeyOnly,
typename It>
1803 meta_iterator(
const meta_ctx &area, std::bool_constant<KeyOnly>, It iter) noexcept
1805 vtable{&basic_vtable<KeyOnly, It>},
1808 meta_iterator &operator++() noexcept {
1809 vtable(
handle.data(),
nullptr);
1813 meta_iterator operator++(
int)
noexcept {
1814 meta_iterator orig = *
this;
1815 vtable(
handle.data(),
nullptr);
1819 [[nodiscard]] reference operator*()
const {
1821 vtable(
handle.data(), &other);
1825 [[nodiscard]] pointer operator->()
const {
1829 [[nodiscard]]
explicit operator bool() const noexcept {
1830 return static_cast<bool>(
handle);
1833 [[nodiscard]]
bool operator==(
const meta_iterator &other)
const noexcept {
1834 return handle == other.handle;
1837 [[nodiscard]]
bool operator!=(
const meta_iterator &other)
const noexcept {
1838 return !(*
this == other);
1842 const meta_ctx *ctx{&locator<meta_ctx>::value_or()};
1843 vtable_type *vtable{};
1853 return (value_type_node !=
nullptr) ?
meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} :
meta_type{};
1861 return size_fn(data);
1870 return !const_only && resize_fn(
const_cast<void *
>(data),
sz);
1878 return !const_only && clear_fn(
const_cast<void *
>(data));
1887 return !const_only && reserve_fn(
const_cast<void *
>(data),
sz);
1895 return begin_fn(*ctx, const_only ?
nullptr :
const_cast<void *
>(data), data);
1903 return end_fn(*ctx, const_only ?
nullptr :
const_cast<void *
>(data), data);
1914 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))}))) {
1928 return const_only ?
iterator{} : erase_fn(*ctx,
const_cast<void *
>(data),
it);
1938 it.operator++(
static_cast<int>(
pos) - 1);
1947 return (data !=
nullptr);
1955 return (key_type_node !=
nullptr) ?
meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))} :
meta_type{};
1963 return (mapped_type_node !=
nullptr) ?
meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))} :
meta_type{};
1968 return (value_type_node !=
nullptr) ?
meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} :
meta_type{};
1973 return size_fn(data);
1978 return !const_only && clear_fn(
const_cast<void *
>(data));
1983 return !const_only && reserve_fn(
const_cast<void *
>(data),
sz);
1988 return begin_fn(*ctx, const_only ?
nullptr :
const_cast<void *
>(data), data);
1993 return end_fn(*ctx, const_only ?
nullptr :
const_cast<void *
>(data), data);
2003 return !const_only &&
key.allow_cast(
meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})
2004 && ((mapped_type_node ==
nullptr) || value.allow_cast(meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))}))
2005 && insert_fn(
const_cast<void *
>(data), std::as_const(
key).data(), std::as_const(value).data());
2014 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;
2023 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{};
2031 return (data !=
nullptr);
pointer data() const noexcept
Direct access to the internal packed array.
deletion_policy policy() const noexcept
Returns the deletion policy of a sparse set.
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 elements.
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.