Michele Caini 7 лет назад
Родитель
Сommit
24b862e32e
4 измененных файлов с 27 добавлено и 12 удалено
  1. 9 3
      README.md
  2. 8 4
      src/entt/entity/registry.hpp
  3. 7 3
      src/entt/signal/dispatcher.hpp
  4. 3 2
      src/entt/signal/sigh.hpp

+ 9 - 3
README.md

@@ -658,11 +658,17 @@ There are also some limitations on what a listener can and cannot do. In
 particular:
 
 * Connecting and disconnecting other functions from within the body of a
-  listener should be avoided. It can lead to undefined behavior.
+  listener should be avoided. It can lead to undefined behavior in some cases.
 * Assigning and removing components and tags from within the body of a listener
   that observes the destruction of instances of a given type should be avoided.
-  It can lead to undefined behavior. This type of listeners is intended to
-  provide users with an easy way to perform cleanup and nothing more.
+  It can lead to undefined behavior in some cases. This type of listeners is
+  intended to provide users with an easy way to perform cleanup and nothing
+  more.
+
+To a certain extent, these limitations do not apply. However, it is risky to try
+to force them and users should respect the limitations unless they know exactly
+what they are doing. Subtle bugs are the price to pay in case of errors
+otherwise.
 
 In general, events and therefore listeners must not be used as replacements for
 systems. They should not contain much logic and interactions with a registry

+ 8 - 4
src/entt/entity/registry.hpp

@@ -425,23 +425,27 @@ public:
     void destroy(entity_type entity) {
         assert(valid(entity));
 
-        std::for_each(pools.begin(), pools.end(), [entity, this](auto &&tup) {
+        for(auto pos = pools.size(); pos; --pos) {
+            auto &tup = pools[pos-1];
             auto &cpool = std::get<0>(tup);
 
             if(cpool && cpool->has(entity)) {
                 std::get<2>(tup).publish(*this, entity);
                 cpool->destroy(entity);
             }
-        });
+        };
 
-        std::for_each(tags.begin(), tags.end(), [entity, this](auto &&tup) {
+        for(auto pos = tags.size(); pos; --pos) {
+            auto &tup = tags[pos-1];
             auto &tag = std::get<0>(tup);
 
             if(tag && tag->entity == entity) {
                 std::get<2>(tup).publish(*this, entity);
                 tag.reset();
             }
-        });
+        };
+
+        assert(orphan(entity));
 
         const auto entt = entity & traits_type::entity_mask;
         const auto version = (((entity >> traits_type::entity_shift) + 1) & traits_type::version_mask) << traits_type::entity_shift;

+ 7 - 3
src/entt/signal/dispatcher.hpp

@@ -168,9 +168,13 @@ public:
      * to reduce at a minimum the time spent in the bodies of the listeners.
      */
     inline void update() {
-        std::for_each(wrappers.begin(), wrappers.end(), [](auto &&wrapper) {
-            return wrapper ? wrapper->publish() : void();
-        });
+        for(auto pos = wrappers.size(); pos; --pos) {
+            auto &wrapper = wrappers[pos-1];
+
+            if(wrapper) {
+                wrapper->publish();
+            }
+        }
     }
 
 private:

+ 3 - 2
src/entt/signal/sigh.hpp

@@ -307,9 +307,10 @@ public:
      * @param args Arguments to use to invoke listeners.
      */
     void publish(Args... args) {
-        std::for_each(calls.begin(), calls.end(), [&args...](auto &&call) {
+        for(auto pos = calls.size(); pos; --pos) {
+            auto &call = calls[pos-1];
             call.second(call.first, args...);
-        });
+        }
     }
 
     /**