Just to clarify, when I'm talking about allocators having state, what I
expect is to be able to do something similar to the following.
Note that this is just an example, there are tons of variants of this:
template< class ComponentType >
class ComponentPool
{
public:
template< typename... Args >
ComponentType* create( Args... args )
{
if( auto free_slot = find_free_slot() )
{
*free_slot = make_optional<ComponentType>( args... ); // or
something similar
return free_slot.get_ptr();
}
return nullptr;
}
void destroy( ComponentType& component )
{
auto slot = find_slot( component );
assert( slot );
*slot = none_t; // reset the slot
}
template< typename Func >
void for_all_living_components( Func&& f )
{
for( ComponentSlot& slot : m_components )
{
if( !slot )
continue;
f( slot.get() );
}
}
private:
using ComponentSlot = boost::optional<ComponentType>; // to know if the
component memory is constructed or not.
std::array< ComponentSlot, MAX_COMPONENTS_PER_WORLD > m_components;
ComponentSlot* find_free_slot()
{
for( auto& slot : m_components )
if( !slot )
return &slot;
return nullptr;
}
ComponentSlot* find_slot( ComponentType& component );
};
class ComponentSystem
{
public:
class Allocator;
Allocator allocator(); // proivde an allocator for component that will
use this;
template< class ComponentType >
void declare_component_type()
{
auto find_it = m_pool_index.find( typeid(ComponentType) );
if( find_it == end(m_pool_index ) )
{
auto new_pool =
std::make_unique();
m_pool_index.insert( std::make_pair( typeid(ComponentType),
std::move(new_pool) ) );
}
}
template< class ComponentType >
ComponentPool<ComponentType>* find_pool()
{
auto find_it = m_pool_index.find( typeid(ComponentType) );
if( find_it != end(m_pool_index ) )
{
return find_it->second.get();
}
return nullptr;
}
private:
struct PoolSlot{};
template< class ComponentType >
struct PoolSlotSpecific
{
CompomentPool<ComponentType> pool;
};
boost::flat_map< std::type_index, std::unique_ptr<PoolSlot> >
m_pool_index;
};
class World
{
public:
using Entity = boost::mixin::object< ComponentSystem::Allocator >;
World()
{
m_component_system.declare_component_type<PhysicsData>();
m_component_system.declare_component_type<BrainData>();
m_component_system.declare_component_type<GraphicData>();
m_component_system.declare_component_type<AudioData>();
}
void update()
{
const now = m_clock.now();
// here we assmue that the data don't communicate or do it through
thread-safe work queues/messages
auto physics_update = async( /*some_executor,*/ [&] {
m_component_system.find_pool( typeid(PhysicsData)
)->for_all_living_components( [&]( PhysicsData& data ) { data.update( now
); } );
};
auto brain_update = async( /*some_executor,*/ [&] {
m_component_system.find_pool( typeid(BrainData)
)->for_all_living_components( [&]( BrainData& data ) { data.update( now );
} );
};
when_all( physics_update, brain_update );
// for some reasons, cannot be updated in parallel
m_component_system.find_pool( typeid(GraphicData)
)->for_all_living_components( [&]( GraphicData& data ) { data.update( now
); } );
m_component_system.find_pool( typeid(AudioData)
)->for_all_living_components( [&]( AudioData& data ) { data.update( now );
} );
}
Entity& create_entity( EntityInfo info )
{
m_entities.emplace_back();
auto& new_entity = m_entities.back( m_component_system.allocator()
); // here we pass an allocator which will use this specific instance of
component system.
using boost::mixin;
mutate( *new_entity )
.add<PhysicsData>( info )
.add<BrainData>( info )
.add<GraphicData>( info )
.add<AudioData>( info )
;
return *new_entity;
}
private:
Clock m_clock; // some kind of clock implementation, which could be or
not real time (often it's a virtual time)
ComponentSystem m_component_system;
boost::stable_vector<Entity> m_entities; // or whatever stable way to
list them
};
class Universe
{
public:
void update()
{
parallel_for( auto world_idx : m_awake_worlds_indice )
{
m_world[world_idx].update();
}
}
private:
boost::stable_vector<World> m_worlds;
std::vector m_awake_worlds_indice;
};
-------------------------
This is a raw and a bit complex example but I hope it can clarify my
request.
Joel Lamotte