build: add EnTT library

This commit is contained in:
2026-07-25 10:29:04 +08:00
parent 3e7ce71219
commit 849386a3bc
111 changed files with 24637 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
#ifndef ENTT_META_ADL_POINTER_HPP
#define ENTT_META_ADL_POINTER_HPP
namespace entt {
/**
* @brief ADL based lookup function for dereferencing meta pointer-like types.
* @tparam Type Element type.
* @param value A pointer-like object.
* @return The value returned from the dereferenced pointer.
*/
template<typename Type>
decltype(auto) dereference_meta_pointer_like(const Type &value) {
return *value;
}
/**
* @brief Fake ADL based lookup function for meta pointer-like types.
* @tparam Type Element type.
*/
template<typename Type>
struct adl_meta_pointer_like {
/**
* @brief Uses the default ADL based lookup method to resolve the call.
* @param value A pointer-like object.
* @return The value returned from the dereferenced pointer.
*/
static decltype(auto) dereference(const Type &value) {
return dereference_meta_pointer_like(value);
}
};
} // namespace entt
#endif

View File

@@ -0,0 +1,298 @@
// IWYU pragma: always_keep
#ifndef ENTT_META_CONTAINER_HPP
#define ENTT_META_CONTAINER_HPP
#include "../core/concepts.hpp"
#include "../core/type_traits.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "context.hpp"
#include "fwd.hpp"
#include "meta.hpp"
#include "type_traits.hpp"
namespace entt {
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename Type>
struct sequence_container_extent: integral_constant<meta_dynamic_extent> {};
template<typename Type>
requires is_complete_v<stl::tuple_size<Type>>
struct sequence_container_extent<Type>: integral_constant<stl::tuple_size_v<Type>> {};
template<typename Type>
inline constexpr stl::size_t sequence_container_extent_v = sequence_container_extent<Type>::value;
template<typename Type>
concept meta_sequence_container_like = requires(Type elem) {
typename Type::value_type;
typename Type::iterator;
requires entt::stl::forward_iterator<typename Type::iterator>;
{ elem.begin() } -> stl::same_as<typename Type::iterator>;
{ elem.end() } -> stl::same_as<typename Type::iterator>;
requires !requires { typename Type::key_type; };
requires !requires { elem.substr(); };
};
template<typename Type>
concept meta_associative_container_like = requires(Type value) {
typename Type::key_type;
typename Type::value_type;
typename Type::iterator;
requires entt::stl::forward_iterator<typename Type::iterator>;
{ value.begin() } -> stl::same_as<typename Type::iterator>;
{ value.end() } -> stl::same_as<typename Type::iterator>;
value.find(stl::declval<typename Type::key_type>());
};
} // namespace internal
/*! @endcond */
/**
* @brief General purpose implementation of meta sequence container traits.
* @tparam Type Type of underlying sequence container.
*/
template<cvref_unqualified Type>
struct basic_meta_sequence_container_traits {
/*! @brief Unsigned integer type. */
using size_type = meta_sequence_container::size_type;
/*! @brief Meta iterator type. */
using iterator = meta_sequence_container::iterator;
/*! @brief Number of elements, or `meta_dynamic_extent` if dynamic. */
static constexpr stl::size_t extent = internal::sequence_container_extent_v<Type>;
/**
* @brief Returns the number of elements in a container.
* @param container Opaque pointer to a container of the given type.
* @return Number of elements.
*/
[[nodiscard]] static size_type size(const void *container) {
return static_cast<const Type *>(container)->size();
}
/**
* @brief Clears a container.
* @param container Opaque pointer to a container of the given type.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool clear([[maybe_unused]] void *container) {
if constexpr(requires(Type elem) { elem.clear(); }) {
static_cast<Type *>(container)->clear();
return true;
} else {
return false;
}
}
/**
* @brief Increases the capacity of a container.
* @param container Opaque pointer to a container of the given type.
* @param sz Desired capacity.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
if constexpr(requires(Type elem) { elem.reserve(sz); }) {
static_cast<Type *>(container)->reserve(sz);
return true;
} else {
return false;
}
}
/**
* @brief Resizes a container.
* @param container Opaque pointer to a container of the given type.
* @param sz The new number of elements.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool resize([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
if constexpr(stl::is_default_constructible_v<typename Type::value_type> && requires(Type elem) { elem.resize(sz); }) {
static_cast<Type *>(container)->resize(sz);
return true;
} else {
return false;
}
}
/**
* @brief Returns a possibly const iterator to the beginning or the end.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param as_const Const opaque pointer fallback.
* @param end False to get a pointer that is past the last element.
* @return An iterator to the first or past the last element of the
* container.
*/
static iterator iter(const meta_ctx &area, void *container, const void *as_const, const bool end) {
return (container == nullptr)
? iterator{area, end ? static_cast<const Type *>(as_const)->cend() : static_cast<const Type *>(as_const)->cbegin()}
: iterator{area, end ? static_cast<Type *>(container)->end() : static_cast<Type *>(container)->begin()};
}
/**
* @brief Assigns one element to a container and constructs its object from
* a given opaque instance.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param value Optional opaque instance of the object to construct (as
* value type).
* @param cref Optional opaque instance of the object to construct (as
* decayed const reference type).
* @param it Iterator before which the element will be inserted.
* @return A possibly invalid iterator to the inserted element.
*/
[[nodiscard]] static iterator insert([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const void *value, [[maybe_unused]] const void *cref, [[maybe_unused]] const iterator &it) {
if constexpr(requires(Type elem, typename Type::const_iterator iter, Type::value_type instance) { elem.insert(iter, instance); }) {
auto *const non_const = any_cast<typename Type::iterator>(&it.base());
return {area, static_cast<Type *>(container)->insert(
non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it.base()),
(value != nullptr) ? *static_cast<const Type::value_type *>(value) : *static_cast<const stl::remove_reference_t<typename Type::const_reference> *>(cref))};
} else {
return iterator{};
}
}
/**
* @brief Erases an element from a container.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param it An opaque iterator to the element to erase.
* @return A possibly invalid iterator following the last removed element.
*/
[[nodiscard]] static iterator erase([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const iterator &it) {
if constexpr(requires(Type elem, typename Type::const_iterator iter) { elem.erase(iter); }) {
auto *const non_const = any_cast<typename Type::iterator>(&it.base());
return {area, static_cast<Type *>(container)->erase(non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it.base()))};
} else {
return iterator{};
}
}
};
/**
* @brief General purpose implementation of meta associative container traits.
* @tparam Type Type of underlying associative container.
*/
template<cvref_unqualified Type>
struct basic_meta_associative_container_traits {
/*! @brief Unsigned integer type. */
using size_type = meta_associative_container::size_type;
/*! @brief Meta iterator type. */
using iterator = meta_associative_container::iterator;
/*! @brief True in case of key-only containers, false otherwise. */
static constexpr bool key_only = !requires { typename Type::mapped_type; };
/**
* @brief Returns the number of elements in a container.
* @param container Opaque pointer to a container of the given type.
* @return Number of elements.
*/
[[nodiscard]] static size_type size(const void *container) {
return static_cast<const Type *>(container)->size();
}
/**
* @brief Clears a container.
* @param container Opaque pointer to a container of the given type.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool clear(void *container) {
static_cast<Type *>(container)->clear();
return true;
}
/**
* @brief Increases the capacity of a container.
* @param container Opaque pointer to a container of the given type.
* @param sz Desired capacity.
* @return True in case of success, false otherwise.
*/
[[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
if constexpr(requires(Type elem) { elem.reserve(sz); }) {
static_cast<Type *>(container)->reserve(sz);
return true;
} else {
return false;
}
}
/**
* @brief Returns a possibly const iterator to the beginning or the end.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param as_const Const opaque pointer fallback.
* @param end False to get a pointer that is past the last element.
* @return An iterator to the first or past the last element of the
* container.
*/
static iterator iter(const meta_ctx &area, void *container, const void *as_const, const bool end) {
return (container == nullptr)
? iterator{area, stl::bool_constant<key_only>{}, end ? static_cast<const Type *>(as_const)->cend() : static_cast<const Type *>(as_const)->cbegin()}
: iterator{area, stl::bool_constant<key_only>{}, end ? static_cast<Type *>(container)->end() : static_cast<Type *>(container)->begin()};
}
/**
* @brief Inserts an element into a container, if the key does not exist.
* @param container Opaque pointer to a container of the given type.
* @param key An opaque key value of an element to insert.
* @param value Optional opaque value to insert (key-value containers).
* @return True if the insertion took place, false otherwise.
*/
[[nodiscard]] static bool insert(void *container, const void *key, [[maybe_unused]] const void *value) {
if constexpr(key_only) {
return static_cast<Type *>(container)->insert(*static_cast<const Type::key_type *>(key)).second;
} else {
return static_cast<Type *>(container)->emplace(*static_cast<const Type::key_type *>(key), *static_cast<const Type::mapped_type *>(value)).second;
}
}
/**
* @brief Removes an element from a container.
* @param container Opaque pointer to a container of the given type.
* @param key An opaque key value of an element to remove.
* @return Number of elements removed (either 0 or 1).
*/
[[nodiscard]] static size_type erase(void *container, const void *key) {
return static_cast<Type *>(container)->erase(*static_cast<const Type::key_type *>(key));
}
/**
* @brief Finds an element with a given key.
* @param area The context to pass to the newly created iterator.
* @param container Opaque pointer to a container of the given type.
* @param as_const Const opaque pointer fallback.
* @param key Opaque key value of an element to search for.
* @return An iterator to the element with the given key, if any.
*/
static iterator find(const meta_ctx &area, void *container, const void *as_const, const void *key) {
return (container != nullptr) ? iterator{area, stl::bool_constant<key_only>{}, static_cast<Type *>(container)->find(*static_cast<const Type::key_type *>(key))}
: iterator{area, stl::bool_constant<key_only>{}, static_cast<const Type *>(as_const)->find(*static_cast<const Type::key_type *>(key))};
}
};
/**
* @brief Traits meta sequence container like types.
* @tparam Type Container type to inspect.
*/
template<internal::meta_sequence_container_like Type>
struct meta_sequence_container_traits<Type>: basic_meta_sequence_container_traits<Type> {};
/**
* @brief Traits for meta associative container like types.
* @tparam Type Container type to inspect.
*/
template<internal::meta_associative_container_like Type>
struct meta_associative_container_traits<Type>: basic_meta_associative_container_traits<Type> {};
} // namespace entt
#endif

