From 0f365758e11ca1669e31324bc6f530186d7c950a Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Tue, 30 May 2017 20:20:20 +0200 Subject: [PATCH] Add optional fieldnames for Pair --- source/tanya/typecons.d | 78 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/source/tanya/typecons.d b/source/tanya/typecons.d index cf09d52..62e9df4 100644 --- a/source/tanya/typecons.d +++ b/source/tanya/typecons.d @@ -5,6 +5,9 @@ /** * Type constructors. * + * This module contains templates that allow to build new types from the + * available ones. + * * Copyright: Eugene Wissner 2017. * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/, * Mozilla Public License, v. 2.0). @@ -15,17 +18,70 @@ module tanya.typecons; import std.meta; /** - * $(D_PSYMBOL Pair) can store two heterogeneous objects. The objects can be - * accessed than by the index. The objects can by accessed by index as - * $(D_INLINECODE obj[0]) and $(D_INLINECODE obj[1]). + * $(D_PSYMBOL Pair) can store two heterogeneous objects. + * + * The objects can by accessed by index as $(D_INLINECODE obj[0]) and + * $(D_INLINECODE obj[1]) or by optional names (e.g. + * $(D_INLINECODE obj.first)). + * + * $(D_PARAM Specs) contains a list of object types and names. First + * comes the object type, then an optional string containing the name. + * If you want the object be accessible only by its index (`0` or `1`), + * just skip the name. + * + * Params: + * Specs = Field types and names. */ -template Pair(Field1, Field2) +template Pair(Specs...) { - /// Field types. - alias Types = AliasSeq!(Field1, Field2); + template parseSpecs(int fieldCount, Specs...) + { + static if (Specs.length == 0) + { + alias parseSpecs = AliasSeq!(); + } + else static if (is(Specs[0]) && fieldCount < 2) + { + static if (is(typeof(Specs[1]) == string)) + { + alias parseSpecs + = AliasSeq!(Specs[0], + parseSpecs!(fieldCount + 1, Specs[2 .. $])); + } + else + { + alias parseSpecs + = AliasSeq!(Specs[0], + parseSpecs!(fieldCount + 1, Specs[1 .. $])); + } + } + else + { + static assert(false, "Invalid argument: " ~ Specs[0].stringof); + } + } struct Pair { + /// Field types. + alias Types = parseSpecs!(0, Specs); + + static assert(Types.length == 2, "Invalid argument count."); + + // Create field aliases. + static if (is(typeof(Specs[1]) == string)) + { + mixin("alias " ~ Specs[1] ~ " = expand[0];"); + } + static if (is(typeof(Specs[2]) == string)) + { + mixin("alias " ~ Specs[2] ~ " = expand[1];"); + } + else static if (is(typeof(Specs[3]) == string)) + { + mixin("alias " ~ Specs[3] ~ " = expand[1];"); + } + /// Represents the values of the $(D_PSYMBOL Pair) as a list of values. Types expand; @@ -38,4 +94,14 @@ unittest { static assert(is(Pair!(int, int))); static assert(!is(Pair!(int, 5))); + + static assert(is(Pair!(int, "first", int))); + static assert(is(Pair!(int, "first", int, "second"))); + static assert(is(Pair!(int, "first", int))); + + static assert(is(Pair!(int, int, "second"))); + static assert(!is(Pair!("first", int, "second", int))); + static assert(!is(Pair!(int, int, int))); + + static assert(!is(Pair!(int, "first"))); }