]> git.seodisparate.com - EntityComponentMetaSystem/commitdiff
Add fn to Manager allowing iterable indices as sig
authorStephen Seo <seo.disparate@gmail.com>
Thu, 11 Jul 2019 12:11:03 +0000 (21:11 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Thu, 11 Jul 2019 12:11:03 +0000 (21:11 +0900)
As an alternative to forMatchingSignatures, which calls the given
function on entities matching the given Components/Tags in the
signature, forMatchingIterable allows filtering entities by an iterable
of indices that corresponds to Components/Tags.

src/EC/Bitset.hpp
src/EC/Manager.hpp
src/test/ECTest.cpp

index 43173131337ee329735a5eefe4a9c1f16043f4ae..786b29c25b02eab1a0b9d69ebbcc236ed4f98e21 100644 (file)
@@ -75,6 +75,28 @@ namespace EC
 
             return bitset;
         }
+
+        template <typename IntegralType>
+        auto getCombinedBit(const IntegralType& i) {
+            static_assert(std::is_integral<IntegralType>::value,
+                "Parameter must be an integral type");
+            if(i >= Combined::size || i < 0) {
+                return (*this)[Combined::size];
+            } else {
+                return (*this)[i];
+            }
+        }
+
+        template <typename IntegralType>
+        auto getCombinedBit(const IntegralType& i) const {
+            static_assert(std::is_integral<IntegralType>::value,
+                "Parameter must be an integral type");
+            if(i >= Combined::size || i < 0) {
+                return (*this)[Combined::size];
+            } else {
+                return (*this)[i];
+            }
+        }
     };
 }
 
index cb4a61276e50dbdd9be47cdc8de378e9d7b6484a..5f10fd6feabfaa9ca5b9e8e95ae63601d2010a38 100644 (file)
@@ -1649,6 +1649,73 @@ namespace EC
             deletedSet.clear();
             resize(EC_INIT_ENTITIES_SIZE);
         }
+
+        typedef void ForMatchingIterableFn(std::size_t, Manager<ComponentsList, TagsList>*, void*);
+
+        /*!
+         * \brief Similar to forMatchingSignature(), but with a collection of Component/Tag indices
+         *
+         * This function works like forMatchingSignature(), but instead of
+         * providing template types that filter out non-matching entities, an
+         * iterable of indices must be provided which correlate to matching
+         * Component/Tag indices. The function given must match the previously
+         * defined typedef of type ForMatchingIterableFn.
+         */
+        template <typename Iterable>
+        void forMatchingIterable(Iterable iterable, ForMatchingIterableFn fn, void* userPtr = nullptr, std::size_t threadCount = 1) {
+            if(threadCount <= 1) {
+                bool isValid;
+                for(std::size_t i = 0; i < currentSize; ++i) {
+                    if(!std::get<bool>(entities[i])) {
+                        continue;
+                    }
+
+                    isValid = true;
+                    for(const auto& integralValue : iterable) {
+                        if(!std::get<BitsetType>(entities[i]).getCombinedBit(integralValue)) {
+                            isValid = false;
+                            break;
+                        }
+                    }
+                    if(!isValid) { continue; }
+
+                    fn(i, this, userPtr);
+                }
+            } else {
+                std::vector<std::thread> threads(threadCount);
+                std::size_t s = currentSize / threadCount;
+                for(std::size_t i = 0; i < threadCount; ++i) {
+                    std::size_t begin = s * i;
+                    std::size_t end = i == threadCount - 1 ?
+                        currentSize :
+                        s * (i + 1);
+                    threads[i] = std::thread(
+                        [this, &fn, &iterable, userPtr] (std::size_t begin, std::size_t end) {
+                            bool isValid;
+                            for(std::size_t i = begin; i < end; ++i) {
+                                if(!std::get<bool>(this->entities[i])) {
+                                    continue;
+                                }
+
+                                isValid = true;
+                                for(const auto& integralValue : iterable) {
+                                    if(!std::get<BitsetType>(entities[i]).getCombinedBit(integralValue)) {
+                                        isValid = false;
+                                        break;
+                                    }
+                                }
+                                if(!isValid) { continue; }
+
+                                fn(i, this, userPtr);
+                            }
+                        },
+                    begin, end);
+                }
+                for(std::size_t i = 0; i < threadCount; ++i) {
+                    threads[i].join();
+                }
+            }
+        }
     };
 }
 