View File

@@ -0,0 +1,47 @@
#ifndef ENTT_META_CTX_HPP
#define ENTT_META_CTX_HPP
#include "../container/dense_map.hpp"
#include "../core/fwd.hpp"
#include "../stl/functional.hpp"
#include "../stl/memory.hpp"
#include "fwd.hpp"
namespace entt {
/*! @cond ENTT_INTERNAL */
namespace internal {
struct meta_type_node;
struct meta_context {
using bucket_type = dense_map<id_type, stl::unique_ptr<meta_type_node>, stl::identity>;
bucket_type bucket;
[[nodiscard]] inline static meta_context &from(meta_ctx &);
[[nodiscard]] inline static const meta_context &from(const meta_ctx &);
};
} // namespace internal
/*! @endcond */
/*! @brief Opaque meta context type. */
struct meta_ctx: private internal::meta_context {
// attorney idiom like model to access the base class
friend struct internal::meta_context;
};
/*! @cond ENTT_INTERNAL */
[[nodiscard]] inline internal::meta_context &internal::meta_context::from(meta_ctx &ctx) {
return ctx;
}
[[nodiscard]] inline const internal::meta_context &internal::meta_context::from(const meta_ctx &ctx) {
return ctx;
}
/*! @endcond */
} // namespace entt
#endif

View File

