1 /** 2 Precise and detailed description of the expected behaviour of 3 `checkedint.smartOp` against which it can be automatically tested. 4 80+ bit floating-point is used to compute the expected value for each 5 operation with many different combinations of inputs. 6 7 $(RED Note:) These tests currently will not work on systems where 8 `is(real == double)`, because `Precision!double < Precision!ulong`. 9 10 Copyright: Copyright Thomas Stuart Bockman 2015 11 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 12 Authors: Thomas Stuart Bockman 13 **/ 14 module checkedint.tests.contract.smartop; 15 import checkedint.tests.contract.internal; 16 17 import checkedint.flags; 18 19 void all()() 20 { 21 writeln(); 22 write("Testing smartOp... "); 23 stdout.flush(); 24 25 cmp(); 26 abs(); 27 ilogb(); 28 unary(); 29 binary(); 30 byPow2(); 31 pow(); 32 33 writeln("DONE"); 34 } 35 36 @safe: 37 38 void cmp(string op = null, N = void, M = void)() 39 { 40 static if (op == null) 41 { 42 foreach (op1; AliasSeq!("==", "!=", "<", "<=", ">", ">=")) 43 cmp!(op1, N, M)(); 44 } 45 else static if (is(N == void)) 46 { 47 foreach (N1; AliasSeq!(IntegralTypes, CharTypes)) 48 cmp!(op, N1, M)(); 49 } 50 else static if (is(M == void)) 51 { 52 foreach (M1; AliasSeq!(IntegralTypes, CharTypes)) 53 cmp!(op, N, M1)(); 54 } 55 else 56 { 57 static assert(isScalarType!N && isScalarType!M); 58 59 static void cover(bool direct)() 60 { 61 static if (direct) 62 enum sc = "smartOp.cmp!\"" ~ op ~ "\"(n, m)"; 63 else 64 enum sc = "smartOp.cmp(n, m) " ~ op ~ " 0"; 65 66 static assert(real.mant_dig >= max(precision!N, precision!M)); 67 auto control(const real n, const real m) 68 { 69 auto wret = stdm.cmp(n, m); 70 return mixin("wret " ~ op ~ " 0"); 71 } 72 73 fuzz!(sc, Unqual, OutIs!bool, control, N, M)(); 74 } 75 cover!true(); 76 cover!false(); 77 } 78 } 79 alias cmp(N, M = void) = cmp!(null, N, M); 80 81 void abs(N = void)() 82 { 83 static if (is(N == void)) 84 { 85 foreach (N1; AliasSeq!(IntegralTypes, CharTypes)) 86 abs!N1(); 87 } 88 else 89 { 90 static assert(isFixedPoint!N); 91 92 enum sc = "smartOp.abs(n)"; 93 94 static assert(real.mant_dig >= precision!N); 95 auto control(const real n, Unused m = null) 96 { 97 return stdm.abs(n); 98 } 99 alias R = Unsigned!(IntFromChar!N); 100 101 fuzz!(sc, Unqual, OutIs!R, control, N)(); 102 } 103 } 104 105 void ilogb(N = void)() 106 { 107 static if (is(N == void)) 108 { 109 foreach (N1; AliasSeq!(IntegralTypes, CharTypes)) 110 ilogb!N1(); 111 } 112 else 113 { 114 static assert(isFixedPoint!N); 115 116 enum sc = "smartOp.ilogb(n)"; 117 118 static assert(real.mant_dig >= (8 * N.sizeof)); 119 auto control(const real n, Unused m = null) 120 { 121 return n != 0? stdm.ilogb(n) : real.nan; 122 } 123 124 fuzz!(sc, Unqual, OutIs!ubyte, control, N)(); 125 } 126 } 127 128 void unary(string op = null, N = void)() 129 { 130 static if (op == null) 131 { 132 foreach (op1; AliasSeq!("~", "+", "-", "++", "--")) 133 unary!(op1, N)(); 134 } 135 else static if (is(N == void)) 136 { 137 foreach (N1; AliasSeq!(IntegralTypes, CharTypes)) 138 unary!(op, N1)(); 139 } 140 else 141 { 142 static assert(isFixedPoint!N); 143 144 enum sc = "smartOp.unary!\"" ~ op ~ "\"(n)"; 145 146 static assert(real.mant_dig >= precision!N); 147 static if (op == "~") 148 { 149 auto control(const N n, Unused m = null) 150 { 151 return cast(N)~cast(Promoted!N)n; 152 } 153 } 154 else 155 { 156 auto control(real n, Unused m = null) 157 { 158 return mixin(op ~ "n"); 159 } 160 } 161 enum isVO(N, M, PR) = (PR.sizeof >= N.sizeof) && (isSigned!PR || !op.among!("-", "+")); 162 163 static if (isIntegral!N || !op.among!("++", "--")) 164 fuzz!(sc, Unqual, isVO, control, N)(); 165 else 166 forbid!(sc, N)(); 167 } 168 } 169 alias unary(N) = unary!(null, N); 170 171 void binary(string op = null, N = void, M = void)() 172 { 173 static if (op == null) 174 { 175 foreach (op1; AliasSeq!("+", "-", "*", "/", "%", "<<", ">>", ">>>", "&", "|", "^")) 176 binary!(op1, N, M)(); 177 } 178 else static if (is(N == void)) 179 { 180 foreach (N1; AliasSeq!(IntegralTypes, CharTypes)) 181 binary!(op, N1, M)(); 182 } 183 else static if (is(M == void)) 184 { 185 foreach (M1; AliasSeq!(IntegralTypes, CharTypes)) 186 binary!(op, N, M1)(); 187 } 188 else 189 { 190 static assert(isFixedPoint!N && isFixedPoint!M); 191 192 static if (isIntegral!N) 193 alias UN = Unsigned!N; 194 else 195 alias UN = N; 196 197 static if (isIntegral!M) 198 alias UM = Unsigned!M; 199 else 200 alias UM = M; 201 202 static void cover(bool assign)() 203 { 204 enum sc = "smartOp.binary!\"" ~ op ~ (assign? "=" : "") ~ "\"(n, m)"; 205 206 static assert(real.mant_dig >= max(precision!N, precision!M)); 207 static if (op.among!("<<", ">>", ">>>")) 208 { 209 static N control(const N n, const M m) 210 { 211 const shL = (op == "<<") ^ (m < 0); 212 enum int maxSh = (8 * N.sizeof) - 1; 213 const um = cast(UM)stdm.abs(cast(Promoted!M)m); 214 215 static if (op == ">>>") 216 auto wret = cast(UN)n; 217 else 218 N wret = n; 219 bool again = um > maxSh; 220 const im = again? maxSh : cast(int)um; 221 Lagain: 222 wret = cast(typeof(wret))(shL? 223 wret << im : 224 wret >> im); 225 if (again) 226 { 227 again = false; 228 goto Lagain; 229 } 230 231 return cast(N)wret; 232 } 233 enum isVO(N, M, PR) = isIntegral!PR && (PR.sizeof == N.sizeof) && (isSigned!PR == isSigned!N); 234 } 235 else static if (op.among!("&", "|", "^")) 236 { 237 static auto control(const N n, const M m) 238 { 239 static if (assign) 240 alias R = N; 241 else 242 { 243 alias P = Select!(N.sizeof >= M.sizeof, N, M); 244 static if (isIntegral!P) 245 alias UP = Unsigned!P; 246 else 247 alias UP = P; 248 249 alias R = Select!(isSigned!N && isSigned!M, P, UP); 250 } 251 252 return cast(R)mixin("n " ~ op ~ " m"); 253 } 254 enum isVO(N, M, PR) = isIntegral!PR && (PR.sizeof == max(N.sizeof, M.sizeof)) && 255 (isSigned!PR == (isSigned!N && isSigned!M)); 256 } 257 else 258 { 259 static auto control(const real n, const real m) 260 { 261 static if (op == "/") 262 return stdm.trunc(n / m); 263 else 264 return mixin("n " ~ op ~ " m"); 265 } 266 enum isVO(N, M, PR) = isIntegral!PR && 267 ((isSigned!PR == (isSigned!N || (isSigned!M && op != "%"))) || op == "-"); 268 } 269 270 static if (isIntegral!N || !assign) 271 fuzz!(sc, Unqual, Select!(assign, OutIs!N, isVO), control, N, M)(); 272 else 273 forbid!(sc, N, M)(); 274 } 275 cover!false(); 276 cover!true(); 277 } 278 } 279 alias binary(N, M = void) = binary!(null, N, M); 280 281 void byPow2(string op = null, N = void, M = void)() 282 { 283 static if (op == null) 284 { 285 foreach (op1; AliasSeq!("*", "/", "%")) 286 byPow2!(op1, N, M)(); 287 } 288 else static if (is(N == void)) 289 { 290 foreach (N1; AliasSeq!(IntegralTypes, CharTypes)) 291 byPow2!(op, N1, M)(); 292 } 293 else static if (is(M == void)) 294 { 295 foreach (M1; AliasSeq!(IntegralTypes, CharTypes)) 296 byPow2!(op, N, M1)(); 297 } 298 else 299 { 300 static assert(isScalarType!N && isScalarType!M); 301 302 enum sc = "smartOp." ~ (op == "*"? "mul" : (op == "/"? "div" : "mod")) ~ "Pow2(n, m)"; 303 304 static assert(real.mant_dig >= max(precision!N, precision!M)); 305 real control(const real n, const real m) 306 { 307 if (n == 0 && stdm.isFinite(m)) 308 return 0; 309 else 310 { 311 const p2 = stdm.exp2(m); 312 313 static if (op.among!("*", "/")) 314 { 315 const wret = mixin("n " ~ op ~ " p2"); 316 static if (isFloatingPoint!N || isFloatingPoint!M) 317 return wret; 318 else 319 return stdm.trunc(wret); 320 } 321 else 322 { 323 if (!stdm.isFinite(p2)) 324 return (p2 > 0)? n : (p2 < 0)? 0 : real.nan; 325 else 326 return n % (p2 == 0? real.min_normal : p2); 327 } 328 } 329 } 330 enum isVO(N, M, PR) = (PR.sizeof >= N.sizeof) && 331 ((isFloatingPoint!N || isFloatingPoint!M)? 332 isFloatingPoint!PR : 333 isIntegral!PR && (isSigned!PR || !isSigned!N)); 334 335 fuzz!(sc, Unqual, isVO, control, N, M)(); 336 } 337 } 338 alias byPow2(N, M = void) = byPow2!(null, N, M); 339 340 void pow(N = void, M = void)() 341 { 342 static if (is(N == void)) 343 { 344 foreach (N1; AliasSeq!(IntegralTypes, CharTypes)) 345 pow!(N1, M)(); 346 } 347 else static if (is(M == void)) 348 { 349 foreach (M1; AliasSeq!(IntegralTypes, CharTypes)) 350 pow!(N, M1)(); 351 } 352 else 353 { 354 static assert(isFixedPoint!N && isFixedPoint!M); 355 forbid!("smartOp.binary!\"^^\"(n, m)", N, M)(); 356 forbid!("smartOp.binary!\"^^=\"(n, m)", N, M)(); 357 358 enum sc = "smartOp.pow(n, m)"; 359 360 static assert(real.mant_dig >= max(precision!N, precision!M)); 361 real control(const real n, const real m) 362 { 363 return stdm.trunc(stdm.pow(n, m)); 364 } 365 enum isVO(N, M, PR) = isIntegral!PR && (PR.sizeof >= N.sizeof) && (isSigned!PR == isSigned!N); 366 367 fuzz!(sc, Unqual, isVO, control, N, M)(); 368 } 369 }