1 /** 2 Copyright: Copyright Thomas Stuart Bockman 2015 3 License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>. 4 Authors: Thomas Stuart Bockman 5 */ 6 7 module checkedint.internal; 8 import checkedint.flags; 9 10 import future.bitop, core.checkedint, std.algorithm, std.conv, future.traits; 11 static import std.math; 12 13 @safe: 14 15 private: 16 17 template trueMax(N) 18 if(isScalarType!N) 19 { 20 static if(isSomeChar!N) 21 enum trueMax = ~cast(N)0; 22 else 23 enum trueMax = N.max; 24 } 25 26 package: 27 28 template NumFromScal(N) 29 if(isScalarType!N) 30 { 31 static if(isNumeric!N) 32 alias NumFromScal = N; 33 else 34 static if(isSomeChar!N) 35 alias NumFromScal = IntFromChar!N; 36 else //if(isBoolean!N) 37 alias NumFromScal = ubyte; 38 } 39 40 /+pragma(inline, true) {+/ 41 // nothrow alternative to std.conv.to() using IntFlag 42 T toImpl(T, bool throws, S)(const S value) 43 if(isScalarType!T && isScalarType!S) 44 { 45 static if(throws) 46 return to!T(value); 47 else { 48 static if(! isFloatingPoint!T) { 49 static if(isFloatingPoint!S) { 50 if(value >= T.min) { 51 if(value > trueMax!T) 52 IntFlag.posOver.raise!throws(); 53 } else 54 (value.isNaN? IntFlag.undef : IntFlag.negOver).raise!throws(); 55 } else { 56 static if(cast(long)S.min < cast(long)T.min) { 57 if(value < cast(S)T.min) 58 IntFlag.negOver.raise!throws(); 59 } 60 static if(cast(ulong)trueMax!S > cast(ulong)trueMax!T) { 61 if(value > cast(S)trueMax!T) 62 IntFlag.posOver.raise!throws(); 63 } 64 } 65 } 66 return cast(T)value; 67 } 68 } 69 70 int bsrImpl(bool throws, N)(const N num) 71 if(isFixedPoint!N) 72 { 73 if(num == 0) 74 IntFlag.undef.raise!throws(); 75 76 static assert(N.sizeof <= ulong.sizeof); 77 alias WN = Select!(N.sizeof > size_t.sizeof, ulong, size_t); 78 79 return bsr(cast(WN)num); 80 } 81 int bsfImpl(bool throws, N)(const N num) 82 if(isFixedPoint!N) 83 { 84 if(num == 0) 85 IntFlag.undef.raise!throws(); 86 87 static assert(N.sizeof <= ulong.sizeof); 88 alias WN = Select!(N.sizeof > size_t.sizeof, ulong, size_t); 89 90 return bsf(cast(WN)num); 91 } 92 93 auto byPow2Impl(string op, N, M)(const N coef, const M exp) pure nothrow @nogc 94 if(op.among!("*", "/") && ((isFloatingPoint!N && isNumeric!M) || (isNumeric!N && isFloatingPoint!M))) 95 { 96 enum wantPrec = max(precision!N, precision!M); 97 alias R = 98 Select!(wantPrec <= precision!float, float, 99 Select!(wantPrec <= precision!double, double, real)); 100 101 static if(isFloatingPoint!M) { 102 R ret = void; 103 if(coef == 0 && std.math.isFinite(exp)) 104 ret = 0; 105 else { 106 R wexp = cast(R)exp; 107 static if(op == "/") 108 wexp = -wexp; 109 110 ret = cast(R)coef * std.math.exp2(wexp); 111 } 112 113 return ret; 114 } else { 115 int wexp = 116 (exp > int.max)? int.max : 117 (cast(long)exp < -int.max)? -int.max : cast(int)exp; 118 static if(op == "/") 119 wexp = -wexp; 120 121 return std.math.ldexp(cast(R)coef, wexp); 122 } 123 } 124 Promoted!N byPow2Impl(string op, bool throws, N, M)(const N coef, const M exp) 125 if(op.among!("*", "/") && isIntegral!N && isIntegral!M) 126 { 127 alias R = typeof(return); 128 129 const rc = cast(R)coef; 130 const negE = exp < 0; 131 const shR = (op == "*")? negE : !negE; 132 const absE = cast(Unsigned!M)(negE? 133 -exp : 134 exp); 135 136 R ret = void; 137 R back = void; 138 enum shLim = 8 * N.sizeof; 139 if(absE >= shLim) { 140 if(shR) 141 return 0; 142 else { 143 ret = 0; 144 back = 0; 145 goto LcheckL; 146 } 147 } 148 149 if(shR) { 150 // ">>" rounds as floor(), but we want trunc() like "/" 151 ret = (rc < 0)? 152 -(-rc >>> absE) : 153 rc >>> absE; 154 } else { 155 ret = rc << absE; 156 back = ret >> absE; 157 158 LcheckL: 159 if(back != rc) 160 IntFlag.over.raise!throws(); 161 } 162 163 return ret; 164 } 165 /+}+/ 166 167 168 //pragma(inline, false) // Minimize template bloat by using a common pow() implementation 169 B powImpl(B, E)(const B base, const E exp, ref IntFlag flag) 170 if((is(B == int) || is(B == uint) || is(B == long) || is(B == ulong)) && 171 (is(E == long) || is(E == ulong))) 172 { 173 static if(isSigned!B) { 174 alias cmul = muls; 175 const smallB = (1 >= base && base >= -1); 176 } else { 177 alias cmul = mulu; 178 const smallB = (base <= 1); 179 } 180 181 if(smallB) { 182 if(base == 0) { 183 static if(isSigned!E) { 184 if(exp < 0) 185 flag = IntFlag.div0; 186 } 187 188 return (exp == 0); 189 } 190 191 return (exp & 0x1)? base : 1; 192 } 193 if(exp <= 0) 194 return (exp == 0); 195 196 B ret = 1; 197 if(exp <= precision!B) { 198 B b = base; 199 int e = cast(int)exp; 200 if(e & 0x1) 201 ret = b; 202 e >>>= 1; 203 204 bool over = false; 205 while(e != 0) { 206 b = cmul(b, b, over); 207 if(e & 0x1) 208 ret = cmul(ret, b, over); 209 210 e >>>= 1; 211 } 212 213 if(!over) 214 return ret; 215 } 216 217 flag = (base < 0 && (exp & 0x1))? 218 IntFlag.negOver : 219 IntFlag.posOver; 220 return ret; 221 }