1 /**
2 Generate numeric test values hitting all the likely corner cases for simple
3 integer math algorithms. Floating-point is also well-covered, with the
4 exception of subnormal values.
5 
6 Copyright: Copyright Thomas Stuart Bockman 2015
7 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
8 Authors: Thomas Stuart Bockman
9 **/
10 module checkedint.tests.values;
11 
12 import std.math, future.traits0;
13 import std.meta : AliasSeq;
14 
15 pure: nothrow: @nogc: @safe:
16 
17 alias
18     IntegralTypes = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong),
19     FloatingTypes = AliasSeq!(float, double ,real),
20     NumericTypes = AliasSeq!(IntegralTypes, FloatingTypes),
21     CharTypes = AliasSeq!(char, wchar, dchar),
22     FixedTypes = AliasSeq!(bool, CharTypes, IntegralTypes),
23     ScalarTypes = AliasSeq!(FixedTypes, FloatingTypes);
24 
25 struct TestValues(N)
26     if (is(N == void*))
27 {
28     bool empty = false;
29     void* front() const
30     {
31         return null;
32     }
33     void popFront()
34     {
35         empty = true;
36     }
37 }
38 
39 struct TestValues(N)
40     if (is(N == bool))
41 {
42 private:
43     int idx = 0;
44 
45 public:
46     @property bool empty() const
47     {
48         return idx <= 1;
49     }
50     @property bool front() const
51     {
52         return idx != 0;
53     }
54     @property void popFront()
55     {
56         ++idx;
57     }
58 }
59 
60 private enum ulong[] naturals = function()
61 {
62     ulong[34 + 3*(64 - 5) - 2] nats;
63 
64     size_t n = 0;
65     while (n <= 33)
66     {
67         nats[n] = n;
68         ++n;
69     }
70 
71     int sh = 6;
72     while (sh < 64)
73     {
74         nats[n++] = (1uL << sh) -1;
75         nats[n++] = (1uL << sh);
76         nats[n++] = (1uL << sh) + 1;
77         ++sh;
78     }
79     nats[n] = ulong.max;
80 
81     return nats;
82 }();
83 struct TestValues(N)
84     if (isIntegral!N || isSomeChar!N)
85 {
86 private:
87     enum maxIdx = function()
88     {
89         // Test dchar values greater than dchar.max, also:
90         enum ulong trueNmax = isSomeChar!N? ~cast(N)0 : N.max;
91 
92         auto x = cast(ptrdiff_t)(naturals.length - 1);
93         while (naturals[x] > trueNmax)
94             --x;
95         return x;
96     }();
97     enum minIdx = isSigned!N? -(maxIdx + 1) : 0;
98 
99     ptrdiff_t index = minIdx;
100 
101 public:
102     @property bool empty() const
103     {
104         return index > maxIdx;
105     }
106     @property N front() const
107     {
108         static if (isSigned!N)
109         {
110             if (index < 0)
111                 return -cast(N)naturals[-index];
112         }
113 
114         return cast(N)naturals[index];
115     }
116     @property void popFront()
117     {
118         ++index;
119     }
120 }
121 
122 private enum real[] normal_exps = [
123     real.min_exp < double.min_exp? pow(2.0L, real.min_exp - 1) : 0.0,
124     real.min_exp < double.min_exp? pow(2.0L, real.min_exp) : 0.0,
125 
126     pow(2.0L, double.min_exp - 1),
127     pow(2.0L, double.min_exp),
128 
129     pow(2.0L, -722),
130 
131     pow(2.0L, float.min_exp - 1),
132     pow(2.0L, float.min_exp),
133 
134     pow(2.0L, -13),
135     pow(2.0L, -12),
136 
137     pow(2.0L, -4),
138     pow(2.0L, -3),
139     pow(2.0L, -2),
140     pow(2.0L, -1),
141 
142     1uL << 0,
143     1uL << 1,
144     1uL << 2,
145     1uL << 3,
146     1uL << 4,
147 
148     // byte
149     (byte.max >> 1) + 1,
150     // ubyte
151     (ubyte.max >> 1) + 1,
152     1uL << 8,
153     1uL << 10,
154     1uL << 11,
155     1uL << 12,
156     1uL << 13,
157     // short
158     (short.max >> 1) + 1,
159     // ushort
160     (ushort.max >> 1) + 1,
161     1uL << 16,
162     1uL << 23,
163     1uL << 24,
164     1uL << 25,
165     // int
166     (int.max >> 1) + 1,
167     // uint
168     (uint.max >> 1) + 1,
169     1uL << 32,
170     1uL << 52,
171     1uL << 53,
172     1uL << 54,
173     1uL << 61,
174     // long
175     (long.max >> 1) + 1,
176     // ulong
177     (ulong.max >> 1) + 1,
178     pow(2.0L, 64),
179 
180     pow(2.0L, 104),
181     pow(2.0L, 105),
182     pow(2.0L, 106),
183     pow(2.0L, 111),
184     pow(2.0L, 112),
185     pow(2.0L, 113),
186     pow(2.0L, 125),
187 
188     // cent
189     pow(2.0L, float.max_exp - 2),
190     // ucent
191     pow(2.0L, float.max_exp - 1),
192     pow(2.0L, float.max_exp),
193     pow(2.0L, 437),
194     pow(2.0L, double.max_exp - 2),
195     pow(2.0L, double.max_exp - 1),
196     pow(2.0L, double.max_exp),
197     real.max_exp > double.max_exp? pow(2.0L, real.max_exp - 2) : real.infinity,
198     real.max_exp > double.max_exp? pow(2.0L, real.max_exp - 1) : real.infinity
199 ];
200 struct TestValues(N)
201     if (isFloatingPoint!N)
202 {
203 private:
204     enum minExpIdx = function()
205     {
206         ptrdiff_t expX = 0;
207         while (!(normal_exps[expX] >= N.min_normal))
208             ++expX;
209         return expX;
210     }();
211     enum maxExpIdx = function()
212     {
213         ptrdiff_t expX = normal_exps.length - 1;
214         while (!(normal_exps[expX] <= N.max))
215             --expX;
216         return expX;
217     }();
218     enum expCount = (maxExpIdx - minExpIdx) + 1;
219 
220     enum N[] normal_mants = [
221         1.0L,
222         1.0L + N.epsilon,
223         LN2 * 2.0L,
224         E * 0.5L,
225         SQRT2,
226         PI * 0.5L,
227         2.0L - (N.epsilon * 2.0L),
228         2.0L - N.epsilon
229     ];
230     enum ptrdiff_t maxIdx = (expCount * normal_mants.length) + 2;
231 
232     auto index = -maxIdx;
233     N _front = -N.infinity;
234 
235 public:
236     @property bool empty() const
237     {
238         return index > maxIdx;
239     }
240     @property N front() const
241     {
242         return _front;
243     }
244     @property void popFront()
245     {
246         ++index;
247 
248         const negIdx = index < 0;
249         const absIdx = negIdx? -index : index;
250 
251         if (absIdx <= 1)
252             _front = (absIdx == 0)? N.nan : 0;
253         else if (absIdx < maxIdx)
254         {
255             const mant = normal_mants[(absIdx - 2) % normal_mants.length];
256             const expC = normal_exps[minExpIdx + (absIdx - 2) / normal_mants.length];
257             _front = mant * expC;
258         }
259         else
260             _front = N.infinity;
261 
262         if (negIdx)
263             _front = -_front;
264     }
265 }