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