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 == typeof(null))) 27 { 28 bool empty = false; 29 typeof(null) 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 struct TestValues(N) 61 if ((isIntegral!N || isSomeChar!N) && isUnqual!N) 62 { 63 private: 64 static if (is(N == ulong)) 65 { 66 static immutable N[] 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 90 enum ptrdiff_t maxIdx = naturals.length - 1; 91 } 92 else 93 { 94 alias naturals = TestValues!(ulong).naturals; 95 96 enum ptrdiff_t maxIdx = function() 97 { 98 // Test dchar values greater than dchar.max, also: 99 enum ulong trueNmax = isSomeChar!N? ~0uL : N.max; 100 101 auto x = cast(ptrdiff_t)(naturals.length - 1); 102 while (naturals[x] > trueNmax) 103 --x; 104 return x; 105 }(); 106 } 107 enum ptrdiff_t minIdx = isSigned!N? -(maxIdx + 1) : 0; 108 109 ptrdiff_t index = minIdx; 110 111 public: 112 @property bool empty() const 113 { 114 return index > maxIdx; 115 } 116 @property N front() const 117 { 118 static if (isSigned!N) 119 { 120 if (index < 0) 121 return cast(N)-cast(Promoted!N)naturals[-index]; 122 } 123 124 return cast(N)naturals[index]; 125 } 126 @property void popFront() 127 { 128 ++index; 129 } 130 } 131 132 private enum real ctPow2(int exponent) = mixin("0x1.0p" ~ exponent.stringof ~ "L"); 133 134 struct TestValues(N) 135 if (isFloatingPoint!N && isUnqual!N) 136 { 137 private: 138 static if (is(N == real)) 139 { 140 enum real[] normal_exps_small = [ 141 ctPow2!(real.min_exp - 1), 142 ctPow2!(real.min_exp) 143 ]; 144 enum real[] normal_exps_core = [ 145 ctPow2!(double.min_exp - 1), 146 ctPow2!(double.min_exp), 147 148 ctPow2!(-722), 149 150 ctPow2!(float.min_exp - 1), 151 ctPow2!(float.min_exp), 152 153 ctPow2!(-13), 154 ctPow2!(-12), 155 156 ctPow2!(-4), 157 ctPow2!(-3), 158 ctPow2!(-2), 159 ctPow2!(-1), 160 161 1uL << 0, 162 1uL << 1, 163 1uL << 2, 164 1uL << 3, 165 1uL << 4, 166 167 // byte 168 (byte.max >> 1) + 1, 169 // ubyte 170 (ubyte.max >> 1) + 1, 171 1uL << 8, 172 1uL << 10, 173 1uL << 11, 174 1uL << 12, 175 1uL << 13, 176 // short 177 (short.max >> 1) + 1, 178 // ushort 179 (ushort.max >> 1) + 1, 180 1uL << 16, 181 1uL << 23, 182 1uL << 24, 183 1uL << 25, 184 // int 185 (int.max >> 1) + 1, 186 // uint 187 (uint.max >> 1) + 1, 188 1uL << 32, 189 1uL << 52, 190 1uL << 53, 191 1uL << 54, 192 1uL << 61, 193 // long 194 (long.max >> 1) + 1, 195 // ulong 196 (ulong.max >> 1) + 1, 197 ctPow2!(64), 198 199 ctPow2!(104), 200 ctPow2!(105), 201 ctPow2!(106), 202 ctPow2!(111), 203 ctPow2!(112), 204 ctPow2!(113), 205 ctPow2!(125), 206 207 // cent 208 ctPow2!(float.max_exp - 2), 209 // ucent 210 ctPow2!(float.max_exp - 1), 211 ctPow2!(float.max_exp), 212 ctPow2!(437), 213 ctPow2!(double.max_exp - 2), 214 ctPow2!(double.max_exp - 1) 215 ]; 216 enum real[] normal_exps_large = [ 217 ctPow2!(double.max_exp), 218 ctPow2!(real.max_exp - 2), 219 ctPow2!(real.max_exp - 1) 220 ]; 221 222 static if (is(real == double)) 223 static immutable real[] normal_exps = normal_exps_core; 224 else 225 static immutable real[] normal_exps = normal_exps_small ~ normal_exps_core ~ normal_exps_large; 226 } 227 else 228 { 229 static immutable N[] normal_exps = function() 230 { 231 const normal_exps = TestValues!(real).normal_exps; 232 233 ptrdiff_t minExpIdx = 0; 234 while (!(normal_exps[minExpIdx] >= N.min_normal)) 235 ++minExpIdx; 236 237 ptrdiff_t maxExpIdx = normal_exps.length - 1; 238 while (!(normal_exps[maxExpIdx] <= N.max)) 239 --maxExpIdx; 240 241 auto ret = new N[(maxExpIdx - minExpIdx) + 1]; 242 foreach(x; minExpIdx .. maxExpIdx + 1) 243 ret[x - minExpIdx] = cast(N)normal_exps[x]; 244 return ret.idup; 245 }(); 246 } 247 248 static immutable N[] normal_mants = [ 249 1.0L, 250 1.0L + N.epsilon, 251 LN2 * 2.0L, 252 E * 0.5L, 253 SQRT2, 254 PI * 0.5L, 255 2.0L - (N.epsilon * 2.0L), 256 2.0L - N.epsilon 257 ]; 258 enum ptrdiff_t maxIdx = (normal_exps.length * normal_mants.length) + 2; 259 260 auto index = -maxIdx; 261 N _front = -N.infinity; 262 263 public: 264 @property bool empty() const 265 { 266 return index > maxIdx; 267 } 268 @property N front() const 269 { 270 return _front; 271 } 272 @property void popFront() 273 { 274 ++index; 275 276 const negIdx = index < 0; 277 const absIdx = negIdx? -index : index; 278 279 if (absIdx <= 1) 280 _front = (absIdx == 0)? N.nan : 0; 281 else if (absIdx < maxIdx) 282 { 283 const mant = normal_mants[(absIdx - 2) % normal_mants.length]; 284 const expC = normal_exps[(absIdx - 2) / normal_mants.length]; 285 _front = mant * expC; 286 } 287 else 288 _front = N.infinity; 289 290 if (negIdx) 291 _front = -_front; 292 } 293 }