Selaa lähdekoodia

handle: remove visit, use iterable objects instead

Michele Caini 3 vuotta sitten
vanhempi
commit
c441a9ad97
3 muutettua tiedostoa jossa 109 lisäystä ja 27 poistoa
  1. 1 1
      TODO
  2. 106 24
      src/entt/entity/handle.hpp
  3. 2 2
      test/entt/entity/handle.cpp

+ 1 - 1
TODO

@@ -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
src/entt/entity/handle.hpp

@@ -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
test/entt/entity/handle.cpp

@@ -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>()));