1 /**
2 	Additions to std.typetuple pending for inclusion into Phobos.
3 
4 	Copyright: © 2013 RejectedSoftware e.K.
5 	License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
6 	Authors: Михаил Страшун
7 */
8 
9 module vson.meta.typetuple;
10 
11 import std.typetuple;
12 import std.traits;
13 
14 /**
15 	TypeTuple which does not auto-expand.
16 	
17 	Useful when you need
18 	to multiple several type tuples as different template argument
19 	list parameters, without merging those.	
20 */
21 template Group(T...)
22 {
23 	alias expand = T;
24 }
25 
26 ///
27 unittest
28 {
29 	alias group = Group!(int, double, string);
30 	static assert (!is(typeof(group.length)));
31 	static assert (group.expand.length == 3);
32 	static assert (is(group.expand[1] == double));
33 }
34 
35 /**
36 */
37 template isGroup(T...)
38 {
39 	static if (T.length != 1) enum isGroup = false;
40 	else enum isGroup =
41 		!is(T[0]) && is(typeof(T[0]) == void)      // does not evaluate to something
42 		&& is(typeof(T[0].expand.length) : size_t) // expands to something with length
43 		&& !is(typeof(&(T[0].expand)));            // expands to not addressable
44 }
45 
46 version (unittest) // NOTE: GDC complains about template definitions in unittest blocks
47 {
48 	alias group = Group!(int, double, string);
49 	alias group2 = Group!();
50 	
51 	template Fake(T...)
52 	{
53 		int[] expand;
54 	}
55 	alias fake = Fake!(int, double, string);
56 
57 	alias fake2 = TypeTuple!(int, double, string);
58 
59 	static assert (isGroup!group);
60 	static assert (isGroup!group2);
61 	static assert (!isGroup!fake);
62 	static assert (!isGroup!fake2);
63 }
64 
65 /* Copied from Phobos as it is private there.
66  */
67 private template isSame(ab...)
68     if (ab.length == 2)
69 {
70     static if (is(ab[0]) && is(ab[1]))
71     {
72         enum isSame = is(ab[0] == ab[1]);
73     }
74     else static if (!is(ab[0]) &&
75                     !is(ab[1]) &&
76                     is(typeof(ab[0] == ab[1]) == bool) &&
77 					(ab[0] == ab[1]))
78     {
79         static if (!__traits(compiles, &ab[0]) ||
80                    !__traits(compiles, &ab[1]))
81             enum isSame = (ab[0] == ab[1]);
82         else
83             enum isSame = __traits(isSame, ab[0], ab[1]);
84     }
85     else
86     {
87         enum isSame = __traits(isSame, ab[0], ab[1]);
88     }
89 }
90 
91 /**
92 	Compares two groups for element identity
93 	
94 	Params:
95 		Group1, Group2 = any instances of `Group`
96 
97 	Returns:
98 		`true` if each element of Group1 is identical to
99 		the one of Group2 at the same index
100 */
101 template Compare(alias Group1, alias Group2)
102 	if (isGroup!Group1 && isGroup!Group2)
103 {
104 	private bool implementation()
105 	{
106 		static if (Group1.expand.length == Group2.expand.length) {
107 			foreach (index, element; Group1.expand)
108 			{
109 				static if (!isSame!(Group1.expand[index], Group2.expand[index])) {
110 					return false;
111 				}
112 			}
113 			return true;
114 		}
115 		else {
116 			return false;
117 		}
118 	}
119 
120 	enum Compare = implementation();
121 }
122 
123 ///
124 unittest
125 {
126 	alias one = Group!(int, double);
127 	alias two = Group!(int, double);
128 	alias three = Group!(double, int);
129 	static assert (Compare!(one, two));
130 	static assert (!Compare!(one, three));
131 }