At
I've implemented a lightweight-polymorphic array container I call VariantArrays(Types...) indexed by a corresponding polymorphic index I call VariantIndex(Types...).
It uses .mangleof together with mixins to automatically infer the definition (including its name) of each array store for each element type in Types. The element types are passed in the template parameter Types to the two templated structs mentioned above.
Everything works except for when I try to instantiate VariantArrays from within a module other than variant_arrays.d. For instance, if I try to use it in another module containing
unittest
{
struct S { int x; }
import variant_arrays : VariantArrays;
VariantArrays!S a;
}
I get the error
variant_arrays.d-mixin-130(130,1): Error: undefined identifier `S`
foo.d(5,5): Error: template instance variant_arrays.VariantArrays!(S) error instantiating
In other words, the symbol S cannot be resolved in the scope of VariantArrays eventhough it's feed as a template parameter.
Is there a way around this problem?
Posted also here: http://forum.dlang.org/post/[email protected]
Here follows the definition of variant_arrays.d (excluding unittests):
/** Polymorphic index into an element in `VariantArrays`. */
private struct VariantIndex(Types...)
{
import std.meta : staticIndexOf;
private:
alias Kind = ubyte; // kind code
alias Size = size_t; // size type
import bit_traits : bitsNeeded;
/// Number of bits needed to represent kind.
enum kindBits = bitsNeeded!(Types.length);
/// Get number kind of kind type `SomeKind`.
enum nrOfKind(SomeKind) = staticIndexOf!(SomeKind, Types); // TODO cast to ubyte if Types.length is <= 256
/// Is `true` iff an index to a `SomeKind`-kind can be stored.
enum canReferTo(SomeKind) = nrOfKind!SomeKind >= 0;
/// Construct.
this(Kind kind, Size index) // TODO can ctor inferred by bitfields?
{
_kindNr = kind;
_index = index;
}
import std.bitmanip : bitfields;
mixin(bitfields!(Size, "_index", 8*Size.sizeof - kindBits,
Kind, "_kindNr", kindBits));
}
/** Stores set of variants.
Enables lightweight storage of polymorphic objects.
Each element is indexed by a corresponding `VariantIndex`.
*/
private struct VariantArrays(Types...)
{
alias Index = VariantIndex!Types;
import basic_copyable_array : CopyableArray;
/// Returns: array type (as a string) of `Type`.
private static immutable(string) arrayTypeString(Type)()
{
return `CopyableArray!(` ~ Type.stringof ~ `)`;
}
/// Returns: array instance (as a strinng) storing `Type`.
private static immutable(string) arrayInstanceString(Type)()
{
return `_values` ~ Type.mangleof;
}
/** Insert `value` at back.
*/
pragma(inline) // DMD cannot inline
Index insertBack(SomeKind)(SomeKind value) // TODO add array type overload
if (Index.canReferTo!SomeKind)
{
mixin(`alias arrayInstance = ` ~ arrayInstanceString!SomeKind ~ `;`);
const currentIndex = arrayInstance.length;
arrayInstance.insertBack(value);
return Index(Index.nrOfKind!SomeKind,
currentIndex);
}
alias put = insertBack; // polymorphic `OutputRange` support
/// Get reference to element of type `SomeKind` at `index`.
scope ref inout(SomeKind) at(SomeKind)(in size_t index) inout return
if (Index.canReferTo!SomeKind)
{
mixin(`return ` ~ arrayInstanceString!SomeKind ~ `[index];`);
}
/// Peek at element of type `SomeKind` at `index`.
scope inout(SomeKind)* peek(SomeKind)(in Index index) inout return @system
if (Index.canReferTo!SomeKind)
{
if (Index.nrOfKind!SomeKind == index._kindNr)
{
return &at!SomeKind(index._index);
}
else
{
return null;
}
}
private:
// TODO this fails:
mixin({
string s = "";
foreach (Type; Types)
{
s ~= arrayTypeString!Type ~ ` ` ~ arrayInstanceString!Type ~ `;`;
}
return s;
}());
}