@@ -0,0 +1,656 @@
#ifndef ENTT_META_FACTORY_HPP
#define ENTT_META_FACTORY_HPP
#include "../config/config.h"
#include "../core/bit.hpp"
#include "../core/fwd.hpp"
#include "../core/hashed_string.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../locator/locator.hpp"
#include "../stl/algorithm.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/cstdint.hpp"
#include "../stl/functional.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "context.hpp"
#include "fwd.hpp"
#include "meta.hpp"
#include "node.hpp"
#include "policy.hpp"
#include "range.hpp"
#include "utility.hpp"
namespace entt {
/*! @cond ENTT_INTERNAL */
namespace internal {
class basic_meta_factory {
using invoke_type = stl::remove_pointer_t<decltype(meta_func_node::invoke)>;
enum class mode {
type,
data,
func
};
[[nodiscard]] auto *find_member_or_assert() {
auto *member = find_member(parent->details->data, bucket);
ENTT_ASSERT(member != nullptr, "Cannot find member");
return member;
}
[[nodiscard]] auto *find_overload_or_assert() {
ENTT_ASSERT(invoke != nullptr, "Invoke function not available");
auto *overload = find_overload(find_member(parent->details->func, bucket), invoke);
ENTT_ASSERT(overload != nullptr, "Cannot find overload");
return overload;
}
bool unique_alias(const id_type alias) const noexcept {
return (ctx->bucket.find(alias) == ctx->bucket.cend()) && (stl::find_if(ctx->bucket.cbegin(), ctx->bucket.cend(), [alias](const auto &value) { return value.second->alias == alias; }) == ctx->bucket.cend());
}
protected:
void type(const id_type alias, const char *name) noexcept {
state = mode::type;
ENTT_ASSERT((parent->alias == alias) || unique_alias(alias), "Duplicate identifier");
parent->alias = alias;
parent->name = name;
}
template<typename Type>
void insert_or_assign(Type node) {
state = mode::type;
if constexpr(stl::is_same_v<Type, meta_base_node>) {
auto *member = find_member(parent->details->base, node.id);
member ? (*member = node) : parent->details->base.emplace_back(node);
} else if constexpr(stl::is_same_v<Type, meta_conv_node>) {
auto *member = find_member(parent->details->conv, node.id);
member ? (*member = node) : parent->details->conv.emplace_back(node);
} else {
static_assert(stl::is_same_v<Type, meta_ctor_node>, "Unexpected type");
auto *member = find_member(parent->details->ctor, node.id);
member ? (*member = node) : parent->details->ctor.emplace_back(node);
}
}
void data(meta_data_node node) {
state = mode::data;
bucket = node.id;
if(auto *member = find_member(parent->details->data, node.id); member == nullptr) {
parent->details->data.emplace_back(stl::move(node));
} else if(member->set != node.set || member->get != node.get) {
*member = stl::move(node);
}
}
void func(meta_func_node node) {
state = mode::func;
bucket = node.id;
invoke = node.invoke;
if(auto *member = find_member(parent->details->func, node.id); member == nullptr) {
parent->details->func.emplace_back(stl::move(node));
} else if(auto *overload = find_overload(member, node.invoke); overload == nullptr) {
while(member->next != nullptr) { member = member->next.get(); }
member->next = stl::make_unique<meta_func_node>(stl::move(node));
}
}
void traits(const meta_traits value, const bool unset) {
const auto set_or_unset_on = [=](auto &node) {
node.traits = (unset ? (node.traits & ~value) : (node.traits | value));
};
switch(state) {
case mode::type:
set_or_unset_on(*parent);
break;
case mode::data:
set_or_unset_on(*find_member_or_assert());
break;
case mode::func:
set_or_unset_on(*find_overload_or_assert());
break;
}
}
void custom(meta_custom_node node) {
switch(state) {
case mode::type:
parent->custom = stl::move(node);
break;
case mode::data:
find_member_or_assert()->custom = stl::move(node);
break;
case mode::func:
find_overload_or_assert()->custom = stl::move(node);
break;
}
}
public:
basic_meta_factory(meta_ctx &area, meta_type_node node, const id_type id)
: ctx{&meta_context::from(area)},
bucket{},
state{mode::type} {
if(const auto it = ctx->bucket.find(id); it == ctx->bucket.cend()) {
ENTT_ASSERT(unique_alias(id), "Duplicate identifier");
parent = ctx->bucket.emplace(id, stl::make_unique<meta_type_node>(stl::move(node))).first->second.get();
parent->details = stl::make_unique<meta_type_descriptor>();
parent->alias = id;
} else {
parent = it->second.get();
}
}
private:
meta_context *ctx{};
invoke_type *invoke{};
meta_type_node *parent{};
id_type bucket{};
mode state{};
};
} // namespace internal
/*! @endcond */
/**
* @brief Meta factory to be used for reflection purposes.
* @tparam Type Type for which the factory was created.
*/
template<typename Type>
class meta_factory: private internal::basic_meta_factory {
using base_type = internal::basic_meta_factory;
public:
/*! @brief Type of object for which this factory builds a meta type. */
using element_type = Type;
/*! @brief Default constructor. */
meta_factory() noexcept
: meta_factory{locator<meta_ctx>::value_or()} {}
/**
* @brief Context aware constructor.
* @param area The context into which to construct meta types.
*/
meta_factory(meta_ctx &area) noexcept
: base_type{area, internal::setup_node_for<element_type>(), type_hash<Type>::value()} {}
/**
* @brief Constructs an unconstrained type assigned to a given identifier.
* @param id A custom unique identifier.
*/
meta_factory(const id_type id) noexcept
: meta_factory{locator<meta_ctx>::value_or(), id} {}
/**
* @brief Context aware constructor.
* @param id A custom unique identifier.
* @param area The context into which to construct meta types.
*/
meta_factory(meta_ctx &area, const id_type id) noexcept
: base_type{area, internal::setup_node_for<element_type>(), id} {}
/**
* @brief Assigns a custom unique identifier to a meta type.
* @param name A custom unique identifier as a **string literal**.
* @return A meta factory for the given type.
*/
meta_factory type(const char *name) noexcept {
return type(hashed_string::value(name), name);
}
/**
* @brief Assigns a custom unique identifier to a meta type.
* @param alias A custom unique identifier.
* @param name An optional name for the type as a **string literal**.
* @return A meta factory for the given type.
*/
meta_factory type(const id_type alias, const char *name = nullptr) noexcept {
base_type::type(alias, name);
return *this;
}
/**
* @brief Assigns a meta base to a meta type.
*
* A reflected base class must be a real base class of the reflected type.
*
* @tparam Base Type of the base class to assign to the meta type.
* @return A meta factory for the parent type.
*/
template<typename Base>
requires stl::derived_from<element_type, Base>
meta_factory base() noexcept {
if constexpr(!stl::same_as<element_type, Base>) {
auto *const op = +[](const void *instance) noexcept { return static_cast<const void *>(static_cast<const Base *>(static_cast<const element_type *>(instance))); };
base_type::insert_or_assign(
internal::meta_base_node{
type_id<Base>().hash(),
&internal::resolve<Base>,
op});
}
return *this;
}
/**
* @brief Assigns a meta conversion function to a meta type.
*
* Conversion functions can be either free functions or member
* functions.<br/>
* In case of free functions, they must accept a const reference to an
* instance of the parent type as an argument. In case of member functions,
* they should have no arguments at all.
*
* @tparam Candidate The actual function to use for the conversion.
* @return A meta factory for the parent type.
*/
template<auto Candidate>
auto conv() noexcept {
using conv_type = stl::remove_cvref_t<stl::invoke_result_t<decltype(Candidate), element_type &>>;
auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, stl::invoke(Candidate, *static_cast<const element_type *>(instance))); };
base_type::insert_or_assign(
internal::meta_conv_node{
type_id<conv_type>().hash(),
op});
return *this;
}
/**
* @brief Assigns a meta conversion function to a meta type.
*
* The given type must be such that an instance of the reflected type can be
* converted to it.
*
* @tparam To Type of the conversion function to assign to the meta type.
* @return A meta factory for the parent type.
*/
template<typename To>
meta_factory conv() noexcept {
using conv_type = stl::remove_cvref_t<To>;
auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast<To>(*static_cast<const element_type *>(instance))); };
base_type::insert_or_assign(
internal::meta_conv_node{
type_id<conv_type>().hash(),
op});
return *this;
}
/**
* @brief Assigns a meta constructor to a meta type.
*
* Both member functions and free function can be assigned to meta types in
* the role of constructors. All that is required is that they return an
* instance of the underlying type.<br/>
* From a client's point of view, nothing changes if a constructor of a meta
* type is a built-in one or not.
*
* @tparam Candidate The actual function to use as a constructor.
* @tparam Policy Optional policy (no policy set by default).
* @return A meta factory for the parent type.
*/
template<auto Candidate, typename Policy = as_value_t>
meta_factory ctor() noexcept {
using descriptor = meta_function_helper_t<element_type, decltype(Candidate)>;
static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
static_assert(stl::is_same_v<stl::remove_cvref_t<typename descriptor::return_type>, element_type>, "The function doesn't return an object of the required type");
base_type::insert_or_assign(
internal::meta_ctor_node{
type_id<typename descriptor::args_type>().hash(),
descriptor::args_type::size,
&meta_arg<typename descriptor::args_type>,
&meta_construct<element_type, Candidate, Policy>});
return *this;
}
/**
* @brief Assigns a meta constructor to a meta type.
*
* A meta constructor is uniquely identified by the types of its arguments
* and is such that there exists an actual constructor of the underlying
* type that can be invoked with parameters whose types are those given.
*
* @tparam Args Types of arguments to use to construct an instance.
* @return A meta factory for the parent type.
*/
template<typename... Args>
meta_factory ctor() noexcept {
// default constructor is already implicitly generated, no need for redundancy
if constexpr(sizeof...(Args) != 0u) {
using descriptor = meta_function_helper_t<element_type, element_type (*)(Args...)>;
base_type::insert_or_assign(
internal::meta_ctor_node{
type_id<typename descriptor::args_type>().hash(),
descriptor::args_type::size,
&meta_arg<typename descriptor::args_type>,
&meta_construct<element_type, Args...>});
}
return *this;
}
/**
* @brief Assigns a meta data to a meta type.
* @tparam Data The actual variable to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param name A custom unique identifier as a **string literal**.
* @return A meta factory for the given type.
*/
template<auto Data, typename Policy = as_value_t>
meta_factory data(const char *name) noexcept {
return data<Data, Policy>(hashed_string::value(name), name);
}
/**
* @brief Assigns a meta data to a meta type.
*
* Both data members and static and global variables, as well as constants
* of any kind, can be assigned to a meta type.<br/>
* From a client's point of view, all the variables associated with the
* reflected object will appear as if they were part of the type itself.
*
* @tparam Data The actual variable to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @param name An optional name for the meta data as a **string literal**.
* @return A meta factory for the parent type.
*/
template<auto Data, typename Policy = as_value_t>
meta_factory data(const id_type id, const char *name = nullptr) noexcept {
if constexpr(stl::is_member_object_pointer_v<decltype(Data)>) {
using data_type = stl::invoke_result_t<decltype(Data), element_type &>;
static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
base_type::data(
internal::meta_data_node{
id,
name,
/* this is never static */
stl::is_const_v<stl::remove_reference_t<data_type>> ? internal::meta_traits::is_const : internal::meta_traits::is_none,
1u,
0u,
&meta_arg<type_list<stl::remove_cvref_t<data_type>>>,
&meta_arg<type_list<>>,
&internal::resolve<stl::remove_cvref_t<data_type>>,
&meta_setter<element_type, Data>,
&meta_getter<element_type, Data, Policy>});
} else {
using data_type = stl::remove_pointer_t<decltype(Data)>;
if constexpr(stl::is_pointer_v<decltype(Data)>) {
static_assert(Policy::template value<decltype(*Data)>, "Invalid return type for the given policy");
} else {
static_assert(Policy::template value<data_type>, "Invalid return type for the given policy");
}
base_type::data(
internal::meta_data_node{
id,
name,
((!stl::is_pointer_v<decltype(Data)> || stl::is_const_v<data_type>) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static,
1u,
0u,
&meta_arg<type_list<stl::remove_cvref_t<data_type>>>,
&meta_arg<type_list<>>,
&internal::resolve<stl::remove_cvref_t<data_type>>,
&meta_setter<element_type, Data>,
&meta_getter<element_type, Data, Policy>});
}
return *this;
}
/**
* @brief Assigns a meta data to a meta type by means of its setter and
* getter.
* @tparam Setter The actual function to use as a setter.
* @tparam Getter The actual function to use as a getter.
* @tparam Policy Optional policy (no policy set by default).
* @param name A custom unique identifier as a **string literal**.
* @return A meta factory for the given type.
*/
template<auto Setter, auto Getter, typename Policy = as_value_t>
meta_factory data(const char *name) noexcept {
return data<Setter, Getter, Policy>(hashed_string::value(name), name);
}
/**
* @brief Assigns a meta data to a meta type by means of its setter and
* getter.
*
* Setters and getters can be either free functions, member functions or a
* mix of them.<br/>
* In case of free functions, setters and getters must accept a reference to
* an instance of the parent type as their first argument. A setter has then
* an extra argument of a type convertible to that of the parameter to
* set.<br/>
* In case of member functions, getters have no arguments at all, while
* setters has an argument of a type convertible to that of the parameter to
* set.
*
* @tparam Setter The actual function to use as a setter.
* @tparam Getter The actual function to use as a getter.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @param name An optional name for the meta data as a **string literal**.
* @return A meta factory for the parent type.
*/
template<auto Setter, auto Getter, typename Policy = as_value_t>
meta_factory data(const id_type id, const char *name = nullptr) noexcept {
using getter = meta_function_helper_t<element_type, decltype(Getter)>;
static_assert(Policy::template value<typename getter::return_type>, "Invalid return type for the given policy");
if constexpr(stl::is_same_v<decltype(Setter), stl::nullptr_t>) {
base_type::data(
internal::meta_data_node{
id,
name,
/* this is never static */
internal::meta_traits::is_const,
0u,
getter::args_type::size,
&meta_arg<type_list<>>,
&meta_arg<typename getter::args_type>,
&internal::resolve<stl::remove_cvref_t<typename getter::return_type>>,
&meta_setter<element_type, Setter>,
&meta_getter<element_type, Getter, Policy>});
} else {
using setter = meta_function_helper_t<element_type, decltype(Setter)>;
base_type::data(
internal::meta_data_node{
id,
name,
/* this is never static nor const */
internal::meta_traits::is_none,
setter::args_type::size,
getter::args_type::size,
&meta_arg<typename setter::args_type>,
&meta_arg<typename getter::args_type>,
&internal::resolve<stl::remove_cvref_t<typename getter::return_type>>,
&meta_setter<element_type, Setter>,
&meta_getter<element_type, Getter, Policy>});
}
return *this;
}
/**
* @brief Assigns a meta function to a meta type.
* @tparam Candidate The actual function to attach to the meta function.
* @tparam Policy Optional policy (no policy set by default).
* @param name A custom unique identifier as a **string literal**.
* @return A meta factory for the given type.
*/
template<auto Candidate, typename Policy = as_value_t>
meta_factory func(const char *name) noexcept {
return func<Candidate, Policy>(hashed_string::value(name), name);
}
/**
* @brief Assigns a meta function to a meta type.
*
* Both member functions and free functions can be assigned to a meta
* type.<br/>
* From a client's point of view, all the functions associated with the
* reflected object will appear as if they were part of the type itself.
*
* @tparam Candidate The actual function to attach to the meta type.
* @tparam Policy Optional policy (no policy set by default).
* @param id Unique identifier.
* @param name An optional name for the function as a **string literal**.
* @return A meta factory for the parent type.
*/
template<auto Candidate, typename Policy = as_value_t>
meta_factory func(const id_type id, const char *name = nullptr) noexcept {
using descriptor = meta_function_helper_t<element_type, decltype(Candidate)>;
static_assert(Policy::template value<typename descriptor::return_type>, "Invalid return type for the given policy");
base_type::func(
internal::meta_func_node{
id,
name,
(descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none),
descriptor::args_type::size,
&internal::resolve<stl::conditional_t<stl::is_same_v<Policy, as_void_t>, void, stl::remove_cvref_t<typename descriptor::return_type>>>,
&meta_arg<typename descriptor::args_type>,
&meta_invoke<element_type, Candidate, Policy>});
return *this;
}
/**
* @brief Sets traits on the last created meta object.
*
* The assigned value must be an enum and intended as a bitmask.
*
* @tparam Value Type of the traits value.
* @param value Traits value.
* @param unset True to unset the given traits, false otherwise.
* @return A meta factory for the parent type.
*/
template<typename Value>
meta_factory traits(const Value value, const bool unset = false) {
static_assert(stl::is_enum_v<Value>, "Invalid enum type");
base_type::traits(internal::user_to_meta_traits(value), unset);
return *this;
}
/**
* @brief Sets user defined data that will never be used by the library.
* @tparam Value Type of user defined data to store.
* @tparam Args Types of arguments to use to construct the user data.
* @param args Parameters to use to initialize the user data.
* @return A meta factory for the parent type.
*/
template<typename Value, typename... Args>
meta_factory custom(Args &&...args) {
base_type::custom(internal::meta_custom_node{type_id<Value>().hash(), stl::make_shared<Value>(stl::forward<Args>(args)...)});
return *this;
}
};
/**
* @brief Resets a type and all its parts.
*
* Resets a type and all its data members, member functions and properties, as
* well as its constructors, destructors and conversion functions if any.<br/>
* Base classes aren't reset but the link between the two types is removed.
*
* The type is also removed from the set of searchable types.
*
* @param alias Unique identifier.
* @param ctx The context from which to reset meta types.
*/
inline void meta_reset(meta_ctx &ctx, const id_type alias) noexcept {
auto &bucket = internal::meta_context::from(ctx).bucket;
// fast path for unsearchable and overloaded types
if(bucket.erase(alias) == 0u) {
if(const auto it = stl::find_if(bucket.cbegin(), bucket.cend(), [alias](const auto &value) { return value.second->alias == alias; }); it != bucket.cend()) {
bucket.erase(it);
}
}
}
/**
* @brief Resets a type and all its parts.
*
* Resets a type and all its data members, member functions and properties, as
* well as its constructors, destructors and conversion functions if any.<br/>
* Base classes aren't reset but the link between the two types is removed.
*
* The type is also removed from the set of searchable types.
*
* @param alias Unique identifier.
*/
inline void meta_reset(const id_type alias) noexcept {
meta_reset(locator<meta_ctx>::value_or(), alias);
}
/**
* @brief Resets a type and all its parts.
*
* @sa meta_reset
*
* @tparam Type Type to reset.
* @param ctx The context from which to reset meta types.
*/
template<typename Type>
void meta_reset(meta_ctx &ctx) noexcept {
internal::meta_context::from(ctx).bucket.erase(type_id<Type>().hash());
}
/**
* @brief Resets a type and all its parts.
*
* @sa meta_reset
*
* @tparam Type Type to reset.
*/
template<typename Type>
void meta_reset() noexcept {
meta_reset<Type>(locator<meta_ctx>::value_or());
}
/**
* @brief Resets all meta types.
*
* @sa meta_reset
*
* @param ctx The context from which to reset meta types.
*/
inline void meta_reset(meta_ctx &ctx) noexcept {
internal::meta_context::from(ctx).bucket.clear();
}
/**
* @brief Resets all meta types.
*
* @sa meta_reset
*/
inline void meta_reset() noexcept {
meta_reset(locator<meta_ctx>::value_or());
}
} // namespace entt
#endif

