]> git.seodisparate.com - EntityComponentMetaSystem/commitdiff
Reformat EC/Manager.hpp
authorStephen Seo <seo.disparate@gmail.com>
Thu, 16 Jun 2022 04:27:43 +0000 (13:27 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Thu, 16 Jun 2022 04:27:43 +0000 (13:27 +0900)
src/EC/Manager.hpp

index 6c93f9026068b00bf01bc08f24871447f1f97d64..5215e14e51b81629972a7cd8eb053dc8da41e0cc 100644 (file)
 // under the Academic Free License.
 // His code is available here: https://github.com/SuperV1234/cppcon2015
 
-
 #ifndef EC_MANAGER_HPP
 #define EC_MANAGER_HPP
 
-#include <chrono>
 #define EC_INIT_ENTITIES_SIZE 256
 #define EC_GROW_SIZE_AMOUNT 256
 
+#include <algorithm>
 #include <array>
 #include <atomic>
+#include <chrono>
 #include <cstddef>
-#include <vector>
 #include <deque>
-#include <tuple>
-#include <utility>
 #include <functional>
 #include <map>
-#include <unordered_map>
+#include <mutex>
 #include <set>
-#include <unordered_set>
-#include <algorithm>
 #include <thread>
-#include <mutex>
+#include <tuple>
 #include <type_traits>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
 
 #ifndef NDEBUG
-  #include <iostream>
+#include <iostream>
 #endif
 
+#include "Bitset.hpp"
 #include "Meta/Combine.hpp"
-#include "Meta/Matching.hpp"
-#include "Meta/ForEachWithIndex.hpp"
 #include "Meta/ForEachDoubleTuple.hpp"
+#include "Meta/ForEachWithIndex.hpp"
 #include "Meta/IndexOf.hpp"
-#include "Bitset.hpp"
-
+#include "Meta/Matching.hpp"
 #include "ThreadPool.hpp"
 
-namespace EC
-{
-    /*!
-        \brief Manages an EntityComponent system.
-
-        EC::Manager must be created with a list of all used Components and all
-        used tags.
-
-        Note that all components must have a default constructor.
-
-        An optional third template parameter may be given, which is the size of
-        the number of threads in the internal ThreadPool, and should be at
-        least 2. If ThreadCount is 1 or less, then the ThreadPool will not be
-        created and it will never be used, even if the "true" parameter is given
-        for functions that enable its usage.
+namespace EC {
+/*!
+    \brief Manages an EntityComponent system.
+
+    EC::Manager must be created with a list of all used Components and all
+    used tags.
+
+    Note that all components must have a default constructor.
+
+    An optional third template parameter may be given, which is the size of
+    the number of threads in the internal ThreadPool, and should be at
+    least 2. If ThreadCount is 1 or less, then the ThreadPool will not be
+    created and it will never be used, even if the "true" parameter is given
+    for functions that enable its usage.
+
+    Note that when calling one of the "forMatching" functions that make use
+    of the internal ThreadPool, it is allowed to call addEntity() or
+    deleteEntity() as the functions cache which entities are alive before
+    running (allowing for addEntity()), and the functions defer deletions
+    during concurrent execution (allowing for deleteEntity()).
+
+    Example:
+    \code{.cpp}
+        EC::Manager<TypeList<C0, C1, C2>, TypeList<T0, T1>> manager;
+    \endcode
+*/
+template <typename ComponentsList, typename TagsList,
+          unsigned int ThreadCount = 4>
+struct Manager {
+   public:
+    using Components = ComponentsList;
+    using Tags = TagsList;
+    using Combined = EC::Meta::Combine<ComponentsList, TagsList>;
+    using BitsetType = EC::Bitset<ComponentsList, TagsList>;
+
+   private:
+    using ComponentsTuple = EC::Meta::Morph<ComponentsList, std::tuple<> >;
+    static_assert(std::is_default_constructible<ComponentsTuple>::value,
+                  "All components must be default constructible");
+
+    template <typename... Types>
+    struct Storage {
+        using type = std::tuple<std::deque<Types>..., std::deque<char> >;
+    };
+    using ComponentsStorage =
+        typename EC::Meta::Morph<ComponentsList, Storage<> >::type;
+
+    // Entity: isAlive, ComponentsTags Info
+    using EntitiesTupleType = std::tuple<bool, BitsetType>;
+    using EntitiesType = std::deque<EntitiesTupleType>;
+
+    EntitiesType entities;
+    ComponentsStorage componentsStorage;
+    std::size_t currentCapacity = 0;
+    std::size_t currentSize = 0;
+    std::unordered_set<std::size_t> deletedSet;
+
+    std::unique_ptr<ThreadPool<ThreadCount> > threadPool;
+
+    std::atomic_uint deferringDeletions;
+    std::vector<std::size_t> deferredDeletions;
+    std::mutex deferredDeletionsMutex;
+
+    std::vector<std::size_t> idStack;
+    std::size_t idStackCounter;
+    std::mutex idStackMutex;
+
+   public:
+    // section for "temporary" structures {{{
+    /// Temporary struct used internally by ThreadPool
+    struct TPFnDataStructZero {
+        std::array<std::size_t, 2> range;
+        Manager* manager;
+        EntitiesType* entities;
+        const BitsetType* signature;
+        void* userData;
+        std::unordered_set<std::size_t> dead;
+    };
+    /// Temporary struct used internally by ThreadPool
+    template <typename Function>
+    struct TPFnDataStructOne {
+        std::array<std::size_t, 2> range;
+        Manager* manager;
+        EntitiesType* entities;
+        BitsetType* signature;
+        void* userData;
+        Function* fn;
+        std::unordered_set<std::size_t> dead;
+    };
+    /// Temporary struct used internally by ThreadPool
+    struct TPFnDataStructTwo {
+        std::array<std::size_t, 2> range;
+        Manager* manager;
+        EntitiesType* entities;
+        void* userData;
+        const std::vector<std::size_t>* matching;
+        std::unordered_set<std::size_t> dead;
+    };
+    /// Temporary struct used internally by ThreadPool
+    struct TPFnDataStructThree {
+        std::array<std::size_t, 2> range;
+        Manager* manager;
+        std::vector<std::vector<std::size_t> >* matchingV;
+        const std::vector<BitsetType*>* bitsets;
+        EntitiesType* entities;
+        std::mutex* mutex;
+        std::unordered_set<std::size_t> dead;
+    };
+    /// Temporary struct used internally by ThreadPool
+    struct TPFnDataStructFour {
+        std::array<std::size_t, 2> range;
+        Manager* manager;
+        std::vector<std::vector<std::size_t> >* multiMatchingEntities;
+        BitsetType* signatures;
+        std::mutex* mutex;
+        std::unordered_set<std::size_t> dead;
+    };
+    /// Temporary struct used internally by ThreadPool
+    struct TPFnDataStructFive {
+        std::array<std::size_t, 2> range;
+        std::size_t index;
+        Manager* manager;
+        void* userData;
+        std::vector<std::vector<std::size_t> >* multiMatchingEntities;
+        std::unordered_set<std::size_t> dead;
+    };
+    /// Temporary struct used internally by ThreadPool
+    struct TPFnDataStructSix {
+        std::array<std::size_t, 2> range;
+        Manager* manager;
+        std::vector<std::vector<std::size_t> >* multiMatchingEntities;
+        BitsetType* bitsets;
+        std::mutex* mutex;
+        std::unordered_set<std::size_t> dead;
+    };
+    /// Temporary struct used internally by ThreadPool
+    template <typename Iterable>
+    struct TPFnDataStructSeven {
+        std::array<std::size_t, 2> range;
+        Manager* manager;
+        EntitiesType* entities;
+        Iterable* iterable;
+        void* userData;
+        std::unordered_set<std::size_t> dead;
+    };
+    // end section for "temporary" structures }}}
 
-        Note that when calling one of the "forMatching" functions that make use
-        of the internal ThreadPool, it is allowed to call addEntity() or
-        deleteEntity() as the functions cache which entities are alive before
-        running (allowing for addEntity()), and the functions defer deletions
-        during concurrent execution (allowing for deleteEntity()).
+    /*!
+        \brief Initializes the manager with a default capacity.
 
-        Example:
-        \code{.cpp}
-            EC::Manager<TypeList<C0, C1, C2>, TypeList<T0, T1>> manager;
-        \endcode
+        The default capacity is set with macro EC_INIT_ENTITIES_SIZE,
+        and will grow by amounts of EC_GROW_SIZE_AMOUNT when needed.
     */
-    template <typename ComponentsList,
-              typename TagsList,
-              unsigned int ThreadCount = 4>
-    struct Manager
-    {
-    public:
-        using Components = ComponentsList;
-        using Tags = TagsList;
-        using Combined = EC::Meta::Combine<ComponentsList, TagsList>;
-        using BitsetType = EC::Bitset<ComponentsList, TagsList>;
-
-    private:
-        using ComponentsTuple = EC::Meta::Morph<ComponentsList, std::tuple<> >;
-        static_assert(std::is_default_constructible<ComponentsTuple>::value,
-            "All components must be default constructible");
-
-        template <typename... Types>
-        struct Storage
-        {
-            using type = std::tuple<std::deque<Types>..., std::deque<char> >;
-        };
-        using ComponentsStorage =
-            typename EC::Meta::Morph<ComponentsList, Storage<> >::type;
-
-        // Entity: isAlive, ComponentsTags Info
-        using EntitiesTupleType = std::tuple<bool, BitsetType>;
-        using EntitiesType = std::deque<EntitiesTupleType>;
-
-        EntitiesType entities;
-        ComponentsStorage componentsStorage;
-        std::size_t currentCapacity = 0;
-        std::size_t currentSize = 0;
-        std::unordered_set<std::size_t> deletedSet;
-
-        std::unique_ptr<ThreadPool<ThreadCount> > threadPool;
-
-        std::atomic_uint deferringDeletions;
-        std::vector<std::size_t> deferredDeletions;
-        std::mutex deferredDeletionsMutex;
-
-        std::vector<std::size_t> idStack;
-        std::size_t idStackCounter;
-        std::mutex idStackMutex;
-
-    public:
-        // section for "temporary" structures {{{
-        /// Temporary struct used internally by ThreadPool
-        struct TPFnDataStructZero {
-            std::array<std::size_t, 2> range;
-            Manager *manager;
-            EntitiesType *entities;
-            const BitsetType *signature;
-            void *userData;
-            std::unordered_set<std::size_t> dead;
-        };
-        /// Temporary struct used internally by ThreadPool
-        template <typename Function>
-        struct TPFnDataStructOne {
-            std::array<std::size_t, 2> range;
-            Manager *manager;
-            EntitiesType *entities;
-            BitsetType *signature;
-            void *userData;
-            Function *fn;
-            std::unordered_set<std::size_t> dead;
-        };
-        /// Temporary struct used internally by ThreadPool
-        struct TPFnDataStructTwo {
-            std::array<std::size_t, 2> range;
-            Manager *manager;
-            EntitiesType *entities;
-            void *userData;
-            const std::vector<std::size_t> *matching;
-            std::unordered_set<std::size_t> dead;
-        };
-        /// Temporary struct used internally by ThreadPool
-        struct TPFnDataStructThree {
-            std::array<std::size_t, 2> range;
-            Manager *manager;
-            std::vector<std::vector<std::size_t> > *matchingV;
-            const std::vector<BitsetType*> *bitsets;
-            EntitiesType *entities;
-            std::mutex *mutex;
-            std::unordered_set<std::size_t> dead;
-        };
-        /// Temporary struct used internally by ThreadPool
-        struct TPFnDataStructFour {
-            std::array<std::size_t, 2> range;
-            Manager *manager;
-            std::vector<std::vector<std::size_t> >*
-                multiMatchingEntities;
-            BitsetType *signatures;
-            std::mutex *mutex;
-            std::unordered_set<std::size_t> dead;
-        };
-        /// Temporary struct used internally by ThreadPool
-        struct TPFnDataStructFive {
-            std::array<std::size_t, 2> range;
-            std::size_t index;
-            Manager *manager;
-            void *userData;
-            std::vector<std::vector<std::size_t> >*
-                multiMatchingEntities;
-            std::unordered_set<std::size_t> dead;
-        };
-        /// Temporary struct used internally by ThreadPool
-        struct TPFnDataStructSix {
-            std::array<std::size_t, 2> range;
-            Manager *manager;
-            std::vector<std::vector<std::size_t> > *
-                multiMatchingEntities;
-            BitsetType *bitsets;
-            std::mutex *mutex;
-            std::unordered_set<std::size_t> dead;
-        };
-        /// Temporary struct used internally by ThreadPool
-        template <typename Iterable>
-        struct TPFnDataStructSeven {
-            std::array<std::size_t, 2> range;
-            Manager *manager;
-            EntitiesType *entities;
-            Iterable *iterable;
-            void *userData;
-            std::unordered_set<std::size_t> dead;
-        };
-        // end section for "temporary" structures }}}
-
-        /*!
-            \brief Initializes the manager with a default capacity.
-
-            The default capacity is set with macro EC_INIT_ENTITIES_SIZE,
-            and will grow by amounts of EC_GROW_SIZE_AMOUNT when needed.
-        */
-        Manager() :
-            threadPool{},
-            idStackCounter(0)
-        {
-            resize(EC_INIT_ENTITIES_SIZE);
-            if(ThreadCount >= 2) {
-                threadPool = std::make_unique<ThreadPool<ThreadCount> >();
-            }
-
-            deferringDeletions.store(0);
+    Manager() : threadPool{}, idStackCounter(0) {
+        resize(EC_INIT_ENTITIES_SIZE);
+        if (ThreadCount >= 2) {
+            threadPool = std::make_unique<ThreadPool<ThreadCount> >();
         }
 
-        ~Manager() {
-            if (threadPool) {
-                while(!threadPool->isNotRunning()) {
-                    std::this_thread::sleep_for(std::chrono::microseconds(30));
-                }
-            }
-        }
+        deferringDeletions.store(0);
+    }
 
-    private:
-        void resize(std::size_t newCapacity)
-        {
-            if(currentCapacity >= newCapacity)
-            {
-                return;
+    ~Manager() {
+        if (threadPool) {
+            while (!threadPool->isNotRunning()) {
+                std::this_thread::sleep_for(std::chrono::microseconds(30));
             }
+        }
+    }
 
-            EC::Meta::forEach<ComponentsList>([this, newCapacity] (auto t) {
-                std::get<std::deque<decltype(t)> >(
-                    this->componentsStorage).resize(newCapacity);
-            });
+   private:
+    void resize(std::size_t newCapacity) {
+        if (currentCapacity >= newCapacity) {
+            return;
+        }
 
-            entities.resize(newCapacity);
-            for(std::size_t i = currentCapacity; i < newCapacity; ++i)
-            {
-                entities[i] = std::make_tuple(false, BitsetType{});
-            }
+        EC::Meta::forEach<ComponentsList>([this, newCapacity](auto t) {
+            std::get<std::deque<decltype(t)> >(this->componentsStorage)
+                .resize(newCapacity);
+        });
 
-            currentCapacity = newCapacity;
+        entities.resize(newCapacity);
+        for (std::size_t i = currentCapacity; i < newCapacity; ++i) {
+            entities[i] = std::make_tuple(false, BitsetType{});
         }
 
-    public:
-        /*!
-            \brief Adds an entity to the system, returning the ID of the entity.
-
-            Note: The ID of an entity is guaranteed to not change.
-        */
-        std::size_t addEntity()
-        {
-            if(deletedSet.empty())
-            {
-                if(currentSize == currentCapacity)
-                {
-                    resize(currentCapacity + EC_GROW_SIZE_AMOUNT);
-                }
+        currentCapacity = newCapacity;
+    }
 
-                std::get<bool>(entities[currentSize]) = true;
+   public:
+    /*!
+        \brief Adds an entity to the system, returning the ID of the entity.
 
-                return currentSize++;
+        Note: The ID of an entity is guaranteed to not change.
+    */
+    std::size_t addEntity() {
+        if (deletedSet.empty()) {
+            if (currentSize == currentCapacity) {
+                resize(currentCapacity + EC_GROW_SIZE_AMOUNT);
             }
-            else
+
+            std::get<bool>(entities[currentSize]) = true;
+
+            return currentSize++;
+        } else {
+            std::size_t id;
             {
-                std::size_t id;
-                {
-                    auto iter = deletedSet.begin();
-                    id = *iter;
-                    deletedSet.erase(iter);
-                }
-                std::get<bool>(entities[id]) = true;
-                return id;
+                auto iter = deletedSet.begin();
+                id = *iter;
+                deletedSet.erase(iter);
             }
+            std::get<bool>(entities[id]) = true;
+            return id;
         }
-
-    private:
-        void deleteEntityImpl(std::size_t id) {
-            if(hasEntity(id)) {
-                std::get<bool>(entities.at(id)) = false;
-                std::get<BitsetType>(entities.at(id)).reset();
-                deletedSet.insert(id);
-            }
+    }
+
+   private:
+    void deleteEntityImpl(std::size_t id) {
+        if (hasEntity(id)) {
+            std::get<bool>(entities.at(id)) = false;
+            std::get<BitsetType>(entities.at(id)).reset();
+            deletedSet.insert(id);
         }
+    }
 
-    public:
-        /*!
-            \brief Marks an entity for deletion.
+   public:
+    /*!
+        \brief Marks an entity for deletion.
 
-            A deleted Entity's id is stored to be reclaimed later when
-            addEntity is called. Thus calling addEntity may return an id of
-            a previously deleted Entity.
-        */
-        void deleteEntity(std::size_t index)
-        {
-            if(deferringDeletions.load() != 0) {
-                std::lock_guard<std::mutex> lock(deferredDeletionsMutex);
-                deferredDeletions.push_back(index);
-            } else {
-                deleteEntityImpl(index);
-            }
+        A deleted Entity's id is stored to be reclaimed later when
+        addEntity is called. Thus calling addEntity may return an id of
+        a previously deleted Entity.
+    */
+    void deleteEntity(std::size_t index) {
+        if (deferringDeletions.load() != 0) {
+            std::lock_guard<std::mutex> lock(deferredDeletionsMutex);
+            deferredDeletions.push_back(index);
+        } else {
+            deleteEntityImpl(index);
         }
+    }
 
-    private:
-        void handleDeferredDeletions() {
-            if(deferringDeletions.fetch_sub(1) == 1) {
-                std::lock_guard<std::mutex> lock(deferredDeletionsMutex);
-                for(std::size_t id : deferredDeletions) {
-                    deleteEntityImpl(id);
-                }
-                deferredDeletions.clear();
+   private:
+    void handleDeferredDeletions() {
+        if (deferringDeletions.fetch_sub(1) == 1) {
+            std::lock_guard<std::mutex> lock(deferredDeletionsMutex);
+            for (std::size_t id : deferredDeletions) {
+                deleteEntityImpl(id);
             }
+            deferredDeletions.clear();
         }
+    }
 
-    public:
+   public:
+    /*!
+        \brief Checks if the Entity with the given ID is in the system.
 
-        /*!
-            \brief Checks if the Entity with the given ID is in the system.
+        Note that deleted Entities are still considered in the system.
+        Consider using isAlive().
+    */
+    bool hasEntity(const std::size_t& index) const {
+        return index < currentSize;
+    }
 
-            Note that deleted Entities are still considered in the system.
-            Consider using isAlive().
-        */
-        bool hasEntity(const std::size_t& index) const
-        {
-            return index < currentSize;
-        }
+    /*!
+        \brief Checks if the Entity is not marked as deleted.
 
+        Note that invalid Entities (Entities where calls to hasEntity()
+        returns false) will return false.
+    */
+    bool isAlive(const std::size_t& index) const {
+        return hasEntity(index) && std::get<bool>(entities.at(index));
+    }
 
-        /*!
-            \brief Checks if the Entity is not marked as deleted.
+    /*!
+        \brief Returns the current size or number of entities in the system.
 
-            Note that invalid Entities (Entities where calls to hasEntity()
-            returns false) will return false.
-        */
-        bool isAlive(const std::size_t& index) const
-        {
-            return hasEntity(index) && std::get<bool>(entities.at(index));
-        }
+        Note this function will only count entities where isAlive() returns
+        true.
+    */
+    std::size_t getCurrentSize() const {
+        return currentSize - deletedSet.size();
+    }
 
-        /*!
-            \brief Returns the current size or number of entities in the system.
+    /*
+        \brief Returns the current capacity or number of entities the system
+            can hold.
 
-            Note this function will only count entities where isAlive() returns
-            true.
-        */
-        std::size_t getCurrentSize() const
-        {
-            return currentSize - deletedSet.size();
-        }
+        Note that when capacity is exceeded, the capacity is increased by
+        EC_GROW_SIZE_AMOUNT.
+    */
+    std::size_t getCurrentCapacity() const { return currentCapacity; }
 
-        /*
-            \brief Returns the current capacity or number of entities the system
-                can hold.
+    /*!
+        \brief Returns a const reference to an Entity's info.
 
-            Note that when capacity is exceeded, the capacity is increased by
-            EC_GROW_SIZE_AMOUNT.
-        */
-        std::size_t getCurrentCapacity() const
-        {
-            return currentCapacity;
-        }
+        An Entity's info is a std::tuple with a bool, and a
+        bitset.
 
-        /*!
-            \brief Returns a const reference to an Entity's info.
+        \n The bool determines if the Entity is alive.
+        \n The bitset shows what Components and Tags belong to the Entity.
+    */
+    const EntitiesTupleType& getEntityInfo(const std::size_t& index) const {
+        return entities.at(index);
+    }
 
-            An Entity's info is a std::tuple with a bool, and a
-            bitset.
+    /*!
+        \brief Returns a pointer to a component belonging to the given
+            Entity.
 
-            \n The bool determines if the Entity is alive.
-            \n The bitset shows what Components and Tags belong to the Entity.
-        */
-        const EntitiesTupleType& getEntityInfo(const std::size_t& index) const
-        {
-            return entities.at(index);
-        }
+        This function will return a pointer to a Component regardless of
+        whether or not the Entity actually owns the Component. If the Entity
+        doesn't own the Component, changes to the Component will not affect
+        any Entity. It is recommended to use hasComponent() to determine if
+        the Entity actually owns that Component.
 
-        /*!
-            \brief Returns a pointer to a component belonging to the given
-                Entity.
-
-            This function will return a pointer to a Component regardless of
-            whether or not the Entity actually owns the Component. If the Entity
-            doesn't own the Component, changes to the Component will not affect
-            any Entity. It is recommended to use hasComponent() to determine if
-            the Entity actually owns that Component.
-
-            If the given Component is unknown to the Manager, then this function
-            will return a nullptr.
-        */
-        template <typename Component>
-        Component* getEntityData(const std::size_t& index)
-        {
-            constexpr auto componentIndex = EC::Meta::IndexOf<
-                Component, Components>::value;
-            if(componentIndex < Components::size)
-            {
-                // Cast required due to compiler thinking that an invalid
-                // Component is needed even though the enclosing if statement
-                // prevents this from ever happening.
-                return (Component*) &std::get<componentIndex>(
-                    componentsStorage).at(index);
-            }
-            else
-            {
-                return nullptr;
-            }
+        If the given Component is unknown to the Manager, then this function
+        will return a nullptr.
+    */
+    template <typename Component>
+    Component* getEntityData(const std::size_t& index) {
+        constexpr auto componentIndex =
+            EC::Meta::IndexOf<Component, Components>::value;
+        if (componentIndex < Components::size) {
+            // Cast required due to compiler thinking that an invalid
+            // Component is needed even though the enclosing if statement
+            // prevents this from ever happening.
+            return (Component*)&std::get<componentIndex>(componentsStorage)
+                .at(index);
+        } else {
+            return nullptr;
         }
+    }
 
-        /*!
-            \brief Returns a pointer to a component belonging to the given
-                Entity.
+    /*!
+        \brief Returns a pointer to a component belonging to the given
+            Entity.
 
-            Note that this function is the same as getEntityData().
+        Note that this function is the same as getEntityData().
 
-            This function will return a pointer to a Component regardless of
-            whether or not the Entity actually owns the Component. If the Entity
-            doesn't own the Component, changes to the Component will not affect
-            any Entity. It is recommended to use hasComponent() to determine if
-            the Entity actually owns that Component.
+        This function will return a pointer to a Component regardless of
+        whether or not the Entity actually owns the Component. If the Entity
+        doesn't own the Component, changes to the Component will not affect
+        any Entity. It is recommended to use hasComponent() to determine if
+        the Entity actually owns that Component.
 
-            If the given Component is unknown to the Manager, then this function
-            will return a nullptr.
-        */
-        template <typename Component>
-        Component* getEntityComponent(const std::size_t& index)
-        {
-            return getEntityData<Component>(index);
-        }
+        If the given Component is unknown to the Manager, then this function
+        will return a nullptr.
+    */
+    template <typename Component>
+    Component* getEntityComponent(const std::size_t& index) {
+        return getEntityData<Component>(index);
+    }
 
-        /*!
-            \brief Returns a const pointer to a component belonging to the
-                given Entity.
-
-            This function will return a const pointer to a Component
-            regardless of whether or not the Entity actually owns the Component.
-            If the Entity doesn't own the Component, changes to the Component
-            will not affect any Entity. It is recommended to use hasComponent()
-            to determine if the Entity actually owns that Component.
-
-            If the given Component is unknown to the Manager, then this function
-            will return a nullptr.
-        */
-        template <typename Component>
-        const Component* getEntityData(const std::size_t& index) const
-        {
-            constexpr auto componentIndex = EC::Meta::IndexOf<
-                Component, Components>::value;
-            if(componentIndex < Components::size)
-            {
-                // Cast required due to compiler thinking that an invalid
-                // Component is needed even though the enclosing if statement
-                // prevents this from ever happening.
-                return (Component*) &std::get<componentIndex>(
-                    componentsStorage).at(index);
-            }
-            else
-            {
-                return nullptr;
-            }
-        }
+    /*!
+        \brief Returns a const pointer to a component belonging to the
+            given Entity.
 
-        /*!
-            \brief Returns a const pointer to a component belonging to the
-                given Entity.
+        This function will return a const pointer to a Component
+        regardless of whether or not the Entity actually owns the Component.
+        If the Entity doesn't own the Component, changes to the Component
+        will not affect any Entity. It is recommended to use hasComponent()
+        to determine if the Entity actually owns that Component.
 
-            Note that this function is the same as getEntityData() (const).
+        If the given Component is unknown to the Manager, then this function
+        will return a nullptr.
+    */
+    template <typename Component>
+    const Component* getEntityData(const std::size_t& index) const {
+        constexpr auto componentIndex =
+            EC::Meta::IndexOf<Component, Components>::value;
+        if (componentIndex < Components::size) {
+            // Cast required due to compiler thinking that an invalid
+            // Component is needed even though the enclosing if statement
+            // prevents this from ever happening.
+            return (Component*)&std::get<componentIndex>(componentsStorage)
+                .at(index);
+        } else {
+            return nullptr;
+        }
+    }
 
-            This function will return a const pointer to a Component
-            regardless of whether or not the Entity actually owns the Component.
-            If the Entity doesn't own the Component, changes to the Component
-            will not affect any Entity. It is recommended to use hasComponent()
-            to determine if the Entity actually owns that Component.
+    /*!
+        \brief Returns a const pointer to a component belonging to the
+            given Entity.
 
-            If the given Component is unknown to the Manager, then this function
-            will return a nullptr.
-        */
-        template <typename Component>
-        const Component* getEntityComponent(const std::size_t& index) const
-        {
-            return getEntityData<Component>(index);
-        }
+        Note that this function is the same as getEntityData() (const).
 
-        /*!
-            \brief Checks whether or not the given Entity has the given
-                Component.
-
-            Example:
-            \code{.cpp}
-                manager.hasComponent<C0>(entityID);
-            \endcode
-        */
-        template <typename Component>
-        bool hasComponent(const std::size_t& index) const
-        {
-            return std::get<BitsetType>(
-                entities.at(index)).template getComponentBit<Component>();
-        }
+        This function will return a const pointer to a Component
+        regardless of whether or not the Entity actually owns the Component.
+        If the Entity doesn't own the Component, changes to the Component
+        will not affect any Entity. It is recommended to use hasComponent()
+        to determine if the Entity actually owns that Component.
 
-        /*!
-            \brief Checks whether or not the given Entity has the given Tag.
+        If the given Component is unknown to the Manager, then this function
+        will return a nullptr.
+    */
+    template <typename Component>
+    const Component* getEntityComponent(const std::size_t& index) const {
+        return getEntityData<Component>(index);
+    }
 
-            Example:
-            \code{.cpp}
-                manager.hasTag<T0>(entityID);
-            \endcode
-        */
-        template <typename Tag>
-        bool hasTag(const std::size_t& index) const
-        {
-            return std::get<BitsetType>(
-                entities.at(index)).template getTagBit<Tag>();
-        }
+    /*!
+        \brief Checks whether or not the given Entity has the given
+            Component.
 
-        /*!
-            \brief Adds a component to the given Entity.
+        Example:
+        \code{.cpp}
+            manager.hasComponent<C0>(entityID);
+        \endcode
+    */
+    template <typename Component>
+    bool hasComponent(const std::size_t& index) const {
+        return std::get<BitsetType>(entities.at(index))
+            .template getComponentBit<Component>();
+    }
 
-            Additional parameters given to this function will construct the
-            Component with those parameters.
+    /*!
+        \brief Checks whether or not the given Entity has the given Tag.
 
-            Note that if the Entity already has the same component, then it
-            will be overwritten by the newly created Component with the given
-            arguments.
+        Example:
+        \code{.cpp}
+            manager.hasTag<T0>(entityID);
+        \endcode
+    */
+    template <typename Tag>
+    bool hasTag(const std::size_t& index) const {
+        return std::get<BitsetType>(entities.at(index))
+            .template getTagBit<Tag>();
+    }
 
-            If the Entity is not alive or the given Component is not known to
-            the Manager, then nothing will change.
+    /*!
+        \brief Adds a component to the given Entity.
 
-            Example:
-            \code{.cpp}
-                struct C0
-                {
-                    // constructor is compatible as a default constructor
-                    C0(int a = 0, char b = 'b') :
-                    a(a), b(b)
-                    {}
+        Additional parameters given to this function will construct the
+        Component with those parameters.
 
-                    int a;
-                    char b;
-                }
+        Note that if the Entity already has the same component, then it
+        will be overwritten by the newly created Component with the given
+        arguments.
 
-                manager.addComponent<C0>(entityID, 10, 'd');
-            \endcode
-        */
-        template <typename Component, typename... Args>
-        void addComponent(const std::size_t& entityID, Args&&... args)
-        {
-            if(!EC::Meta::Contains<Component, Components>::value
-                || !isAlive(entityID))
+        If the Entity is not alive or the given Component is not known to
+        the Manager, then nothing will change.
+
+        Example:
+        \code{.cpp}
+            struct C0
             {
-                return;
+                // constructor is compatible as a default constructor
+                C0(int a = 0, char b = 'b') :
+                a(a), b(b)
+                {}
+
+                int a;
+                char b;
             }
 
-            Component component(std::forward<Args>(args)...);
+            manager.addComponent<C0>(entityID, 10, 'd');
+        \endcode
+    */
+    template <typename Component, typename... Args>
+    void addComponent(const std::size_t& entityID, Args&&... args) {
+        if (!EC::Meta::Contains<Component, Components>::value ||
+            !isAlive(entityID)) {
+            return;
+        }
 
-            std::get<BitsetType>(
-                entities[entityID]
-            ).template getComponentBit<Component>() = true;
+        Component component(std::forward<Args>(args)...);
 
-            constexpr auto index =
-                EC::Meta::IndexOf<Component, Components>::value;
+        std::get<BitsetType>(entities[entityID])
+            .template getComponentBit<Component>() = true;
 
-            // Cast required due to compiler thinking that deque<char> at
-            // index = Components::size is being used, even if the previous
-            // if statement will prevent this from ever happening.
-            (*((std::deque<Component>*)(&std::get<index>(
-                componentsStorage
-            ))))[entityID] = std::move(component);
-        }
+        constexpr auto index = EC::Meta::IndexOf<Component, Components>::value;
 
-        /*!
-            \brief Removes the given Component from the given Entity.
+        // Cast required due to compiler thinking that deque<char> at
+        // index = Components::size is being used, even if the previous
+        // if statement will prevent this from ever happening.
+        (*((std::deque<Component>*)(&std::get<index>(
+            componentsStorage))))[entityID] = std::move(component);
+    }
 
-            If the Entity does not have the Component given, nothing will
-            change.
+    /*!
+        \brief Removes the given Component from the given Entity.
 
-            Example:
-            \code{.cpp}
-                manager.removeComponent<C0>(entityID);
-            \endcode
-        */
-        template <typename Component>
-        void removeComponent(const std::size_t& entityID)
-        {
-            if(!EC::Meta::Contains<Component, Components>::value
-                || !isAlive(entityID))
-            {
-                return;
-            }
+        If the Entity does not have the Component given, nothing will
+        change.
 
-            std::get<BitsetType>(
-                entities[entityID]
-            ).template getComponentBit<Component>() = false;
+        Example:
+        \code{.cpp}
+            manager.removeComponent<C0>(entityID);
+        \endcode
+    */
+    template <typename Component>
+    void removeComponent(const std::size_t& entityID) {
+        if (!EC::Meta::Contains<Component, Components>::value ||
+            !isAlive(entityID)) {
+            return;
         }
 
-        /*!
-            \brief Adds the given Tag to the given Entity.
+        std::get<BitsetType>(entities[entityID])
+            .template getComponentBit<Component>() = false;
+    }
 
-            Example:
-            \code{.cpp}
-                manager.addTag<T0>(entityID);
-            \endcode
-        */
-        template <typename Tag>
-        void addTag(const std::size_t& entityID)
-        {
-            if(!EC::Meta::Contains<Tag, Tags>::value
-                || !isAlive(entityID))
-            {
-                return;
-            }
+    /*!
+        \brief Adds the given Tag to the given Entity.
 
-            std::get<BitsetType>(
-                entities[entityID]
-            ).template getTagBit<Tag>() = true;
+        Example:
+        \code{.cpp}
+            manager.addTag<T0>(entityID);
+        \endcode
+    */
+    template <typename Tag>
+    void addTag(const std::size_t& entityID) {
+        if (!EC::Meta::Contains<Tag, Tags>::value || !isAlive(entityID)) {
+            return;
         }
 
-        /*!
-            \brief Removes the given Tag from the given Entity.
+        std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() =
+            true;
+    }
 
-            If the Entity does not have the Tag given, nothing will change.
+    /*!
+        \brief Removes the given Tag from the given Entity.
 
-            Example:
-            \code{.cpp}
-                manager.removeTag<T0>(entityID);
-            \endcode
-        */
-        template <typename Tag>
-        void removeTag(const std::size_t& entityID)
-        {
-            if(!EC::Meta::Contains<Tag, Tags>::value
-                || !isAlive(entityID))
-            {
-                return;
-            }
+        If the Entity does not have the Tag given, nothing will change.
 
-            std::get<BitsetType>(
-                entities[entityID]
-            ).template getTagBit<Tag>() = false;
+        Example:
+        \code{.cpp}
+            manager.removeTag<T0>(entityID);
+        \endcode
+    */
+    template <typename Tag>
+    void removeTag(const std::size_t& entityID) {
+        if (!EC::Meta::Contains<Tag, Tags>::value || !isAlive(entityID)) {
+            return;
         }
 
-        /*!
-            \brief Resets the Manager, removing all entities.
+        std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() =
+            false;
+    }
 
-            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();
+    /*!
+        \brief Resets the Manager, removing all entities.
 
-            currentSize = 0;
-            currentCapacity = 0;
-            deletedSet.clear();
-            resize(EC_INIT_ENTITIES_SIZE);
+        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);
+
+        std::lock_guard<std::mutex> lock(deferredDeletionsMutex);
+        deferringDeletions.store(0);
+        deferredDeletions.clear();
+    }
+
+   private:
+    template <typename... Types>
+    struct ForMatchingSignatureHelper {
+        template <typename CType, typename Function>
+        static void call(const std::size_t& entityID, CType& ctype,
+                         Function&& function, void* userData = nullptr) {
+            function(entityID, userData,
+                     ctype.template getEntityData<Types>(entityID)...);
+        }
 
-            std::lock_guard<std::mutex> lock(deferredDeletionsMutex);
-            deferringDeletions.store(0);
-            deferredDeletions.clear();
+        template <typename CType, typename Function>
+        static void callPtr(const std::size_t& entityID, CType& ctype,
+                            Function* function, void* userData = nullptr) {
+            (*function)(entityID, userData,
+                        ctype.template getEntityData<Types>(entityID)...);
         }
 
-    private:
-        template <typename... Types>
-        struct ForMatchingSignatureHelper
-        {
-            template <typename CType, typename Function>
-            static void call(
-                const std::size_t& entityID,
-                CType& ctype,
-                Function&& function,
-                void* userData = nullptr)
-            {
-                function(
-                    entityID,
-                    userData,
-                    ctype.template getEntityData<Types>(entityID)...
-                );
-            }
+        template <typename CType, typename Function>
+        void callInstance(const std::size_t& entityID, CType& ctype,
+                          Function&& function, void* userData = nullptr) const {
+            ForMatchingSignatureHelper<Types...>::call(
+                entityID, ctype, std::forward<Function>(function), userData);
+        }
 
-            template <typename CType, typename Function>
-            static void callPtr(
-                const std::size_t& entityID,
-                CType& ctype,
-                Function* function,
-                void* userData = nullptr)
-            {
-                (*function)(
-                    entityID,
-                    userData,
-                    ctype.template getEntityData<Types>(entityID)...
-                );
-            }
+        template <typename CType, typename Function>
+        void callInstancePtr(const std::size_t& entityID, CType& ctype,
+                             Function* function,
+                             void* userData = nullptr) const {
+            ForMatchingSignatureHelper<Types...>::callPtr(entityID, ctype,
+                                                          function, userData);
+        }
+    };
 
-            template <typename CType, typename Function>
-            void callInstance(
-                const std::size_t& entityID,
-                CType& ctype,
-                Function&& function,
-                void* userData = nullptr) const
-            {
-                ForMatchingSignatureHelper<Types...>::call(
-                    entityID,
-                    ctype,
-                    std::forward<Function>(function),
-                    userData);
-            }
+   public:
+    /*!
+        \brief Calls the given function on all Entities matching the given
+            Signature.
+
+        The function object given to this function must accept std::size_t
+        as its first parameter, void* as its second parameter, and Component
+        pointers for the rest of the parameters. Tags specified in the
+        Signature are only used as filters and will not be given as a
+        parameter to the function.
+
+        The second parameter is default nullptr and will be passed to the
+        function call as the second parameter as a means of providing
+        context (useful when the function is not a lambda function).
+
+        The third parameter is default false (not multi-threaded).
+        Otherwise, if true, then the thread pool will be used to call the
+        given function in parallel across all entities. Note that
+        multi-threading is based on splitting the task of calling the
+        function across sections of entities. Thus if there are only a small
+        amount of entities in the manager, then using multiple threads may
+        not have as great of a speed-up.
 
-            template <typename CType, typename Function>
-            void callInstancePtr(
-                const std::size_t& entityID,
-                CType& ctype,
-                Function* function,
-                void* userData = nullptr) const
+        Example:
+        \code{.cpp}
+            Context c; // some class/struct with data
+            manager.forMatchingSignature<TypeList<C0, C1, T0>>([]
+                (std::size_t ID,
+                void* context,
+                C0* component0, C1* component1)
             {
-                ForMatchingSignatureHelper<Types...>::callPtr(
-                    entityID,
-                    ctype,
-                    function,
-                    userData);
-            }
-        };
-
-    public:
-        /*!
-            \brief Calls the given function on all Entities matching the given
-                Signature.
-
-            The function object given to this function must accept std::size_t
-            as its first parameter, void* as its second parameter, and Component
-            pointers for the rest of the parameters. Tags specified in the
-            Signature are only used as filters and will not be given as a
-            parameter to the function.
-
-            The second parameter is default nullptr and will be passed to the
-            function call as the second parameter as a means of providing
-            context (useful when the function is not a lambda function).
-
-            The third parameter is default false (not multi-threaded).
-            Otherwise, if true, then the thread pool will be used to call the
-            given function in parallel across all entities. Note that
-            multi-threading is based on splitting the task of calling the
-            function across sections of entities. Thus if there are only a small
-            amount of entities in the manager, then using multiple threads may
-            not have as great of a speed-up.
-
-            Example:
-            \code{.cpp}
-                Context c; // some class/struct with data
-                manager.forMatchingSignature<TypeList<C0, C1, T0>>([]
-                    (std::size_t ID,
-                    void* context,
-                    C0* component0, C1* component1)
-                {
-                    // Lambda function contents here
-                },
-                &c, // "Context" object passed to the function
-                true // enable use of internal ThreadPool
-                );
-            \endcode
-            Note, the ID given to the function is not permanent. An entity's ID
-            may change when cleanup() is called.
-        */
-        template <typename Signature, typename Function>
-        void forMatchingSignature(Function&& function,
-            void* userData = nullptr,
-            const bool useThreadPool = false)
+                // Lambda function contents here
+            },
+            &c, // "Context" object passed to the function
+            true // enable use of internal ThreadPool
+            );
+        \endcode
+        Note, the ID given to the function is not permanent. An entity's ID
+        may change when cleanup() is called.
+    */
+    template <typename Signature, typename Function>
+    void forMatchingSignature(Function&& function, void* userData = nullptr,
+                              const bool useThreadPool = false) {
+        std::size_t current_id;
         {
-            std::size_t current_id;
-            {
-                // push to idStack "call stack"
-                std::lock_guard<std::mutex> lock(idStackMutex);
-                current_id = idStackCounter++;
-                idStack.push_back(current_id);
-            }
-            deferringDeletions.fetch_add(1);
-            using SignatureComponents =
-                typename EC::Meta::Matching<Signature, ComponentsList>::type;
-            using Helper =
-                EC::Meta::Morph<
-                    SignatureComponents,
-                    ForMatchingSignatureHelper<> >;
-
-            BitsetType signatureBitset =
-                BitsetType::template generateBitset<Signature>();
-            if(!useThreadPool || !threadPool)
-            {
-                for(std::size_t i = 0; i < currentSize; ++i)
-                {
-                    if(!std::get<bool>(entities[i]))
-                    {
-                        continue;
-                    }
+            // push to idStack "call stack"
+            std::lock_guard<std::mutex> lock(idStackMutex);
+            current_id = idStackCounter++;
+            idStack.push_back(current_id);
+        }
+        deferringDeletions.fetch_add(1);
+        using SignatureComponents =
+            typename EC::Meta::Matching<Signature, ComponentsList>::type;
+        using Helper =
+            EC::Meta::Morph<SignatureComponents, ForMatchingSignatureHelper<> >;
+
+        BitsetType signatureBitset =
+            BitsetType::template generateBitset<Signature>();
+        if (!useThreadPool || !threadPool) {
+            for (std::size_t i = 0; i < currentSize; ++i) {
+                if (!std::get<bool>(entities[i])) {
+                    continue;
+                }
 
-                    if((signatureBitset & std::get<BitsetType>(entities[i]))
-                        == signatureBitset)
-                    {
-                        Helper::call(i, *this,
-                            std::forward<Function>(function), userData);
-                    }
+                if ((signatureBitset & std::get<BitsetType>(entities[i])) ==
+                    signatureBitset) {
+                    Helper::call(i, *this, std::forward<Function>(function),
+                                 userData);
                 }
             }
-            else
-            {
-                std::array<TPFnDataStructZero, ThreadCount * 2> fnDataAr;
-
-                std::size_t s = currentSize / (ThreadCount * 2);
-                for(std::size_t i = 0; i < ThreadCount * 2; ++i) {
-                    std::size_t begin = s * i;
-                    std::size_t end;
-                    if(i == ThreadCount * 2 - 1) {
-                        end = currentSize;
-                    } else {
-                        end = s * (i + 1);
-                    }
-                    if(begin == end) {
-                        continue;
-                    }
-                    fnDataAr[i].range = {begin, end};
-                    fnDataAr[i].manager = this;
-                    fnDataAr[i].entities = &entities;
-                    fnDataAr[i].signature = &signatureBitset;
-                    fnDataAr[i].userData = userData;
-                    for(std::size_t j = begin; j < end; ++j) {
-                        if(!isAlive(j)) {
-                            fnDataAr[i].dead.insert(j);
-                        }
+        } else {
+            std::array<TPFnDataStructZero, ThreadCount * 2> fnDataAr;
+
+            std::size_t s = currentSize / (ThreadCount * 2);
+            for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
+                std::size_t begin = s * i;
+                std::size_t end;
+                if (i == ThreadCount * 2 - 1) {
+                    end = currentSize;
+                } else {
+                    end = s * (i + 1);
+                }
+                if (begin == end) {
+                    continue;
+                }
+                fnDataAr[i].range = {begin, end};
+                fnDataAr[i].manager = this;
+                fnDataAr[i].entities = &entities;
+                fnDataAr[i].signature = &signatureBitset;
+                fnDataAr[i].userData = userData;
+                for (std::size_t j = begin; j < end; ++j) {
+                    if (!isAlive(j)) {
+                        fnDataAr[i].dead.insert(j);
                     }
+                }
 
-                    threadPool->queueFn([&function] (void *ud) {
-                        auto *data = static_cast<TPFnDataStructZero*>(ud);
-                        for(std::size_t i = data->range[0]; i < data->range[1];
-                                ++i) {
-                            if(data->dead.find(i) != data->dead.end()) {
+                threadPool->queueFn(
+                    [&function](void* ud) {
+                        auto* data = static_cast<TPFnDataStructZero*>(ud);
+                        for (std::size_t i = data->range[0]; i < data->range[1];
+                             ++i) {
+                            if (data->dead.find(i) != data->dead.end()) {
                                 continue;
                             }
 
-                            if(((*data->signature)
-                                        & std::get<BitsetType>(
-                                            data->entities->at(i)))
-                                    == *data->signature) {
-                                Helper::call(i,
-                                             *data->manager,
+                            if (((*data->signature) &
+                                 std::get<BitsetType>(data->entities->at(i))) ==
+                                *data->signature) {
+                                Helper::call(i, *data->manager,
                                              std::forward<Function>(function),
                                              data->userData);
                             }
                         }
-                    }, &fnDataAr[i]);
-                }
-                threadPool->easyStartAndWait();
+                    },
+                    &fnDataAr[i]);
             }
-
-            // pop from idStack "call stack"
-            do {
-                {
-                    std::lock_guard<std::mutex> lock(idStackMutex);
-                    if (idStack.back() == current_id) {
-                        idStack.pop_back();
-                        break;
-                    }
-                }
-                std::this_thread::sleep_for(std::chrono::microseconds(15));
-            } while (true);
-
-            handleDeferredDeletions();
+            threadPool->easyStartAndWait();
         }
 
-        /*!
-            \brief Calls the given function on all Entities matching the given
-                Signature.
-
-            The function pointer given to this function must accept std::size_t
-            as its first parameter, void* as its second parameter,  and
-            Component pointers for the rest of the parameters. Tags specified in
-            the Signature are only used as filters and will not be given as a
-            parameter to the function.
-
-            The second parameter is default nullptr and will be passed to the
-            function call as the second parameter as a means of providing
-            context (useful when the function is not a lambda function).
-
-            The third parameter is default false (not multi-threaded).
-            Otherwise, if true, then the thread pool will be used to call the
-            given function in parallel across all entities. Note that
-            multi-threading is based on splitting the task of calling the
-            function across sections of entities. Thus if there are only a small
-            amount of entities in the manager, then using multiple threads may
-            not have as great of a speed-up.
-
-            Example:
-            \code{.cpp}
-                Context c; // some class/struct with data
-                auto function = []
-                    (std::size_t ID,
-                    void* context,
-                    C0* component0, C1* component1)
-                {
-                    // Lambda function contents here
-                };
-                manager.forMatchingSignaturePtr<TypeList<C0, C1, T0>>(
-                    &function, // ptr
-                    &c, // "Context" object passed to the function
-                    true // enable use of ThreadPool
-                );
-            \endcode
-            Note, the ID given to the function is not permanent. An entity's ID
-            may change when cleanup() is called.
-        */
-        template <typename Signature, typename Function>
-        void forMatchingSignaturePtr(Function* function,
-            void* userData = nullptr,
-            const bool useThreadPool = false)
-        {
-            std::size_t current_id;
+        // pop from idStack "call stack"
+        do {
             {
-                // push to idStack "call stack"
                 std::lock_guard<std::mutex> lock(idStackMutex);
-                current_id = idStackCounter++;
-                idStack.push_back(current_id);
+                if (idStack.back() == current_id) {
+                    idStack.pop_back();
+                    break;
+                }
             }
-            deferringDeletions.fetch_add(1);
-            using SignatureComponents =
-                typename EC::Meta::Matching<Signature, ComponentsList>::type;
-            using Helper =
-                EC::Meta::Morph<
-                    SignatureComponents,
-                    ForMatchingSignatureHelper<> >;
-
-            BitsetType signatureBitset =
-                BitsetType::template generateBitset<Signature>();
-            if(!useThreadPool || !threadPool)
+            std::this_thread::sleep_for(std::chrono::microseconds(15));
+        } while (true);
+
+        handleDeferredDeletions();
+    }
+
+    /*!
+        \brief Calls the given function on all Entities matching the given
+            Signature.
+
+        The function pointer given to this function must accept std::size_t
+        as its first parameter, void* as its second parameter,  and
+        Component pointers for the rest of the parameters. Tags specified in
+        the Signature are only used as filters and will not be given as a
+        parameter to the function.
+
+        The second parameter is default nullptr and will be passed to the
+        function call as the second parameter as a means of providing
+        context (useful when the function is not a lambda function).
+
+        The third parameter is default false (not multi-threaded).
+        Otherwise, if true, then the thread pool will be used to call the
+        given function in parallel across all entities. Note that
+        multi-threading is based on splitting the task of calling the
+        function across sections of entities. Thus if there are only a small
+        amount of entities in the manager, then using multiple threads may
+        not have as great of a speed-up.
+
+        Example:
+        \code{.cpp}
+            Context c; // some class/struct with data
+            auto function = []
+                (std::size_t ID,
+                void* context,
+                C0* component0, C1* component1)
             {
-                for(std::size_t i = 0; i < currentSize; ++i)
-                {
-                    if(!std::get<bool>(entities[i]))
-                    {
-                        continue;
-                    }
+                // Lambda function contents here
+            };
+            manager.forMatchingSignaturePtr<TypeList<C0, C1, T0>>(
+                &function, // ptr
+                &c, // "Context" object passed to the function
+                true // enable use of ThreadPool
+            );
+        \endcode
+        Note, the ID given to the function is not permanent. An entity's ID
+        may change when cleanup() is called.
+    */
+    template <typename Signature, typename Function>
+    void forMatchingSignaturePtr(Function* function, void* userData = nullptr,
+                                 const bool useThreadPool = false) {
+        std::size_t current_id;
+        {
+            // push to idStack "call stack"
+            std::lock_guard<std::mutex> lock(idStackMutex);
+            current_id = idStackCounter++;
+            idStack.push_back(current_id);
+        }
+        deferringDeletions.fetch_add(1);
+        using SignatureComponents =
+            typename EC::Meta::Matching<Signature, ComponentsList>::type;
+        using Helper =
+            EC::Meta::Morph<SignatureComponents, ForMatchingSignatureHelper<> >;
+
+        BitsetType signatureBitset =
+            BitsetType::template generateBitset<Signature>();
+        if (!useThreadPool || !threadPool) {
+            for (std::size_t i = 0; i < currentSize; ++i) {
+                if (!std::get<bool>(entities[i])) {
+                    continue;
+                }
 
-                    if((signatureBitset & std::get<BitsetType>(entities[i]))
-                        == signatureBitset)
-                    {
-                        Helper::callPtr(i, *this, function, userData);
-                    }
+                if ((signatureBitset & std::get<BitsetType>(entities[i])) ==
+                    signatureBitset) {
+                    Helper::callPtr(i, *this, function, userData);
                 }
             }
-            else
-            {
-                std::array<TPFnDataStructOne<Function>, ThreadCount * 2> fnDataAr;
-
-                std::size_t s = currentSize / (ThreadCount * 2);
-                for(std::size_t i = 0; i < ThreadCount * 2; ++i) {
-                    std::size_t begin = s * i;
-                    std::size_t end;
-                    if(i == ThreadCount * 2 - 1) {
-                        end = currentSize;
-                    } else {
-                        end = s * (i + 1);
-                    }
-                    if(begin == end) {
-                        continue;
-                    }
-                    fnDataAr[i].range = {begin, end};
-                    fnDataAr[i].manager = this;
-                    fnDataAr[i].entities = &entities;
-                    fnDataAr[i].signature = &signatureBitset;
-                    fnDataAr[i].userData = userData;
-                    fnDataAr[i].fn = function;
-                    for(std::size_t j = begin; j < end; ++j) {
-                        if(!isAlive(j)) {
-                            fnDataAr[i].dead.insert(j);
-                        }
+        } else {
+            std::array<TPFnDataStructOne<Function>, ThreadCount * 2> fnDataAr;
+
+            std::size_t s = currentSize / (ThreadCount * 2);
+            for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
+                std::size_t begin = s * i;
+                std::size_t end;
+                if (i == ThreadCount * 2 - 1) {
+                    end = currentSize;
+                } else {
+                    end = s * (i + 1);
+                }
+                if (begin == end) {
+                    continue;
+                }
+                fnDataAr[i].range = {begin, end};
+                fnDataAr[i].manager = this;
+                fnDataAr[i].entities = &entities;
+                fnDataAr[i].signature = &signatureBitset;
+                fnDataAr[i].userData = userData;
+                fnDataAr[i].fn = function;
+                for (std::size_t j = begin; j < end; ++j) {
+                    if (!isAlive(j)) {
+                        fnDataAr[i].dead.insert(j);
                     }
-                    threadPool->queueFn([] (void *ud) {
-                        auto *data = static_cast<TPFnDataStructOne<Function>*>(ud);
-                        for(std::size_t i = data->range[0]; i < data->range[1];
-                                ++i) {
-                            if(data->dead.find(i) != data->dead.end()) {
+                }
+                threadPool->queueFn(
+                    [](void* ud) {
+                        auto* data =
+                            static_cast<TPFnDataStructOne<Function>*>(ud);
+                        for (std::size_t i = data->range[0]; i < data->range[1];
+                             ++i) {
+                            if (data->dead.find(i) != data->dead.end()) {
                                 continue;
                             }
 
-                            if(((*data->signature)
-                                        & std::get<BitsetType>(
-                                            data->entities->at(i)))
-                                    == *data->signature) {
-                                Helper::callPtr(i,
-                                                *data->manager,
-                                                data->fn,
+                            if (((*data->signature) &
+                                 std::get<BitsetType>(data->entities->at(i))) ==
+                                *data->signature) {
+                                Helper::callPtr(i, *data->manager, data->fn,
                                                 data->userData);
                             }
                         }
-                    }, &fnDataAr[i]);
-                }
-                threadPool->easyStartAndWait();
+                    },
+                    &fnDataAr[i]);
             }
+            threadPool->easyStartAndWait();
+        }
 
-            // pop from idStack "call stack"
-            do {
-                {
-                    std::lock_guard<std::mutex> lock(idStackMutex);
-                    if (idStack.back() == current_id) {
-                        idStack.pop_back();
-                        break;
-                    }
+        // pop from idStack "call stack"
+        do {
+            {
+                std::lock_guard<std::mutex> lock(idStackMutex);
+                if (idStack.back() == current_id) {
+                    idStack.pop_back();
+                    break;
                 }
-                std::this_thread::sleep_for(std::chrono::microseconds(15));
-            } while (true);
+            }
+            std::this_thread::sleep_for(std::chrono::microseconds(15));
+        } while (true);
 
-            handleDeferredDeletions();
-        }
+        handleDeferredDeletions();
+    }
 
+   private:
+    std::map<std::size_t,
+             std::tuple<BitsetType, void*,
+                        std::function<void(std::size_t,
+                                           std::vector<std::size_t>, void*)> > >
+        forMatchingFunctions;
+    std::size_t functionIndex = 0;
 
+   public:
+    /*!
+        \brief Stores a function in the manager to be called later.
 
-    private:
-        std::map<std::size_t, std::tuple<
-            BitsetType,
-            void*,
-            std::function<void(
-                std::size_t,
-                std::vector<std::size_t>,
-                void*)> > >
-            forMatchingFunctions;
-        std::size_t functionIndex = 0;
-
-    public:
-        /*!
-            \brief Stores a function in the manager to be called later.
-
-            As an alternative to calling functions directly with
-            forMatchingSignature(), functions can be stored in the manager to
-            be called later with callForMatchingFunctions() and
-            callForMatchingFunction, and removed with
-            clearForMatchingFunctions() and removeForMatchingFunction().
-
-            The syntax for the Function is the same as with
-            forMatchingSignature().
-
-            Note that functions will be called in the same order they are
-            inserted if called by callForMatchingFunctions() unless the
-            internal functionIndex counter has wrapped around (is a
-            std::size_t). Calling clearForMatchingFunctions() will reset this
-            counter to zero.
-
-            Note that the context pointer provided here (default nullptr) will
-            be provided to the stored function when called.
-
-            Example:
-            \code{.cpp}
-                manager.addForMatchingFunction<TypeList<C0, C1, T0>>([]
-                    (std::size_t ID,
-                    void* context,
-                    C0* component0, C1* component1)
-                {
-                    // Lambda function contents here
-                });
-
-                // call all stored functions
-                manager.callForMatchingFunctions();
-
-                // remove all stored functions
-                manager.clearForMatchingFunctions();
-            \endcode
-
-            \return The index of the function, used for deletion with
-                removeForMatchingFunction() or filtering with
-                keepSomeMatchingFunctions() or removeSomeMatchingFunctions(),
-                or calling with callForMatchingFunction().
-        */
-        template <typename Signature, typename Function>
-        std::size_t addForMatchingFunction(
-            Function&& function,
-            void* userData = nullptr)
-        {
-            deferringDeletions.fetch_add(1);
-            while(forMatchingFunctions.find(functionIndex)
-                != forMatchingFunctions.end())
+        As an alternative to calling functions directly with
+        forMatchingSignature(), functions can be stored in the manager to
+        be called later with callForMatchingFunctions() and
+        callForMatchingFunction, and removed with
+        clearForMatchingFunctions() and removeForMatchingFunction().
+
+        The syntax for the Function is the same as with
+        forMatchingSignature().
+
+        Note that functions will be called in the same order they are
+        inserted if called by callForMatchingFunctions() unless the
+        internal functionIndex counter has wrapped around (is a
+        std::size_t). Calling clearForMatchingFunctions() will reset this
+        counter to zero.
+
+        Note that the context pointer provided here (default nullptr) will
+        be provided to the stored function when called.
+
+        Example:
+        \code{.cpp}
+            manager.addForMatchingFunction<TypeList<C0, C1, T0>>([]
+                (std::size_t ID,
+                void* context,
+                C0* component0, C1* component1)
             {
-                ++functionIndex;
-            }
+                // Lambda function contents here
+            });
+
+            // call all stored functions
+            manager.callForMatchingFunctions();
+
+            // remove all stored functions
+            manager.clearForMatchingFunctions();
+        \endcode
+
+        \return The index of the function, used for deletion with
+            removeForMatchingFunction() or filtering with
+            keepSomeMatchingFunctions() or removeSomeMatchingFunctions(),
+            or calling with callForMatchingFunction().
+    */
+    template <typename Signature, typename Function>
+    std::size_t addForMatchingFunction(Function&& function,
+                                       void* userData = nullptr) {
+        deferringDeletions.fetch_add(1);
+        while (forMatchingFunctions.find(functionIndex) !=
+               forMatchingFunctions.end()) {
+            ++functionIndex;
+        }
 
-            using SignatureComponents =
-                typename EC::Meta::Matching<Signature, ComponentsList>::type;
-            using Helper =
-                EC::Meta::Morph<
-                    SignatureComponents,
-                    ForMatchingSignatureHelper<> >;
-
-            Helper helper;
-            BitsetType signatureBitset =
-                BitsetType::template generateBitset<Signature>();
-
-            forMatchingFunctions.emplace(std::make_pair(
-                functionIndex,
-                std::make_tuple(
-                    signatureBitset,
-                    userData,
-                    [function, helper, this]
-                        (const bool useThreadPool,
-                        std::vector<std::size_t> matching,
-                        void* userData)
-                {
-                    if(!useThreadPool || !threadPool)
-                    {
-                        for(auto eid : matching)
-                        {
-                            if(isAlive(eid))
-                            {
-                                helper.callInstancePtr(
-                                    eid, *this, &function, userData);
+        using SignatureComponents =
+            typename EC::Meta::Matching<Signature, ComponentsList>::type;
+        using Helper =
+            EC::Meta::Morph<SignatureComponents, ForMatchingSignatureHelper<> >;
+
+        Helper helper;
+        BitsetType signatureBitset =
+            BitsetType::template generateBitset<Signature>();
+
+        forMatchingFunctions.emplace(std::make_pair(
+            functionIndex,
+            std::make_tuple(
+                signatureBitset, userData,
+                [function, helper, this](const bool useThreadPool,
+                                         std::vector<std::size_t> matching,
+                                         void* userData) {
+                    if (!useThreadPool || !threadPool) {
+                        for (auto eid : matching) {
+                            if (isAlive(eid)) {
+                                helper.callInstancePtr(eid, *this, &function,
+                                                       userData);
                             }
                         }
-                    }
-                    else
-                    {
+                    } else {
                         std::array<TPFnDataStructTwo, ThreadCount * 2> fnDataAr;
 
                         std::size_t s = matching.size() / (ThreadCount * 2);
-                        for(std::size_t i = 0; i < ThreadCount * 2; ++i) {
+                        for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
                             std::size_t begin = s * i;
                             std::size_t end;
-                            if(i == ThreadCount * 2 - 1) {
+                            if (i == ThreadCount * 2 - 1) {
                                 end = matching.size();
                             } else {
                                 end = s * (i + 1);
                             }
-                            if(begin == end) {
+                            if (begin == end) {
                                 continue;
                             }
                             fnDataAr[i].range = {begin, end};
@@ -1130,490 +1005,452 @@ namespace EC
                             fnDataAr[i].entities = &entities;
                             fnDataAr[i].userData = userData;
                             fnDataAr[i].matching = &matching;
-                            for(std::size_t j = begin; j < end; ++j) {
-                                if(!isAlive(matching.at(j))) {
+                            for (std::size_t j = begin; j < end; ++j) {
+                                if (!isAlive(matching.at(j))) {
                                     fnDataAr[i].dead.insert(j);
                                 }
                             }
-                            threadPool->queueFn([&function, helper] (void* ud) {
-                                auto *data = static_cast<TPFnDataStructTwo*>(ud);
-                                for(std::size_t i = data->range[0];
-                                        i < data->range[1];
-                                        ++i) {
-                                    if(data->dead.find(i) == data->dead.end()) {
-                                        helper.callInstancePtr(
-                                            data->matching->at(i),
-                                            *data->manager,
-                                            &function,
-                                            data->userData);
+                            threadPool->queueFn(
+                                [&function, helper](void* ud) {
+                                    auto* data =
+                                        static_cast<TPFnDataStructTwo*>(ud);
+                                    for (std::size_t i = data->range[0];
+                                         i < data->range[1]; ++i) {
+                                        if (data->dead.find(i) ==
+                                            data->dead.end()) {
+                                            helper.callInstancePtr(
+                                                data->matching->at(i),
+                                                *data->manager, &function,
+                                                data->userData);
+                                        }
                                     }
-                                }
-                            }, &fnDataAr[i]);
+                                },
+                                &fnDataAr[i]);
                         }
                         threadPool->easyStartAndWait();
                     }
                 })));
 
-            handleDeferredDeletions();
-            return functionIndex++;
-        }
+        handleDeferredDeletions();
+        return functionIndex++;
+    }
 
-    private:
-        std::vector<std::vector<std::size_t> > getMatchingEntities(
-            std::vector<BitsetType*> bitsets, const bool useThreadPool = false)
-        {
-            std::vector<std::vector<std::size_t> > matchingV(bitsets.size());
+   private:
+    std::vector<std::vector<std::size_t> > getMatchingEntities(
+        std::vector<BitsetType*> bitsets, const bool useThreadPool = false) {
+        std::vector<std::vector<std::size_t> > matchingV(bitsets.size());
 
-            if(!useThreadPool || !threadPool)
-            {
-                for(std::size_t i = 0; i < currentSize; ++i)
-                {
-                    if(!isAlive(i))
-                    {
-                        continue;
-                    }
-                    for(std::size_t j = 0; j < bitsets.size(); ++j)
-                    {
-                        if(((*bitsets[j]) & std::get<BitsetType>(entities[i]))
-                            == (*bitsets[j]))
-                        {
-                            matchingV[j].push_back(i);
-                        }
+        if (!useThreadPool || !threadPool) {
+            for (std::size_t i = 0; i < currentSize; ++i) {
+                if (!isAlive(i)) {
+                    continue;
+                }
+                for (std::size_t j = 0; j < bitsets.size(); ++j) {
+                    if (((*bitsets[j]) & std::get<BitsetType>(entities[i])) ==
+                        (*bitsets[j])) {
+                        matchingV[j].push_back(i);
                     }
                 }
             }
-            else
-            {
-                std::array<TPFnDataStructThree, ThreadCount * 2> fnDataAr;
-
-                std::size_t s = currentSize / (ThreadCount * 2);
-                std::mutex mutex;
-                for(std::size_t i = 0; i < ThreadCount * 2; ++i) {
-                    std::size_t begin = s * i;
-                    std::size_t end;
-                    if(i == ThreadCount * 2 - 1) {
-                        end = currentSize;
-                    } else {
-                        end = s * (i + 1);
-                    }
-                    if(begin == end) {
-                        continue;
-                    }
-                    fnDataAr[i].range = {begin, end};
-                    fnDataAr[i].manager = this;
-                    fnDataAr[i].matchingV = &matchingV;
-                    fnDataAr[i].bitsets = &bitsets;
-                    fnDataAr[i].entities = &entities;
-                    fnDataAr[i].mutex = &mutex;
-                    for(std::size_t j = begin; j < end; ++j) {
-                        if(!isAlive(j)) {
-                            fnDataAr[i].dead.insert(j);
-                        }
+        } else {
+            std::array<TPFnDataStructThree, ThreadCount * 2> fnDataAr;
+
+            std::size_t s = currentSize / (ThreadCount * 2);
+            std::mutex mutex;
+            for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
+                std::size_t begin = s * i;
+                std::size_t end;
+                if (i == ThreadCount * 2 - 1) {
+                    end = currentSize;
+                } else {
+                    end = s * (i + 1);
+                }
+                if (begin == end) {
+                    continue;
+                }
+                fnDataAr[i].range = {begin, end};
+                fnDataAr[i].manager = this;
+                fnDataAr[i].matchingV = &matchingV;
+                fnDataAr[i].bitsets = &bitsets;
+                fnDataAr[i].entities = &entities;
+                fnDataAr[i].mutex = &mutex;
+                for (std::size_t j = begin; j < end; ++j) {
+                    if (!isAlive(j)) {
+                        fnDataAr[i].dead.insert(j);
                     }
-                    threadPool->queueFn([] (void *ud) {
-                        auto *data = static_cast<TPFnDataStructThree*>(ud);
-                        for(std::size_t i = data->range[0]; i < data->range[1];
-                                ++i) {
-                            if(data->dead.find(i) != data->dead.end()) {
+                }
+                threadPool->queueFn(
+                    [](void* ud) {
+                        auto* data = static_cast<TPFnDataStructThree*>(ud);
+                        for (std::size_t i = data->range[0]; i < data->range[1];
+                             ++i) {
+                            if (data->dead.find(i) != data->dead.end()) {
                                 continue;
                             }
-                            for(std::size_t j = 0; j < data->bitsets->size();
-                                    ++j) {
-                                if((*data->bitsets->at(j)
-                                            & std::get<BitsetType>(
-                                                data->entities->at(i)))
-                                        == *data->bitsets->at(j)) {
+                            for (std::size_t j = 0; j < data->bitsets->size();
+                                 ++j) {
+                                if ((*data->bitsets->at(j) &
+                                     std::get<BitsetType>(data->entities->at(
+                                         i))) == *data->bitsets->at(j)) {
                                     std::lock_guard<std::mutex> lock(
-                                            *data->mutex);
+                                        *data->mutex);
                                     data->matchingV->at(j).push_back(i);
                                 }
                             }
                         }
-                    }, &fnDataAr[i]);
-                }
-                threadPool->easyStartAndWait();
+                    },
+                    &fnDataAr[i]);
             }
-
-            return matchingV;
+            threadPool->easyStartAndWait();
         }
 
-    public:
-
-        /*!
-            \brief Call all stored functions.
-
-            The first (and only) parameter can be optionally used to enable the
-            use of the internal ThreadPool to call all stored functions in
-            parallel. Using the value false (which is the default) will not use
-            the ThreadPool and run all stored functions sequentially on the main
-            thread.  Note that multi-threading is based on splitting the task of
-            calling the functions across sections of entities. Thus if there are
-            only a small amount of entities in the manager, then using multiple
-            threads may not have as great of a speed-up.
-
-            Example:
-            \code{.cpp}
-                manager.addForMatchingFunction<TypeList<C0, C1, T0>>([]
-                    (std::size_t ID,
-                    void* context,
-                    C0* component0, C1* component1) {
-                    // Lambda function contents here
-                });
-
-                // call all stored functions
-                manager.callForMatchingFunctions();
-
-                // call all stored functions with ThreadPool enabled
-                manager.callForMatchingFunctions(true);
-
-                // remove all stored functions
-                manager.clearForMatchingFunctions();
-            \endcode
-        */
-        void callForMatchingFunctions(const bool useThreadPool = false)
-        {
-            deferringDeletions.fetch_add(1);
-            std::vector<BitsetType*> bitsets;
-            for(auto iter = forMatchingFunctions.begin();
-                iter != forMatchingFunctions.end();
-                ++iter)
-            {
-                bitsets.push_back(&std::get<BitsetType>(iter->second));
-            }
+        return matchingV;
+    }
 
-            std::vector<std::vector<std::size_t> > matching =
-                getMatchingEntities(bitsets, useThreadPool);
+   public:
+    /*!
+        \brief Call all stored functions.
 
-            std::size_t i = 0;
-            for(auto iter = forMatchingFunctions.begin();
-                iter != forMatchingFunctions.end();
-                ++iter)
-            {
-                std::get<2>(iter->second)(
-                    useThreadPool, matching[i++], std::get<1>(iter->second));
-            }
+        The first (and only) parameter can be optionally used to enable the
+        use of the internal ThreadPool to call all stored functions in
+        parallel. Using the value false (which is the default) will not use
+        the ThreadPool and run all stored functions sequentially on the main
+        thread.  Note that multi-threading is based on splitting the task of
+        calling the functions across sections of entities. Thus if there are
+        only a small amount of entities in the manager, then using multiple
+        threads may not have as great of a speed-up.
 
-            handleDeferredDeletions();
-        }
+        Example:
+        \code{.cpp}
+            manager.addForMatchingFunction<TypeList<C0, C1, T0>>([]
+                (std::size_t ID,
+                void* context,
+                C0* component0, C1* component1) {
+                // Lambda function contents here
+            });
 
-        /*!
-            \brief Call a specific stored function.
-
-            The second parameter can be optionally used to enable the use of the
-            internal ThreadPool to call the stored function in parallel. Using
-            the value false (which is the default) will not use the ThreadPool
-            and run the stored function sequentially on the main thread.  Note
-            that multi-threading is based on splitting the task of calling the
-            functions across sections of entities. Thus if there are only a
-            small amount of entities in the manager, then using multiple threads
-            may not have as great of a speed-up.
-
-            Example:
-            \code{.cpp}
-                std::size_t id =
-                    manager.addForMatchingFunction<TypeList<C0, C1, T0>>(
-                        [] (std::size_t ID, void* context, C0* c0, C1* c1) {
-                    // Lambda function contents here
-                });
-
-                // call the previously added function
-                manager.callForMatchingFunction(id);
-
-                // call the previously added function with ThreadPool enabled
-                manager.callForMatchingFunction(id, true);
-            \endcode
-
-            \return False if a function with the given id does not exist.
-        */
-        bool callForMatchingFunction(std::size_t id,
-                                     const bool useThreadPool = false)
-        {
-            auto iter = forMatchingFunctions.find(id);
-            if(iter == forMatchingFunctions.end())
-            {
-                return false;
-            }
-            deferringDeletions.fetch_add(1);
-            std::vector<std::vector<std::size_t> > matching =
-                getMatchingEntities(std::vector<BitsetType*>{
-                    &std::get<BitsetType>(iter->second)}, useThreadPool);
-            std::get<2>(iter->second)(
-                useThreadPool, matching[0], std::get<1>(iter->second));
-
-            handleDeferredDeletions();
-            return true;
-        }
+            // call all stored functions
+            manager.callForMatchingFunctions();
 
-        /*!
-            \brief Remove all stored functions.
-
-            Also resets the index counter of stored functions to 0.
-
-            Example:
-            \code{.cpp}
-                manager.addForMatchingFunction<TypeList<C0, C1, T0>>([]
-                    (std::size_t ID,
-                    void* context,
-                    C0* component0, C1* component1)
-                {
-                    // Lambda function contents here
-                });
-
-                // call all stored functions
-                manager.callForMatchingFunctions();
-
-                // remove all stored functions
-                manager.clearForMatchingFunctions();
-            \endcode
-        */
-        void clearForMatchingFunctions()
-        {
-            forMatchingFunctions.clear();
-            functionIndex = 0;
+            // call all stored functions with ThreadPool enabled
+            manager.callForMatchingFunctions(true);
+
+            // remove all stored functions
+            manager.clearForMatchingFunctions();
+        \endcode
+    */
+    void callForMatchingFunctions(const bool useThreadPool = false) {
+        deferringDeletions.fetch_add(1);
+        std::vector<BitsetType*> bitsets;
+        for (auto iter = forMatchingFunctions.begin();
+             iter != forMatchingFunctions.end(); ++iter) {
+            bitsets.push_back(&std::get<BitsetType>(iter->second));
         }
 
-        /*!
-            \brief Removes a function that has the given id.
+        std::vector<std::vector<std::size_t> > matching =
+            getMatchingEntities(bitsets, useThreadPool);
 
-            \return True if a function was erased.
-        */
-        bool removeForMatchingFunction(std::size_t id)
-        {
-            return forMatchingFunctions.erase(id) == 1;
+        std::size_t i = 0;
+        for (auto iter = forMatchingFunctions.begin();
+             iter != forMatchingFunctions.end(); ++iter) {
+            std::get<2>(iter->second)(useThreadPool, matching[i++],
+                                      std::get<1>(iter->second));
         }
 
-        /*!
-            \brief Removes all functions that do not have the index specified
-                in argument "list".
+        handleDeferredDeletions();
+    }
 
-            The given List must be iterable.
-            This is the only requirement, so a set could also be given.
+    /*!
+        \brief Call a specific stored function.
 
-            \return The number of functions deleted.
-        */
-        template <typename List>
-        std::size_t keepSomeMatchingFunctions(List list)
-        {
-            std::size_t deletedCount = 0;
-            for(auto iter = forMatchingFunctions.begin();
-                iter != forMatchingFunctions.end();)
-            {
-                if(std::find(list.begin(), list.end(), iter->first)
-                    == list.end())
-                {
-                    iter = forMatchingFunctions.erase(iter);
-                    ++deletedCount;
-                }
-                else
-                {
-                    ++iter;
-                }
-            }
+        The second parameter can be optionally used to enable the use of the
+        internal ThreadPool to call the stored function in parallel. Using
+        the value false (which is the default) will not use the ThreadPool
+        and run the stored function sequentially on the main thread.  Note
+        that multi-threading is based on splitting the task of calling the
+        functions across sections of entities. Thus if there are only a
+        small amount of entities in the manager, then using multiple threads
+        may not have as great of a speed-up.
 
-            return deletedCount;
-        }
+        Example:
+        \code{.cpp}
+            std::size_t id =
+                manager.addForMatchingFunction<TypeList<C0, C1, T0>>(
+                    [] (std::size_t ID, void* context, C0* c0, C1* c1) {
+                // Lambda function contents here
+            });
 
-        /*!
-            \brief Removes all functions that do not have the index specified
-                in argument "list".
+            // call the previously added function
+            manager.callForMatchingFunction(id);
 
-            This function allows for passing an initializer list.
+            // call the previously added function with ThreadPool enabled
+            manager.callForMatchingFunction(id, true);
+        \endcode
 
-            \return The number of functions deleted.
-        */
-        std::size_t keepSomeMatchingFunctions(
-            std::initializer_list<std::size_t> list)
-        {
-            return keepSomeMatchingFunctions<decltype(list)>(list);
+        \return False if a function with the given id does not exist.
+    */
+    bool callForMatchingFunction(std::size_t id,
+                                 const bool useThreadPool = false) {
+        auto iter = forMatchingFunctions.find(id);
+        if (iter == forMatchingFunctions.end()) {
+            return false;
         }
+        deferringDeletions.fetch_add(1);
+        std::vector<std::vector<std::size_t> > matching = getMatchingEntities(
+            std::vector<BitsetType*>{&std::get<BitsetType>(iter->second)},
+            useThreadPool);
+        std::get<2>(iter->second)(useThreadPool, matching[0],
+                                  std::get<1>(iter->second));
+
+        handleDeferredDeletions();
+        return true;
+    }
 
-        /*!
-            \brief Removes all functions that do have the index specified
-                in argument "list".
+    /*!
+        \brief Remove all stored functions.
 
-            The given List must be iterable.
-            This is the only requirement, so a set could also be given.
+        Also resets the index counter of stored functions to 0.
 
-            \return The number of functions deleted.
-        */
-        template <typename List>
-        std::size_t removeSomeMatchingFunctions(List list)
-        {
-            std::size_t deletedCount = 0;
-            for(auto listIter = list.begin();
-                listIter != list.end();
-                ++listIter)
+        Example:
+        \code{.cpp}
+            manager.addForMatchingFunction<TypeList<C0, C1, T0>>([]
+                (std::size_t ID,
+                void* context,
+                C0* component0, C1* component1)
             {
-                deletedCount += forMatchingFunctions.erase(*listIter);
-            }
+                // Lambda function contents here
+            });
+
+            // call all stored functions
+            manager.callForMatchingFunctions();
+
+            // remove all stored functions
+            manager.clearForMatchingFunctions();
+        \endcode
+    */
+    void clearForMatchingFunctions() {
+        forMatchingFunctions.clear();
+        functionIndex = 0;
+    }
+
+    /*!
+        \brief Removes a function that has the given id.
 
-            return deletedCount;
+        \return True if a function was erased.
+    */
+    bool removeForMatchingFunction(std::size_t id) {
+        return forMatchingFunctions.erase(id) == 1;
+    }
+
+    /*!
+        \brief Removes all functions that do not have the index specified
+            in argument "list".
+
+        The given List must be iterable.
+        This is the only requirement, so a set could also be given.
+
+        \return The number of functions deleted.
+    */
+    template <typename List>
+    std::size_t keepSomeMatchingFunctions(List list) {
+        std::size_t deletedCount = 0;
+        for (auto iter = forMatchingFunctions.begin();
+             iter != forMatchingFunctions.end();) {
+            if (std::find(list.begin(), list.end(), iter->first) ==
+                list.end()) {
+                iter = forMatchingFunctions.erase(iter);
+                ++deletedCount;
+            } else {
+                ++iter;
+            }
         }
 
-        /*!
-            \brief Removes all functions that do have the index specified
-                in argument "list".
+        return deletedCount;
+    }
 
-            This function allows for passing an initializer list.
+    /*!
+        \brief Removes all functions that do not have the index specified
+            in argument "list".
 
-            \return The number of functions deleted.
-        */
-        std::size_t removeSomeMatchingFunctions(
-            std::initializer_list<std::size_t> list)
-        {
-            return removeSomeMatchingFunctions<decltype(list)>(list);
+        This function allows for passing an initializer list.
+
+        \return The number of functions deleted.
+    */
+    std::size_t keepSomeMatchingFunctions(
+        std::initializer_list<std::size_t> list) {
+        return keepSomeMatchingFunctions<decltype(list)>(list);
+    }
+
+    /*!
+        \brief Removes all functions that do have the index specified
+            in argument "list".
+
+        The given List must be iterable.
+        This is the only requirement, so a set could also be given.
+
+        \return The number of functions deleted.
+    */
+    template <typename List>
+    std::size_t removeSomeMatchingFunctions(List list) {
+        std::size_t deletedCount = 0;
+        for (auto listIter = list.begin(); listIter != list.end(); ++listIter) {
+            deletedCount += forMatchingFunctions.erase(*listIter);
         }
 
-        /*!
-            \brief Sets the context pointer of a stored function
+        return deletedCount;
+    }
 
-            \return True if id is valid and context was updated
-        */
-        bool changeForMatchingFunctionContext(std::size_t id, void* userData)
-        {
-            auto f = forMatchingFunctions.find(id);
-            if(f != forMatchingFunctions.end())
-            {
-                std::get<1>(f->second) = userData;
-                return true;
-            }
-            return false;
+    /*!
+        \brief Removes all functions that do have the index specified
+            in argument "list".
+
+        This function allows for passing an initializer list.
+
+        \return The number of functions deleted.
+    */
+    std::size_t removeSomeMatchingFunctions(
+        std::initializer_list<std::size_t> list) {
+        return removeSomeMatchingFunctions<decltype(list)>(list);
+    }
+
+    /*!
+        \brief Sets the context pointer of a stored function
+
+        \return True if id is valid and context was updated
+    */
+    bool changeForMatchingFunctionContext(std::size_t id, void* userData) {
+        auto f = forMatchingFunctions.find(id);
+        if (f != forMatchingFunctions.end()) {
+            std::get<1>(f->second) = userData;
+            return true;
         }
+        return false;
+    }
 
-        /*!
-            \brief Call multiple functions with mulitple signatures on all
-                living entities.
-
-            (Living entities as in entities that have not been marked for
-            deletion.)
-
-            This function requires the first template parameter to be a
-            EC::Meta::TypeList of signatures. Note that a signature is a
-            EC::Meta::TypeList of components and tags, meaning that SigList
-            is a TypeList of TypeLists.
-
-            The second template parameter can be inferred from the function
-            parameter which should be a tuple of functions. The function
-            at any index in the tuple should match with a signature of the
-            same index in the SigList. Behavior is undefined if there are
-            less functions than signatures.
-
-            See the Unit Test of this function in src/test/ECTest.cpp for
-            usage examples.
-
-            The second parameter (default nullptr) will be provided to every
-            function call as a void* (context).
-
-            The third parameter is default false (not multi-threaded).
-            Otherwise, if true, then the thread pool will be used to call the
-            given function in parallel across all entities. Note that
-            multi-threading is based on splitting the task of calling the
-            function across sections of entities. Thus if there are only a small
-            amount of entities in the manager, then using multiple threads may
-            not have as great of a speed-up.
-
-            This function was created for the use case where there are many
-            entities in the system which can cause multiple calls to
-            forMatchingSignature to be slow due to the overhead of iterating
-            through the entire list of entities on each invocation.
-            This function instead iterates through all entities once,
-            storing matching entities in a vector of vectors (for each
-            signature and function pair) and then calling functions with
-            the matching list of entities.
-
-            Note that multi-threaded or not, functions will be called in order
-            of signatures. The first function signature pair will be called
-            first, then the second, third, and so on.
-            If this function is called with more than 1 thread specified, then
-            the order of entities called is not guaranteed. Otherwise entities
-            will be called in consecutive order by their ID.
-        */
-        template <typename SigList, typename FTuple>
-        void forMatchingSignatures(
-            FTuple fTuple,
-            void* userData = nullptr,
-            const bool useThreadPool = false)
+    /*!
+        \brief Call multiple functions with mulitple signatures on all
+            living entities.
+
+        (Living entities as in entities that have not been marked for
+        deletion.)
+
+        This function requires the first template parameter to be a
+        EC::Meta::TypeList of signatures. Note that a signature is a
+        EC::Meta::TypeList of components and tags, meaning that SigList
+        is a TypeList of TypeLists.
+
+        The second template parameter can be inferred from the function
+        parameter which should be a tuple of functions. The function
+        at any index in the tuple should match with a signature of the
+        same index in the SigList. Behavior is undefined if there are
+        less functions than signatures.
+
+        See the Unit Test of this function in src/test/ECTest.cpp for
+        usage examples.
+
+        The second parameter (default nullptr) will be provided to every
+        function call as a void* (context).
+
+        The third parameter is default false (not multi-threaded).
+        Otherwise, if true, then the thread pool will be used to call the
+        given function in parallel across all entities. Note that
+        multi-threading is based on splitting the task of calling the
+        function across sections of entities. Thus if there are only a small
+        amount of entities in the manager, then using multiple threads may
+        not have as great of a speed-up.
+
+        This function was created for the use case where there are many
+        entities in the system which can cause multiple calls to
+        forMatchingSignature to be slow due to the overhead of iterating
+        through the entire list of entities on each invocation.
+        This function instead iterates through all entities once,
+        storing matching entities in a vector of vectors (for each
+        signature and function pair) and then calling functions with
+        the matching list of entities.
+
+        Note that multi-threaded or not, functions will be called in order
+        of signatures. The first function signature pair will be called
+        first, then the second, third, and so on.
+        If this function is called with more than 1 thread specified, then
+        the order of entities called is not guaranteed. Otherwise entities
+        will be called in consecutive order by their ID.
+    */
+    template <typename SigList, typename FTuple>
+    void forMatchingSignatures(FTuple fTuple, void* userData = nullptr,
+                               const bool useThreadPool = false) {
+        std::size_t current_id;
         {
-            std::size_t current_id;
-            {
-                // push to idStack "call stack"
-                std::lock_guard<std::mutex> lock(idStackMutex);
-                current_id = idStackCounter++;
-                idStack.push_back(current_id);
-            }
-            deferringDeletions.fetch_add(1);
-            std::vector<std::vector<std::size_t> >
-                multiMatchingEntities(SigList::size);
-            BitsetType signatureBitsets[SigList::size];
-
-            // generate bitsets for each signature
-            EC::Meta::forEachWithIndex<SigList>(
-            [&signatureBitsets] (auto signature, const auto index) {
+            // push to idStack "call stack"
+            std::lock_guard<std::mutex> lock(idStackMutex);
+            current_id = idStackCounter++;
+            idStack.push_back(current_id);
+        }
+        deferringDeletions.fetch_add(1);
+        std::vector<std::vector<std::size_t> > multiMatchingEntities(
+            SigList::size);
+        BitsetType signatureBitsets[SigList::size];
+
+        // generate bitsets for each signature
+        EC::Meta::forEachWithIndex<SigList>(
+            [&signatureBitsets](auto signature, const auto index) {
                 signatureBitsets[index] =
-                    BitsetType::template generateBitset
-                        <decltype(signature)>();
+                    BitsetType::template generateBitset<decltype(signature)>();
             });
 
-            // find and store entities matching signatures
-            if(!useThreadPool || !threadPool)
-            {
-                for(std::size_t eid = 0; eid < currentSize; ++eid)
-                {
-                    if(!isAlive(eid))
-                    {
-                        continue;
-                    }
-                    for(std::size_t i = 0; i < SigList::size; ++i)
-                    {
-                        if((signatureBitsets[i]
-                            & std::get<BitsetType>(entities[eid]))
-                                == signatureBitsets[i])
-                        {
-                            multiMatchingEntities[i].push_back(eid);
-                        }
+        // find and store entities matching signatures
+        if (!useThreadPool || !threadPool) {
+            for (std::size_t eid = 0; eid < currentSize; ++eid) {
+                if (!isAlive(eid)) {
+                    continue;
+                }
+                for (std::size_t i = 0; i < SigList::size; ++i) {
+                    if ((signatureBitsets[i] &
+                         std::get<BitsetType>(entities[eid])) ==
+                        signatureBitsets[i]) {
+                        multiMatchingEntities[i].push_back(eid);
                     }
                 }
             }
-            else
-            {
-                std::array<TPFnDataStructFour, ThreadCount * 2> fnDataAr;
-
-                std::mutex mutex;
-                std::size_t s = currentSize / (ThreadCount * 2);
-                for(std::size_t i = 0; i < ThreadCount * 2; ++i) {
-                    std::size_t begin = s * i;
-                    std::size_t end;
-                    if(i == ThreadCount * 2 - 1) {
-                        end = currentSize;
-                    } else {
-                        end = s * (i + 1);
-                    }
-                    if(begin == end) {
-                        continue;
-                    }
-                    fnDataAr[i].range = {begin, end};
-                    fnDataAr[i].manager = this;
-                    fnDataAr[i].multiMatchingEntities = &multiMatchingEntities;
-                    fnDataAr[i].signatures = signatureBitsets;
-                    fnDataAr[i].mutex = &mutex;
-                    for(std::size_t j = begin; j < end; ++j) {
-                        if(!isAlive(j)) {
-                            fnDataAr[i].dead.insert(j);
-                        }
+        } else {
+            std::array<TPFnDataStructFour, ThreadCount * 2> fnDataAr;
+
+            std::mutex mutex;
+            std::size_t s = currentSize / (ThreadCount * 2);
+            for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
+                std::size_t begin = s * i;
+                std::size_t end;
+                if (i == ThreadCount * 2 - 1) {
+                    end = currentSize;
+                } else {
+                    end = s * (i + 1);
+                }
+                if (begin == end) {
+                    continue;
+                }
+                fnDataAr[i].range = {begin, end};
+                fnDataAr[i].manager = this;
+                fnDataAr[i].multiMatchingEntities = &multiMatchingEntities;
+                fnDataAr[i].signatures = signatureBitsets;
+                fnDataAr[i].mutex = &mutex;
+                for (std::size_t j = begin; j < end; ++j) {
+                    if (!isAlive(j)) {
+                        fnDataAr[i].dead.insert(j);
                     }
+                }
 
-                    threadPool->queueFn([] (void *ud) {
-                        auto *data = static_cast<TPFnDataStructFour*>(ud);
-                        for(std::size_t i = data->range[0]; i < data->range[1];
-                                ++i) {
-                            if(data->dead.find(i) != data->dead.end()) {
+                threadPool->queueFn(
+                    [](void* ud) {
+                        auto* data = static_cast<TPFnDataStructFour*>(ud);
+                        for (std::size_t i = data->range[0]; i < data->range[1];
+                             ++i) {
+                            if (data->dead.find(i) != data->dead.end()) {
                                 continue;
                             }
-                            for(std::size_t j = 0; j < SigList::size; ++j) {
-                                if((data->signatures[j]
-                                                & std::get<BitsetType>(
-                                                    data->manager->entities[i]))
-                                        == data->signatures[j]) {
+                            for (std::size_t j = 0; j < SigList::size; ++j) {
+                                if ((data->signatures[j] &
+                                     std::get<BitsetType>(
+                                         data->manager->entities[i])) ==
+                                    data->signatures[j]) {
                                     std::lock_guard<std::mutex> lock(
                                         *data->mutex);
                                     data->multiMatchingEntities->at(j)
@@ -1621,229 +1458,219 @@ namespace EC
                                 }
                             }
                         }
-                    }, &fnDataAr[i]);
-                }
-                threadPool->easyStartAndWait();
+                    },
+                    &fnDataAr[i]);
             }
+            threadPool->easyStartAndWait();
+        }
 
-            // call functions on matching entities
-            EC::Meta::forEachDoubleTuple(
-                EC::Meta::Morph<SigList, std::tuple<> >{},
-                fTuple,
-                [this, &multiMatchingEntities, useThreadPool, &userData]
-                (auto sig, auto func, auto index)
-                {
-                    using SignatureComponents =
-                        typename EC::Meta::Matching<
-                            decltype(sig), ComponentsList>::type;
-                    using Helper =
-                        EC::Meta::Morph<
-                            SignatureComponents,
-                            ForMatchingSignatureHelper<> >;
-                    if(!useThreadPool || !threadPool) {
-                        for(const auto& id : multiMatchingEntities[index]) {
-                            if(isAlive(id)) {
-                                Helper::call(id, *this, func, userData);
-                            }
+        // call functions on matching entities
+        EC::Meta::forEachDoubleTuple(
+            EC::Meta::Morph<SigList, std::tuple<> >{}, fTuple,
+            [this, &multiMatchingEntities, useThreadPool, &userData](
+                auto sig, auto func, auto index) {
+                using SignatureComponents =
+                    typename EC::Meta::Matching<decltype(sig),
+                                                ComponentsList>::type;
+                using Helper = EC::Meta::Morph<SignatureComponents,
+                                               ForMatchingSignatureHelper<> >;
+                if (!useThreadPool || !threadPool) {
+                    for (const auto& id : multiMatchingEntities[index]) {
+                        if (isAlive(id)) {
+                            Helper::call(id, *this, func, userData);
                         }
-                    } else {
-                        std::array<TPFnDataStructFive, ThreadCount * 2>
-                            fnDataAr;
-                        std::size_t s = multiMatchingEntities[index].size()
-                            / (ThreadCount * 2);
-                        for(unsigned int i = 0; i < ThreadCount * 2; ++i) {
-                            std::size_t begin = s * i;
-                            std::size_t end;
-                            if(i == ThreadCount * 2 - 1) {
-                                end = multiMatchingEntities[index].size();
-                            } else {
-                                end = s * (i + 1);
-                            }
-                            if(begin == end) {
-                                continue;
-                            }
-                            fnDataAr[i].range = {begin, end};
-                            fnDataAr[i].index = index;
-                            fnDataAr[i].manager = this;
-                            fnDataAr[i].userData = userData;
-                            fnDataAr[i].multiMatchingEntities =
-                                &multiMatchingEntities;
-                            for(std::size_t j = begin; j < end; ++j) {
-                                if(!isAlive(multiMatchingEntities.at(index).at(j))) {
-                                    fnDataAr[i].dead.insert(j);
-                                }
+                    }
+                } else {
+                    std::array<TPFnDataStructFive, ThreadCount * 2> fnDataAr;
+                    std::size_t s =
+                        multiMatchingEntities[index].size() / (ThreadCount * 2);
+                    for (unsigned int i = 0; i < ThreadCount * 2; ++i) {
+                        std::size_t begin = s * i;
+                        std::size_t end;
+                        if (i == ThreadCount * 2 - 1) {
+                            end = multiMatchingEntities[index].size();
+                        } else {
+                            end = s * (i + 1);
+                        }
+                        if (begin == end) {
+                            continue;
+                        }
+                        fnDataAr[i].range = {begin, end};
+                        fnDataAr[i].index = index;
+                        fnDataAr[i].manager = this;
+                        fnDataAr[i].userData = userData;
+                        fnDataAr[i].multiMatchingEntities =
+                            &multiMatchingEntities;
+                        for (std::size_t j = begin; j < end; ++j) {
+                            if (!isAlive(
+                                    multiMatchingEntities.at(index).at(j))) {
+                                fnDataAr[i].dead.insert(j);
                             }
-                            threadPool->queueFn([&func] (void *ud) {
-                                auto *data = static_cast<TPFnDataStructFive*>(ud);
-                                for(std::size_t i = data->range[0];
-                                        i < data->range[1]; ++i) {
-                                    if(data->dead.find(i) == data->dead.end()) {
-                                        Helper::call(
-                                            data->multiMatchingEntities
-                                                ->at(data->index).at(i),
-                                            *data->manager,
-                                            func,
-                                            data->userData);
+                        }
+                        threadPool->queueFn(
+                            [&func](void* ud) {
+                                auto* data =
+                                    static_cast<TPFnDataStructFive*>(ud);
+                                for (std::size_t i = data->range[0];
+                                     i < data->range[1]; ++i) {
+                                    if (data->dead.find(i) ==
+                                        data->dead.end()) {
+                                        Helper::call(data->multiMatchingEntities
+                                                         ->at(data->index)
+                                                         .at(i),
+                                                     *data->manager, func,
+                                                     data->userData);
                                     }
                                 }
-                            }, &fnDataAr[i]);
-                        }
-                        threadPool->easyStartAndWait();
+                            },
+                            &fnDataAr[i]);
                     }
+                    threadPool->easyStartAndWait();
                 }
-            );
+            });
 
-            // pop from idStack "call stack"
-            do {
-                {
-                    std::lock_guard<std::mutex> lock(idStackMutex);
-                    if (idStack.back() == current_id) {
-                        idStack.pop_back();
-                        break;
-                    }
+        // pop from idStack "call stack"
+        do {
+            {
+                std::lock_guard<std::mutex> lock(idStackMutex);
+                if (idStack.back() == current_id) {
+                    idStack.pop_back();
+                    break;
                 }
-                std::this_thread::sleep_for(std::chrono::microseconds(15));
-            } while (true);
+            }
+            std::this_thread::sleep_for(std::chrono::microseconds(15));
+        } while (true);
 
-            handleDeferredDeletions();
-        }
+        handleDeferredDeletions();
+    }
 
-        /*!
-            \brief Call multiple functions with mulitple signatures on all
-                living entities.
-
-            (Living entities as in entities that have not been marked for
-            deletion.)
-
-            Note that this function requires the tuple of functions to hold
-            pointers to functions, not just functions.
-
-            This function requires the first template parameter to be a
-            EC::Meta::TypeList of signatures. Note that a signature is a
-            EC::Meta::TypeList of components and tags, meaning that SigList
-            is a TypeList of TypeLists.
-
-            The second template parameter can be inferred from the function
-            parameter which should be a tuple of functions. The function
-            at any index in the tuple should match with a signature of the
-            same index in the SigList. Behavior is undefined if there are
-            less functions than signatures.
-
-            See the Unit Test of this function in src/test/ECTest.cpp for
-            usage examples.
-
-            The second parameter (default nullptr) will be provided to every
-            function call as a void* (context).
-
-            The third parameter is default false (not multi-threaded).
-            Otherwise, if true, then the thread pool will be used to call the
-            given function in parallel across all entities. Note that
-            multi-threading is based on splitting the task of calling the
-            function across sections of entities. Thus if there are only a small
-            amount of entities in the manager, then using multiple threads may
-            not have as great of a speed-up.
-
-            This function was created for the use case where there are many
-            entities in the system which can cause multiple calls to
-            forMatchingSignature to be slow due to the overhead of iterating
-            through the entire list of entities on each invocation.
-            This function instead iterates through all entities once,
-            storing matching entities in a vector of vectors (for each
-            signature and function pair) and then calling functions with
-            the matching list of entities.
-
-            Note that multi-threaded or not, functions will be called in order
-            of signatures. The first function signature pair will be called
-            first, then the second, third, and so on.
-            If this function is called with more than 1 thread specified, then
-            the order of entities called is not guaranteed. Otherwise entities
-            will be called in consecutive order by their ID.
-        */
-        template <typename SigList, typename FTuple>
-        void forMatchingSignaturesPtr(FTuple fTuple,
-            void* userData = nullptr,
-            const bool useThreadPool = false)
+    /*!
+        \brief Call multiple functions with mulitple signatures on all
+            living entities.
+
+        (Living entities as in entities that have not been marked for
+        deletion.)
+
+        Note that this function requires the tuple of functions to hold
+        pointers to functions, not just functions.
+
+        This function requires the first template parameter to be a
+        EC::Meta::TypeList of signatures. Note that a signature is a
+        EC::Meta::TypeList of components and tags, meaning that SigList
+        is a TypeList of TypeLists.
+
+        The second template parameter can be inferred from the function
+        parameter which should be a tuple of functions. The function
+        at any index in the tuple should match with a signature of the
+        same index in the SigList. Behavior is undefined if there are
+        less functions than signatures.
+
+        See the Unit Test of this function in src/test/ECTest.cpp for
+        usage examples.
+
+        The second parameter (default nullptr) will be provided to every
+        function call as a void* (context).
+
+        The third parameter is default false (not multi-threaded).
+        Otherwise, if true, then the thread pool will be used to call the
+        given function in parallel across all entities. Note that
+        multi-threading is based on splitting the task of calling the
+        function across sections of entities. Thus if there are only a small
+        amount of entities in the manager, then using multiple threads may
+        not have as great of a speed-up.
+
+        This function was created for the use case where there are many
+        entities in the system which can cause multiple calls to
+        forMatchingSignature to be slow due to the overhead of iterating
+        through the entire list of entities on each invocation.
+        This function instead iterates through all entities once,
+        storing matching entities in a vector of vectors (for each
+        signature and function pair) and then calling functions with
+        the matching list of entities.
+
+        Note that multi-threaded or not, functions will be called in order
+        of signatures. The first function signature pair will be called
+        first, then the second, third, and so on.
+        If this function is called with more than 1 thread specified, then
+        the order of entities called is not guaranteed. Otherwise entities
+        will be called in consecutive order by their ID.
+    */
+    template <typename SigList, typename FTuple>
+    void forMatchingSignaturesPtr(FTuple fTuple, void* userData = nullptr,
+                                  const bool useThreadPool = false) {
+        std::size_t current_id;
         {
-            std::size_t current_id;
-            {
-                // push to idStack "call stack"
-                std::lock_guard<std::mutex> lock(idStackMutex);
-                current_id = idStackCounter++;
-                idStack.push_back(current_id);
-            }
-            deferringDeletions.fetch_add(1);
-            std::vector<std::vector<std::size_t> > multiMatchingEntities(
-                SigList::size);
-            BitsetType signatureBitsets[SigList::size];
-
-            // generate bitsets for each signature
-            EC::Meta::forEachWithIndex<SigList>(
-            [&signatureBitsets] (auto signature, const auto index) {
+            // push to idStack "call stack"
+            std::lock_guard<std::mutex> lock(idStackMutex);
+            current_id = idStackCounter++;
+            idStack.push_back(current_id);
+        }
+        deferringDeletions.fetch_add(1);
+        std::vector<std::vector<std::size_t> > multiMatchingEntities(
+            SigList::size);
+        BitsetType signatureBitsets[SigList::size];
+
+        // generate bitsets for each signature
+        EC::Meta::forEachWithIndex<SigList>(
+            [&signatureBitsets](auto signature, const auto index) {
                 signatureBitsets[index] =
-                    BitsetType::template generateBitset
-                        <decltype(signature)>();
+                    BitsetType::template generateBitset<decltype(signature)>();
             });
 
-            // find and store entities matching signatures
-            if(!useThreadPool || !threadPool)
-            {
-                for(std::size_t eid = 0; eid < currentSize; ++eid)
-                {
-                    if(!isAlive(eid))
-                    {
-                        continue;
-                    }
-                    for(std::size_t i = 0; i < SigList::size; ++i)
-                    {
-                        if((signatureBitsets[i]
-                            & std::get<BitsetType>(entities[eid]))
-                                == signatureBitsets[i])
-                        {
-                            multiMatchingEntities[i].push_back(eid);
-                        }
+        // find and store entities matching signatures
+        if (!useThreadPool || !threadPool) {
+            for (std::size_t eid = 0; eid < currentSize; ++eid) {
+                if (!isAlive(eid)) {
+                    continue;
+                }
+                for (std::size_t i = 0; i < SigList::size; ++i) {
+                    if ((signatureBitsets[i] &
+                         std::get<BitsetType>(entities[eid])) ==
+                        signatureBitsets[i]) {
+                        multiMatchingEntities[i].push_back(eid);
                     }
                 }
             }
-            else
-            {
-                std::array<TPFnDataStructSix, ThreadCount * 2> fnDataAr;
-
-                std::mutex mutex;
-                std::size_t s = currentSize / (ThreadCount * 2);
-                for(std::size_t i = 0; i < ThreadCount * 2; ++i) {
-                    std::size_t begin = s * i;
-                    std::size_t end;
-                    if(i == ThreadCount * 2 - 1) {
-                        end = currentSize;
-                    } else {
-                        end = s * (i + 1);
-                    }
-                    if(begin == end) {
-                        continue;
-                    }
-                    fnDataAr[i].range = {begin, end};
-                    fnDataAr[i].manager = this;
-                    fnDataAr[i].multiMatchingEntities = &multiMatchingEntities;
-                    fnDataAr[i].bitsets = signatureBitsets;
-                    fnDataAr[i].mutex = &mutex;
-                    for(std::size_t j = begin; j < end; ++j) {
-                        if(!isAlive(j)) {
-                            fnDataAr[i].dead.insert(j);
-                        }
+        } else {
+            std::array<TPFnDataStructSix, ThreadCount * 2> fnDataAr;
+
+            std::mutex mutex;
+            std::size_t s = currentSize / (ThreadCount * 2);
+            for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
+                std::size_t begin = s * i;
+                std::size_t end;
+                if (i == ThreadCount * 2 - 1) {
+                    end = currentSize;
+                } else {
+                    end = s * (i + 1);
+                }
+                if (begin == end) {
+                    continue;
+                }
+                fnDataAr[i].range = {begin, end};
+                fnDataAr[i].manager = this;
+                fnDataAr[i].multiMatchingEntities = &multiMatchingEntities;
+                fnDataAr[i].bitsets = signatureBitsets;
+                fnDataAr[i].mutex = &mutex;
+                for (std::size_t j = begin; j < end; ++j) {
+                    if (!isAlive(j)) {
+                        fnDataAr[i].dead.insert(j);
                     }
+                }
 
-                    threadPool->queueFn([] (void *ud) {
-                        auto *data = static_cast<TPFnDataStructSix*>(ud);
-                        for(std::size_t i = data->range[0]; i < data->range[1];
-                                ++i) {
-                            if(data->dead.find(i) != data->dead.end()) {
+                threadPool->queueFn(
+                    [](void* ud) {
+                        auto* data = static_cast<TPFnDataStructSix*>(ud);
+                        for (std::size_t i = data->range[0]; i < data->range[1];
+                             ++i) {
+                            if (data->dead.find(i) != data->dead.end()) {
                                 continue;
                             }
-                            for(std::size_t j = 0; j < SigList::size; ++j) {
-                                if((data->bitsets[j]
-                                            & std::get<BitsetType>(
-                                                data->manager->entities[i]))
-                                        == data->bitsets[j]) {
+                            for (std::size_t j = 0; j < SigList::size; ++j) {
+                                if ((data->bitsets[j] &
+                                     std::get<BitsetType>(
+                                         data->manager->entities[i])) ==
+                                    data->bitsets[j]) {
                                     std::lock_guard<std::mutex> lock(
                                         *data->mutex);
                                     data->multiMatchingEntities->at(j)
@@ -1851,319 +1678,318 @@ namespace EC
                                 }
                             }
                         }
-                    }, &fnDataAr[i]);
-                }
-                threadPool->easyStartAndWait();
+                    },
+                    &fnDataAr[i]);
             }
+            threadPool->easyStartAndWait();
+        }
 
-            // call functions on matching entities
-            EC::Meta::forEachDoubleTuple(
-                EC::Meta::Morph<SigList, std::tuple<> >{},
-                fTuple,
-                [this, &multiMatchingEntities, useThreadPool, &userData]
-                (auto sig, auto func, auto index)
-                {
-                    using SignatureComponents =
-                        typename EC::Meta::Matching<
-                            decltype(sig), ComponentsList>::type;
-                    using Helper =
-                        EC::Meta::Morph<
-                            SignatureComponents,
-                            ForMatchingSignatureHelper<> >;
-                    if(!useThreadPool || !threadPool)
-                    {
-                        for(const auto& id : multiMatchingEntities[index])
-                        {
-                            if(isAlive(id))
-                            {
-                                Helper::callPtr(id, *this, func, userData);
-                            }
+        // call functions on matching entities
+        EC::Meta::forEachDoubleTuple(
+            EC::Meta::Morph<SigList, std::tuple<> >{}, fTuple,
+            [this, &multiMatchingEntities, useThreadPool, &userData](
+                auto sig, auto func, auto index) {
+                using SignatureComponents =
+                    typename EC::Meta::Matching<decltype(sig),
+                                                ComponentsList>::type;
+                using Helper = EC::Meta::Morph<SignatureComponents,
+                                               ForMatchingSignatureHelper<> >;
+                if (!useThreadPool || !threadPool) {
+                    for (const auto& id : multiMatchingEntities[index]) {
+                        if (isAlive(id)) {
+                            Helper::callPtr(id, *this, func, userData);
                         }
                     }
-                    else
-                    {
-                        std::array<TPFnDataStructFive, ThreadCount * 2>
-                            fnDataAr;
-                        std::size_t s = multiMatchingEntities[index].size()
-                            / (ThreadCount * 2);
-                        for(unsigned int i = 0; i < ThreadCount * 2; ++i) {
-                            std::size_t begin = s * i;
-                            std::size_t end;
-                            if(i == ThreadCount * 2 - 1) {
-                                end = multiMatchingEntities[index].size();
-                            } else {
-                                end = s * (i + 1);
-                            }
-                            if(begin == end) {
-                                continue;
-                            }
-                            fnDataAr[i].range = {begin, end};
-                            fnDataAr[i].index = index;
-                            fnDataAr[i].manager = this;
-                            fnDataAr[i].userData = userData;
-                            fnDataAr[i].multiMatchingEntities =
-                                &multiMatchingEntities;
-                            for(std::size_t j = begin; j < end; ++j) {
-                                if(!isAlive(multiMatchingEntities.at(index).at(j))) {
-                                    fnDataAr[i].dead.insert(j);
-                                }
+                } else {
+                    std::array<TPFnDataStructFive, ThreadCount * 2> fnDataAr;
+                    std::size_t s =
+                        multiMatchingEntities[index].size() / (ThreadCount * 2);
+                    for (unsigned int i = 0; i < ThreadCount * 2; ++i) {
+                        std::size_t begin = s * i;
+                        std::size_t end;
+                        if (i == ThreadCount * 2 - 1) {
+                            end = multiMatchingEntities[index].size();
+                        } else {
+                            end = s * (i + 1);
+                        }
+                        if (begin == end) {
+                            continue;
+                        }
+                        fnDataAr[i].range = {begin, end};
+                        fnDataAr[i].index = index;
+                        fnDataAr[i].manager = this;
+                        fnDataAr[i].userData = userData;
+                        fnDataAr[i].multiMatchingEntities =
+                            &multiMatchingEntities;
+                        for (std::size_t j = begin; j < end; ++j) {
+                            if (!isAlive(
+                                    multiMatchingEntities.at(index).at(j))) {
+                                fnDataAr[i].dead.insert(j);
                             }
-                            threadPool->queueFn([&func] (void *ud) {
-                                auto *data = static_cast<TPFnDataStructFive*>(ud);
-                                for(std::size_t i = data->range[0];
-                                        i < data->range[1]; ++i) {
-                                    if(data->dead.find(i) == data->dead.end()) {
+                        }
+                        threadPool->queueFn(
+                            [&func](void* ud) {
+                                auto* data =
+                                    static_cast<TPFnDataStructFive*>(ud);
+                                for (std::size_t i = data->range[0];
+                                     i < data->range[1]; ++i) {
+                                    if (data->dead.find(i) ==
+                                        data->dead.end()) {
                                         Helper::callPtr(
                                             data->multiMatchingEntities
-                                                ->at(data->index).at(i),
-                                            *data->manager,
-                                            func,
+                                                ->at(data->index)
+                                                .at(i),
+                                            *data->manager, func,
                                             data->userData);
                                     }
                                 }
-                            }, &fnDataAr[i]);
-                        }
-                        threadPool->easyStartAndWait();
+                            },
+                            &fnDataAr[i]);
                     }
+                    threadPool->easyStartAndWait();
                 }
-            );
+            });
 
-            // pop from idStack "call stack"
-            do {
-                {
-                    std::lock_guard<std::mutex> lock(idStackMutex);
-                    if (idStack.back() == current_id) {
-                        idStack.pop_back();
-                        break;
-                    }
+        // pop from idStack "call stack"
+        do {
+            {
+                std::lock_guard<std::mutex> lock(idStackMutex);
+                if (idStack.back() == current_id) {
+                    idStack.pop_back();
+                    break;
                 }
-                std::this_thread::sleep_for(std::chrono::microseconds(15));
-            } while (true);
+            }
+            std::this_thread::sleep_for(std::chrono::microseconds(15));
+        } while (true);
 
-            handleDeferredDeletions();
-        }
+        handleDeferredDeletions();
+    }
 
-        typedef void ForMatchingFn(std::size_t,
-                                   Manager<ComponentsList, TagsList>*,
-                                   void*);
-
-        /*!
-            \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.
-
-            The third parameter can be optionally used to enable the use of the
-            internal ThreadPool to call the function in parallel. Using the
-            value false (which is the default) will not use the ThreadPool and
-            run the function sequentially on all entities on the main thread.
-            Note that multi-threading is based on splitting the task of calling
-            the functions across sections of entities. Thus if there are only a
-            small amount of entities in the manager, then using multiple threads
-            may not have as great of a speed-up.
-         */
-        template <typename Signature>
-        void forMatchingSimple(ForMatchingFn fn,
-                               void *userData = nullptr,
-                               const bool useThreadPool = false) {
-            std::size_t current_id;
-            {
-                // push to idStack "call stack"
-                std::lock_guard<std::mutex> lock(idStackMutex);
-                current_id = idStackCounter++;
-                idStack.push_back(current_id);
+    typedef void ForMatchingFn(std::size_t, Manager<ComponentsList, TagsList>*,
+                               void*);
+
+    /*!
+        \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.
+
+        The third parameter can be optionally used to enable the use of the
+        internal ThreadPool to call the function in parallel. Using the
+        value false (which is the default) will not use the ThreadPool and
+        run the function sequentially on all entities on the main thread.
+        Note that multi-threading is based on splitting the task of calling
+        the functions across sections of entities. Thus if there are only a
+        small amount of entities in the manager, then using multiple threads
+        may not have as great of a speed-up.
+     */
+    template <typename Signature>
+    void forMatchingSimple(ForMatchingFn fn, void* userData = nullptr,
+                           const bool useThreadPool = false) {
+        std::size_t current_id;
+        {
+            // push to idStack "call stack"
+            std::lock_guard<std::mutex> lock(idStackMutex);
+            current_id = idStackCounter++;
+            idStack.push_back(current_id);
+        }
+        deferringDeletions.fetch_add(1);
+        const BitsetType signatureBitset =
+            BitsetType::template generateBitset<Signature>();
+        if (!useThreadPool || !threadPool) {
+            for (std::size_t i = 0; i < currentSize; ++i) {
+                if (!std::get<bool>(entities[i])) {
+                    continue;
+                } else if ((signatureBitset &
+                            std::get<BitsetType>(entities[i])) ==
+                           signatureBitset) {
+                    fn(i, this, userData);
+                }
             }
-            deferringDeletions.fetch_add(1);
-            const BitsetType signatureBitset =
-                BitsetType::template generateBitset<Signature>();
-            if(!useThreadPool || !threadPool) {
-                for(std::size_t i = 0; i < currentSize; ++i) {
-                    if(!std::get<bool>(entities[i])) {
-                        continue;
-                    } else if((signatureBitset
-                                & std::get<BitsetType>(entities[i]))
-                            == signatureBitset) {
-                        fn(i, this, userData);
-                    }
+        } else {
+            std::array<TPFnDataStructZero, ThreadCount * 2> fnDataAr;
+
+            std::size_t s = currentSize / (ThreadCount * 2);
+            for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
+                std::size_t begin = s * i;
+                std::size_t end;
+                if (i == ThreadCount * 2 - 1) {
+                    end = currentSize;
+                } else {
+                    end = s * (i + 1);
                 }
-            } else {
-                std::array<TPFnDataStructZero, ThreadCount * 2> fnDataAr;
-
-                std::size_t s = currentSize / (ThreadCount * 2);
-                for(std::size_t i = 0; i < ThreadCount * 2; ++i) {
-                    std::size_t begin = s * i;
-                    std::size_t end;
-                    if(i == ThreadCount * 2 - 1) {
-                        end = currentSize;
-                    } else {
-                        end = s * (i + 1);
-                    }
-                    if(begin == end) {
-                        continue;
-                    }
-                    fnDataAr[i].range = {begin, end};
-                    fnDataAr[i].manager = this;
-                    fnDataAr[i].entities = &entities;
-                    fnDataAr[i].signature = &signatureBitset;
-                    fnDataAr[i].userData = userData;
-                    for(std::size_t j = begin; j < end; ++j) {
-                        if(!isAlive(j)) {
-                            fnDataAr[i].dead.insert(j);
-                        }
+                if (begin == end) {
+                    continue;
+                }
+                fnDataAr[i].range = {begin, end};
+                fnDataAr[i].manager = this;
+                fnDataAr[i].entities = &entities;
+                fnDataAr[i].signature = &signatureBitset;
+                fnDataAr[i].userData = userData;
+                for (std::size_t j = begin; j < end; ++j) {
+                    if (!isAlive(j)) {
+                        fnDataAr[i].dead.insert(j);
                     }
-                    threadPool->queueFn([&fn] (void *ud) {
-                        auto *data = static_cast<TPFnDataStructZero*>(ud);
-                        for(std::size_t i = data->range[0]; i < data->range[1];
-                                ++i) {
-                            if(data->dead.find(i) != data->dead.end()) {
+                }
+                threadPool->queueFn(
+                    [&fn](void* ud) {
+                        auto* data = static_cast<TPFnDataStructZero*>(ud);
+                        for (std::size_t i = data->range[0]; i < data->range[1];
+                             ++i) {
+                            if (data->dead.find(i) != data->dead.end()) {
                                 continue;
-                            } else if((*data->signature
-                                        & std::get<BitsetType>(
-                                            data->entities->at(i)))
-                                    == *data->signature) {
+                            } else if ((*data->signature &
+                                        std::get<BitsetType>(data->entities->at(
+                                            i))) == *data->signature) {
                                 fn(i, data->manager, data->userData);
                             }
                         }
-                    }, &fnDataAr[i]);
-                }
-                threadPool->easyStartAndWait();
+                    },
+                    &fnDataAr[i]);
             }
-
-            // pop from idStack "call stack"
-            do {
-                {
-                    std::lock_guard<std::mutex> lock(idStackMutex);
-                    if (idStack.back() == current_id) {
-                        idStack.pop_back();
-                        break;
-                    }
-                }
-                std::this_thread::sleep_for(std::chrono::microseconds(15));
-            } while (true);
-
-            handleDeferredDeletions();
+            threadPool->easyStartAndWait();
         }
 
-        /*!
-            \brief Similar to forMatchingSimple(), but with a collection of Component/Tag indices
-
-            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 ForMatchingFn.
-
-            The fourth parameter can be optionally used to enable the use of the
-            internal ThreadPool to call the function in parallel. Using the
-            value false (which is the default) will not use the ThreadPool and
-            run the function sequentially on all entities on the main thread.
-            Note that multi-threading is based on splitting the task of calling
-            the functions across sections of entities. Thus if there are only a
-            small amount of entities in the manager, then using multiple threads
-            may not have as great of a speed-up.
-         */
-        template <typename Iterable>
-        void forMatchingIterable(Iterable iterable,
-                                 ForMatchingFn fn,
-                                 void* userData = nullptr,
-                                 const bool useThreadPool = false) {
-            std::size_t current_id;
+        // pop from idStack "call stack"
+        do {
             {
-                // push to idStack "call stack"
                 std::lock_guard<std::mutex> lock(idStackMutex);
-                current_id = idStackCounter++;
-                idStack.push_back(current_id);
+                if (idStack.back() == current_id) {
+                    idStack.pop_back();
+                    break;
+                }
             }
+            std::this_thread::sleep_for(std::chrono::microseconds(15));
+        } while (true);
 
-            deferringDeletions.fetch_add(1);
-            if(!useThreadPool || !threadPool) {
-                bool isValid;
-                for(std::size_t i = 0; i < currentSize; ++i) {
-                    if(!std::get<bool>(entities[i])) {
-                        continue;
-                    }
+        handleDeferredDeletions();
+    }
 
-                    isValid = true;
-                    for(const auto& integralValue : iterable) {
-                        if(!std::get<BitsetType>(entities[i]).getCombinedBit(
-                                integralValue)) {
-                            isValid = false;
-                            break;
-                        }
-                    }
-                    if(!isValid) { continue; }
+    /*!
+        \brief Similar to forMatchingSimple(), but with a collection of
+       Component/Tag indices
+
+        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 ForMatchingFn.
+
+        The fourth parameter can be optionally used to enable the use of the
+        internal ThreadPool to call the function in parallel. Using the
+        value false (which is the default) will not use the ThreadPool and
+        run the function sequentially on all entities on the main thread.
+        Note that multi-threading is based on splitting the task of calling
+        the functions across sections of entities. Thus if there are only a
+        small amount of entities in the manager, then using multiple threads
+        may not have as great of a speed-up.
+     */
+    template <typename Iterable>
+    void forMatchingIterable(Iterable iterable, ForMatchingFn fn,
+                             void* userData = nullptr,
+                             const bool useThreadPool = false) {
+        std::size_t current_id;
+        {
+            // push to idStack "call stack"
+            std::lock_guard<std::mutex> lock(idStackMutex);
+            current_id = idStackCounter++;
+            idStack.push_back(current_id);
+        }
 
-                    fn(i, this, userData);
+        deferringDeletions.fetch_add(1);
+        if (!useThreadPool || !threadPool) {
+            bool isValid;
+            for (std::size_t i = 0; i < currentSize; ++i) {
+                if (!std::get<bool>(entities[i])) {
+                    continue;
                 }
-            } else {
-                std::array<TPFnDataStructSeven<Iterable>, ThreadCount * 2>
-                    fnDataAr;
-
-                std::size_t s = currentSize / (ThreadCount * 2);
-                for(std::size_t i = 0; i < ThreadCount * 2; ++i) {
-                    std::size_t begin = s * i;
-                    std::size_t end;
-                    if(i == ThreadCount * 2 - 1) {
-                        end = currentSize;
-                    } else {
-                        end = s * (i + 1);
-                    }
-                    if(begin == end) {
-                        continue;
+
+                isValid = true;
+                for (const auto& integralValue : iterable) {
+                    if (!std::get<BitsetType>(entities[i])
+                             .getCombinedBit(integralValue)) {
+                        isValid = false;
+                        break;
                     }
-                    fnDataAr[i].range = {begin, end};
-                    fnDataAr[i].manager = this;
-                    fnDataAr[i].entities = &entities;
-                    fnDataAr[i].iterable = &iterable;
-                    fnDataAr[i].userData = userData;
-                    for(std::size_t j = begin; j < end; ++j) {
-                        if(!isAlive(j)) {
-                            fnDataAr[i].dead.insert(j);
-                        }
+                }
+                if (!isValid) {
+                    continue;
+                }
+
+                fn(i, this, userData);
+            }
+        } else {
+            std::array<TPFnDataStructSeven<Iterable>, ThreadCount * 2> fnDataAr;
+
+            std::size_t s = currentSize / (ThreadCount * 2);
+            for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
+                std::size_t begin = s * i;
+                std::size_t end;
+                if (i == ThreadCount * 2 - 1) {
+                    end = currentSize;
+                } else {
+                    end = s * (i + 1);
+                }
+                if (begin == end) {
+                    continue;
+                }
+                fnDataAr[i].range = {begin, end};
+                fnDataAr[i].manager = this;
+                fnDataAr[i].entities = &entities;
+                fnDataAr[i].iterable = &iterable;
+                fnDataAr[i].userData = userData;
+                for (std::size_t j = begin; j < end; ++j) {
+                    if (!isAlive(j)) {
+                        fnDataAr[i].dead.insert(j);
                     }
-                    threadPool->queueFn([&fn] (void *ud) {
-                        auto *data = static_cast<TPFnDataStructSeven<Iterable>*>(ud);
+                }
+                threadPool->queueFn(
+                    [&fn](void* ud) {
+                        auto* data =
+                            static_cast<TPFnDataStructSeven<Iterable>*>(ud);
                         bool isValid;
-                        for(std::size_t i = data->range[0]; i < data->range[1];
-                                ++i) {
-                            if(data->dead.find(i) != data->dead.end()) {
+                        for (std::size_t i = data->range[0]; i < data->range[1];
+                             ++i) {
+                            if (data->dead.find(i) != data->dead.end()) {
                                 continue;
                             }
                             isValid = true;
-                            for(const auto& integralValue : *data->iterable) {
-                                if(!std::get<BitsetType>(data->entities->at(i))
-                                        .getCombinedBit(integralValue)) {
+                            for (const auto& integralValue : *data->iterable) {
+                                if (!std::get<BitsetType>(data->entities->at(i))
+                                         .getCombinedBit(integralValue)) {
                                     isValid = false;
                                     break;
                                 }
                             }
-                            if(!isValid) { continue; }
+                            if (!isValid) {
+                                continue;
+                            }
 
                             fn(i, data->manager, data->userData);
                         }
-                    }, &fnDataAr[i]);
-                }
-                threadPool->easyStartAndWait();
+                    },
+                    &fnDataAr[i]);
             }
+            threadPool->easyStartAndWait();
+        }
 
-            // pop from idStack "call stack"
-            do {
-                {
-                    std::lock_guard<std::mutex> lock(idStackMutex);
-                    if (idStack.back() == current_id) {
-                        idStack.pop_back();
-                        break;
-                    }
+        // pop from idStack "call stack"
+        do {
+            {
+                std::lock_guard<std::mutex> lock(idStackMutex);
+                if (idStack.back() == current_id) {
+                    idStack.pop_back();
+                    break;
                 }
-                std::this_thread::sleep_for(std::chrono::microseconds(15));
-            } while (true);
+            }
+            std::this_thread::sleep_for(std::chrono::microseconds(15));
+        } while (true);
 
-            handleDeferredDeletions();
-        }
-    };
-}
+        handleDeferredDeletions();
+    }
+};
+}  // namespace EC
 
 #endif
-