Reputation: 12138
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;
}());
}
Upvotes: 0
Views: 49