1 /**
2 	Additions to std.typetuple pending for inclusion into Phobos.
3 
4 	Copyright: © 2013 Sönke Ludwig
5 	License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
6 	Authors: Михаил Страшун
7 */
8 
9 module vibe.internal.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 template implementation(size_t index)
105 	{
106 		static if (Group1.expand.length != Group2.expand.length) enum implementation = false;
107 		else static if (index >= Group1.expand.length) enum implementation = true;
108 		else static if (!isSame!(Group1.expand[index], Group2.expand[index])) enum implementation = false;
109 		else enum implementation = implementation!(index+1);
110 	}
111 
112 	enum Compare = implementation!0;
113 }
114 
115 ///
116 unittest
117 {
118 	alias one = Group!(int, double);
119 	alias two = Group!(int, double);
120 	alias three = Group!(double, int);
121 	static assert (Compare!(one, two));
122 	static assert (!Compare!(one, three));
123 }