handle: remove visit, use iterable objects instead

This commit is contained in:
Michele Caini
2022-06-20 08:22:57 +02:00
parent c2d2ba29ea
commit c441a9ad97
3 changed files with 109 additions and 27 deletions
+1 -1
View File
@@ -13,9 +13,9 @@ DOC:
* update entity doc when the storage based model is in place
WIP:
* dense_map/set and registry: move ctor/op should be noexcept (op is conditionally noexcept though)
* "replace" organizer with flow
* add directed/undirected support to adjacency matrix (see brief) and refine iterators a little
* handle: replace visit with an iterable object
* add storage getter for filters to views and groups
* exploit the tombstone mechanism to allow enabling/disabling entities (see bump, compact and clear for further details)
* emitter: runtime handlers, allocator support (ready for both already)
+106 -24
View File
@@ -1,6 +1,7 @@
#ifndef ENTT_ENTITY_HANDLE_HPP
#define ENTT_ENTITY_HANDLE_HPP
#include <iterator>
#include <tuple>
#include <type_traits>
#include <utility>
@@ -10,6 +11,88 @@
namespace entt {
/**
* @cond TURN_OFF_DOXYGEN
* Internal details not to be documented.
*/
namespace internal {
template<typename It>
class handle_storage_iterator final {
template<typename Other>
friend class handle_storage_iterator;
using underlying_type = std::remove_reference_t<typename It::value_type::second_type>;
using entity_type = typename underlying_type::entity_type;
public:
using value_type = typename std::iterator_traits<It>::value_type;
using pointer = input_iterator_pointer<value_type>;
using reference = value_type;
using difference_type = std::ptrdiff_t;
using iterator_category = std::input_iterator_tag;
constexpr handle_storage_iterator() noexcept
: entt{null},
it{},
last{} {}
constexpr handle_storage_iterator(entity_type value, It from, It to) noexcept
: entt{value},
it{from},
last{to} {
while(it != last && !it->second.contains(entt)) { ++it; }
}
template<typename Other, typename = std::enable_if_t<!std::is_same_v<It, Other> && std::is_constructible_v<It, Other>>>
constexpr handle_storage_iterator(const handle_storage_iterator<Other> &other) noexcept
: handle_storage_iterator{other.entt, other it, other.last} {}
constexpr handle_storage_iterator &operator++() noexcept {
while(++it != last && !it->second.contains(entt)) {}
return *this;
}
constexpr handle_storage_iterator operator++(int) noexcept {
handle_storage_iterator orig = *this;
return ++(*this), orig;
}
[[nodiscard]] constexpr reference operator*() const noexcept {
return *it;
}
[[nodiscard]] constexpr pointer operator->() const noexcept {
return operator*();
}
template<typename ILhs, typename IRhs>
friend constexpr bool operator==(const handle_storage_iterator<ILhs> &, const handle_storage_iterator<IRhs> &) noexcept;
private:
entity_type entt;
It it;
It last;
};
template<typename ILhs, typename IRhs>
[[nodiscard]] constexpr bool operator==(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept {
return lhs.it == rhs.it;
}
template<typename ILhs, typename IRhs>
[[nodiscard]] constexpr bool operator!=(const handle_storage_iterator<ILhs> &lhs, const handle_storage_iterator<IRhs> &rhs) noexcept {
return !(lhs == rhs);
}
} // namespace internal
/**
* Internal details not to be documented.
* @endcond
*/
/**
* @brief Non-owning handle to an entity.
*
@@ -43,6 +126,29 @@ struct basic_handle {
: reg{&ref},
entt{value} {}
/**
* @brief Returns an iterable object to use to _visit_ a handle.
*
* The iterable object returns a pair that contains the name and a reference
* to the current storage.<br/>
* Returned storage are those that contain the entity associated with the
* handle.
*
* @return An iterable object to use to _visit_ the handle.
*/
[[nodiscard]] auto storage() noexcept {
auto iterable = reg->storage();
using iterator_type = internal::handle_storage_iterator<typename decltype(iterable)::iterator>;
return iterable_adaptor{iterator_type{entt, iterable.begin(), iterable.end()}, iterator_type{entt, iterable.end(), iterable.end()}};
}
/*! @copydoc storage */
[[nodiscard]] auto storage() const noexcept {
auto iterable = reg->storage();
using iterator_type = internal::handle_storage_iterator<typename decltype(iterable)::const_iterator>;
return iterable_adaptor{iterator_type{entt, iterable.cbegin(), iterable.cend()}, iterator_type{entt, iterable.cend(), iterable.cend()}};
}
/**
* @brief Constructs a const handle from a non-const one.
* @tparam Other A valid entity type (see entt_traits for more details).
@@ -263,30 +369,6 @@ struct basic_handle {
return reg->orphan(entt);
}
/**
* @brief Visits a handle and returns the pools for its components.
*
* The signature of the function should be equivalent to the following:
*
* @code{.cpp}
* void(id_type, const basic_sparse_set<entity_type> &);
* @endcode
*
* Returned pools are those that contain the entity associated with the
* handle.
*
* @tparam Func Type of the function object to invoke.
* @param func A valid function object.
*/
template<typename Func>
void visit(Func &&func) const {
for(auto [id, storage]: reg->storage()) {
if(storage.contains(entt)) {
func(id, storage);
}
}
}
private:
registry_type *reg;
entity_type entt;
+2 -2
View File
@@ -170,10 +170,10 @@ TEST(BasicHandle, Component) {
ASSERT_TRUE(registry.storage<double>().empty());
ASSERT_EQ(0u, (handle.remove<char, double>()));
handle.visit([&handle](const auto id, const auto &pool) {
for(auto [id, pool]: handle.storage()) {
ASSERT_EQ(id, entt::type_id<int>().hash());
ASSERT_TRUE(pool.contains(handle.entity()));
});
}
ASSERT_TRUE((handle.any_of<int, char, double>()));
ASSERT_FALSE((handle.all_of<int, char, double>()));