meta: fake vtable for meta sequence containers

This commit is contained in:
skypjack
2023-07-17 14:58:36 +02:00
committed by Michele Caini
parent 4b307cb2b2
commit 44f30dc01c
2 changed files with 103 additions and 82 deletions

View File

@@ -48,72 +48,69 @@ template<typename Type>
struct basic_meta_sequence_container_traits {
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Unexpected type");
using iterator = meta_sequence_container::iterator;
using size_type = std::size_t;
using operation = internal::meta_sequence_container_operation;
using size_type = typename meta_sequence_container::size_type;
using iterator = typename meta_sequence_container::iterator;
[[nodiscard]] static size_type size(const void *container) noexcept {
return static_cast<const Type *>(container)->size();
}
[[nodiscard]] static bool clear(void *container) {
if constexpr(dynamic_sequence_container<Type>::value) {
static_cast<Type *>(container)->clear();
return true;
} else {
return false;
}
}
[[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
if constexpr(reserve_aware_container<Type>::value) {
static_cast<Type *>(container)->reserve(sz);
return true;
} else {
return false;
}
}
[[nodiscard]] static bool resize([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) {
if constexpr(dynamic_sequence_container<Type>::value) {
static_cast<Type *>(container)->resize(sz);
return true;
} else {
return false;
}
}
[[nodiscard]] static iterator iter(const meta_ctx &ctx, const void *container, const bool as_const, const bool as_end) {
if(as_const) {
const auto it = as_end ? static_cast<const Type *>(container)->end() : static_cast<const Type *>(container)->begin();
return iterator{ctx, it};
} else {
const auto it = as_end ? static_cast<Type *>(const_cast<void *>(container))->end() : static_cast<Type *>(const_cast<void *>(container))->begin();
return iterator{ctx, it};
}
}
[[nodiscard]] static iterator insert_or_erase([[maybe_unused]] const meta_ctx &ctx, [[maybe_unused]] void *container, [[maybe_unused]] const any &handle, [[maybe_unused]] meta_any &value) {
if constexpr(dynamic_sequence_container<Type>::value) {
typename Type::const_iterator it{};
if(auto *const non_const = any_cast<typename Type::iterator>(&handle); non_const) {
it = *non_const;
static size_type basic_vtable(const operation op, const meta_ctx &ctx, const void *container, const void *value, iterator *it) {
switch(const Type *cont = static_cast<const Type *>(container); op) {
case operation::size:
return cont->size();
case operation::clear:
if constexpr(dynamic_sequence_container<Type>::value) {
const_cast<Type *>(cont)->clear();
return true;
} else {
it = any_cast<const typename Type::const_iterator &>(handle);
break;
}
case operation::reserve:
if constexpr(reserve_aware_container<Type>::value) {
const_cast<Type *>(cont)->reserve(*static_cast<const size_type *>(value));
return true;
} else {
break;
}
case operation::resize:
if constexpr(dynamic_sequence_container<Type>::value) {
const_cast<Type *>(cont)->resize(*static_cast<const size_type *>(value));
return true;
} else {
break;
}
case operation::begin:
*it = iterator{ctx, const_cast<Type *>(cont)->begin()};
return true;
case operation::end:
*it = iterator{ctx, const_cast<Type *>(cont)->end()};
return true;
case operation::cbegin:
*it = iterator{ctx, cont->begin()};
return true;
case operation::cend:
*it = iterator{ctx, cont->end()};
return true;
case operation::insert:
case operation::erase:
if constexpr(dynamic_sequence_container<Type>::value) {
auto *const non_const = any_cast<typename Type::iterator>(&it->base());
typename Type::const_iterator underlying{non_const ? *non_const : any_cast<const typename Type::const_iterator &>(it->base())};
if(auto *const cont = static_cast<Type *>(container); value) {
// this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
if(value.allow_cast<typename Type::const_reference>() || value.allow_cast<typename Type::value_type>()) {
const auto *element = value.try_cast<std::remove_reference_t<typename Type::const_reference>>();
return iterator{ctx, cont->insert(it, element ? *element : value.cast<typename Type::value_type>())};
if(op == operation::insert) {
// this abomination is necessary because only on macos value_type and const_reference are different types for std::vector<bool>
if(static_cast<meta_any *>(const_cast<void *>(value))->allow_cast<typename Type::const_reference>() || static_cast<meta_any *>(const_cast<void *>(value))->allow_cast<typename Type::value_type>()) {
const auto *element = static_cast<meta_any *>(const_cast<void *>(value))->try_cast<std::remove_reference_t<typename Type::const_reference>>();
*it = iterator{ctx, const_cast<Type *>(cont)->insert(underlying, element ? *element : static_cast<meta_any *>(const_cast<void *>(value))->cast<typename Type::value_type>())};
return true;
}
} else {
*it = iterator{ctx, const_cast<Type *>(cont)->erase(underlying)};
return true;
}
} else {
return iterator{ctx, cont->erase(it)};
}
break;
}
return iterator{};
return false;
}
};
@@ -121,8 +118,8 @@ template<typename Type>
struct basic_meta_associative_container_traits {
static_assert(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>, "Unexpected type");
using iterator = meta_associative_container::iterator;
using size_type = std::size_t;
using size_type = typename meta_associative_container::size_type;
using iterator = typename meta_associative_container::iterator;
static constexpr auto key_only = key_only_associative_container<Type>::value;

View File

@@ -26,9 +26,37 @@ namespace entt {
class meta_any;
class meta_type;
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
enum class meta_sequence_container_operation {
size,
clear,
reserve,
resize,
begin,
end,
cbegin,
cend,
insert,
erase
};
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/*! @brief Proxy object for sequence containers. */
class meta_sequence_container {
class meta_iterator;
using operation = internal::meta_sequence_container_operation;
public:
/*! @brief Unsigned integer type. */
@@ -52,12 +80,7 @@ public:
void rebind(any instance) noexcept {
ENTT_ASSERT(instance.type() == type_id<Type>(), "Unexpected type");
value_type_node = &internal::resolve<typename Type::value_type>;
size_fn = &meta_sequence_container_traits<Type>::size;
clear_fn = &meta_sequence_container_traits<Type>::clear;
reserve_fn = &meta_sequence_container_traits<Type>::reserve;
resize_fn = &meta_sequence_container_traits<Type>::resize;
iter_fn = &meta_sequence_container_traits<Type>::iter;
insert_or_erase_fn = &meta_sequence_container_traits<Type>::insert_or_erase;
vtable = &meta_sequence_container_traits<Type>::basic_vtable;
storage = std::move(instance);
}
@@ -76,12 +99,7 @@ public:
private:
const meta_ctx *ctx{};
internal::meta_type_node (*value_type_node)(const internal::meta_context &){};
size_type (*size_fn)(const void *) noexcept {};
bool (*clear_fn)(void *){};
bool (*reserve_fn)(void *, const size_type){};
bool (*resize_fn)(void *, const size_type){};
iterator (*iter_fn)(const meta_ctx &, const void *, const bool, const bool){};
iterator (*insert_or_erase_fn)(const meta_ctx &, void *, const any &, meta_any &){};
size_type (*vtable)(const operation, const meta_ctx &, const void *, const void *, iterator *){};
any storage{};
};
@@ -1675,8 +1693,6 @@ inline bool meta_any::assign(meta_any &&other) {
*/
class meta_sequence_container::meta_iterator final {
friend class meta_sequence_container;
using vtable_type = void(const void *, const std::ptrdiff_t, meta_any *);
template<typename It>
@@ -1750,6 +1766,10 @@ public:
return !(*this == other);
}
[[nodiscard]] const any &base() const noexcept {
return handle;
}
private:
const meta_ctx *ctx;
vtable_type *vtable;
@@ -1847,7 +1867,7 @@ private:
* @return The size of the container.
*/
[[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const noexcept {
return size_fn(storage.data());
return vtable(operation::size, *ctx, std::as_const(storage).data(), nullptr, nullptr);
}
/**
@@ -1856,7 +1876,7 @@ private:
* @return True in case of success, false otherwise.
*/
inline bool meta_sequence_container::resize(const size_type sz) {
return (storage.policy() != any_policy::cref) && resize_fn(storage.data(), sz);
return (storage.policy() != any_policy::cref) && vtable(operation::resize, *ctx, storage.data(), &sz, nullptr);
}
/**
@@ -1864,7 +1884,7 @@ inline bool meta_sequence_container::resize(const size_type sz) {
* @return True in case of success, false otherwise.
*/
inline bool meta_sequence_container::clear() {
return (storage.policy() != any_policy::cref) && clear_fn(storage.data());
return (storage.policy() != any_policy::cref) && vtable(operation::clear, *ctx, storage.data(), nullptr, nullptr);
}
/**
@@ -1873,7 +1893,7 @@ inline bool meta_sequence_container::clear() {
* @return True in case of success, false otherwise.
*/
inline bool meta_sequence_container::reserve(const size_type sz) {
return (storage.policy() != any_policy::cref) && reserve_fn(storage.data(), sz);
return (storage.policy() != any_policy::cref) && vtable(operation::reserve, *ctx, storage.data(), &sz, nullptr);
}
/**
@@ -1881,7 +1901,9 @@ inline bool meta_sequence_container::reserve(const size_type sz) {
* @return An iterator to the first element of the container.
*/
[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() {
return iter_fn(*ctx, std::as_const(storage).data(), (storage.policy() == any_policy::cref), false);
iterator it{};
vtable(storage.policy() == any_policy::cref ? operation::cbegin : operation::begin, *ctx, std::as_const(storage).data(), nullptr, &it);
return it;
}
/**
@@ -1889,7 +1911,9 @@ inline bool meta_sequence_container::reserve(const size_type sz) {
* @return An iterator that is past the last element of the container.
*/
[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() {
return iter_fn(*ctx, std::as_const(storage).data(), (storage.policy() == any_policy::cref), true);
iterator it{};
vtable(storage.policy() == any_policy::cref ? operation::cend : operation::end, *ctx, std::as_const(storage).data(), nullptr, &it);
return it;
}
/**
@@ -1899,7 +1923,7 @@ inline bool meta_sequence_container::reserve(const size_type sz) {
* @return A possibly invalid iterator to the inserted element.
*/
inline meta_sequence_container::iterator meta_sequence_container::insert(iterator it, meta_any value) {
return (storage.policy() != any_policy::cref) ? insert_or_erase_fn(*ctx, storage.data(), it.handle, value) : iterator{};
return ((storage.policy() != any_policy::cref) && vtable(operation::insert, *ctx, storage.data(), &value, &it)) ? it : iterator{};
}
/**
@@ -1908,7 +1932,7 @@ inline meta_sequence_container::iterator meta_sequence_container::insert(iterato
* @return A possibly invalid iterator following the last removed element.
*/
inline meta_sequence_container::iterator meta_sequence_container::erase(iterator it) {
return insert(it, {});
return ((storage.policy() != any_policy::cref) && vtable(operation::erase, *ctx, storage.data(), nullptr, &it)) ? it : iterator{};
}
/**