1 /**
2 *   Copyright: © 2014-2015 Anton Gushcha
3 *   License: Subject to the terms of the Boost 1.0 license as specified in LICENSE file
4 *   Authors: Anton Gushcha <ncrashed@gmail.com>
5 *
6 *   Template for aggregates members expection - extension of std.traits;
7 */
8 module stribog.meta.iota;
9 
10 import stribog.meta.base;
11 
12 /**
13 *   Template, similar to iota(), but generates a tuple at compile time.
14 *
15 *   Useful for "static foreach" loops, where range extrema are compile time constants:
16 *   -----------
17 *   foreach (i; Iota!(3))
18 *   a[i] = b[i];
19 * 
20 *   // becomes unrolled and compiled as:
21 *   a[0] = b[0];
22 *   a[1] = b[1];
23 *   a[2] = b[2];
24 *   -----------
25 *
26 *   Source: https://issues.dlang.org/show_bug.cgi?id=4085
27 */
28 template Iota(int stop) {
29     static if (stop <= 0)
30         alias ExpressionList!() Iota;
31     else
32         alias ExpressionList!(Iota!(stop-1), stop-1) Iota;
33 }
34 
35 /// ditto
36 template Iota(int start, int stop) {
37     static if (stop <= start)
38         alias ExpressionList!() Iota;
39     else
40         alias ExpressionList!(Iota!(start, stop-1), stop-1) Iota;
41 }
42 
43 /// ditto
44 template Iota(int start, int stop, int step) {
45     static assert(step != 0, "Iota: step must be != 0");
46 
47     static if (step > 0) {
48         static if (stop <= start)
49             alias ExpressionList!() Iota;
50         else
51             alias ExpressionList!(Iota!(start, stop-step, step), stop-step) Iota;
52     } else {
53         static if (stop >= start)
54             alias ExpressionList!() Iota;
55         else
56             alias ExpressionList!(Iota!(start, stop-step, step), stop-step) Iota;
57     }
58 } // End Iota!(a,b,c)
59 
60 unittest { // Tests of Iota!()
61     static assert(Iota!(0).length == 0);
62 
63     int[] a;
64 
65     foreach (n; Iota!(5))
66         a ~= n;
67     assert(a == [0, 1, 2, 3, 4]);
68 
69     a.length = 0;
70     foreach (n; Iota!(-5))
71         a ~= n;
72     assert(a == new int[0]);
73 
74     a.length = 0;
75     foreach (n; Iota!(4, 7))
76         a ~= n;
77     assert(a == [4, 5, 6]);
78 
79     a.length = 0;
80     foreach (n; Iota!(-1, 4))
81         a ~= n;
82     static assert(Iota!(-1, 4).length == 5);
83     assert(a == [-1, 0, 1, 2, 3]);
84 
85     a.length = 0;
86     foreach (n; Iota!(4, 2))
87         a ~= n;
88     assert(a == new int[0]);
89 
90     a.length = 0;
91     foreach (n; Iota!(0, 10, 2))
92         a ~= n;
93     assert(a == [0, 2, 4, 6, 8]);
94 
95     a.length = 0;
96     foreach (n; Iota!(3, 15, 3))
97         a ~= n;
98     assert(a == [3, 6, 9, 12]);
99 
100     a.length = 0;
101     foreach (n; Iota!(15, 3, 1))
102         a ~= n;
103     assert(a == new int[0]);
104 
105     a.length = 0;
106     foreach (n; Iota!(10, 0, -1))
107         a ~= n;
108     assert(a == [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
109 
110     a.length = 0;
111     foreach (n; Iota!(15, 3, -2))
112         a ~= n;
113     assert(a == [15, 13, 11, 9, 7, 5]);
114 
115     static assert(!is(typeof( Iota!(15, 3, 0) ))); // stride = 0 statically asserts
116 } // End tests of Iota!()