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