diff --git a/src/EC/Manager.hpp b/src/EC/Manager.hpp index 40c60cd..e6d4625 100644 --- a/src/EC/Manager.hpp +++ b/src/EC/Manager.hpp @@ -14,6 +14,9 @@ #include #include #include +#include +#include +#include #include "Meta/Combine.hpp" #include "Meta/Matching.hpp" @@ -427,7 +430,8 @@ namespace EC } private: - std::vector > forMatchingFunctions; + std::map > forMatchingFunctions; + unsigned long long functionIndex = 0; public: /*! @@ -440,6 +444,12 @@ namespace EC The syntax for the Function is the same as with forMatchingSignature(). + Note that functions will be called in the same order they are inserted. + + Old functions may be overwritten if there are more functions than + sizeof(unsigned long long) as they are stored in a map with + unsigned long long as the key (index). + Example: \code{.cpp} manager.addForMatchingFunction>([] (std::size_t ID, C0& component0, C1& component1) { @@ -450,9 +460,13 @@ namespace EC manager.clearForMatchingFunctions(); // remove all stored functions \endcode + + \return The index of the function, used for deletion with + deleteForMatchingFunction() or filtering with + clearSomeMatchingFunctions(). */ template - void addForMatchingFunction(Function&& function) + unsigned long long addForMatchingFunction(Function&& function) { using SignatureComponents = typename EC::Meta::Matching::type; using Helper = EC::Meta::Morph >; @@ -460,7 +474,7 @@ namespace EC Helper helper; BitsetType signatureBitset = BitsetType::template generateBitset(); - forMatchingFunctions.emplace_back( [function, signatureBitset, helper, this] () { + forMatchingFunctions.emplace(std::make_pair(functionIndex, [function, signatureBitset, helper, this] () { for(std::size_t i = 0; i < this->currentSize; ++i) { if(!std::get(this->entities[i])) @@ -472,7 +486,9 @@ namespace EC helper.callInstance(i, *this, function); } } - }); + })); + + return functionIndex++; } /*! @@ -493,13 +509,15 @@ namespace EC { for(auto functionIter = forMatchingFunctions.begin(); functionIter != forMatchingFunctions.end(); ++functionIter) { - (*functionIter)(); + functionIter->second(); } } /*! \brief Remove all stored functions. + Also resets the index counter of stored functions to 0. + Example: \code{.cpp} manager.addForMatchingFunction>([] (std::size_t ID, C0& component0, C1& component1) { @@ -514,8 +532,128 @@ namespace EC void clearForMatchingFunctions() { forMatchingFunctions.clear(); + functionIndex = 0; } + /*! + \brief Removes all functions that do not have the index specified + in argument "list". + + Note this function is slower than the variant that uses a set + argument as all items in the List are traversed during + traversal through all entities to check if they are in the list. + Thus the complexity of this function is n^2. + */ + template + void clearSomeMatchingFunctions(List list) + { + bool willErase = true; + for(auto functionIter = forMatchingFunctions.begin(); + functionIter != forMatchingFunctions.end(); + ++functionIter) + { + willErase = true; + for(auto listIter = list.begin(); + listIter != list.end(); + ++listIter) + { + if(functionIter->first == *listIter) + { + willErase = false; + break; + } + } + if(willErase) + { + functionIter = --(forMatchingFunctions.erase(functionIter)); + } + } + } + + /*! + \brief Removes all functions that do not have the index specified + in argument "list". + + Note this function is slower than the variant that uses a set + argument as all items in the List are traversed during + traversal through all entities to check if they are in the list. + Thus the complexity of this function is n^2. + */ + void clearSomeMatchingFunctions(std::initializer_list list) + { + clearSomeMatchingFunctions(list); + } + + private: + template + void clearSomeMatchingFunctionsWithSet(Set set) + { + for(auto functionIter = forMatchingFunctions.begin(); + functionIter != forMatchingFunctions.end(); + ++functionIter) + { + if(set.find(functionIter->first) == set.end()) + { + functionIter = --(forMatchingFunctions.erase(functionIter)); + } + } + } + + public: + /*! + \brief Removes all functions that do not have the index specified + in argument "set". + + Note this function is faster than the variant that uses a list + argument as the set's implementation as a tree allows for + log(n) time checking of an index to the set. Thus the complexity + of this function is n*log(n). + */ + void clearSomeMatchingFunctions(std::set set) + { + clearSomeMatchingFunctionsWithSet(set); + } + + /*! + \brief Removes all functions that do not have the index specified + in argument "set". + + Note this function is faster than the variant that uses a list + argument as the unordered_set's implementation as a hash table + allows for constant time checking of an index to the set. Thus the + complexity of this function is n. + */ + void clearSomeMatchingFunctions(std::unordered_set set) + { + clearSomeMatchingFunctionsWithSet(set); + } + + /*! + \brief Deletes the specified function. + + The index of a function is returned from addForMatchingFunction() + so there is no other way to get the index of a function. + */ + void deleteForMatchingFunction(unsigned long long index) + { + forMatchingFunctions.erase(index); + } + + /*! + \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; + resize(EC_INIT_ENTITIES_SIZE); + } }; } diff --git a/src/test/ECTest.cpp b/src/test/ECTest.cpp index 0e5e4eb..02b83fb 100644 --- a/src/test/ECTest.cpp +++ b/src/test/ECTest.cpp @@ -246,17 +246,29 @@ TEST(EC, FunctionStorage) { EC::Manager manager; auto eid = manager.addEntity(); - manager.addComponent(eid); + manager.addComponent(eid, 0, 1); manager.addComponent(eid); + manager.addComponent(eid); + manager.addComponent(eid); - manager.addForMatchingFunction>( [] (std::size_t eid, C0& c0) { - c0.x = 1; - c0.y = 2; + auto f0index = manager.addForMatchingFunction>( [] (std::size_t eid, C0& c0) { + ++c0.x; + ++c0.y; }); - manager.addForMatchingFunction>( [] (std::size_t eid, C0& c0, C1& c1) { + auto f1index = manager.addForMatchingFunction>( [] (std::size_t eid, C0& c0, C1& c1) { c1.vx = c0.x + 10; - c1.vy = c1.vx + c0.y + 10; + c1.vy = c1.vy + c1.vx + c0.y + 10; + }); + + manager.addForMatchingFunction>( + [] (std::size_t eid) { + //derp 0 + }); + + manager.addForMatchingFunction>( + [] (std::size_t eid) { + //derp 1 }); manager.callForMatchingFunctions(); @@ -264,29 +276,57 @@ TEST(EC, FunctionStorage) { auto c0 = manager.getEntityData(eid); - EXPECT_EQ(c0.x, 1); - EXPECT_EQ(c0.y, 2); + EXPECT_EQ(1, c0.x); + EXPECT_EQ(2, c0.y); auto c1 = manager.getEntityData(eid); - EXPECT_EQ(c1.vx, 11); - EXPECT_EQ(c1.vy, 23); + EXPECT_EQ(11, c1.vx); + EXPECT_EQ(23, c1.vy); + } + + manager.clearSomeMatchingFunctions({f1index}); + + { + std::vector indices{f1index}; + manager.clearSomeMatchingFunctions(indices); + } + { + std::set indices{f1index}; + manager.clearSomeMatchingFunctions(indices); + } + { + std::unordered_set indices{f1index}; + manager.clearSomeMatchingFunctions(indices); + } + + manager.callForMatchingFunctions(); + + { + auto c0 = manager.getEntityData(eid); + + EXPECT_EQ(1, c0.x); + EXPECT_EQ(2, c0.y); + + auto c1 = manager.getEntityData(eid); + + EXPECT_EQ(11, c1.vx); + EXPECT_EQ(46, c1.vy); } manager.clearForMatchingFunctions(); - manager.callForMatchingFunctions(); { auto c0 = manager.getEntityData(eid); - EXPECT_EQ(c0.x, 1); - EXPECT_EQ(c0.y, 2); + EXPECT_EQ(1, c0.x); + EXPECT_EQ(2, c0.y); auto c1 = manager.getEntityData(eid); - EXPECT_EQ(c1.vx, 11); - EXPECT_EQ(c1.vy, 23); + EXPECT_EQ(11, c1.vx); + EXPECT_EQ(46, c1.vy); } }