diff options
Diffstat (limited to 'source/tanya/typecons.d')
| -rw-r--r-- | source/tanya/typecons.d | 273 |
1 files changed, 0 insertions, 273 deletions
diff --git a/source/tanya/typecons.d b/source/tanya/typecons.d index 5e570f6..68c629e 100644 --- a/source/tanya/typecons.d +++ b/source/tanya/typecons.d @@ -152,276 +152,3 @@ template tuple(Names...) assert(t.one == 20); assert(t.two == 5); } - -/** - * Type that can hold one of the types listed as its template parameters. - * - * $(D_PSYMBOL Variant) is a type similar to $(D_KEYWORD union), but - * $(D_PSYMBOL Variant) keeps track of the actually used type and throws an - * assertion error when trying to access an invalid type at runtime. - * - * Params: - * Specs = Types this $(D_SPYBMOL Variant) can hold. - */ -template Variant(Specs...) -if (isTypeTuple!Specs && NoDuplicates!Specs.length == Specs.length) -{ - union AlignedUnion(Args...) - { - static if (Args.length > 0) - { - Args[0] value; - } - static if (Args.length > 1) - { - AlignedUnion!(Args[1 .. $]) rest; - } - } - - private struct VariantAccessorInfo - { - string accessor; - ptrdiff_t tag; - } - - template accessor(T, Union) - { - enum VariantAccessorInfo info = accessorImpl!(T, Union, 1); - enum accessor = VariantAccessorInfo("this.values" ~ info.accessor, info.tag); - } - - template accessorImpl(T, Union, size_t tag) - { - static if (is(T == typeof(Union.value))) - { - enum accessorImpl = VariantAccessorInfo(".value", tag); - } - else - { - enum VariantAccessorInfo info = accessorImpl!(T, typeof(Union.rest), tag + 1); - enum accessorImpl = VariantAccessorInfo(".rest" ~ info.accessor, info.tag); - } - } - - struct Variant - { - /// Types can be present in this $(D_PSYMBOL Variant). - alias Types = Specs; - - private ptrdiff_t tag = -1; - private AlignedUnion!Types values; - - /** - * Constructs this $(D_PSYMBOL Variant) with one of the types supported - * in it. - * - * Params: - * T = Type of the initial value. - * value = Initial value. - */ - this(T)(ref T value) - if (canFind!(T, Types)) - { - copyAssign!T(value); - } - - /// ditto - this(T)(T value) - if (canFind!(T, Types)) - { - moveAssign!T(value); - } - - ~this() - { - reset(); - } - - this(this) - { - alias pred(U) = hasElaborateCopyConstructor!(U.Seq[1]); - static foreach (Type; Filter!(pred, Enumerate!Types)) - { - if (this.tag == Type.Seq[0]) - { - get!(Type.Seq[1]).__postblit(); - } - } - } - - /** - * Tells whether this $(D_PSYMBOL Variant) is initialized. - * - * Returns: $(D_KEYWORD true) if this $(D_PSYMBOL Variant) contains a - * value, $(D_KEYWORD false) otherwise. - */ - bool hasValue() const - { - return this.tag != -1; - } - - /** - * Tells whether this $(D_PSYMBOL Variant) holds currently a value of - * type $(D_PARAM T). - * - * Params: - * T = Examined type. - * - * Returns: $(D_KEYWORD true) if this $(D_PSYMBOL Variant) currently - * contains a value of type $(D_PARAM T), $(D_KEYWORD false) - * otherwise. - */ - bool peek(T)() const - if (canFind!(T, Types)) - { - return this.tag == staticIndexOf!(T, Types); - } - - /** - * Returns the underlying value, assuming it is of the type $(D_PARAM T). - * - * Params: - * T = Type of the value should be returned. - * - * Returns: The underyling value. - * - * Precondition: The $(D_PSYMBOL Variant) has a value. - * - * See_Also: $(D_PSYMBOL peek), $(D_PSYMBOL hasValue). - */ - ref inout(T) get(T)() inout - if (canFind!(T, Types)) - in - { - assert(this.tag == staticIndexOf!(T, Types), "Variant isn't initialized"); - } - do - { - mixin("return " ~ accessor!(T, AlignedUnion!Types).accessor ~ ";"); - } - - /** - * Reassigns the value. - * - * Params: - * T = Type of the new value - * that = New value. - * - * Returns: $(D_KEYWORD this). - */ - ref typeof(this) opAssign(T)(T that) - if (canFind!(T, Types)) - { - reset(); - return moveAssign!T(that); - } - - /// ditto - ref typeof(this) opAssign(T)(ref T that) - if (canFind!(T, Types)) - { - reset(); - return copyAssign!T(that); - } - - private ref typeof(this) moveAssign(T)(ref T that) @trusted - { - this.tag = staticIndexOf!(T, Types); - - enum string accessorMixin = accessor!(T, AlignedUnion!Types).accessor; - moveEmplace(that, mixin(accessorMixin)); - - return this; - } - - private ref typeof(this) copyAssign(T)(ref T that) return - { - this.tag = staticIndexOf!(T, Types); - - enum string accessorMixin = accessor!(T, AlignedUnion!Types).accessor; - emplace!T((() @trusted => (&mixin(accessorMixin))[0 .. 1])(), that); - - return this; - } - - private void reset() - { - alias pred(U) = hasElaborateDestructor!(U.Seq[1]); - static foreach (Type; Filter!(pred, Enumerate!Types)) - { - if (this.tag == Type.Seq[0]) - { - destroy(get!(Type.Seq[1])); - } - } - } - - /** - * Returns $(D_PSYMBOL TypeInfo) corresponding to the current type. - * - * If this $(D_PSYMBOL Variant) isn't initialized, returns - * $(D_KEYWORD null). - * - * Returns: $(D_PSYMBOL TypeInfo) of the current type. - */ - @property TypeInfo type() - { - static foreach (i, Type; Types) - { - if (this.tag == i) - { - return typeid(Type); - } - } - return null; - } - - /** - * Compares this $(D_PSYMBOL Variant) with another one with the same - * specification for equality. - * - * $(UL - * $(LI If both hold values of the same type, these values are - * compared.) - * $(LI If they hold values of different types, then the - * $(D_PSYMBOL Variant)s aren't equal.) - * $(LI If only one of them is initialized but another one not, they - * aren't equal.) - * $(LI If neither of them is initialized, they are equal.) - * ) - * - * Params: - * that = The $(D_PSYMBOL Variant) to compare with. - * - * Returns: $(D_KEYWORD true) if this $(D_PSYMBOL Variant) is equal to - * $(D_PARAM that), $(D_KEYWORD false) otherwise. - */ - bool opEquals()(auto ref inout(Variant) that) inout - { - if (this.tag != that.tag) - { - return false; - } - static foreach (i, Type; Types) - { - if (this.tag == i) - { - return get!Type == that.get!Type; - } - } - return true; - } - } -} - -/// -@nogc nothrow pure @safe unittest -{ - Variant!(int, double) variant = 5; - assert(variant.peek!int); - assert(variant.get!int == 5); - - variant = 5.4; - assert(!variant.peek!int); - assert(variant.get!double == 5.4); -} |