index f5f63fd79cf5d0555cf6ef01102f649f46db2721..d15cc7ad9be57575b4075fce79c7d413924a3213 100644 (file)
@@ -39,6 +39,8 @@ using EmptyList = EC::Meta::TypeList<>;
 
 using MixedList = EC::Meta::TypeList<C2, T1>;
 
+using ListCombinedComponentsTags = EC::Meta::Combine<ListComponentsAll, ListTagsAll>;
+
 typedef std::unique_ptr<C0> C0Ptr;
 
 struct Base
@@ -1074,3 +1076,200 @@ TEST(EC, FunctionStorageOrder)
     EXPECT_EQ(5, v.at(4));
     EXPECT_EQ(6, v.at(5));
 }
+
+TEST(EC, forMatchingIterableFn)
+{
+    EC::Manager<ListComponentsAll, ListTagsAll> manager;
+    auto e0 = manager.addEntity();
+    manager.addComponent<C0>(e0, 0, 1);
+
+    auto e1 = manager.addEntity();
+    manager.addComponent<C0>(e1, 2, 3);
+    manager.addTag<T0>(e1);
+
+    auto e2 = manager.addEntity();
+    manager.addComponent<C0>(e2, 4, 5);
+    manager.addTag<T0>(e2);
+    manager.addTag<T1>(e2);
+
+    auto c0Index = EC::Meta::IndexOf<C0, ListCombinedComponentsTags>::value;
+    auto c1Index = EC::Meta::IndexOf<C1, ListCombinedComponentsTags>::value;
+    auto t0Index = EC::Meta::IndexOf<T0, ListCombinedComponentsTags>::value;
+    auto t1Index = EC::Meta::IndexOf<T1, ListCombinedComponentsTags>::value;
+
+    {
+        // test valid indices
+        auto iterable = {c0Index};
+        auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
+            auto* c = m->getEntityComponent<C0>(i);
+            c->x += 1;
+            c->y += 1;
+        };
+        manager.forMatchingIterable(iterable, fn, nullptr);
+    }
+
+    {
+        auto* c = manager.getEntityComponent<C0>(e0);
+        EXPECT_EQ(c->x, 1);
+        EXPECT_EQ(c->y, 2);
+
+        c = manager.getEntityComponent<C0>(e1);
+        EXPECT_EQ(c->x, 3);
+        EXPECT_EQ(c->y, 4);
+
+        c = manager.getEntityComponent<C0>(e2);
+        EXPECT_EQ(c->x, 5);
+        EXPECT_EQ(c->y, 6);
+    }
+
+    {
+        // test invalid indices
+        auto iterable = {c0Index, c1Index};
+        auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
+            auto* c = m->getEntityComponent<C0>(i);
+            c->x += 1;
+            c->y += 1;
+        };
+        manager.forMatchingIterable(iterable, fn, nullptr);
+    }
+
+    {
+        auto* c = manager.getEntityComponent<C0>(e0);
+        EXPECT_EQ(c->x, 1);
+        EXPECT_EQ(c->y, 2);
+
+        c = manager.getEntityComponent<C0>(e1);
+        EXPECT_EQ(c->x, 3);
+        EXPECT_EQ(c->y, 4);
+
+        c = manager.getEntityComponent<C0>(e2);
+        EXPECT_EQ(c->x, 5);
+        EXPECT_EQ(c->y, 6);
+    }
+
+    {
+        // test partially valid indices
+        auto iterable = {c0Index, t1Index};
+        auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
+            auto* c = m->getEntityComponent<C0>(i);
+            c->x += 1;
+            c->y += 1;
+        };
+        manager.forMatchingIterable(iterable, fn, nullptr);
+    }
+
+    {
+        auto* c = manager.getEntityComponent<C0>(e0);
+        EXPECT_EQ(c->x, 1);
+        EXPECT_EQ(c->y, 2);
+
+        c = manager.getEntityComponent<C0>(e1);
+        EXPECT_EQ(c->x, 3);
+        EXPECT_EQ(c->y, 4);
+
+        c = manager.getEntityComponent<C0>(e2);
+        EXPECT_EQ(c->x, 6);
+        EXPECT_EQ(c->y, 7);
+    }
+
+    {
+        // test partially valid indices
+        auto iterable = {c0Index, t0Index};
+        auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
+            auto* c = m->getEntityComponent<C0>(i);
+            c->x += 10;
+            c->y += 10;
+        };
+        manager.forMatchingIterable(iterable, fn, nullptr);
+    }
+
+    {
+        auto* c = manager.getEntityComponent<C0>(e0);
+        EXPECT_EQ(c->x, 1);
+        EXPECT_EQ(c->y, 2);
+
+        c = manager.getEntityComponent<C0>(e1);
+        EXPECT_EQ(c->x, 13);
+        EXPECT_EQ(c->y, 14);
+
+        c = manager.getEntityComponent<C0>(e2);
+        EXPECT_EQ(c->x, 16);
+        EXPECT_EQ(c->y, 17);
+    }
+
+    {
+        // test invalid indices
+        auto iterable = {(unsigned int)c0Index, 1000u};
+        auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
+            auto* c = m->getEntityComponent<C0>(i);
+            c->x += 1000;
+            c->y += 1000;
+        };
+        manager.forMatchingIterable(iterable, fn, nullptr);
+    }
+
+    {
+        auto* c = manager.getEntityComponent<C0>(e0);
+        EXPECT_EQ(c->x, 1);
+        EXPECT_EQ(c->y, 2);
+
+        c = manager.getEntityComponent<C0>(e1);
+        EXPECT_EQ(c->x, 13);
+        EXPECT_EQ(c->y, 14);
+
+        c = manager.getEntityComponent<C0>(e2);
+        EXPECT_EQ(c->x, 16);
+        EXPECT_EQ(c->y, 17);
+    }
+
+    {
+        // test concurrent update
+        auto iterable = {c0Index};
+        auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
+            auto *c = m->getEntityComponent<C0>(i);
+            c->x += 100;
+            c->y += 100;
+        };
+        manager.forMatchingIterable(iterable, fn, nullptr, 3);
+    }
+
+    {
+        auto* c = manager.getEntityComponent<C0>(e0);
+        EXPECT_EQ(c->x, 101);
+        EXPECT_EQ(c->y, 102);
+
+        c = manager.getEntityComponent<C0>(e1);
+        EXPECT_EQ(c->x, 113);
+        EXPECT_EQ(c->y, 114);
+
+        c = manager.getEntityComponent<C0>(e2);
+        EXPECT_EQ(c->x, 116);
+        EXPECT_EQ(c->y, 117);
+    }
+
+
+    {
+        // test invalid concurrent update
+        auto iterable = {(unsigned int)c0Index, 1000u};
+        auto fn = [] (std::size_t i, decltype(manager)* m, void*) {
+            auto *c = m->getEntityComponent<C0>(i);
+            c->x += 1000;
+            c->y += 1000;
+        };
+        manager.forMatchingIterable(iterable, fn, nullptr, 3);
+    }
+
+    {
+        auto* c = manager.getEntityComponent<C0>(e0);
+        EXPECT_EQ(c->x, 101);
+        EXPECT_EQ(c->y, 102);
+
+        c = manager.getEntityComponent<C0>(e1);
+        EXPECT_EQ(c->x, 113);
+        EXPECT_EQ(c->y, 114);
+
+        c = manager.getEntityComponent<C0>(e2);
+        EXPECT_EQ(c->x, 116);
+        EXPECT_EQ(c->y, 117);
+    }
+}