I'm working on an Entity Component System library. Right know I'm trying to clean up the Entity/Component part (only the code which manage the data).But I have a class which I think is not really readable. Maybe the implementation can be improved too, but I reduced the implementation to be small and fast, so it's not really why I'm here (but every review is always welcome).DefaultManager.hpp:#ifndef  DEFAULT_MANAGER_HPP#define  DEFAULT_MANAGER_HPP#include  Defines.hpp#include  HandleEntry.hpp#include  <cstddef>#include  <vector>#include  <type_traits>//!//! @namespace ECS//!namespace  ECS {  //!  //! @class DefaultManager  //!  template < typename Object,             bool Shared >  class  DefaultManager {    //-----------------------------------------    //! Allow iterator to access the Pool    template < ECS_INT Filter >    friend class iterator;    //-----------------------------------------    //! GoogleTest Define#ifdef  UTESTS  #include DefaultManager.utests#endif    //-----------------------------------------    private:      static const size_t  BASE_SIZE = 1024;    //-----------------------------------------    //! Internal Structs    private:      struct ObjectPair {        std::conditional_t<Shared,                           HandleEntryShared,                           HandleEntry>  entry;        Object  data;      };    //-----------------------------------------    //! Attributs    protected:      std::vector<ObjectPair>  m_pool;      ECS_INT                  m_activeEntryCount;      ECS_INT                  m_firstFreeEntry;    //-----------------------------------------    //! Iterator    public:      //! TODO: Need specialization for Filter = 0 (just remove the check on the filter)      template < ECS_INT Filter = 0 >      class iterator {        private:          size_t                           m_index;          DefaultManager<Object, Shared>&  m_manager;        public:          using difference_type   = ptrdiff_t;          using size_type         = size_t;          using value_type        = Object;          using pointer           = Object*;          using const_pointer     = const Object*;          using reference         = Object&;          using const_reference   = const Object&;          using iterator_category = std::bidirectional_iterator_tag;          iterator(DefaultManager<Object, Shared>& manager,                   size_t index = 0)            : m_index(index),              m_manager(manager)          {}          iterator& operator++() { while(!isValid()) ++m_index; return *this;}          iterator& operator++(int) { iterator it = *this; ++(*this); return it;}          iterator& operator--() { while(!isValid()) --m_index; return *this;}          iterator& operator--(int) { iterator it = *this; --(*this); return it;}          bool operator==(iterator other) const {return &m_pool[m_index] == &other.m_pool[m_index];}          bool operator!=(iterator other) const {return !(*this == other);}          reference operator*() { return m_manager.m_pool[m_index].data; }          bool isValid() const {            Object& obj = m_manager.m_pool[m_index].data;            return (obj.type() & Filter) == obj.type();          }      };      template < ECS_INT Filter = 0 >      iterator<Filter>       begin();      template < ECS_INT Filter = 0 >      const iterator<Filter> cbegin() { return begin<Filter>(); }      template < ECS_INT Filter = 0 >      iterator<Filter>       end();      template < ECS_INT Filter = 0 >      const iterator<Filter> cend() { return end<Filter>(); }    //-----------------------------------------    //-----------------------------------------    //! Constructors    public:      DefaultManager(size_t allocSize = BASE_SIZE)        : m_pool(allocSize),          m_activeEntryCount(0),          m_firstFreeEntry(0) {      }    //-----------------------------------------    //! Getters and Setters    public:      Object&  getObject(const ECS_INT index) {        return m_pool[index].data;      }    //-----------------------------------------    //! Functions    protected:      //!      //! @brief Used by the manager to extend the pool when it's needed      //!      //! Add + BASIC_SIZE to the current pool capacity      //! Copy current data into the new pool and init the new HandleEntry      //!      void  extendPool();      //! @brief Primitive function used by the manager to release the data from one pool entry      //!      //! Put the activate bit to false for the pool entry whose index is specified as a parameter      //! Update the manager firstFreeEntry, depend on the data released position      //!      //! @param index the index where the data to release is positionned.      void  releaseObject(const ECS_INT index);    public:      //! @brief Specifie to the manager the need to reserve some memory space      //!      //! Use std::vector.resize() to reserve memory for the pool      //! Initialize HandleEntry for every ObjectPair reserved      //!      //! @warning if you attempt do to so for every DefaultManager, think about change BASIC_SIZE      //! @param allocSize the size to reserve in bytes      void  reserveObjectMemory(size_t allocSize);      //!      //! @warning Don't use, not sure to be keep      //!      void  reset(size_t allocSize = BASE_SIZE);      //!      //! @brief Ask the manager to give a data segment from the pool      //!      //! Check if the pool has enough memory left (extend if not)      //! Take the first free entry of the pool and activate the entry      //! Initialize the data with args      //!      //! @param args pack of arguments you need to initialize your Object      //! @return the index of the activated object      template < typename ... Args >      ECS_INT  addNewObject(Args && ... args);      //!      //! @brief Ask the manager to assign the object given to another entity      //!      //! Just increment the assigned counter of the HandleEntry which correspond      //!      //! @warning this function need the Shared from DefaultManager<typename Object, bool Shared> to be true      //! @param index the index of the already added Object      void  assignExistingObject(const ECS_INT index);      //!      //! @biref Remove need to be called when an entity revoke her access to an Object      //!      //! Depend on Shared value      //! if Shared == true --> Will decrement the assigned counter and if the counter reach zero, release the memory      //! if Shared == false --> Will just release the memory of the Object selected      //!      //! @param index the index of the data that you want remove      void  removeObject(const ECS_INT index);  };}#include  DefaultManager.tpp#endifDefaultManager.tpp:namespace  ECS {#define TEMPLATE_ARGS  typename Object, \                       bool Shared#define CLASS    DefaultManager<Object, Shared>#define ITERATOR CLASS::iterator<Filter>  //! Iterator  //!------------------------------------------  //!  //! Begin  //!  template < TEMPLATE_ARGS >    template < ECS_INT Filter >  ITERATOR  CLASS::begin() {    ITERATOR it(*this);    while (! it.is_Valid())      ++it;    return std::move(it);  }  //!  //! End  //!  template < TEMPLATE_ARGS >    template < ECS_INT Filter >  ITERATOR  CLASS::end() {    ITERATOR it(*this);    while (! it.is_Valid())      ++it;    return std::move(it);  }  //!------------------------------------------  //!------------------------------------------  //!  //! ExtendPool  //!  template < typename Object,             bool Shared >  void   DefaultManager<Object, Shared>::extendPool() {    size_t i = m_pool.capacity();    m_pool.reserve(m_pool.capacity() + BASE_SIZE);    for (;i < m_pool.capacity(); ++i)      m_pool[i].entry.nextFreeIndex = i;  }  //!  //!  ReleaseObject  //!  template < typename Object,             bool Shared >  void   DefaultManager<Object, Shared>::releaseObject(const ECS_INT index) {    if (index < m_firstFreeEntry) {      m_pool[index].entry.nextFreeIndex = m_firstFreeEntry;      m_pool[index].entry.active = false;      m_firstFreeEntry = index;    }    else {      m_pool[index].entry.nextFreeIndex = m_pool[m_firstFreeEntry].entry.nextFreeIndex;      m_pool[m_firstFreeEntry].entry.nextFreeIndex = index;      m_pool[index].entry.active = false;    }    --m_activeEntryCount;  }  //!  //! ReserveObjectMemory  //!  template < typename Object,             bool Shared >  void   DefaultManager<Object, Shared>::reserveObjectMemory(size_t allocSize) {    m_pool.reserve(allocSize);    for (unsigned int i = 0; i < m_pool.capacity(); ++i)      m_pool[i].entry.nextFreeIndex = i + 1;  }  //!  //! Reset  //!  template < typename Object,             bool Shared >  void   DefaultManager<Object, Shared>::reset(size_t allocSize) {    m_pool.resize(allocSize);    m_pool.shrink_to_fit();    for (unsigned int i = 0; i < m_pool.capacity(); ++i)      m_pool[i].entry.nextFreeIndex = i + 1;    m_activeEntryCount = 0;    m_firstFreeEntry = 0;  }  //!  //! AddObject  //!  template < typename Object,             bool Shared >  template < typename ... Args >  ECS_INT  DefaultManager<Object, Shared>::addNewObject(Args && ... args) {    if (m_activeEntryCount >= m_pool.capacity())      extendPool();    const ECS_INT index = m_firstFreeEntry;    HandleEntry& nHandle = m_pool[index].entry;    m_firstFreeEntry = nHandle.nextFreeIndex;    nHandle.nextFreeIndex = 0;    nHandle.active = true;    m_pool[index].data = Object(std::forward<Args>(args) ...);    ++m_activeEntryCount;    return index;  }  //!  //!  AssignExistingObject  //!  template < typename Object,             bool Shared >  void   DefaultManager<Object, Shared>::assignExistingObject(const ECS_INT index) {    // Waiting for if constexpr  }  //!  //! RemoveObject  //!  template < typename Object,             bool Shared >  void  DefaultManager<Object, Shared>::removeObject(const ECS_INT index) {    //Waiting for if constexpr    releaseObject(index);  }}The most weird code seems to be the iterator and begin/end function. The whole code is here if you want to see more.
Template class for an Entity Component System library
c++;template;library;entity component system