meta:
* improved sequence container support for non-contiguous containers * added support to (standard) deque as sequence containers
This commit is contained in:
1
TODO
1
TODO
@@ -12,7 +12,6 @@ DOC:
|
||||
* update entity doc when the storage based model is in place
|
||||
|
||||
WIP:
|
||||
* meta: add deque support as sequence container
|
||||
* no gh-pages, use main/docs or similar, see settings/pages on gh
|
||||
* sparse set/storage support for move-only types, internal rework required
|
||||
* get rid of observers, storage based views made them pointless - document alternatives
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define ENTT_META_CONTAINER_HPP
|
||||
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <map>
|
||||
@@ -58,26 +59,29 @@ struct basic_meta_sequence_container_traits {
|
||||
|
||||
[[nodiscard]] static iterator iter(any &container, const bool as_end) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
return iterator{*cont, static_cast<typename iterator::difference_type>(as_end * cont->size())};
|
||||
return iterator{as_end ? cont->end() : cont->begin()};
|
||||
}
|
||||
|
||||
const Type &as_const = any_cast<const Type &>(container);
|
||||
return iterator{as_const, static_cast<typename iterator::difference_type>(as_end * as_const.size())};
|
||||
return iterator{as_end ? as_const.end() : as_const.begin()};
|
||||
}
|
||||
|
||||
[[nodiscard]] static iterator insert_or_erase([[maybe_unused]] any &container, [[maybe_unused]] const std::ptrdiff_t offset, [[maybe_unused]] meta_any &value) {
|
||||
[[nodiscard]] static iterator insert_or_erase([[maybe_unused]] any &container, [[maybe_unused]] const any &handle, [[maybe_unused]] meta_any &value) {
|
||||
if constexpr(is_dynamic_sequence_container<Type>::value) {
|
||||
if(auto *const cont = any_cast<Type>(&container); cont) {
|
||||
if(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>>();
|
||||
const auto curr = cont->insert(std::next(cont->begin(), offset), element ? *element : value.cast<typename Type::value_type>());
|
||||
return iterator{*cont, static_cast<std::ptrdiff_t>(offset)};
|
||||
auto *it = any_cast<typename Type::iterator>(&handle);
|
||||
|
||||
return iterator{cont->insert(
|
||||
it ? *it : any_cast<typename Type::const_iterator>(handle),
|
||||
element ? *element : value.cast<typename Type::value_type>())};
|
||||
}
|
||||
} else {
|
||||
const auto curr = cont->erase(std::next(cont->begin(), offset));
|
||||
return iterator{*cont, static_cast<std::ptrdiff_t>(offset)};
|
||||
auto *it = any_cast<typename Type::iterator>(&handle);
|
||||
return iterator{it ? cont->erase(*it) : cont->erase(any_cast<typename Type::const_iterator>(handle))};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,6 +182,15 @@ template<typename Type, typename... Args>
|
||||
struct meta_sequence_container_traits<std::list<Type, Args...>>
|
||||
: internal::basic_meta_sequence_container_traits<std::list<Type, Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta sequence container traits for `std::deque`s of any type.
|
||||
* @tparam Type The type of elements.
|
||||
* @tparam Args Other arguments.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
struct meta_sequence_container_traits<std::deque<Type, Args...>>
|
||||
: internal::basic_meta_sequence_container_traits<std::deque<Type, Args...>> {};
|
||||
|
||||
/**
|
||||
* @brief Meta associative container traits for `std::map`s of any type.
|
||||
* @tparam Key The key type of elements.
|
||||
|
||||
@@ -68,7 +68,7 @@ private:
|
||||
size_type (*size_fn)(const any &) noexcept = nullptr;
|
||||
bool (*resize_fn)(any &, size_type) = nullptr;
|
||||
iterator (*iter_fn)(any &, const bool) = nullptr;
|
||||
iterator (*insert_or_erase_fn)(any &, const std::ptrdiff_t, meta_any &) = nullptr;
|
||||
iterator (*insert_or_erase_fn)(any &, const any &, meta_any &) = nullptr;
|
||||
any storage{};
|
||||
};
|
||||
|
||||
@@ -1467,11 +1467,25 @@ inline bool meta_any::assign(meta_any &&other) {
|
||||
class meta_sequence_container::meta_iterator final {
|
||||
friend class meta_sequence_container;
|
||||
|
||||
using deref_fn_type = meta_any(const any &, const std::ptrdiff_t);
|
||||
enum class operation : std::uint8_t {
|
||||
incr,
|
||||
deref
|
||||
};
|
||||
|
||||
using vtable_type = void(const operation, const any &, const std::ptrdiff_t, meta_any *);
|
||||
|
||||
template<typename It>
|
||||
static meta_any deref_fn(const any &value, const std::ptrdiff_t pos) {
|
||||
return meta_any{std::in_place_type<typename std::iterator_traits<It>::reference>, *std::next(any_cast<const It &>(value), pos)};
|
||||
static void basic_vtable(const operation op, const any &value, const std::ptrdiff_t offset, meta_any *other) {
|
||||
switch(op) {
|
||||
case operation::incr: {
|
||||
auto &it = any_cast<It &>(const_cast<any &>(value));
|
||||
it = std::next(it, offset);
|
||||
} break;
|
||||
case operation::deref: {
|
||||
const auto &it = any_cast<const It &>(value);
|
||||
other->emplace<decltype(*it)>(*it);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -1482,38 +1496,40 @@ public:
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
constexpr meta_iterator() noexcept
|
||||
: deref{},
|
||||
offset{},
|
||||
: vtable{},
|
||||
handle{} {}
|
||||
|
||||
template<typename Type>
|
||||
explicit meta_iterator(Type &cont, const difference_type init) noexcept
|
||||
: deref{&deref_fn<decltype(cont.begin())>},
|
||||
offset{init},
|
||||
handle{cont.begin()} {}
|
||||
template<typename It>
|
||||
explicit meta_iterator(It iter) noexcept
|
||||
: vtable{&basic_vtable<It>},
|
||||
handle{std::move(iter)} {}
|
||||
|
||||
meta_iterator &operator++() noexcept {
|
||||
return ++offset, *this;
|
||||
vtable(operation::incr, handle, 1, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
meta_iterator operator++(int value) noexcept {
|
||||
meta_iterator orig = *this;
|
||||
offset += ++value;
|
||||
vtable(operation::incr, handle, ++value, nullptr);
|
||||
return orig;
|
||||
}
|
||||
|
||||
meta_iterator &operator--() noexcept {
|
||||
return --offset, *this;
|
||||
vtable(operation::incr, handle, -1, nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
meta_iterator operator--(int value) noexcept {
|
||||
meta_iterator orig = *this;
|
||||
offset -= ++value;
|
||||
vtable(operation::incr, handle, --value, nullptr);
|
||||
return orig;
|
||||
}
|
||||
|
||||
[[nodiscard]] reference operator*() const {
|
||||
return deref(handle, offset);
|
||||
reference other;
|
||||
vtable(operation::deref, handle, 0, &other);
|
||||
return other;
|
||||
}
|
||||
|
||||
[[nodiscard]] pointer operator->() const {
|
||||
@@ -1525,7 +1541,7 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const meta_iterator &other) const noexcept {
|
||||
return offset == other.offset;
|
||||
return handle == other.handle;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator!=(const meta_iterator &other) const noexcept {
|
||||
@@ -1533,8 +1549,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
deref_fn_type *deref;
|
||||
difference_type offset;
|
||||
vtable_type *vtable;
|
||||
any handle;
|
||||
};
|
||||
|
||||
@@ -1678,7 +1693,7 @@ inline bool meta_sequence_container::clear() {
|
||||
* @return A possibly invalid iterator to the inserted element.
|
||||
*/
|
||||
inline meta_sequence_container::iterator meta_sequence_container::insert(iterator it, meta_any value) {
|
||||
return insert_or_erase_fn(storage, it.offset, value);
|
||||
return insert_or_erase_fn(storage, it.handle, value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <array>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <set>
|
||||
@@ -252,6 +253,53 @@ TEST_F(MetaContainer, StdList) {
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, StdDeque) {
|
||||
std::deque<int> deque{};
|
||||
auto any = entt::forward_as_meta(deque);
|
||||
auto view = any.as_sequence_container();
|
||||
|
||||
ASSERT_TRUE(view);
|
||||
ASSERT_EQ(view.value_type(), entt::resolve<int>());
|
||||
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
ASSERT_EQ(view.begin(), view.end());
|
||||
ASSERT_TRUE(view.resize(3u));
|
||||
ASSERT_EQ(view.size(), 3u);
|
||||
ASSERT_NE(view.begin(), view.end());
|
||||
|
||||
view[0].cast<int &>() = 2;
|
||||
view[1].cast<int &>() = 3;
|
||||
view[2].cast<int &>() = 4;
|
||||
|
||||
ASSERT_EQ(view[1u].cast<int>(), 3);
|
||||
|
||||
auto it = view.begin();
|
||||
auto ret = view.insert(it, 0);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_FALSE(view.insert(ret, invalid_type{}));
|
||||
ASSERT_TRUE(view.insert(++ret, 1.));
|
||||
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ(view.begin()->cast<int>(), 0);
|
||||
ASSERT_EQ((++view.begin())->cast<int>(), 1);
|
||||
|
||||
ret = view.insert(view.end(), 42);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(*ret, 42);
|
||||
|
||||
it = view.begin();
|
||||
ret = view.erase(it);
|
||||
|
||||
ASSERT_TRUE(ret);
|
||||
ASSERT_EQ(view.size(), 5u);
|
||||
ASSERT_EQ(ret->cast<int>(), 1);
|
||||
|
||||
ASSERT_TRUE(view.clear());
|
||||
ASSERT_EQ(view.size(), 0u);
|
||||
}
|
||||
|
||||
TEST_F(MetaContainer, StdMap) {
|
||||
std::map<int, char> map{{2, 'c'}, {3, 'd'}, {4, 'e'}};
|
||||
auto any = entt::forward_as_meta(map);
|
||||
|
||||
Reference in New Issue
Block a user