1 /**
2  * The tuple module defines a template struct used for arbitrary data grouping.
3  *
4  * Copyright:
5  *     Copyright (C) 2005-2006 Sean Kelly.
6  *     Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
7  *     All rights reserved.
8  *
9  * License:
10  *     Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
11  *     See LICENSE_TANGO.txt for details.
12  *
13  * Authors: Walter Bright, Sean Kelly
14  *
15  */
16 module ocean.core.Tuple;
17 
18 
19 /**
20  * A Tuple is a an aggregate of typed values.  Tuples are useful for returning
21  * a set of values from a function or for passing a set of parameters to a
22  * function.
23  *
24  * NOTE: Since the transition from user-defined to built-in tuples, the ability
25  *       to return tuples from a function has been lost.  Until this issue is
26  *       addressed within the language, tuples must be enclosed in a struct
27  *       if they are to be returned from a function.
28  *
29  * Example:
30  * ----------------------------------------------------------------------
31  * alias Tuple!(int, real) T1;
32  * alias Tuple!(int, long) T2;
33  * struct Wrap( Vals... )
34  * {
35  *     Vals val;
36  * }
37  *
38  * Wrap!(T2) func( T1 val )
39  * {
40  *     Wrap!(T2) ret;
41  *     ret.val[0] = val[0];
42  *     ret.val[1] = val[0] * cast(long) val[1];
43  *     return ret;
44  * }
45  * ----------------------------------------------------------------------
46  *
47  * This is the original tuple example, and demonstates what should be possible
48  * with tuples.  Hopefully, language support will be added for this feature
49  * soon.
50  *
51  * Example:
52  * ----------------------------------------------------------------------
53  * alias Tuple!(int, real) T1;
54  * alias Tuple!(int, long) T2;
55  *
56  * T2 func( T1 val )
57  * {
58  *     T2 ret;
59  *     ret[0] = val[0];
60  *     ret[1] = val[0] * cast(long) val[1];
61  *     return ret;
62  * }
63  *
64  *
65  * // tuples may be composed
66  * alias Tuple!(int) IntTuple;
67  * alias Tuple!(IntTuple, long) RetTuple;
68  *
69  * // tuples are equivalent to a set of function parameters of the same type
70  * RetTuple t = func( 1, 2.3 );
71  * ----------------------------------------------------------------------
72  */
73 template Tuple( TList... )
74 {
75     alias TList Tuple;
76 }
77 
78 
79 /**
80  * Returns the index of the first occurrence of T in TList or Tlist.length if
81  * not found.
82  */
83 template IndexOf( T, TList... )
84 {
85     static if( TList.length == 0 )
86         static immutable size_t IndexOf = 0;
87     else static if( is( T == TList[0] ) )
88         static immutable size_t IndexOf = 0;
89     else
90         static immutable size_t IndexOf = 1 + IndexOf!( T, TList[1 .. $] );
91 }
92 
93 
94 /**
95  * Returns a Tuple with the first occurrence of T removed from TList.
96  */
97 template Remove( T, TList... )
98 {
99     static if( TList.length == 0 )
100         alias TList Remove;
101     else static if( is( T == TList[0] ) )
102         alias TList[1 .. $] Remove;
103     else
104         alias Tuple!( TList[0], Remove!( T, TList[1 .. $] ) ) Remove;
105 }
106 
107 
108 /**
109  * Returns a Tuple with all occurrences of T removed from TList.
110  */
111 template RemoveAll( T, TList... )
112 {
113     static if( TList.length == 0 )
114         alias TList RemoveAll;
115     else static if( is( T == TList[0] ) )
116         alias .RemoveAll!( T, TList[1 .. $] ) RemoveAll;
117     else
118         alias Tuple!( TList[0], .RemoveAll!( T, TList[1 .. $] ) ) RemoveAll;
119 }
120 
121 
122 /**
123  * Returns a Tuple with the first offuccrence of T replaced with U.
124  */
125 template Replace( T, U, TList... )
126 {
127     static if( TList.length == 0 )
128         alias TList Replace;
129     else static if( is( T == TList[0] ) )
130         alias Tuple!(U, TList[1 .. $]) Replace;
131     else
132         alias Tuple!( TList[0], Replace!( T, U, TList[1 .. $] ) ) Replace;
133 }
134 
135 
136 /**
137  * Returns a Tuple with all occurrences of T replaced with U.
138  */
139 template ReplaceAll( T, U, TList... )
140 {
141     static if( TList.length == 0 )
142         alias TList ReplaceAll;
143     else static if( is( T == TList[0] ) )
144         alias Tuple!( U, ReplaceAll!( T, U, TList[1 .. $] ) ) ReplaceAll;
145     else
146         alias Tuple!( TList[0], ReplaceAll!( T, U, TList[1 .. $] ) ) ReplaceAll;
147 }
148 
149 
150 /**
151  * Returns a Tuple with the types from TList declared in reverse order.
152  */
153 template Reverse( TList... )
154 {
155     static if( TList.length == 0 )
156         alias TList Reverse;
157     else
158         alias Tuple!( Reverse!( TList[1 .. $]), TList[0] ) Reverse;
159 }
160 
161 
162 /**
163  * Returns a Tuple with all duplicate types removed.
164  */
165 template Unique( TList... )
166 {
167     static if( TList.length == 0 )
168         alias TList Unique;
169     else
170         alias Tuple!( TList[0],
171                       Unique!( RemoveAll!( TList[0],
172                                            TList[1 .. $] ) ) ) Unique;
173 }
174 
175 
176 /**
177  * Returns the type from TList that is the most derived from T.  If no such
178  * type is found then T will be returned.
179  */
180 template MostDerived( T, TList... )
181 {
182     static if( TList.length == 0 )
183         alias T MostDerived;
184     else static if( is( TList[0] : T ) )
185         alias MostDerived!( TList[0], TList[1 .. $] ) MostDerived;
186     else
187         alias MostDerived!( T, TList[1 .. $] ) MostDerived;
188 }
189 
190 
191 /**
192  * Returns a Tuple with the types sorted so that the most derived types are
193  * ordered before the remaining types.
194  */
195 template DerivedToFront( TList... )
196 {
197     static if( TList.length == 0 )
198         alias TList DerivedToFront;
199     else
200         alias Tuple!( MostDerived!( TList[0], TList[1 .. $] ),
201                       DerivedToFront!( ReplaceAll!( MostDerived!( TList[0], TList[1 .. $] ),
202                                                     TList[0],
203                                                     TList[1 .. $] ) ) ) DerivedToFront;
204 }
205 
206 
207 /*
208  * A brief test of the above templates.
209  */
210 static assert( 0 == IndexOf!(int, int, float, char));
211 static assert( 1 == IndexOf!(float, int, float, char));
212 static assert( 3 == IndexOf!(double, int, float, char));
213 
214 static assert( is( Remove!(int, int, float, int) == Remove!(void, float, int) ) );
215 static assert( is( RemoveAll!(int, int, float, int) == Remove!(void, float) ) );
216 static assert( is( Remove!(float, int, float, int) == Remove!(void, int, int) ) );
217 static assert( is( Remove!(double, int, float, int) == Remove!(void, int, float, int) ) );
218 
219 static assert( is( Replace!(int, char, int, float, int) == Remove!(void, char, float, int) ) );
220 static assert( is( ReplaceAll!(int, char, int, float, int) == Remove!(void, char, float, char) ) );
221 static assert( is( Replace!(float, char, int, float, int) == Remove!(void, int, char, int) ) );
222 static assert( is( Replace!(double, char, int, float, int) == Remove!(void, int, float, int) ) );
223 
224 static assert( is( Reverse!(float, float[], double, char, int) ==
225                    Unique!(int, char, double, float[], char, int, float, double) ) );
226 
227 static assert( is( MostDerived!(int, long, short) == short ) );