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 "adl_pointer.hpp"
21 #include "type_traits.hpp"
46 template<typename Type>
48 : value_type_node{internal::meta_node<std::remove_cv_t<std::remove_reference_t<typename Type::value_type>>>
::resolve()},
50 resize_fn{&meta_sequence_container_traits<Type>::resize},
51 iter_fn{&meta_sequence_container_traits<Type>::iter},
52 insert_fn{&meta_sequence_container_traits<Type>::insert},
53 erase_fn{&meta_sequence_container_traits<Type>::erase},
54 storage{std::move(instance)} {}
56 [[nodiscard]]
inline meta_type
value_type() const ENTT_NOEXCEPT;
64 [[nodiscard]] inline meta_any operator[](const
size_type);
65 [[nodiscard]] inline explicit operator
bool() const ENTT_NOEXCEPT;
68 internal::meta_type_node *value_type_node =
nullptr;
69 size_type (*size_fn)(const
any &) ENTT_NOEXCEPT =
nullptr;
72 iterator (*insert_fn)(
any &, const std::ptrdiff_t, meta_any &) =
nullptr;
73 iterator (*erase_fn)(
any &, const std::ptrdiff_t) =
nullptr;
95 template<typename Type>
98 key_type_node{internal::meta_node<std::remove_cv_t<std::remove_reference_t<typename Type::key_type>>>
::resolve()},
99 mapped_type_node{
nullptr},
100 value_type_node{internal::meta_node<std::remove_cv_t<std::remove_reference_t<typename Type::value_type>>>
::resolve()},
101 size_fn{&meta_associative_container_traits<Type>::size},
102 clear_fn{&meta_associative_container_traits<Type>::clear},
103 iter_fn{&meta_associative_container_traits<Type>::iter},
104 insert_fn{&meta_associative_container_traits<Type>::insert},
105 erase_fn{&meta_associative_container_traits<Type>::erase},
106 find_fn{&meta_associative_container_traits<Type>::find},
107 storage{std::move(instance)} {
108 if constexpr(!meta_associative_container_traits<Type>::key_only) {
109 mapped_type_node = internal::meta_node<std::remove_cv_t<std::remove_reference_t<typename Type::mapped_type>>>
::resolve();
113 [[nodiscard]]
inline bool key_only() const ENTT_NOEXCEPT;
114 [[nodiscard]] inline meta_type
key_type() const ENTT_NOEXCEPT;
115 [[nodiscard]] inline meta_type
mapped_type() const ENTT_NOEXCEPT;
116 [[nodiscard]] inline meta_type
value_type() const ENTT_NOEXCEPT;
121 inline
bool insert(meta_any, meta_any);
122 inline
bool erase(meta_any);
124 [[nodiscard]] inline explicit operator
bool() const ENTT_NOEXCEPT;
127 bool key_only_container{};
128 internal::meta_type_node *key_type_node =
nullptr;
129 internal::meta_type_node *mapped_type_node =
nullptr;
130 internal::meta_type_node *value_type_node =
nullptr;
131 size_type (*size_fn)(
const any &) ENTT_NOEXCEPT =
nullptr;
132 bool (*clear_fn)(
any &) =
nullptr;
134 bool (*insert_fn)(
any &, meta_any &, meta_any &) =
nullptr;
135 bool (*erase_fn)(
any &, meta_any &) =
nullptr;
142 enum class operation : std::uint8_t {
148 using vtable_type = void(
const operation,
const any &,
void *);
150 template<
typename Type>
151 static void basic_vtable([[maybe_unused]]
const operation op, [[maybe_unused]]
const any &value, [[maybe_unused]]
void *other) {
152 static_assert(std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>,
"Invalid type");
154 if constexpr(!std::is_void_v<Type>) {
156 case operation::deref:
157 if constexpr(is_meta_pointer_like_v<Type>) {
158 if constexpr(std::is_function_v<std::remove_const_t<
typename std::pointer_traits<Type>::element_type>>) {
159 *
static_cast<meta_any *
>(other) = any_cast<Type>(value);
160 }
else if constexpr(!std::is_same_v<std::remove_const_t<
typename std::pointer_traits<Type>::element_type>,
void>) {
163 if constexpr(std::is_constructible_v<bool, Type>) {
164 if(
const auto &pointer_like = any_cast<const Type &>(value); pointer_like) {
178 case operation::assoc:
188 if(node && node->dtor &&
storage.owner()) {
195 node{
storage ? other.node :
nullptr},
196 vtable{
storage ? other.vtable : &basic_vtable<void>} {}
203 vtable{&basic_vtable<void>} {}
211 template<
typename Type,
typename... Args>
212 explicit meta_any(std::in_place_type_t<Type>, Args &&...args)
213 :
storage{std::in_place_type<Type>, std::forward<Args>(args)...},
214 node{internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>::
resolve()},
215 vtable{&basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>} {}
222 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_any>>>
224 :
meta_any{std::in_place_type<std::remove_cv_t<std::remove_reference_t<Type>>>, std::forward<Type>(value)} {}
237 :
storage{std::move(other.storage)},
238 node{std::exchange(other.node,
nullptr)},
239 vtable{std::exchange(other.vtable, &basic_vtable<void>)} {}
253 vtable = other.vtable;
266 vtable = std::exchange(other.vtable, &basic_vtable<void>);
267 storage = std::move(other.storage);
268 node = std::exchange(other.node,
nullptr);
278 template<
typename Type>
281 emplace<std::decay_t<Type>>(std::forward<Type>(value));
289 [[nodiscard]] const
void *
data() const ENTT_NOEXCEPT {
294 [[nodiscard]]
void *
data() ENTT_NOEXCEPT {
308 template<
typename... Args>
312 template<
typename... Args>
326 template<
typename Type>
344 template<
typename Type>
346 if(
const auto &info = type_id<Type>(); node && *node->info == info) {
347 return any_cast<Type>(&
storage);
349 for(
auto *it = node->base; it; it = it->next) {
350 const auto as_const = it->cast(
as_ref());
352 if(
const Type *base = as_const.template try_cast<Type>(); base) {
362 template<
typename Type>
364 if(
const auto &info = type_id<Type>(); node && *node->info == info) {
365 return any_cast<Type>(&
storage);
367 for(
auto *it = node->base; it; it = it->next) {
368 if(Type *base = it->cast(
as_ref()).
template try_cast<Type>(); base) {
388 template<
typename Type>
389 [[nodiscard]] Type
cast()
const {
390 auto *
const instance = try_cast<std::remove_reference_t<Type>>();
391 ENTT_ASSERT(instance,
"Invalid instance");
392 return static_cast<Type
>(*instance);
396 template<
typename Type>
399 auto *
const instance = try_cast<std::remove_reference_t<const Type>>();
400 ENTT_ASSERT(instance,
"Invalid instance");
401 return static_cast<Type
>(*instance);
418 if(
auto other = std::as_const(*this).allow_cast(
type); other) {
419 if(other.storage.owner()) {
420 std::swap(*
this, other);
435 template<
typename Type>
437 const auto other =
allow_cast(internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>::
resolve());
439 if constexpr(std::is_reference_v<Type> && !std::is_const_v<std::remove_reference_t<Type>>) {
440 return other.storage.owner() ? other :
meta_any{};
451 template<
typename Type>
453 if(
auto other = std::as_const(*this).allow_cast(internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>::
resolve()); other) {
454 if(other.storage.owner()) {
455 std::swap(*
this, other);
466 template<
typename Type,
typename... Args>
469 vtable = &basic_vtable<std::remove_cv_t<std::remove_reference_t<Type>>>;
471 node = internal::meta_node<std::remove_cv_t<std::remove_reference_t<Type>>>
::resolve();
483 vtable = &basic_vtable<void>;
495 vtable(operation::seq, detached, &proxy);
503 vtable(operation::seq, detached, &proxy);
514 vtable(operation::assoc, detached, &proxy);
522 vtable(operation::assoc, detached, &proxy);
533 vtable(operation::deref,
storage, &ret);
541 [[nodiscard]]
explicit operator bool() const ENTT_NOEXCEPT {
542 return !(node ==
nullptr);
547 return (!node && !other.node) || (node && other.node && *node->info == *other.node->info &&
storage == other.storage);
561 [[nodiscard]]
bool owner() const ENTT_NOEXCEPT {
567 internal::meta_type_node *node;
578 return !(lhs == rhs);
588 template<
typename Type,
typename... Args>
590 return meta_any{std::in_place_type<Type>, std::forward<Args>(args)...};
599 template<
typename Type>
601 return meta_any{std::in_place_type<std::conditional_t<std::is_rvalue_reference_v<Type>, std::decay_t<Type>, Type>>, std::forward<Type>(value)};
638 template<
typename Type,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, meta_handle>>>
641 if constexpr(std::is_same_v<std::decay_t<Type>,
meta_any>) {
652 [[nodiscard]]
explicit operator bool() const ENTT_NOEXCEPT {
653 return static_cast<bool>(
any);
690 return node->id.as_ref();
705 [[nodiscard]]
explicit operator bool() const ENTT_NOEXCEPT {
706 return !(node ==
nullptr);
741 [[nodiscard]]
bool is_const() const ENTT_NOEXCEPT {
742 return !!(node->traits & internal::meta_traits::is_const);
750 return !!(node->traits & internal::meta_traits::is_static);
769 template<typename Type>
771 return node->set && node->set(std::move(instance), std::forward<Type>(value));
784 return node->get(std::move(instance));
808 for(
auto curr:
prop()) {
809 if(curr.key() == key) {
821 [[nodiscard]]
explicit operator bool() const ENTT_NOEXCEPT {
822 return !(node ==
nullptr);
857 [[nodiscard]]
bool is_const() const ENTT_NOEXCEPT {
858 return !!(node->traits & internal::meta_traits::is_const);
866 return !!(node->traits & internal::meta_traits::is_static);
873 [[nodiscard]]
inline meta_type ret() const ENTT_NOEXCEPT;
897 return sz ==
arity() ? node->invoke(std::move(instance), args) :
meta_any{};
910 template<
typename... Args>
912 meta_any arguments[
sizeof...(Args) + 1u]{std::forward<Args>(args)...};
913 return invoke(std::move(instance), arguments,
sizeof...(Args));
927 for(
auto curr:
prop()) {
928 if(curr.key() == key) {
940 [[nodiscard]]
explicit operator bool() const ENTT_NOEXCEPT {
941 return !(node ==
nullptr);
950 template<auto Member,
typename Pred>
951 [[nodiscard]] std::decay_t<decltype(std::declval<internal::meta_type_node>().*Member)> lookup(
meta_any *
const args,
const typename internal::meta_type_node::size_type sz, Pred pred)
const {
952 std::decay_t<decltype(node->*Member)> candidate{};
956 for(
auto *curr = (node->*Member); curr; curr = curr->next) {
957 if(pred(curr) && curr->arity == sz) {
961 for(
size_type next{}; next < sz && next == (direct + ext) && args[next]; ++next) {
962 const auto type = args[next].
type();
963 const auto other = curr->arg(next);
965 if(
const auto &
info = other.info();
info == type.info()) {
968 ext += internal::find_by<&node_type::base>(
info, type.node)
969 || internal::find_by<&node_type::conv>(
info, type.node)
970 || (type.node->conversion_helper && other.node->conversion_helper);
974 if((direct + ext) == sz) {
979 }
else if(ext == extent) {
986 return (candidate && !ambiguous) ? candidate : decltype(candidate){};
1006 : node{curr ? curr->type :
nullptr} {}
1029 return node->size_of;
1038 return !!(node->traits & internal::meta_traits::is_arithmetic);
1046 return !!(node->traits & internal::meta_traits::is_array);
1053 [[nodiscard]]
bool is_enum() const ENTT_NOEXCEPT {
1054 return !!(node->traits & internal::meta_traits::is_enum);
1062 return !!(node->traits & internal::meta_traits::is_class);
1070 return !!(node->traits & internal::meta_traits::is_pointer);
1079 return !!(node->traits & internal::meta_traits::is_meta_pointer_like);
1087 return !!(node->traits & internal::meta_traits::is_meta_sequence_container);
1095 return !!(node->traits & internal::meta_traits::is_meta_associative_container);
1105 return (node->templ !=
nullptr);
1113 return node->templ ? node->templ->arity :
size_type{};
1124 return node->templ ? node->templ->type :
meta_type{};
1150 return internal::find_by<&node_type::base>(
id, node);
1170 return internal::find_by<&node_type::data>(
id, node);
1192 return internal::find_by<&node_type::func>(
id, node);
1207 const auto *candidate = lookup<&node_type::ctor>(args, sz, [](
const auto *) {
return true; });
1208 return candidate ? candidate->
invoke(args) : ((!sz && node->default_constructor) ? node->default_constructor() :
meta_any{});
1220 template<
typename... Args>
1222 meta_any arguments[
sizeof...(Args) + 1u]{std::forward<Args>(args)...};
1223 return construct(arguments,
sizeof...(Args));
1241 const auto *candidate = lookup<&node_type::func>(args, sz, [
id](
const auto *curr) {
return curr->id ==
id; });
1243 for(
auto it =
base().begin(), last =
base().end(); it != last && !candidate; ++it) {
1244 candidate = it->lookup<&node_type::func>(args, sz, [
id](
const auto *curr) {
return curr->id ==
id; });
1247 return candidate ? candidate->
invoke(std::move(instance), args) :
meta_any{};
1261 template<
typename... Args>
1263 meta_any arguments[
sizeof...(Args) + 1u]{std::forward<Args>(args)...};
1264 return invoke(
id, std::move(instance), arguments,
sizeof...(Args));
1281 template<
typename Type>
1283 const auto candidate =
data(
id);
1284 return candidate && candidate.set(std::move(instance), std::forward<Type>(value));
1298 const auto candidate =
data(
id);
1299 return candidate ? candidate.get(std::move(instance)) :
meta_any{};
1319 return internal::find_by<&internal::meta_type_node::prop>(key, node);
1326 [[nodiscard]]
explicit operator bool() const ENTT_NOEXCEPT {
1327 return !(node ==
nullptr);
1336 return (!node && !other.node) || (node && other.node && *node->info == *other.node->info);
1350 return !(lhs == rhs);
1357 template<
typename... Args>
1359 return type().
invoke(
id, *
this, std::forward<Args>(args)...);
1362 template<
typename... Args>
1364 return type().
invoke(
id, *
this, std::forward<Args>(args)...);
1367 template<
typename Type>
1369 return type().
set(
id, *
this, std::forward<Type>(value));
1381 if(
const auto &info =
type.
info(); node && *node->info == info) {
1384 for(
auto *it = node->conv; it; it = it->next) {
1385 if(*it->type->info == info) {
1386 return it->conv(*
this);
1393 ENTT_ASSERT(other.node->conversion_helper,
"Conversion helper not found");
1394 const auto value = node->conversion_helper(
nullptr,
storage.
data());
1395 other.node->conversion_helper(other.storage.data(), &value);
1399 for(
auto *it = node->base; it; it = it->next) {
1400 const auto as_const = it->cast(
as_ref());
1402 if(
auto other = as_const.allow_cast(
type); other) {
1413 return value &&
storage.assign(std::move(value.storage));
1417 if(*node->info == *other.node->info) {
1418 return storage.assign(std::move(other.storage));
1421 return assign(std::as_const(other));
1433 return index < arity() ? node->arg(index) :
meta_type{};
1437 return index < arity() ? node->arg(index) :
meta_type{};
1445 class meta_sequence_container::meta_iterator final {
1448 using deref_fn_type =
meta_any(
const any &,
const std::ptrdiff_t);
1450 template<
typename It>
1451 static meta_any deref_fn(
const any &value,
const std::ptrdiff_t pos) {
1452 return meta_any{std::in_place_type<typename std::iterator_traits<It>::reference>, any_cast<const It &>(value)[pos]};
1456 using difference_type = std::ptrdiff_t;
1458 using pointer = input_iterator_pointer<value_type>;
1460 using iterator_category = std::input_iterator_tag;
1462 meta_iterator() ENTT_NOEXCEPT
1467 template<
typename It>
1468 explicit meta_iterator(It iter,
const difference_type init) ENTT_NOEXCEPT
1469 : deref{&deref_fn<It>},
1471 handle{std::move(iter)} {}
1473 meta_iterator &operator++() ENTT_NOEXCEPT {
1474 return ++offset, *
this;
1477 meta_iterator operator++(
int value) ENTT_NOEXCEPT {
1478 meta_iterator orig = *
this;
1483 meta_iterator &operator--() ENTT_NOEXCEPT {
1484 return --offset, *
this;
1487 meta_iterator operator--(
int value) ENTT_NOEXCEPT {
1488 meta_iterator orig = *
this;
1493 [[nodiscard]] reference operator*()
const {
1494 return deref(
handle, offset);
1497 [[nodiscard]] pointer operator->()
const {
1501 [[nodiscard]]
explicit operator bool() const ENTT_NOEXCEPT {
1502 return static_cast<bool>(
handle);
1505 [[nodiscard]]
bool operator==(
const meta_iterator &other)
const ENTT_NOEXCEPT {
1506 return offset == other.offset;
1509 [[nodiscard]]
bool operator!=(
const meta_iterator &other)
const ENTT_NOEXCEPT {
1510 return !(*
this == other);
1514 deref_fn_type *deref;
1515 difference_type offset;
1519 class meta_associative_container::meta_iterator final {
1520 enum class operation : std::uint8_t {
1525 using vtable_type = void(
const operation,
const any &, std::pair<meta_any, meta_any> *);
1527 template<
bool KeyOnly,
typename It>
1528 static void basic_vtable(
const operation op,
const any &value, std::pair<meta_any, meta_any> *other) {
1530 case operation::incr:
1531 ++any_cast<It &>(
const_cast<any &
>(value));
1533 case operation::deref:
1534 const auto &it = any_cast<const It &>(value);
1535 if constexpr(KeyOnly) {
1536 other->first.emplace<decltype(*it)>(*it);
1538 other->first.emplace<decltype((it->first))>(it->first);
1539 other->second.emplace<decltype((it->second))>(it->second);
1546 using difference_type = std::ptrdiff_t;
1547 using value_type = std::pair<meta_any, meta_any>;
1548 using pointer = input_iterator_pointer<value_type>;
1550 using iterator_category = std::input_iterator_tag;
1552 meta_iterator() ENTT_NOEXCEPT
1556 template<
bool KeyOnly,
typename It>
1557 meta_iterator(std::integral_constant<bool, KeyOnly>, It iter) ENTT_NOEXCEPT
1558 : vtable{&basic_vtable<KeyOnly, It>},
1559 handle{std::move(iter)} {}
1561 meta_iterator &operator++() ENTT_NOEXCEPT {
1562 vtable(operation::incr,
handle,
nullptr);
1566 meta_iterator operator++(
int) ENTT_NOEXCEPT {
1567 meta_iterator orig = *
this;
1568 return ++(*this), orig;
1571 [[nodiscard]] reference operator*()
const {
1573 vtable(operation::deref,
handle, &other);
1577 [[nodiscard]] pointer operator->()
const {
1581 [[nodiscard]]
explicit operator bool() const ENTT_NOEXCEPT {
1582 return static_cast<bool>(
handle);
1585 [[nodiscard]]
bool operator==(
const meta_iterator &other)
const ENTT_NOEXCEPT {
1586 return handle == other.handle;
1589 [[nodiscard]]
bool operator!=(
const meta_iterator &other)
const ENTT_NOEXCEPT {
1590 return !(*
this == other);
1594 vtable_type *vtable;
1608 return value_type_node;
1625 return resize_fn(
storage, sz);
1633 return resize_fn(
storage, 0u);
1641 return iter_fn(
storage,
false);
1649 return iter_fn(
storage,
true);
1659 return insert_fn(
storage, it.offset, value);
1668 return erase_fn(
storage, it.offset);
1679 it.operator++(
static_cast<int>(pos) - 1);
1687 [[nodiscard]]
inline meta_sequence_container::operator bool() const ENTT_NOEXCEPT {
1688 return static_cast<bool>(
storage);
1696 return key_only_container;
1704 return key_type_node;
1712 return mapped_type_node;
1717 return value_type_node;
1732 return iter_fn(
storage,
false);
1737 return iter_fn(
storage,
true);
1747 return insert_fn(
storage, key, value);
1756 return erase_fn(
storage, key);
1772 [[nodiscard]]
inline meta_associative_container::operator bool() const ENTT_NOEXCEPT {
1773 return static_cast<bool>(
storage);
basic_any as_ref()
Aliasing constructor.
pointer data() const
Direct access to the internal packed array.
Basic storage implementation.
value_type & emplace(const entity_type entt, Args &&...args)
Assigns an entity to a storage and constructs its object.
constexpr bool operator==(const basic_hashed_string< Char > &lhs, const basic_hashed_string< Char > &rhs)
Compares two hashed strings.
meta_type resolve()
Returns the meta type associated with a given type.
std::uint32_t id_type
Alias declaration for type identifiers.
basic_any<> any
Alias declaration for the most common use case.
basic_handle< entity > handle
Alias declaration for the most common use case.
meta_any forward_as_meta(Type &&value)
Forwards its argument and avoids copies for lvalue references.
typename constness_as< To, From >::type constness_as_t
Alias template to facilitate the transcription of the constness.
constexpr bool is_complete_v
Helper variable template.
basic_storage< entity, Args... > storage
Alias declaration for the most common use case.
meta_any make_meta(Args &&...args)
Constructs a wrapper from a given type, passing it all arguments.
bool operator!=(const basic_any< Len, Align > &lhs, const basic_any< Len, Align > &rhs)
Checks if two wrappers differ in their content.
Implementation specific information about a type.