43
include/entt/meta/fwd.hpp Normal file
View File

@@ -0,0 +1,43 @@
#ifndef ENTT_META_FWD_HPP
#define ENTT_META_FWD_HPP
#include "../stl/cstddef.hpp"
#include "../stl/limits.hpp"
namespace entt {
struct meta_ctx;
class meta_sequence_container;
class meta_associative_container;
class meta_any;
class meta_handle;
struct meta_custom;
struct meta_data;
struct meta_func;
struct meta_base;
class meta_type;
template<typename>
class meta_factory;
/*! @brief Used to identicate that a sequence container has not a fixed size. */
inline constexpr stl::size_t meta_dynamic_extent = (stl::numeric_limits<stl::size_t>::max)();
/*! @brief Disambiguation tag for constructors and the like. */
struct meta_ctx_arg_t final {};
/*! @brief Constant of type meta_context_arg_t used to disambiguate calls. */
inline constexpr meta_ctx_arg_t meta_ctx_arg{};
} // namespace entt
#endif

1902
include/entt/meta/meta.hpp Normal file

File diff suppressed because it is too large Load Diff

287
include/entt/meta/node.hpp Normal file
View File

@@ -0,0 +1,287 @@
#ifndef ENTT_META_NODE_HPP
#define ENTT_META_NODE_HPP
#include "../config/config.h"
#include "../core/bit.hpp"
#include "../core/concepts.hpp"
#include "../core/enum.hpp"
#include "../core/fwd.hpp"
#include "../core/type_info.hpp"
#include "../core/type_traits.hpp"
#include "../core/utility.hpp"
#include "../stl/array.hpp"
#include "../stl/bit.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/cstdint.hpp"
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "../stl/vector.hpp"
#include "context.hpp"
#include "fwd.hpp"
#include "type_traits.hpp"
namespace entt {
/*! @cond ENTT_INTERNAL */
namespace internal {
enum class meta_traits : stl::uint32_t {
is_none = 0x0000,
is_const = 0x0001,
is_static = 0x0002,
is_arithmetic = 0x0004,
is_integral = 0x0008,
is_signed = 0x0010,
is_array = 0x0020,
is_enum = 0x0040,
is_class = 0x0080,
is_pointer = 0x0100,
is_pointer_like = 0x0200,
is_sequence_container = 0x0400,
is_associative_container = 0x0800,
_user_defined_traits = 0xFFFF,
_entt_enum_as_bitmask = 0xFFFF
};
template<typename Type>
requires stl::is_enum_v<Type>
[[nodiscard]] auto meta_to_user_traits(const meta_traits traits) noexcept {
constexpr auto shift = stl::popcount(static_cast<stl::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
return Type{static_cast<stl::underlying_type_t<Type>>(static_cast<stl::underlying_type_t<meta_traits>>(traits) >> shift)};
}
template<typename Type>
requires stl::is_enum_v<Type>
[[nodiscard]] auto user_to_meta_traits(const Type value) noexcept {
constexpr auto shift = stl::popcount(static_cast<stl::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits));
const auto traits = static_cast<stl::underlying_type_t<internal::meta_traits>>(static_cast<stl::underlying_type_t<Type>>(value));
ENTT_ASSERT(traits < ((~static_cast<stl::underlying_type_t<meta_traits>>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits");
return meta_traits{traits << shift};
}
struct meta_type_node;
struct meta_custom_node {
id_type id{};
stl::shared_ptr<void> value{};
};
struct meta_base_node {
id_type id{};
const meta_type_node &(*type)(const meta_context &) noexcept {};
const void *(*cast)(const void *) noexcept {};
};
struct meta_conv_node {
id_type id{};
meta_any (*conv)(const meta_ctx &, const void *){};
};
struct meta_ctor_node {
using size_type = stl::size_t;
id_type id{};
size_type arity{0u};
meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
meta_any (*invoke)(const meta_ctx &, meta_any *const){};
};
struct meta_data_node {
using size_type = stl::size_t;
id_type id{};
const char *name{};
meta_traits traits{meta_traits::is_none};
size_type set_arity{0u};
size_type get_arity{0u};
meta_type (*set_arg)(const meta_ctx &, const size_type) noexcept {};
meta_type (*get_arg)(const meta_ctx &, const size_type) noexcept {};
const meta_type_node &(*type)(const meta_context &) noexcept {};
bool (*set)(meta_handle, meta_any *const){};
meta_any (*get)(meta_handle, meta_any *const){};
meta_custom_node custom{};
};
struct meta_func_node {
using size_type = stl::size_t;
id_type id{};
const char *name{};
meta_traits traits{meta_traits::is_none};
size_type arity{0u};
const meta_type_node &(*ret)(const meta_context &) noexcept {};
meta_type (*arg)(const meta_ctx &, const size_type) noexcept {};
meta_any (*invoke)(meta_handle, meta_any *const){};
stl::unique_ptr<meta_func_node> next;
meta_custom_node custom{};
};
struct meta_template_node {
using size_type = stl::size_t;
size_type arity{0u};
const meta_type_node &(*resolve)(const meta_context &) noexcept {};
const meta_type_node &(*arg)(const meta_context &, const size_type) noexcept {};
};
struct meta_type_descriptor {
stl::vector<meta_ctor_node> ctor{};
stl::vector<meta_base_node> base{};
stl::vector<meta_conv_node> conv{};
stl::vector<meta_data_node> data{};
stl::vector<meta_func_node> func{};
};
struct meta_type_node {
using size_type = stl::size_t;
const type_info *info{};
id_type alias{};
const char *name{};
meta_traits traits{meta_traits::is_none};
size_type size_of{0u};
const meta_type_node &(*remove_pointer)(const meta_context &) noexcept {};
meta_any (*default_constructor)(const meta_ctx &){};
double (*conversion_helper)(void *, const void *){};
meta_any (*from_void)(const meta_ctx &, void *, const void *){};
meta_template_node templ{};
meta_custom_node custom{};
stl::unique_ptr<meta_type_descriptor> details{};
};
template<typename Type, typename Value>
[[nodiscard]] auto *find_member(Type &from, const Value value) {
for(auto &&elem: from) {
if(elem.id == value) {
return &elem;
}
}
return static_cast<Type::value_type *>(nullptr);
}
[[nodiscard]] inline auto *find_overload(meta_func_node *curr, stl::remove_pointer_t<decltype(meta_func_node::invoke)> *const ref) {
while((curr != nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); }
return curr;
}
template<auto Member>
[[nodiscard]] auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id, bool recursive) {
using value_type = stl::remove_reference_t<decltype((node.details.get()->*Member))>::value_type;
if(node.details) {
if(auto *member = find_member((node.details.get()->*Member), id); member != nullptr) {
return member;
}
if(recursive) {
for(auto &&curr: node.details->base) {
if(auto *elem = look_for<Member>(context, curr.type(context), id, recursive); elem) {
return elem;
}
}
}
}
return static_cast<value_type *>(nullptr);
}
template<cvref_unqualified Type>
const meta_type_node &resolve(const meta_context &) noexcept;
template<typename... Args>
[[nodiscard]] const meta_type_node &meta_arg_node(const meta_context &context, type_list<Args...>, const stl::size_t index) noexcept {
using resolve_type = const meta_type_node &(*)(const meta_context &) noexcept;
constexpr stl::array<resolve_type, sizeof...(Args)> list{&resolve<stl::remove_cvref_t<Args>>...};
ENTT_ASSERT(index < sizeof...(Args), "Out of bounds");
return list[index](context);
}
[[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const id_type to, const void *instance) noexcept {
if(from.details) {
for(auto &&curr: from.details->base) {
if(const void *other = curr.cast(instance); curr.id == to) {
return other;
} else if(const void *elem = try_cast(context, curr.type(context), to, other); elem) {
return elem;
}
}
}
return nullptr;
}
template<typename Type>
auto setup_node_for() noexcept {
meta_type_node node{
&type_id<Type>(),
type_id<Type>().hash(),
nullptr,
(stl::is_arithmetic_v<Type> ? meta_traits::is_arithmetic : meta_traits::is_none)
| (stl::is_integral_v<Type> ? meta_traits::is_integral : meta_traits::is_none)
| (stl::is_signed_v<Type> ? meta_traits::is_signed : meta_traits::is_none)
| (stl::is_array_v<Type> ? meta_traits::is_array : meta_traits::is_none)
| (stl::is_enum_v<Type> ? meta_traits::is_enum : meta_traits::is_none)
| (stl::is_class_v<Type> ? meta_traits::is_class : meta_traits::is_none)
| (stl::is_pointer_v<Type> ? meta_traits::is_pointer : meta_traits::is_none)
| (is_meta_pointer_like_v<Type> ? meta_traits::is_pointer_like : meta_traits::is_none)
| (is_complete_v<meta_sequence_container_traits<Type>> ? meta_traits::is_sequence_container : meta_traits::is_none)
| (is_complete_v<meta_associative_container_traits<Type>> ? meta_traits::is_associative_container : meta_traits::is_none),
size_of_v<Type>,
&resolve<stl::remove_const_t<stl::remove_pointer_t<Type>>>};
if constexpr(stl::is_default_constructible_v<Type>) {
node.default_constructor = +[](const meta_ctx &ctx) {
return meta_any{ctx, stl::in_place_type<Type>};
};
}
if constexpr(stl::is_arithmetic_v<Type>) {
node.conversion_helper = +[](void *lhs, const void *rhs) {
return lhs ? static_cast<double>(*static_cast<Type *>(lhs) = static_cast<Type>(*static_cast<const double *>(rhs))) : static_cast<double>(*static_cast<const Type *>(rhs));
};
} else if constexpr(stl::is_enum_v<Type>) {
node.conversion_helper = +[](void *lhs, const void *rhs) {
return lhs ? static_cast<double>(*static_cast<Type *>(lhs) = static_cast<Type>(static_cast<stl::underlying_type_t<Type>>(*static_cast<const double *>(rhs)))) : static_cast<double>(*static_cast<const Type *>(rhs));
};
}
if constexpr(!stl::is_void_v<Type> && !stl::is_function_v<Type>) {
node.from_void = +[](const meta_ctx &ctx, void *elem, const void *celem) {
if(elem && celem) { // ownership construction request
return meta_any{ctx, stl::in_place, static_cast<stl::decay_t<Type> *>(elem)};
}
if(elem) { // non-const reference construction request
return meta_any{ctx, stl::in_place_type<stl::decay_t<Type> &>, *static_cast<stl::decay_t<Type> *>(elem)};
}
// const reference construction request
return meta_any{ctx, stl::in_place_type<const stl::decay_t<Type> &>, *static_cast<const stl::decay_t<Type> *>(celem)};
};
}
if constexpr(is_complete_v<meta_template_traits<Type>>) {
node.templ = meta_template_node{
meta_template_traits<Type>::args_type::size,
&resolve<typename meta_template_traits<Type>::class_type>,
+[](const meta_context &area, const stl::size_t index) noexcept -> decltype(auto) { return meta_arg_node(area, typename meta_template_traits<Type>::args_type{}, index); }};
}
return node;
}
template<cvref_unqualified Type>
[[nodiscard]] const meta_type_node &resolve(const meta_context &context) noexcept {
static const meta_type_node node = setup_node_for<Type>();
const auto it = context.bucket.find(node.info->hash());
return (it == context.bucket.cend()) ? node : *it->second;
}
} // namespace internal
/*! @endcond */
} // namespace entt
#endif

View File

@@ -0,0 +1,42 @@
// IWYU pragma: always_keep
#ifndef ENTT_META_POINTER_HPP
#define ENTT_META_POINTER_HPP
#include "../stl/memory.hpp"
#include "../stl/type_traits.hpp"
#include "type_traits.hpp"
namespace entt {
/**
* @brief Makes `stl::shared_ptr`s of any type pointer-like types for the meta
* system.
* @tparam Type Element type.
*/
template<typename Type>
struct is_meta_pointer_like<stl::shared_ptr<Type>>
: stl::true_type {};
/**
* @brief Makes `stl::unique_ptr`s of any type pointer-like types for the meta
* system.
* @tparam Type Element type.
* @tparam Args Other arguments.
*/
template<typename Type, typename... Args>
struct is_meta_pointer_like<stl::unique_ptr<Type, Args...>>
: stl::true_type {};
/**
* @brief Specialization for self-proclaimed meta pointer like types.
* @tparam Type Element type.
*/
template<typename Type>
requires requires { typename Type::is_meta_pointer_like; }
struct is_meta_pointer_like<Type>
: stl::true_type {};
} // namespace entt
#endif

View File

@@ -0,0 +1,81 @@
#ifndef ENTT_META_POLICY_HPP
#define ENTT_META_POLICY_HPP
#include "../stl/type_traits.hpp"
namespace entt {
/*! @cond ENTT_INTERNAL */
namespace internal {
struct meta_policy {};
} // namespace internal
/*! @endcond */
/*! @brief Empty class type used to request the _as-is_ policy. */
struct as_value_t final: private internal::meta_policy {
/*! @cond ENTT_INTERNAL */
template<typename>
static constexpr bool value = true;
/*! @endcond */
};
/*! @brief Empty class type used to request the _as void_ policy. */
struct as_void_t final: private internal::meta_policy {
/*! @cond ENTT_INTERNAL */
template<typename>
static constexpr bool value = true;
/*! @endcond */
};
/*! @brief Empty class type used to request the _as ref_ policy. */
struct as_ref_t final: private internal::meta_policy {
/*! @cond ENTT_INTERNAL */
template<typename Type>
static constexpr bool value = stl::is_reference_v<Type> && !stl::is_const_v<stl::remove_reference_t<Type>>;
/*! @endcond */
};
/*! @brief Empty class type used to request the _as cref_ policy. */
struct as_cref_t final: private internal::meta_policy {
/*! @cond ENTT_INTERNAL */
template<typename Type>
static constexpr bool value = stl::is_reference_v<Type>;
/*! @endcond */
};
/*! @brief Empty class type used to request the _as auto_ policy. */
struct as_is_t final: private internal::meta_policy {
/*! @cond ENTT_INTERNAL */
template<typename>
static constexpr bool value = true;
/*! @endcond */
};
/**
* @brief Provides the member constant `value` equal to true if a type also is a
* meta policy, false otherwise.
* @tparam Type Type to check.
*/
template<typename Type>
struct is_meta_policy
: stl::bool_constant<stl::is_base_of_v<internal::meta_policy, Type>> {};
/**
* @brief Helper variable template.
* @tparam Type Type to check.
*/
template<typename Type>
inline constexpr bool is_meta_policy_v = is_meta_policy<Type>::value;
/**
* @brief Specifies whether a type is a meta policy.
* @tparam Type Type to check.
*/
template<typename Type>
concept meta_policy = is_meta_policy_v<Type>;
} // namespace entt
#endif

119
include/entt/meta/range.hpp Normal file
View File

@@ -0,0 +1,119 @@
#ifndef ENTT_META_RANGE_HPP
#define ENTT_META_RANGE_HPP
#include <compare>
#include "../core/fwd.hpp"
#include "../core/iterator.hpp"
#include "../stl/concepts.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/iterator.hpp"
#include "../stl/utility.hpp"
#include "context.hpp"
namespace entt {
/*! @cond ENTT_INTERNAL */
namespace internal {
struct meta_base_node;
template<typename Type, typename It>
struct meta_range_iterator final {
using value_type = stl::pair<id_type, Type>;
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = stl::ptrdiff_t;
using iterator_category = stl::input_iterator_tag;
using iterator_concept = stl::random_access_iterator_tag;
constexpr meta_range_iterator() noexcept
: it{},
ctx{} {}
constexpr meta_range_iterator(const meta_ctx &area, const It iter) noexcept
: it{iter},
ctx{&area} {}
constexpr meta_range_iterator &operator++() noexcept {
return ++it, *this;
}
constexpr meta_range_iterator operator++(int) noexcept {
const meta_range_iterator orig = *this;
return ++(*this), orig;
}
constexpr meta_range_iterator &operator--() noexcept {
return --it, *this;
}
constexpr meta_range_iterator operator--(int) noexcept {
const meta_range_iterator orig = *this;
return operator--(), orig;
}
constexpr meta_range_iterator &operator+=(const difference_type value) noexcept {
it += value;
return *this;
}
constexpr meta_range_iterator operator+(const difference_type value) const noexcept {
meta_range_iterator copy = *this;
return (copy += value);
}
constexpr meta_range_iterator &operator-=(const difference_type value) noexcept {
return (*this += -value);
}
constexpr meta_range_iterator operator-(const difference_type value) const noexcept {
return (*this + -value);
}
[[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept {
if constexpr(stl::is_same_v<It, typename meta_context::bucket_type::const_iterator>) {
return {it[value].first, Type{*ctx, *it[value].second}};
} else {
return {it[value].id, Type{*ctx, it[value]}};
}
}
[[nodiscard]] constexpr pointer operator->() const noexcept {
return operator*();
}
[[nodiscard]] constexpr reference operator*() const noexcept {
return operator[](0);
}
[[nodiscard]] constexpr stl::ptrdiff_t operator-(const meta_range_iterator &other) const noexcept {
return it - other.it;
}
[[nodiscard]] constexpr bool operator==(const meta_range_iterator &other) const noexcept {
return it == other.it;
}
[[nodiscard]] constexpr auto operator<=>(const meta_range_iterator &other) const noexcept {
return it <=> other.it;
}
private:
It it;
const meta_ctx *ctx;
};
} // namespace internal
/*! @endcond */
/**
* @brief Iterable range to use to iterate all types of meta objects.
* @tparam Type Type of meta objects returned.
* @tparam It Type of forward iterator.
*/
template<typename Type, stl::forward_iterator It>
using meta_range = iterable_adaptor<internal::meta_range_iterator<Type, It>>;
} // namespace entt
#endif

View File

@@ -0,0 +1,109 @@
#ifndef ENTT_META_RESOLVE_HPP
#define ENTT_META_RESOLVE_HPP
#include "../core/type_info.hpp"
#include "../locator/locator.hpp"
#include "../stl/type_traits.hpp"
#include "context.hpp"
#include "meta.hpp"
#include "node.hpp"
#include "range.hpp"
namespace entt {
/**
* @brief Returns the meta type associated with a given type.
* @tparam Type Type to use to search for a meta type.
* @param ctx The context from which to search for meta types.
* @return The meta type associated with the given type, if any.
*/
template<typename Type>
[[nodiscard]] meta_type resolve(const meta_ctx &ctx) noexcept {
const auto &context = internal::meta_context::from(ctx);
return {ctx, internal::resolve<stl::remove_cvref_t<Type>>(context)};
}
/**
* @brief Returns the meta type associated with a given type.
* @tparam Type Type to use to search for a meta type.
* @return The meta type associated with the given type, if any.
*/
template<typename Type>
[[nodiscard]] meta_type resolve() noexcept {
return resolve<Type>(locator<meta_ctx>::value_or());
}
/**
* @brief Returns a range to use to visit all meta types.
* @param ctx The context from which to search for meta types.
* @return An iterable range to use to visit all meta types.
*/
[[nodiscard]] inline meta_range<meta_type, typename internal::meta_context::bucket_type::const_iterator> resolve(const meta_ctx &ctx) noexcept {
const auto &context = internal::meta_context::from(ctx);
return {{ctx, context.bucket.cbegin()}, {ctx, context.bucket.cend()}};
}
/**
* @brief Returns a range to use to visit all meta types.
* @return An iterable range to use to visit all meta types.
*/
[[nodiscard]] inline meta_range<meta_type, typename internal::meta_context::bucket_type::const_iterator> resolve() noexcept {
return resolve(locator<meta_ctx>::value_or());
}
/**
* @brief Returns the meta type associated with a given identifier, if any.
* @param ctx The context from which to search for meta types.
* @param alias Unique identifier.
* @return The meta type associated with the given identifier, if any.
*/
[[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const id_type alias) noexcept {
const auto &context = internal::meta_context::from(ctx);
// fast lookup for unsearchable and overloaded types
if(const auto it = context.bucket.find(alias); it != context.bucket.end()) {
return meta_type{ctx, *it->second};
}
for(auto &&curr: context.bucket) {
if(curr.second->alias == alias) {
return meta_type{ctx, *curr.second};
}
}
return meta_type{};
}
/**
* @brief Returns the meta type associated with a given identifier, if any.
* @param alias Unique identifier.
* @return The meta type associated with the given identifier, if any.
*/
[[nodiscard]] inline meta_type resolve(const id_type alias) noexcept {
return resolve(locator<meta_ctx>::value_or(), alias);
}
/**
* @brief Returns the meta type associated with a given type info object.
* @param ctx The context from which to search for meta types.
* @param info The type info object of the requested type.
* @return The meta type associated with the given type info object, if any.
*/
[[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const type_info &info) noexcept {
const auto &context = internal::meta_context::from(ctx);
const auto it = context.bucket.find(info.hash());
return (it == context.bucket.cend()) ? meta_type{} : meta_type{ctx, *it->second};
}
/**
* @brief Returns the meta type associated with a given type info object.
* @param info The type info object of the requested type.
* @return The meta type associated with the given type info object, if any.
*/
[[nodiscard]] inline meta_type resolve(const type_info &info) noexcept {
return resolve(locator<meta_ctx>::value_or(), info);
}
} // namespace entt
#endif

View File

@@ -0,0 +1,29 @@
// IWYU pragma: always_keep
#ifndef ENTT_META_TEMPLATE_HPP
#define ENTT_META_TEMPLATE_HPP
#include "../core/type_traits.hpp"
namespace entt {
/*! @brief Utility class to disambiguate class templates. */
template<template<typename...> class>
struct meta_class_template_tag {};
/**
* @brief General purpose traits class for generating meta template information.
* @tparam Clazz Type of class template.
* @tparam Args Types of template arguments.
*/
template<template<typename...> class Clazz, typename... Args>
struct meta_template_traits<Clazz<Args...>> {
/*! @brief Wrapped class template. */
using class_type = meta_class_template_tag<Clazz>;
/*! @brief List of template arguments. */
using args_type = type_list<Args...>;
};
} // namespace entt
#endif

View File

@@ -0,0 +1,54 @@
#ifndef ENTT_META_TYPE_TRAITS_HPP
#define ENTT_META_TYPE_TRAITS_HPP
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
namespace entt {
/**
* @brief Traits class template to be specialized to enable support for meta
* template information.
*/
template<typename>
struct meta_template_traits;
/**
* @brief Traits class template to be specialized to enable support for meta
* sequence containers.
*/
template<typename>
struct meta_sequence_container_traits;
/**
* @brief Traits class template to be specialized to enable support for meta
* associative containers.
*/
template<typename>
struct meta_associative_container_traits;
/**
* @brief Provides the member constant `value` equal to true if a given type is
* a pointer-like type, false otherwise.
*/
template<typename>
struct is_meta_pointer_like: stl::false_type {};
/**
* @brief Partial specialization to ensure that const pointer-like types are
* also accepted.
* @tparam Type Potentially pointer-like type.
*/
template<typename Type>
struct is_meta_pointer_like<const Type>: is_meta_pointer_like<Type> {};
/**
* @brief Helper variable template.
* @tparam Type Potentially pointer-like type.
*/
template<typename Type>
inline constexpr auto is_meta_pointer_like_v = is_meta_pointer_like<Type>::value;
} // namespace entt
#endif

View File

@@ -0,0 +1,500 @@
#ifndef ENTT_META_UTILITY_HPP
#define ENTT_META_UTILITY_HPP
#include "../core/type_traits.hpp"
#include "../locator/locator.hpp"
#include "../stl/cstddef.hpp"
#include "../stl/functional.hpp"
#include "../stl/type_traits.hpp"
#include "../stl/utility.hpp"
#include "meta.hpp"
#include "node.hpp"
#include "policy.hpp"
namespace entt {
/**
* @brief Meta function descriptor traits.
* @tparam Ret Function return type.
* @tparam Args Function arguments.
* @tparam Static Function staticness.
* @tparam Const Function constness.
*/
template<typename Ret, typename Args, bool Static, bool Const>
struct meta_function_descriptor_traits {
/*! @brief Meta function return type. */
using return_type = Ret;
/*! @brief Meta function arguments. */
using args_type = Args;
/*! @brief True if the meta function is static, false otherwise. */
static constexpr bool is_static = Static;
/*! @brief True if the meta function is const, false otherwise. */
static constexpr bool is_const = Const;
};
/*! @brief Primary template isn't defined on purpose. */
template<typename, typename>
struct meta_function_descriptor;
/**
* @brief Meta function descriptor.
* @tparam Type Reflected type to which the meta function is associated.
* @tparam Ret Function return type.
* @tparam Class Actual owner of the member function.
* @tparam Args Function arguments.
*/
template<typename Type, typename Ret, typename Class, typename... Args>
struct meta_function_descriptor<Type, Ret (Class::*)(Args...) const>
: meta_function_descriptor_traits<
Ret,
stl::conditional_t<stl::is_base_of_v<Class, Type>, type_list<Args...>, type_list<const Class &, Args...>>,
!stl::is_base_of_v<Class, Type>,
true> {};
/**
* @brief Meta function descriptor.
* @tparam Type Reflected type to which the meta function is associated.
* @tparam Ret Function return type.
* @tparam Class Actual owner of the member function.
* @tparam Args Function arguments.
*/
template<typename Type, typename Ret, typename Class, typename... Args>
struct meta_function_descriptor<Type, Ret (Class::*)(Args...)>
: meta_function_descriptor_traits<
Ret,
stl::conditional_t<stl::is_base_of_v<Class, Type>, type_list<Args...>, type_list<Class &, Args...>>,
!stl::is_base_of_v<Class, Type>,
false> {};
/**
* @brief Meta function descriptor.
* @tparam Type Reflected type to which the meta data is associated.
* @tparam Class Actual owner of the data member.
* @tparam Ret Data member type.
*/
template<typename Type, typename Ret, typename Class>
struct meta_function_descriptor<Type, Ret Class::*>
: meta_function_descriptor_traits<
Ret &,
stl::conditional_t<stl::is_base_of_v<Class, Type>, type_list<>, type_list<Class &>>,
!stl::is_base_of_v<Class, Type>,
false> {};
/**
* @brief Meta function descriptor.
* @tparam Type Reflected type to which the meta function is associated.
* @tparam Ret Function return type.
* @tparam MaybeType First function argument.
* @tparam Args Other function arguments.
*/
template<typename Type, typename Ret, typename MaybeType, typename... Args>
struct meta_function_descriptor<Type, Ret (*)(MaybeType, Args...)>
: meta_function_descriptor_traits<
Ret,
stl::conditional_t<
stl::is_same_v<stl::remove_cvref_t<MaybeType>, Type> || stl::is_base_of_v<stl::remove_cvref_t<MaybeType>, Type>,
type_list<Args...>,
type_list<MaybeType, Args...>>,
!(stl::is_same_v<stl::remove_cvref_t<MaybeType>, Type> || stl::is_base_of_v<stl::remove_cvref_t<MaybeType>, Type>),
stl::is_const_v<stl::remove_reference_t<MaybeType>> && (stl::is_same_v<stl::remove_cvref_t<MaybeType>, Type> || stl::is_base_of_v<stl::remove_cvref_t<MaybeType>, Type>)> {};
/**
* @brief Meta function descriptor.
* @tparam Type Reflected type to which the meta function is associated.
* @tparam Ret Function return type.
*/
template<typename Type, typename Ret>
struct meta_function_descriptor<Type, Ret (*)()>
: meta_function_descriptor_traits<
Ret,
type_list<>,
true,
false> {};
/**
* @brief Meta function helper.
*
* Converts a function type to be associated with a reflected type into its meta
* function descriptor.
*
* @tparam Type Reflected type to which the meta function is associated.
* @tparam Candidate The actual function to associate with the reflected type.
*/
template<typename Type, typename Candidate>
class meta_function_helper {
template<typename Ret, typename... Args, typename Class>
static meta_function_descriptor<Type, Ret (Class::*)(Args...) const> get_rid_of_noexcept(Ret (Class::*)(Args...) const);
template<typename Ret, typename... Args, typename Class>
static meta_function_descriptor<Type, Ret (Class::*)(Args...)> get_rid_of_noexcept(Ret (Class::*)(Args...));
template<typename Ret, typename Class>
requires stl::is_member_object_pointer_v<Ret Class::*>
static meta_function_descriptor<Type, Ret Class::*> get_rid_of_noexcept(Ret Class::*);
template<typename Ret, typename... Args>
static meta_function_descriptor<Type, Ret (*)(Args...)> get_rid_of_noexcept(Ret (*)(Args...));
template<typename Class>
static meta_function_descriptor<Class, decltype(&Class::operator())> get_rid_of_noexcept(Class);
public:
/*! @brief The meta function descriptor of the given function. */
using type = decltype(get_rid_of_noexcept(stl::declval<Candidate>()));
};
/**
* @brief Helper type.
* @tparam Type Reflected type to which the meta function is associated.
* @tparam Candidate The actual function to associate with the reflected type.
*/
template<typename Type, typename Candidate>
using meta_function_helper_t = meta_function_helper<Type, Candidate>::type;
/**
* @brief Wraps a value depending on the given policy.
*
* This function always returns a wrapped value in the requested context.<br/>
* Therefore, if the passed value is itself a wrapped object with a different
* context, it undergoes a rebinding to the requested context.
*
* @tparam Policy Optional policy (no policy set by default).
* @tparam Type Type of value to wrap.
* @param ctx The context from which to search for meta types.
* @param value Value to wrap.
* @return A meta any containing the returned value, if any.
*/
template<meta_policy Policy = as_value_t, typename Type>
[[nodiscard]] meta_any meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) {
if constexpr(stl::is_same_v<Policy, as_cref_t>) {
static_assert(stl::is_lvalue_reference_v<Type>, "Invalid type");
return meta_any{ctx, stl::in_place_type<const stl::remove_reference_t<Type> &>, stl::as_const(value)};
} else if constexpr(stl::is_same_v<Policy, as_ref_t> || (stl::is_same_v<Policy, as_is_t> && stl::is_lvalue_reference_v<Type>)) {
return meta_any{ctx, stl::in_place_type<Type>, value};
} else if constexpr(stl::is_same_v<Policy, as_void_t>) {
return meta_any{ctx, stl::in_place_type<void>};
} else {
return meta_any{ctx, stl::forward<Type>(value)};
}
}
/**
* @brief Wraps a value depending on the given policy.
* @tparam Policy Optional policy (no policy set by default).
* @tparam Type Type of value to wrap.
* @param value Value to wrap.
* @return A meta any containing the returned value, if any.
*/
template<meta_policy Policy = as_value_t, typename Type>
[[nodiscard]] meta_any meta_dispatch(Type &&value) {
return meta_dispatch<Policy, Type>(locator<meta_ctx>::value_or(), stl::forward<Type>(value));
}
/*! @cond ENTT_INTERNAL */
namespace internal {
template<typename Policy, typename Candidate, typename... Args>
[[nodiscard]] meta_any meta_invoke_with_args(const meta_ctx &ctx, Candidate &&candidate, Args &&...args) {
if constexpr(stl::is_void_v<decltype(stl::invoke(stl::forward<Candidate>(candidate), args...))>) {
stl::invoke(stl::forward<Candidate>(candidate), args...);
return meta_any{ctx, stl::in_place_type<void>};
} else {
return meta_dispatch<Policy>(ctx, stl::invoke(stl::forward<Candidate>(candidate), args...));
}
}
template<typename Type, typename Policy, typename Candidate, stl::size_t... Index>
[[nodiscard]] meta_any meta_invoke(meta_any &instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args, stl::index_sequence<Index...>) {
using descriptor = meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>;
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span)
if constexpr(stl::is_invocable_v<stl::remove_reference_t<Candidate>, const Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
if(const auto *const clazz = instance.try_cast<const Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
return meta_invoke_with_args<Policy>(instance.context(), stl::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
}
} else if constexpr(stl::is_invocable_v<stl::remove_reference_t<Candidate>, Type &, type_list_element_t<Index, typename descriptor::args_type>...>) {
if(auto *const clazz = instance.try_cast<Type>(); clazz && ((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
return meta_invoke_with_args<Policy>(instance.context(), stl::forward<Candidate>(candidate), *clazz, (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
}
} else {
if(((args + Index)->allow_cast<type_list_element_t<Index, typename descriptor::args_type>>() && ...)) {
return meta_invoke_with_args<Policy>(instance.context(), stl::forward<Candidate>(candidate), (args + Index)->cast<type_list_element_t<Index, typename descriptor::args_type>>()...);
}
}
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
return meta_any{meta_ctx_arg, instance.context()};
}
template<typename Type, typename... Args, stl::size_t... Index>
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args, stl::index_sequence<Index...>) {
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span)
if(((args + Index)->allow_cast<Args>() && ...)) {
return meta_any{ctx, stl::in_place_type<Type>, (args + Index)->cast<Args>()...};
}
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
return meta_any{meta_ctx_arg, ctx};
}
} // namespace internal
/*! @endcond */
/**
* @brief Returns the meta type of the i-th element of a list of arguments.
* @tparam Type Type list of the actual types of arguments.
* @param ctx The context from which to search for meta types.
* @param index The index of the element for which to return the meta type.
* @return The meta type of the i-th element of the list of arguments.
*/
template<typename Type>
[[nodiscard]] meta_type meta_arg(const meta_ctx &ctx, const stl::size_t index) noexcept {
const auto &context = internal::meta_context::from(ctx);
return {ctx, internal::meta_arg_node(context, Type{}, index)};
}
/**
* @brief Returns the meta type of the i-th element of a list of arguments.
* @tparam Type Type list of the actual types of arguments.
* @param index The index of the element for which to return the meta type.
* @return The meta type of the i-th element of the list of arguments.
*/
template<typename Type>
[[nodiscard]] meta_type meta_arg(const stl::size_t index) noexcept {
return meta_arg<Type>(locator<meta_ctx>::value_or(), index);
}
/**
* @brief Sets the value of a given variable.
* @tparam Type Reflected type to which the variable is associated.
* @tparam Data The actual variable to set.
* @param instance An opaque instance of the underlying type, if required.
* @param args Parameters to use to set the variable.
* @return True in case of success, false otherwise.
*/
template<typename Type, auto Data>
[[nodiscard]] bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any *const args) {
if constexpr(stl::is_member_function_pointer_v<decltype(Data)> || stl::is_function_v<stl::remove_reference_t<stl::remove_pointer_t<decltype(Data)>>>) {
return static_cast<bool>(internal::meta_invoke<Type, as_void_t>(*instance.operator->(), Data, args, stl::make_index_sequence<meta_function_helper_t<Type, decltype(Data)>::args_type::size>{}));
} else if constexpr(stl::is_member_object_pointer_v<decltype(Data)>) {
using data_type = stl::remove_reference_t<typename meta_function_helper_t<Type, decltype(Data)>::return_type>;
if constexpr(!stl::is_array_v<data_type> && !stl::is_const_v<data_type>) {
if(auto *const clazz = instance->try_cast<Type>(); clazz && args->allow_cast<data_type>()) {
stl::invoke(Data, *clazz) = args->cast<data_type>();
return true;
}
}
return false;
} else if constexpr(stl::is_pointer_v<decltype(Data)>) {
using data_type = stl::remove_reference_t<decltype(*Data)>;
if constexpr(!stl::is_array_v<data_type> && !stl::is_const_v<data_type>) {
if(args->allow_cast<data_type>()) {
*Data = args->cast<data_type>();
return true;
}
}
return false;
} else {
return false;
}
}
/**
* @brief Sets the value of a given variable.
* @tparam Type Reflected type to which the variable is associated.
* @tparam Data The actual variable to set.
* @param instance An opaque instance of the underlying type, if required.
* @param value Parameter to use to set the variable.
* @return True in case of success, false otherwise.
*/
template<typename Type, auto Data>
[[nodiscard]] bool meta_setter(meta_handle instance, meta_any value) {
return meta_setter<Type, Data>(*instance.operator->(), &value);
}
/**
* @brief Gets the value of a given variable.
* @tparam Type Reflected type to which the variable is associated.
* @tparam Data The actual variable to get.
* @tparam Policy Optional policy (no policy set by default).
* @param instance An opaque instance of the underlying type, if required.
* @param args Parameters to use to set the variable.
* @return A meta any containing the value of the underlying variable.
*/
template<typename Type, auto Data, meta_policy Policy = as_value_t>
[[nodiscard]] meta_any meta_getter(meta_handle instance, [[maybe_unused]] meta_any *const args) {
if constexpr(stl::is_member_function_pointer_v<decltype(Data)> || stl::is_function_v<stl::remove_reference_t<stl::remove_pointer_t<decltype(Data)>>>) {
return internal::meta_invoke<Type, Policy>(*instance.operator->(), Data, args, stl::make_index_sequence<meta_function_helper_t<Type, decltype(Data)>::args_type::size>{});
} else if constexpr(stl::is_member_object_pointer_v<decltype(Data)>) {
if constexpr(!stl::is_array_v<stl::remove_cvref_t<stl::invoke_result_t<decltype(Data), Type &>>>) {
if(auto *clazz = instance->try_cast<Type>(); clazz) {
return meta_dispatch<Policy>(instance->context(), stl::invoke(Data, *clazz));
} else if(auto *fallback = instance->try_cast<const Type>(); fallback) {
return meta_dispatch<Policy>(instance->context(), stl::invoke(Data, *fallback));
}
}
return meta_any{meta_ctx_arg, instance->context()};
} else if constexpr(stl::is_pointer_v<decltype(Data)>) {
if constexpr(stl::is_array_v<stl::remove_pointer_t<decltype(Data)>>) {
return meta_any{meta_ctx_arg, instance->context()};
} else {
return meta_dispatch<Policy>(instance->context(), *Data);
}
} else {
return meta_dispatch<Policy>(instance->context(), Data);
}
}
/**
* @brief Gets the value of a given variable.
* @tparam Type Reflected type to which the variable is associated.
* @tparam Data The actual variable to get.
* @tparam Policy Optional policy (no policy set by default).
* @param instance An opaque instance of the underlying type, if required.
* @return A meta any containing the value of the underlying variable.
*/
template<typename Type, auto Data, meta_policy Policy = as_value_t>
[[nodiscard]] meta_any meta_getter(meta_handle instance) {
return meta_getter<Type, Data, Policy>(*instance.operator->(), nullptr);
}
/**
* @brief Tries to _invoke_ an object given a list of erased parameters.
* @tparam Type Reflected type to which the object to _invoke_ is associated.
* @tparam Policy Optional policy (no policy set by default).
* @tparam Candidate The type of the actual object to _invoke_.
* @param instance An opaque instance of the underlying type, if required.
* @param candidate The actual object to _invoke_.
* @param args Parameters to use to _invoke_ the object.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, meta_policy Policy = as_value_t, typename Candidate>
[[nodiscard]] meta_any meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args) {
return internal::meta_invoke<Type, Policy>(*instance.operator->(), stl::forward<Candidate>(candidate), args, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>::args_type::size>{});
}
/**
* @brief Tries to invoke a function given a list of erased parameters.
* @tparam Type Reflected type to which the function is associated.
* @tparam Candidate The actual function to invoke.
* @tparam Policy Optional policy (no policy set by default).
* @param instance An opaque instance of the underlying type, if required.
* @param args Parameters to use to invoke the function.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, auto Candidate, meta_policy Policy = as_value_t>
[[nodiscard]] meta_any meta_invoke(meta_handle instance, meta_any *const args) {
return internal::meta_invoke<Type, Policy>(*instance.operator->(), Candidate, args, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<decltype(Candidate)>>::args_type::size>{});
}
/**
* @brief Tries to construct an instance given a list of erased parameters.
*
* @warning
* The context provided is used only for the return type.<br/>
* It's up to the caller to bind the arguments to the right context(s).
*
* @tparam Type Actual type of the instance to construct.
* @tparam Args Types of arguments expected.
* @param ctx The context from which to search for meta types.
* @param args Parameters to use to construct the instance.
* @return A meta any containing the new instance, if any.
*/
template<typename Type, typename... Args>
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) {
return internal::meta_construct<Type, Args...>(ctx, args, stl::index_sequence_for<Args...>{});
}
/**
* @brief Tries to construct an instance given a list of erased parameters.
* @tparam Type Actual type of the instance to construct.
* @tparam Args Types of arguments expected.
* @param args Parameters to use to construct the instance.
* @return A meta any containing the new instance, if any.
*/
template<typename Type, typename... Args>
[[nodiscard]] meta_any meta_construct(meta_any *const args) {
return meta_construct<Type, Args...>(locator<meta_ctx>::value_or(), args);
}
/**
* @brief Tries to construct an instance given a list of erased parameters.
*
* @warning
* The context provided is used only for the return type.<br/>
* It's up to the caller to bind the arguments to the right context(s).
*
* @tparam Type Reflected type to which the object to _invoke_ is associated.
* @tparam Policy Optional policy (no policy set by default).
* @tparam Candidate The type of the actual object to _invoke_.
* @param ctx The context from which to search for meta types.
* @param candidate The actual object to _invoke_.
* @param args Parameters to use to _invoke_ the object.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, typename Policy = as_value_t, typename Candidate>
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, Candidate &&candidate, meta_any *const args) {
if constexpr(meta_function_helper_t<Type, Candidate>::is_static || stl::is_class_v<stl::remove_cvref_t<Candidate>>) {
meta_any placeholder{meta_ctx_arg, ctx};
return internal::meta_invoke<Type, Policy>(placeholder, stl::forward<Candidate>(candidate), args, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>::args_type::size>{});
} else {
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span)
return internal::meta_invoke<Type, Policy>(*args, stl::forward<Candidate>(candidate), args + 1u, stl::make_index_sequence<meta_function_helper_t<Type, stl::remove_reference_t<Candidate>>::args_type::size>{});
}
}
/**
* @brief Tries to construct an instance given a list of erased parameters.
* @tparam Type Reflected type to which the object to _invoke_ is associated.
* @tparam Policy Optional policy (no policy set by default).
* @tparam Candidate The type of the actual object to _invoke_.
* @param candidate The actual object to _invoke_.
* @param args Parameters to use to _invoke_ the object.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, meta_policy Policy = as_value_t, typename Candidate>
[[nodiscard]] meta_any meta_construct(Candidate &&candidate, meta_any *const args) {
return meta_construct<Type, Policy>(locator<meta_ctx>::value_or(), stl::forward<Candidate>(candidate), args);
}
/**
* @brief Tries to construct an instance given a list of erased parameters.
*
* @warning
* The context provided is used only for the return type.<br/>
* It's up to the caller to bind the arguments to the right context(s).
*
* @tparam Type Reflected type to which the function is associated.
* @tparam Candidate The actual function to invoke.
* @tparam Policy Optional policy (no policy set by default).
* @param ctx The context from which to search for meta types.
* @param args Parameters to use to invoke the function.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, auto Candidate, meta_policy Policy = as_value_t>
[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) {
return meta_construct<Type, Policy>(ctx, Candidate, args);
}
/**
* @brief Tries to construct an instance given a list of erased parameters.
* @tparam Type Reflected type to which the function is associated.
* @tparam Candidate The actual function to invoke.
* @tparam Policy Optional policy (no policy set by default).
* @param args Parameters to use to invoke the function.
* @return A meta any containing the returned value, if any.
*/
template<typename Type, auto Candidate, meta_policy Policy = as_value_t>
[[nodiscard]] meta_any meta_construct(meta_any *const args) {
return meta_construct<Type, Candidate, Policy>(locator<meta_ctx>::value_or(), args);
}
} // namespace entt
#endif