mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
build: add entt library
This commit is contained in:
35
include/entt/meta/adl_pointer.hpp
Normal file
35
include/entt/meta/adl_pointer.hpp
Normal 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
|
||||
298
include/entt/meta/container.hpp
Normal file
298
include/entt/meta/container.hpp
Normal 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
|
||||
47
include/entt/meta/context.hpp
Normal file
47
include/entt/meta/context.hpp
Normal 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
|
||||
656
include/entt/meta/factory.hpp
Normal file
656
include/entt/meta/factory.hpp
Normal 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
43
include/entt/meta/fwd.hpp
Normal 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
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
287
include/entt/meta/node.hpp
Normal 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
|
||||
42
include/entt/meta/pointer.hpp
Normal file
42
include/entt/meta/pointer.hpp
Normal 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
|
||||
81
include/entt/meta/policy.hpp
Normal file
81
include/entt/meta/policy.hpp
Normal 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
119
include/entt/meta/range.hpp
Normal 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
|
||||
109
include/entt/meta/resolve.hpp
Normal file
109
include/entt/meta/resolve.hpp
Normal 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
|
||||
29
include/entt/meta/template.hpp
Normal file
29
include/entt/meta/template.hpp
Normal 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
|
||||
54
include/entt/meta/type_traits.hpp
Normal file
54
include/entt/meta/type_traits.hpp
Normal 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
|
||||
500
include/entt/meta/utility.hpp
Normal file
500
include/entt/meta/utility.hpp
Normal 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
|
||||
Reference in New Issue
Block a user