1 /** 2 * Contains traits for runtime internal usage. 3 * 4 * Copyright: Copyright Digital Mars 2014 -. 5 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 * Authors: Martin Nowak 7 * Source: $(DRUNTIMESRC core/internal/_traits.d) 8 */ 9 module core.internal.traits; 10 11 /// taken from std.typetuple.TypeTuple 12 template TypeTuple(TList...) 13 { 14 alias TypeTuple = TList; 15 } 16 alias AliasSeq = TypeTuple; 17 18 template FieldTypeTuple(T) 19 { 20 static if (is(T == struct) || is(T == union)) 21 alias FieldTypeTuple = typeof(T.tupleof[0 .. $ - __traits(isNested, T)]); 22 else static if (is(T == class)) 23 alias FieldTypeTuple = typeof(T.tupleof); 24 else 25 { 26 alias FieldTypeTuple = TypeTuple!T; 27 } 28 } 29 30 T trustedCast(T, U)(auto ref U u) @trusted pure nothrow 31 { 32 return cast(T)u; 33 } 34 35 template Unconst(T) 36 { 37 static if (is(T U == immutable U)) alias Unconst = U; 38 else static if (is(T U == inout const U)) alias Unconst = U; 39 else static if (is(T U == inout U)) alias Unconst = U; 40 else static if (is(T U == const U)) alias Unconst = U; 41 else alias Unconst = T; 42 } 43 44 /// taken from std.traits.Unqual 45 template Unqual(T) 46 { 47 version (none) // Error: recursive alias declaration @@@BUG1308@@@ 48 { 49 static if (is(T U == const U)) alias Unqual = Unqual!U; 50 else static if (is(T U == immutable U)) alias Unqual = Unqual!U; 51 else static if (is(T U == inout U)) alias Unqual = Unqual!U; 52 else static if (is(T U == shared U)) alias Unqual = Unqual!U; 53 else alias Unqual = T; 54 } 55 else // workaround 56 { 57 static if (is(T U == immutable U)) alias Unqual = U; 58 else static if (is(T U == shared inout const U)) alias Unqual = U; 59 else static if (is(T U == shared inout U)) alias Unqual = U; 60 else static if (is(T U == shared const U)) alias Unqual = U; 61 else static if (is(T U == shared U)) alias Unqual = U; 62 else static if (is(T U == inout const U)) alias Unqual = U; 63 else static if (is(T U == inout U)) alias Unqual = U; 64 else static if (is(T U == const U)) alias Unqual = U; 65 else alias Unqual = T; 66 } 67 } 68 69 // Substitute all `inout` qualifiers that appears in T to `const` 70 template substInout(T) 71 { 72 static if (is(T == immutable)) 73 { 74 alias substInout = T; 75 } 76 else static if (is(T : shared const U, U) || is(T : const U, U)) 77 { 78 // U is top-unqualified 79 mixin("alias substInout = " 80 ~ (is(T == shared) ? "shared " : "") 81 ~ (is(T == const) || is(T == inout) ? "const " : "") // substitute inout to const 82 ~ "substInoutForm!U;"); 83 } 84 else 85 static assert(0); 86 } 87 88 private template substInoutForm(T) 89 { 90 static if (is(T == struct) || is(T == class) || is(T == union) || is(T == interface)) 91 { 92 alias substInoutForm = T; // prevent matching to the form of alias-this-ed type 93 } 94 else static if (is(T : V[K], K, V)) alias substInoutForm = substInout!V[substInout!K]; 95 else static if (is(T : U[n], U, size_t n)) alias substInoutForm = substInout!U[n]; 96 else static if (is(T : U[], U)) alias substInoutForm = substInout!U[]; 97 else static if (is(T : U*, U)) alias substInoutForm = substInout!U*; 98 else alias substInoutForm = T; 99 } 100 101 /// used to declare an extern(D) function that is defined in a different module 102 template externDFunc(string fqn, T:FT*, FT) if (is(FT == function)) 103 { 104 static if (is(FT RT == return) && is(FT Args == function)) 105 { 106 import core.demangle : mangleFunc; 107 enum decl = { 108 string s = "extern(D) RT externDFunc(Args)"; 109 foreach (attr; __traits(getFunctionAttributes, FT)) 110 s ~= " " ~ attr; 111 return s ~ ";"; 112 }(); 113 pragma(mangle, mangleFunc!T(fqn)) mixin(decl); 114 } 115 else 116 static assert(0); 117 } 118 119 template staticIota(int beg, int end) 120 { 121 static if (beg + 1 >= end) 122 { 123 static if (beg >= end) 124 { 125 alias staticIota = TypeTuple!(); 126 } 127 else 128 { 129 alias staticIota = TypeTuple!(+beg); 130 } 131 } 132 else 133 { 134 enum mid = beg + (end - beg) / 2; 135 alias staticIota = TypeTuple!(staticIota!(beg, mid), staticIota!(mid, end)); 136 } 137 } 138 139 private struct __InoutWorkaroundStruct {} 140 @property T rvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init); 141 @property ref T lvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init); 142 143 // taken from std.traits.isAssignable 144 template isAssignable(Lhs, Rhs = Lhs) 145 { 146 enum isAssignable = __traits(compiles, lvalueOf!Lhs = rvalueOf!Rhs) && __traits(compiles, lvalueOf!Lhs = lvalueOf!Rhs); 147 } 148 149 // taken from std.traits.isInnerClass 150 template isInnerClass(T) if (is(T == class)) 151 { 152 static if (is(typeof(T.outer))) 153 { 154 template hasOuterMember(T...) 155 { 156 static if (T.length == 0) 157 enum hasOuterMember = false; 158 else 159 enum hasOuterMember = T[0] == "outer" || hasOuterMember!(T[1 .. $]); 160 } 161 enum isInnerClass = __traits(isSame, typeof(T.outer), __traits(parent, T)) && !hasOuterMember!(__traits(allMembers, T)); 162 } 163 else 164 enum isInnerClass = false; 165 } 166 167 template dtorIsNothrow(T) 168 { 169 enum dtorIsNothrow = is(typeof(function{T t=void;}) : void function() nothrow); 170 } 171 172 // taken from std.meta.allSatisfy 173 template allSatisfy(alias F, T...) 174 { 175 static foreach (Ti; T) 176 { 177 static if (!is(typeof(allSatisfy) == bool) && // not yet defined 178 !F!(Ti)) 179 { 180 enum allSatisfy = false; 181 } 182 } 183 static if (!is(typeof(allSatisfy) == bool)) // if not yet defined 184 { 185 enum allSatisfy = true; 186 } 187 } 188 189 // taken from std.meta.anySatisfy 190 template anySatisfy(alias F, T...) 191 { 192 static foreach (Ti; T) 193 { 194 static if (!is(typeof(anySatisfy) == bool) && // not yet defined 195 F!(Ti)) 196 { 197 enum anySatisfy = true; 198 } 199 } 200 static if (!is(typeof(anySatisfy) == bool)) // if not yet defined 201 { 202 enum anySatisfy = false; 203 } 204 } 205 206 // simplified from std.traits.maxAlignment 207 template maxAlignment(U...) 208 { 209 static if (U.length == 0) 210 static assert(0); 211 else static if (U.length == 1) 212 enum maxAlignment = U[0].alignof; 213 else static if (U.length == 2) 214 enum maxAlignment = U[0].alignof > U[1].alignof ? U[0].alignof : U[1].alignof; 215 else 216 { 217 enum a = maxAlignment!(U[0 .. ($+1)/2]); 218 enum b = maxAlignment!(U[($+1)/2 .. $]); 219 enum maxAlignment = a > b ? a : b; 220 } 221 } 222 223 // std.traits.Fields 224 template Fields(T) 225 { 226 static if (is(T == struct) || is(T == union)) 227 alias Fields = typeof(T.tupleof[0 .. $ - __traits(isNested, T)]); 228 else static if (is(T == class)) 229 alias Fields = typeof(T.tupleof); 230 else 231 alias Fields = TypeTuple!T; 232 } 233 234 // std.traits.hasElaborateDestructor 235 template hasElaborateDestructor(S) 236 { 237 static if (__traits(isStaticArray, S) && S.length) 238 { 239 enum bool hasElaborateDestructor = hasElaborateDestructor!(typeof(S.init[0])); 240 } 241 else static if (is(S == struct)) 242 { 243 enum hasElaborateDestructor = __traits(hasMember, S, "__dtor") 244 || anySatisfy!(.hasElaborateDestructor, Fields!S); 245 } 246 else 247 { 248 enum bool hasElaborateDestructor = false; 249 } 250 } 251 252 // std.traits.hasElaborateCopyDestructor 253 template hasElaborateCopyConstructor(S) 254 { 255 static if (__traits(isStaticArray, S) && S.length) 256 { 257 enum bool hasElaborateCopyConstructor = hasElaborateCopyConstructor!(typeof(S.init[0])); 258 } 259 else static if (is(S == struct)) 260 { 261 enum hasElaborateCopyConstructor = __traits(hasMember, S, "__xpostblit"); 262 } 263 else 264 { 265 enum bool hasElaborateCopyConstructor = false; 266 } 267 } 268 269 template hasElaborateAssign(S) 270 { 271 static if (__traits(isStaticArray, S) && S.length) 272 { 273 enum bool hasElaborateAssign = hasElaborateAssign!(typeof(S.init[0])); 274 } 275 else static if (is(S == struct)) 276 { 277 enum hasElaborateAssign = is(typeof(S.init.opAssign(rvalueOf!S))) || 278 is(typeof(S.init.opAssign(lvalueOf!S))) || 279 anySatisfy!(.hasElaborateAssign, FieldTypeTuple!S); 280 } 281 else 282 { 283 enum bool hasElaborateAssign = false; 284 } 285 } 286 287 // std.meta.Filter 288 template Filter(alias pred, TList...) 289 { 290 static if (TList.length == 0) 291 { 292 alias Filter = TypeTuple!(); 293 } 294 else static if (TList.length == 1) 295 { 296 static if (pred!(TList[0])) 297 alias Filter = TypeTuple!(TList[0]); 298 else 299 alias Filter = TypeTuple!(); 300 } 301 else 302 { 303 alias Filter = 304 TypeTuple!( 305 Filter!(pred, TList[ 0 .. $/2]), 306 Filter!(pred, TList[$/2 .. $ ])); 307 } 308 } 309 310 // std.meta.staticMap 311 template staticMap(alias F, T...) 312 { 313 static if (T.length == 0) 314 { 315 alias staticMap = TypeTuple!(); 316 } 317 else static if (T.length == 1) 318 { 319 alias staticMap = TypeTuple!(F!(T[0])); 320 } 321 else 322 { 323 alias staticMap = 324 TypeTuple!( 325 staticMap!(F, T[ 0 .. $/2]), 326 staticMap!(F, T[$/2 .. $ ])); 327 } 328 } 329 330 // std.exception.assertCTFEable 331 version (unittest) package(core) 332 void assertCTFEable(alias dg)() 333 { 334 static assert({ cast(void) dg(); return true; }()); 335 cast(void) dg(); 336 }