diff --git a/src/EC/Manager.hpp b/src/EC/Manager.hpp index bca25fa..46e7b72 100644 --- a/src/EC/Manager.hpp +++ b/src/EC/Manager.hpp @@ -490,6 +490,23 @@ namespace EC ).template getTagBit() = false; } + /*! + \brief Resets the Manager, removing all entities. + + Some data may persist but will be overwritten when new entities + are added. Thus, do not depend on data to persist after a call to + reset(). + */ + void reset() + { + clearForMatchingFunctions(); + + currentSize = 0; + currentCapacity = 0; + deletedSet.clear(); + resize(EC_INIT_ENTITIES_SIZE); + } + private: template struct ForMatchingSignatureHelper @@ -1634,36 +1651,73 @@ namespace EC ); } + typedef void ForMatchingFn(std::size_t, Manager*, void*); + /*! - \brief Resets the Manager, removing all entities. - - Some data may persist but will be overwritten when new entities - are added. Thus, do not depend on data to persist after a call to - reset(). - */ - void reset() - { - clearForMatchingFunctions(); - - currentSize = 0; - currentCapacity = 0; - deletedSet.clear(); - resize(EC_INIT_ENTITIES_SIZE); + * \brief A simple version of forMatchingSignature() + * + * This function behaves like forMatchingSignature(), but instead of + * providing a function with each requested component as a parameter, + * the function receives a pointer to the manager itself, with which to + * query component/tag data. + */ + template + void forMatchingSimple(ForMatchingFn fn, void *userData = nullptr, std::size_t threadCount = 1) { + const BitsetType signatureBitset = BitsetType::template generateBitset(); + if(threadCount <= 1) { + for(std::size_t i = 0; i < currentSize; ++i) { + if(!std::get(entities[i])) { + continue; + } else if((signatureBitset & std::get(entities[i])) == signatureBitset) { + fn(i, this, userData); + } + } + } else { + std::vector threads(threadCount); + const std::size_t s = currentSize / threadCount; + for(std::size_t i = 0; i < threadCount; ++i) { + const std::size_t begin = s * i; + const std::size_t end = + i == threadCount - 1 ? + currentSize : + s * (i + 1); + threads[i] = std::thread( + [this] (const std::size_t begin, + const std::size_t end, + const BitsetType signatureBitset, + ForMatchingFn fn, + void *userData) { + for(std::size_t i = begin; i < end; ++i) { + if(!std::get(entities[i])) { + continue; + } else if((signatureBitset & std::get(entities[i])) == signatureBitset) { + fn(i, this, userData); + } + } + }, + begin, + end, + signatureBitset, + fn, + userData); + } + for(std::size_t i = 0; i < threadCount; ++i) { + threads[i].join(); + } + } } - typedef void ForMatchingIterableFn(std::size_t, Manager*, void*); - /*! - * \brief Similar to forMatchingSignature(), but with a collection of Component/Tag indices + * \brief Similar to forMatchingSimple(), but with a collection of Component/Tag indices * - * This function works like forMatchingSignature(), but instead of + * This function works like forMatchingSimple(), 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. + * defined typedef of type ForMatchingFn. */ template - void forMatchingIterable(Iterable iterable, ForMatchingIterableFn fn, void* userPtr = nullptr, std::size_t threadCount = 1) { + void forMatchingIterable(Iterable iterable, ForMatchingFn fn, void* userPtr = nullptr, std::size_t threadCount = 1) { if(threadCount <= 1) { bool isValid; for(std::size_t i = 0; i < currentSize; ++i) { @@ -1687,9 +1741,10 @@ namespace EC 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); + 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; diff --git a/src/test/ECTest.cpp b/src/test/ECTest.cpp index d15cc7a..3f1c503 100644 --- a/src/test/ECTest.cpp +++ b/src/test/ECTest.cpp @@ -1077,6 +1077,72 @@ TEST(EC, FunctionStorageOrder) EXPECT_EQ(6, v.at(5)); } +TEST(EC, forMatchingSimple) { + EC::Manager manager; + + auto e0 = manager.addEntity(); + manager.addComponent(e0, 0, 1); + + auto e1 = manager.addEntity(); + manager.addComponent(e1, 2, 3); + manager.addTag(e1); + + auto e2 = manager.addEntity(); + manager.addComponent(e2, 4, 5); + manager.addTag(e2); + manager.addTag(e2); + + // add 10 to C0 components + manager.forMatchingSimple>( + [] (std::size_t id, decltype(manager) *manager, void *) { + C0 *c0 = manager->getEntityData(id); + c0->x += 10; + c0->y += 10; + }, nullptr, 3); + + // verify + { + C0 *c0 = manager.getEntityData(e0); + EXPECT_EQ(c0->x, 10); + EXPECT_EQ(c0->y, 11); + c0 = manager.getEntityData(e1); + EXPECT_EQ(c0->x, 12); + EXPECT_EQ(c0->y, 13); + c0 = manager.getEntityData(e2); + EXPECT_EQ(c0->x, 14); + EXPECT_EQ(c0->y, 15); + } + + auto e3 = manager.addEntity(); + manager.addComponent(e3, 6, 7); + manager.addTag(e3); + manager.addTag(e3); + + // add 100 to entities with C0,T1 + manager.forMatchingSimple>( + [] (std::size_t id, decltype(manager) *manager, void *) { + C0 *c0 = manager->getEntityData(id); + c0->x += 100; + c0->y += 100; + }); + + // verify + { + C0 *c0 = manager.getEntityData(e0); + EXPECT_EQ(c0->x, 10); + EXPECT_EQ(c0->y, 11); + c0 = manager.getEntityData(e1); + EXPECT_EQ(c0->x, 12); + EXPECT_EQ(c0->y, 13); + c0 = manager.getEntityData(e2); + EXPECT_EQ(c0->x, 114); + EXPECT_EQ(c0->y, 115); + c0 = manager.getEntityData(e3); + EXPECT_EQ(c0->x, 106); + EXPECT_EQ(c0->y, 107); + } +} + TEST(EC, forMatchingIterableFn) { EC::Manager manager;