At
https://github.com/nordlow/phobos-next/blob/03b4736fdd65ef84c6fc583eddee4196629cea81/src/variant_arrays.d
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 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?
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;
}());
}