Meta-programming: iterating over a container with different types

Claude via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Oct 20 02:43:30 PDT 2016


On Friday, 23 September 2016 at 12:55:42 UTC, deed wrote:
> // Maybe you can try using std.variant?


Thanks for your answer.
However I cannot use variants, as I have to store the components 
natively in a void[] array (for cache coherency reasons).

So I found a way to solve that problem: delegate callbacks.
There may be more elegant solutions but well, it works.

Basically I register some kind of accessor delegate of the form:

void accessor(Entity e, Component* c)
{
   // Do stuff, like save the component struct for that entity in 
a file
}

And it is stored in the entity class in an array of delegates:

   void delegate(Entity e, void* c);


Here's a very basic implementation:

class Entity
{
public:
   void register!Component(Component val);
   void unregister!Component();
   Component getComponent!Component();

   alias CompDg = void delegate(Entity e, void* c);

   void accessor!Component(void delegate(Entity e, Component* c) 
dg) @property
   {
     auto compId = getComponentId!Component;
     mCompDg[compId] = cast(CompDg)dg;
   }


   // Iterating over the components
   void iterate()
   {
     // For every possible components
     foreach (compId; 0..mMaxNbComponents)
       if (isRegistered(compId))
         if (mCompDg[compId] !is null)
           mCompDg[compId](this, getComponentStoragePtr(compId));
   }

private:
   void* getComponentStoragePtr(uint compId);
   bool isRegistered(uint compId);

   void[]   mComponentStorage;  // Flat contiguous storage of all 
components
   CompDg[] mCompDg;
   // ...
}

unittest
{
   // registering
   auto e = new Entity;
   e.register!int(42);
   e.register!string("loire");
   e.register!float(3.14);

   assert(e.getComponent!float() == 3.14); // that is OK

   e.accessor!int    = (Entity et, int i)    { writefln("%d", i); 
};
   e.accessor!string = (Entity et, string s) { writefln("%s", s); 
};
   e.accessor!float  = (Entity et, float f)  { writefln("%f", f); 
};

   // Print the values
   e.iterate();
}


More information about the Digitalmars-d-learn mailing list