1 /** 2 Templates to facilitate treating $(LINK2 ./package.html#SmartInt, `checkedint.SmartInt`) and $(LINK2 ./package.html#SafeInt, `checkedint.SafeInt`) like the built-in numeric types in 3 generic code. 4 5 Copyright: Copyright Thomas Stuart Bockman 2015 6 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 7 Authors: Thomas Stuart Bockman 8 9 This module wraps various templates from `std.traits` to make them `checkedint`-aware. For example, 10 `std.traits.isSigned!(SmartInt!int)` is `false`, but `checkedint.traits.isSigned!(SmartInt!int)` is `true`. 11 12 This module is separate from `checkedint` because it is only useful in generic code, and its symbols (deliberately) 13 conflict with some from `std.traits`. 14 **/ 15 module checkedint.traits; 16 import checkedint.asserts : SmartInt; 17 18 static if (__VERSION__ >= 2068) 19 { 20 version(GNU) { static assert(false); } 21 import std.meta : AliasSeq; 22 } 23 else 24 import std.typetuple : AliasSeq = TypeTuple; 25 26 // checkedint.flags ////////////////////////////////////// 27 static import checkedint.flags; 28 29 /// See $(LINK2 ./flags.html#intFlagPolicyOf, `checkedint.flags.intFlagPolicyOf`) 30 alias intFlagPolicyOf = checkedint.flags.intFlagPolicyOf; 31 32 33 // checkedint //////////////////////////////////////////// 34 static import chkd = checkedint; 35 36 /// See $(LINK2 ./package.html#isSafeInt, `checkedint.isSafeInt`) 37 alias isSafeInt = chkd.isSafeInt; 38 39 /// See $(LINK2 ./package.html#isSmartInt, `checkedint.isSmartInt`) 40 alias isSmartInt = chkd.isSmartInt; 41 42 /// See $(LINK2 ./package.html#isCheckedInt, `checkedint.isCheckedInt`) 43 alias isCheckedInt = chkd.isCheckedInt; 44 45 /// See $(LINK2 ./package.html#hasBitOps, `checkedint.hasBitOps`) 46 alias hasBitOps = chkd.hasBitOps; 47 48 /// See $(LINK2 ./package.html#BasicScalar, `checkedint.BasicScalar`) 49 alias BasicScalar = chkd.BasicScalar; 50 51 52 // std.traits //////////////////////////////////////////// 53 static import bsct = future.traits0; 54 55 private template isEx(alias Predicate, T) 56 { 57 static if (isCheckedInt!T) 58 enum isEx = Predicate!(BasicScalar!T); 59 else 60 enum isEx = Predicate!T; 61 } 62 63 /// See `std.traits.isScalarType` 64 alias isBasicScalar = bsct.isScalarType; 65 /// `checkedint`-aware wrapper for `std.traits.isScalarType` 66 template isScalarType(T) 67 { 68 alias isScalarType = isEx!(isBasicScalar, T); 69 } 70 /// 71 unittest 72 { 73 foreach(T; AliasSeq!(int, ushort, double, bool)) 74 assert(isBasicScalar!T && isScalarType!T); 75 76 assert(!isBasicScalar!(SmartInt!int)); 77 assert( isScalarType!(SmartInt!int)); 78 79 foreach(T; AliasSeq!(int[])) 80 assert(!(isBasicScalar!T || isScalarType!T)); 81 } 82 83 /// See `std.traits.isNumeric` 84 alias isBasicNum = bsct.isNumeric; 85 /// `checkedint`-aware wrapper for `std.traits.isNumeric` 86 template isNumeric(T) 87 { 88 alias isNumeric = isEx!(isBasicNum, T); 89 } 90 /// 91 unittest 92 { 93 foreach(T; AliasSeq!(int, ushort, double)) 94 assert(isBasicNum!T && isNumeric!T); 95 96 assert(!isBasicNum!(SmartInt!int)); 97 assert( isNumeric!(SmartInt!int)); 98 99 foreach(T; AliasSeq!(int[], bool)) 100 assert(!(isBasicNum!T || isNumeric!T)); 101 } 102 103 /// See `std.traits.isFloatingPoint` 104 alias isFloatingPoint = bsct.isFloatingPoint; 105 106 /// See `future.traits.isFixedPoint` 107 alias isBasicFixed = bsct.isFixedPoint; 108 /// `checkedint`-aware wrapper for `future.traits.isFixedPoint` 109 template isFixedPoint(T) 110 { 111 alias isFixedPoint = isEx!(isBasicFixed, T); 112 } 113 /// 114 unittest 115 { 116 foreach(T; AliasSeq!(int, ushort, bool)) 117 assert(isBasicFixed!T && isFixedPoint!T); 118 119 assert(!isBasicFixed!(SmartInt!int)); 120 assert( isFixedPoint!(SmartInt!int)); 121 122 foreach(T; AliasSeq!(double, int[])) 123 assert(!(isBasicFixed!T || isFixedPoint!T)); 124 } 125 126 /// See `std.traits.isIntegral` 127 alias isBasicInt = bsct.isIntegral; 128 /// `checkedint`-aware wrapper for `std.traits.isIntegral` 129 template isIntegral(T) 130 { 131 alias isIntegral = isEx!(isBasicInt, T); 132 } 133 /// 134 unittest 135 { 136 foreach(T; AliasSeq!(int, ushort)) 137 assert(isBasicInt!T && isIntegral!T); 138 139 assert(!isBasicInt!(SmartInt!int)); 140 assert( isIntegral!(SmartInt!int)); 141 142 foreach(T; AliasSeq!(double, int[], bool)) 143 assert(!(isBasicInt!T || isIntegral!T)); 144 } 145 146 /// See `std.traits.isSomeChar` 147 alias isSomeChar = bsct.isSomeChar; 148 /// See `std.traits.isBoolean` 149 alias isBoolean = bsct.isBoolean; 150 151 /// See `std.traits.isSigned` 152 alias isBasicSigned = bsct.isSigned; 153 /// `checkedint`-aware wrapper for `std.traits.isSigned` 154 template isSigned(T) 155 { 156 alias isSigned = isEx!(isBasicSigned, T); 157 } 158 /// 159 unittest 160 { 161 foreach(T; AliasSeq!(int, double)) 162 assert(isBasicSigned!T && isSigned!T); 163 164 assert(!isBasicSigned!(SmartInt!int)); 165 assert( isSigned!(SmartInt!int)); 166 167 foreach(T; AliasSeq!(ushort, int[], bool)) 168 assert(!(isBasicSigned!T || isSigned!T)); 169 } 170 171 /// See `std.traits.isUnsigned` 172 alias isBasicUnsigned = bsct.isUnsigned; 173 /// `checkedint`-aware wrapper for `isUnsigned` 174 template isUnsigned(T) 175 { 176 alias isUnsigned = isEx!(isBasicUnsigned, T); 177 } 178 /// 179 unittest 180 { 181 foreach(T; AliasSeq!(ushort)) 182 assert(isBasicUnsigned!T && isUnsigned!T); 183 184 assert(!isBasicUnsigned!(SmartInt!uint)); 185 assert( isUnsigned!(SmartInt!uint)); 186 187 foreach(T; AliasSeq!(double, int[], bool)) 188 assert(!(isBasicUnsigned!T || isUnsigned!T)); 189 } 190 191 /// `checkedint`-aware version of `std.traits.mostNegative` 192 template mostNegative(T) 193 if (isNumeric!T) 194 { 195 static if (isFloatingPoint!T) 196 enum mostNegative = -T.max; 197 else 198 enum mostNegative = T.min; 199 } 200 /// 201 unittest 202 { 203 assert(mostNegative!int == int.min); 204 static assert(is(typeof(mostNegative!int) == int)); 205 assert(mostNegative!(SmartInt!int) == SmartInt!(int).min); 206 static assert(is(typeof(mostNegative!(SmartInt!int)) == SmartInt!int)); 207 } 208 209 private template TransEx(alias TypeTransform, T) 210 { 211 static if (isCheckedInt!T) 212 { 213 import checkedint : SmartInt, SafeInt; 214 import future.traits0 : CopyTypeQualifiers, Select; 215 216 alias TTB = TypeTransform!(CopyTypeQualifiers!(T, BasicScalar!T)); 217 alias CheckedInt = Select!(isSmartInt!T, SmartInt, SafeInt); 218 alias TransEx = CopyTypeQualifiers!(TTB, CheckedInt!(TTB, intFlagPolicyOf!T, hasBitOps!T)); 219 } else 220 alias TransEx = TypeTransform!T; 221 } 222 223 /// `checkedint`-aware wrapper for `std.traits.Signed` 224 template Signed(T) 225 { 226 alias Signed = TransEx!(bsct.Signed, T); 227 } 228 /// 229 unittest 230 { 231 static assert(is(Signed!int == int)); 232 static assert(is(Signed!(SmartInt!int) == SmartInt!int)); 233 static assert(is(Signed!ulong == long)); 234 static assert(is(Signed!(SmartInt!ulong) == SmartInt!long)); 235 } 236 237 /// `checkedint`-aware wrapper for `std.traits.Unsigned` 238 template Unsigned(T) 239 { 240 alias Unsigned = TransEx!(bsct.Unsigned, T); 241 } 242 /// 243 unittest 244 { 245 static assert(is(Unsigned!int == uint)); 246 static assert(is(Unsigned!(SmartInt!int) == SmartInt!uint)); 247 static assert(is(Unsigned!ulong == ulong)); 248 static assert(is(Unsigned!(SmartInt!ulong) == SmartInt!ulong)); 249 } 250 251 /// `checkedint`-aware wrapper for `future.traits.Promoted` 252 template Promoted(T) 253 { 254 alias Promoted = TransEx!(bsct.Promoted, T); 255 } 256 /// 257 unittest 258 { 259 static assert(is(Promoted!byte == int)); 260 static assert(is(Promoted!(SmartInt!byte) == SmartInt!int)); 261 static assert(is(Promoted!int == int)); 262 static assert(is(Promoted!(SmartInt!int) == SmartInt!int)); 263 }