1 #!/usr/bin/env rdmd-dev-module 2 3 /** Various extensions to std.traits. 4 Copyright: Per Nordlöw 2014-. 5 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 Authors: $(WEB Per Nordlöw) 7 See also: http://forum.dlang.org/thread/jbyixfbuefvdlttnyclu@forum.dlang.org#post-mailman.2199.1353742037.5162.digitalmars-d-learn:40puremagic.com 8 */ 9 module traits_ex; 10 11 import std.traits: isArray, ParameterTypeTuple, isStaticArray, isDynamicArray, isSomeChar, isSomeString, isExpressions, isIntegral, isSigned, isUnsigned; 12 import std.range: ElementType, isForwardRange, isRandomAccessRange, isInputRange, isBidirectionalRange, isOutputRange, isIterable; 13 import std.typecons : Tuple; 14 15 /** Returns: true iff $(D ptr) is handled by the garbage collector (GC). */ 16 bool isGCPointer(void* ptr) 17 { 18 import core.memory; 19 return !!GC.addrOf(ptr); 20 } 21 alias inGC = isGCPointer; 22 alias isGCed = isGCPointer; 23 24 /** Returns: true iff all values $(D V) are the same. 25 See also: http://forum.dlang.org/post/iflpslqgrixdjwrlqqvn@forum.dlang.org 26 See also: http://forum.dlang.org/post/mheumktihihfsxxxapff@forum.dlang.org 27 */ 28 template allSame(V ...) 29 if (isExpressions!V) 30 { 31 static if (V.length <= 1) 32 enum allSame = true; 33 else static if (V.length & 1) 34 enum allSame = (V[$ - 1] == V[0] && 35 V[0 .. $/2] == V[$/2 .. $-1] && 36 allSame!(V[0 .. $/2])); 37 else 38 enum allSame = (V[0 .. $/2] == V[$/2 .. $] && 39 allSame!(V[0 .. $/2])); 40 } 41 42 unittest 43 { 44 static assert( allSame!()); 45 static assert( allSame!(42)); 46 static assert( allSame!(42, 42, 42)); 47 static assert(!allSame!(42, 43, 42)); 48 } 49 50 template allSameIterative(V...) 51 if (isExpressions!V) 52 { 53 bool impl_(V...)() 54 { 55 static if (V.length >= 2) 56 { 57 foreach (i, _; V[0 .. $ - 1]) 58 { 59 if (V[i] != V[i + 1]) 60 { 61 return false; 62 } 63 } 64 return true; 65 } 66 else 67 { 68 return true; 69 } 70 } 71 enum allSameIterative = impl_!V(); 72 } 73 74 unittest 75 { 76 static assert( allSameIterative!()); 77 static assert( allSameIterative!(42)); 78 static assert( allSameIterative!(42, 42, 42)); 79 static assert(!allSameIterative!(42, 43, 42)); 80 } 81 82 template allSameRecursive(V...) 83 if (isExpressions!(V)) 84 { 85 static if (V.length <= 1) 86 enum allSameRecursive = true; 87 else 88 enum allSameRecursive = V[0] == V[1] && allSameRecursive!(V[1..$]); 89 } 90 91 unittest 92 { 93 static assert(allSameRecursive!()); 94 static assert(allSameRecursive!(42)); 95 static assert(!allSameRecursive!(41, 42)); 96 static assert(allSameRecursive!(42, 42, 42)); 97 } 98 99 /** Returns: true iff all types $(D T) are the same. */ 100 template allSameType(T...) 101 { 102 static if (T.length <= 1) 103 enum allSameType = true; 104 else 105 enum allSameType = is(T[0] == T[1]) && allSameType!(T[1..$]); 106 } 107 108 enum allSameType1(T...) = !T.length || (is(T[0] == T[T.length > 1]) && allSameType1!(T[1 .. $])); 109 110 unittest 111 { 112 static assert(allSameType!(int, int)); 113 static assert(!allSameType!(int, double)); 114 static assert(!allSameType!(int, int, double)); 115 static assert(allSameType!(Tuple!(int, int, int).Types, int)); 116 } 117 118 alias allTypesSame = allSameType; 119 alias isHomogeneous = allSameType; 120 enum isHomogeneousTuple(T) = isHomogeneous!(T.Types); 121 122 unittest 123 { 124 static assert(isHomogeneousTuple!(Tuple!(int, int, int))); 125 static assert(isHomogeneousTuple!(Tuple!(float, float, float))); 126 static assert(!isHomogeneousTuple!(Tuple!(int, float, double))); 127 } 128 129 enum isHomogeneousTupleOf(T, E) = (isHomogeneous!(T.Types) && 130 is(Unqual!(T.Types[0]) == Unqual!E)); 131 132 unittest 133 { 134 import std.typecons : Tuple; 135 static assert(isHomogeneousTupleOf!(Tuple!(int, int, int), int)); 136 static assert(isHomogeneousTupleOf!(Tuple!(float, float, float), float)); 137 static assert(!isHomogeneousTupleOf!(Tuple!(float, float, float), int)); 138 } 139 140 /** 141 Returns $(D true) if at least one type in the $(D Tuple T) 142 is not the same as the others. 143 */ 144 enum isHeterogeneous(T) = !isHomogeneous!T; 145 146 import std.typecons : isTuple; 147 148 /** 149 Returns $(D true) if all types in the $(D Tuple T) are the same. 150 TODO: Remove when this is merged: https://github.com/D-Programming-Language/phobos/pull/3395 151 See also: https://github.com/D-Programming-Language/phobos/pull/1672/files 152 */ 153 template allSameTypesInTuple(T) 154 if (isTuple!T) 155 { 156 alias types = T.Types; 157 static if (types.length > 0) 158 { 159 template isSameTypeAsHead(U) 160 { 161 enum isSameTypeAsHead = is(U == types[0]); 162 } 163 import std.meta : allSatisfy; 164 enum allSameTypesInTuple = allSatisfy!(isSameTypeAsHead, types); 165 } 166 else 167 enum allSameTypesInTuple = true; 168 } 169 170 @safe pure nothrow unittest 171 { 172 import std.typecons : Tuple; 173 alias HOTUP = Tuple!(int, int, int); 174 static assert(allSameTypesInTuple!HOTUP); 175 176 HOTUP hotup = HOTUP(1, 2, 3); 177 static assert(allSameTypesInTuple!(typeof(hotup))); 178 179 alias HETUP = Tuple!(string, bool, float); 180 static assert(!allSameTypesInTuple!(HETUP)); 181 182 HETUP hetup = HETUP("test", false, 2.345); 183 static assert(!allSameTypesInTuple!(typeof(hetup))); 184 185 alias ZTUP = Tuple!(); 186 static assert(allSameTypesInTuple!ZTUP); 187 188 ZTUP ztup = ZTUP(); 189 static assert(allSameTypesInTuple!(typeof(ztup))); 190 } 191 192 /** Return Tuple $(D tup) as a Static Array. 193 See also: http://dpaste.dzfl.pl/d0059e6e6c09 194 */ 195 inout (T.Types[0])[T.length] asStaticArray(T)(inout T tup) 196 if (allSameType!(T.Types)) 197 { 198 return *cast(T.Types[0][T.length]*)&tup; // hackish 199 } 200 201 pure nothrow @nogc unittest 202 { 203 import std.typecons: tuple; 204 auto tup = tuple("a", "b", "c", "d"); 205 string[4] arr = ["a", "b", "c", "d"]; 206 static assert(is(typeof(tup.asStaticArray()) == typeof(arr))); 207 assert(tup.asStaticArray() == arr); 208 } 209 210 /** Return Tuple $(D tup) as a Dynamic Array. 211 */ 212 auto asDynamicArray(T)(inout T tup) 213 if (allSameType!(T.Types)) 214 { 215 alias E = T.Types[0]; 216 E[] a = new E[T.length]; 217 a.length = T.length; 218 foreach (i, e; tup) 219 { 220 a[i] = e; 221 } 222 return a; 223 } 224 225 pure nothrow unittest 226 { 227 import std.typecons: tuple; 228 auto tup = tuple("a", "b", "c", "d"); 229 string[4] arr = ["a", "b", "c", "d"]; 230 assert(tup.asDynamicArray() == arr); 231 } 232 233 /// Useful aliases for combinations of range predicates. 234 enum isIterableOf(R, E) = isIterable!R && is(ElementType!R == E); 235 enum isIterableOfUnqual(R, E) = isIterable!R && is(Unqual!(ElementType!R) == Unqual!E); 236 enum isIterableOfSomeString(R) = (isIterable!R && isSomeString!(ElementType!R)); 237 238 @safe pure nothrow @nogc unittest 239 { 240 alias E = string; 241 alias I = int; 242 alias R = typeof(["a", "b"]); 243 static assert(isIterableOf!(R, E)); 244 static assert(isIterableOfUnqual!(R, const(E))); 245 static assert(isIterableOfSomeString!(R)); 246 static assert(!isIterableOf!(R, I)); 247 } 248 249 /// Useful aliases for combinations of range predicates. 250 enum isRandomAccessRangeOf(R, E) = isRandomAccessRange!R && is(ElementType!R == E); 251 enum isForwardRangeOf(R, E) = isForwardRange!R && is(ElementType!R == E); 252 enum isInputRangeOf(R, E) = isInputRange!R && is(ElementType!R == E); 253 enum isBidirectionalRangeOf(R, E) = isBidirectionalRange!R && is(ElementType!R == E); 254 enum isOutputRangeOf(R, E) = isOutputRange!R && is(ElementType!R == E); 255 enum isArrayOf(R, E) = isArray!R && is(ElementType!R == E); 256 enum isArrayOfSomeString(R) = isArray!R && isSomeString!(ElementType!R); 257 258 unittest 259 { 260 alias R = typeof(["a", "b"]); 261 static assert(isArrayOf!(R, string)); 262 static assert(isArrayOfSomeString!(R)); 263 } 264 265 alias isSource = isInputRange; 266 alias isRange = isInputRange; 267 alias isSourceOf = isInputRangeOf; 268 alias isSink = isOutputRange; 269 alias isSinkOf = isOutputRangeOf; 270 271 enum isSourceOfSomeChar(R) = (isSource!R && isSomeChar!(ElementType!R)); 272 alias isSomeCharSource = isSourceOfSomeChar; 273 alias isSomeLazyString = isSourceOfSomeChar; 274 275 unittest 276 { 277 import std.meta : AliasSeq; 278 foreach (Ch; AliasSeq!(char, wchar, dchar)) 279 { 280 assert(isSourceOfSomeChar!(Ch[])); 281 assert(isSourceOfSomeChar!(const(Ch)[])); 282 assert(isSourceOfSomeChar!(immutable(Ch)[])); 283 } 284 } 285 286 enum isSourceOfSomeString(R) = (isSource!R && isSomeString!(ElementType!R)); 287 alias isSomeStringSource = isSourceOfSomeString; 288 289 import std.functional: unaryFun, binaryFun; 290 291 /* TODO Do we need use of unaryFun and binaryFun here? */ 292 alias isEven = unaryFun!(a => (a & 1) == 0); // Limit to Integers? 293 alias isOdd = unaryFun!(a => (a & 1) == 1); // Limit to Integers? 294 alias lessThan = binaryFun!((a, b) => a < b); 295 alias greaterThan = binaryFun!((a, b) => a > b); 296 297 /** Check if $(D T) has an even length. */ 298 enum hasEvenLength(T...) = !(T.length & 1); 299 unittest 300 { 301 static assert(!hasEvenLength!(1)); 302 static assert(hasEvenLength!(1, 2)); 303 static assert(!hasEvenLength!(1, 2, 3)); 304 static assert(hasEvenLength!(1, 2, 3, 4)); 305 } 306 307 enum isSignedIntegral(T) = isIntegral!T && isSigned!T; 308 enum isUnsignedIntegral(T) = isIntegral!T && isUnsigned!T; 309 310 enum isString (T) = is(T == string); 311 enum isWString(T) = is(T == wstring); 312 enum isDString(T) = is(T == dstring); 313 314 enum isEnum(T) = is(T == enum); 315 unittest 316 { 317 interface I {} 318 class A {} 319 class B( T ) {} 320 class C : B!int, I {} 321 struct S {} 322 enum E { X } 323 static assert(!isEnum!A ); 324 static assert(!isEnum!( B!int ) ); 325 static assert(!isEnum!C ); 326 static assert(!isEnum!I ); 327 static assert(isEnum!E ); 328 static assert(!isEnum!int ); 329 static assert(!isEnum!( int* ) ); 330 } 331 332 /* See also: http://d.puremagic.com/issues/show_bug.cgi?id=4427 */ 333 enum isStruct(T) = is(T == struct); 334 unittest 335 { 336 interface I {} 337 class A {} 338 class B( T ) {} 339 class C : B!int, I {} 340 struct S {} 341 static assert(!isStruct!A ); 342 static assert(!isStruct!( B!int ) ); 343 static assert(!isStruct!C ); 344 static assert(!isStruct!I ); 345 static assert(isStruct!S ); 346 static assert(!isStruct!int ); 347 static assert(!isStruct!( int* ) ); 348 } 349 350 enum isClass(T) = is(T == class); 351 unittest 352 { 353 interface I {} 354 class A {} 355 class B( T ) {} 356 class C : B!int, I {} 357 struct S {} 358 static assert(isClass!A ); 359 static assert(isClass!( B!int ) ); 360 static assert(isClass!C ); 361 static assert(!isClass!I ); 362 static assert(!isClass!S ); 363 static assert(!isClass!int ); 364 static assert(!isClass!( int* ) ); 365 } 366 367 enum isInterface(T) = is(T == interface); 368 unittest 369 { 370 interface I {} 371 class A {} 372 class B( T ) {} 373 class C : B!int, I {} 374 struct S {} 375 static assert(!isInterface!A ); 376 static assert(!isInterface!( B!int ) ); 377 static assert(!isInterface!C ); 378 static assert(isInterface!I ); 379 static assert(!isInterface!S ); 380 static assert(!isInterface!int ); 381 static assert(!isInterface!( int* ) ); 382 } 383 384 template isType(T) { enum isType = true; } 385 template isType(alias T) { enum isType = false; } 386 387 unittest 388 { 389 struct S { alias int foo; } 390 static assert(isType!int ); 391 static assert(isType!float ); 392 static assert(isType!string ); 393 //static assert(isType!S ); // Bugzilla 4431 394 static assert(isType!( S.foo ) ); 395 static assert(!isType!4 ); 396 static assert(!isType!"Hello world!" ); 397 } 398 399 /** Note that `NotNull!T` is not `isNullable` :) */ 400 template isNullable(T) 401 { 402 import std.traits: isAssignable; 403 enum isNullable = isAssignable!(T, typeof(null)); 404 } 405 /// 406 unittest 407 { 408 static assert(isNullable!(int*)); 409 } 410 411 enum nameOf(alias a) = a.stringof; 412 /// 413 unittest 414 { 415 int var; 416 static assert(nameOf!var == var.stringof); 417 } 418 419 /** Is $(D ElementType) of type of $(D a). */ 420 alias ElementTypeOf(alias a) = ElementType!(typeof(a)); 421 alias elTypeOf = ElementTypeOf; 422 /// 423 unittest 424 { 425 int[] var; 426 static assert(is(ElementTypeOf!var == int)); 427 } 428 429 template Chainable() 430 { 431 import std.range: chain; 432 auto ref opCast(Range)(Range r) 433 { 434 return chain(this, r); 435 } 436 } 437 unittest { mixin Chainable; } 438 439 /** Returns true if `T` is an instance of the template `S`. 440 See also: http://forum.dlang.org/thread/mailman.2901.1316118301.14074.digitalmars-d-learn@puremagic.com#post-zzdpfhsgfdgpszdbgbbt:40forum.dlang.org 441 */ 442 template isA(alias S, T) 443 { 444 import std.traits : isInstanceOf; 445 enum isA = isInstanceOf!(S, T); 446 } 447 448 unittest 449 { 450 import std.traits : isInstanceOf; 451 import std.range : SortedRange, assumeSorted; 452 const x = [1, 2, 3].assumeSorted; 453 static assert(isInstanceOf!(SortedRange, typeof(x))); 454 static assert(isA!(SortedRange, typeof(x))); 455 } 456 457 /** See also: http://forum.dlang.org/thread/bug-6384-3@http.d.puremagic.com/issues/ 458 See also: http://forum.dlang.org/thread/jrqiiicmtpenzokfxvlz@forum.dlang.org */ 459 enum isOpBinary(T, string op, U) = is(typeof(mixin("T.init" ~ op ~ "U.init"))); 460 461 enum isComparable(T) = is(typeof({ return T.init < T.init; })); 462 enum isEquable (T) = is(typeof({ return T.init == T.init; })); 463 enum isNotEquable(T) = is(typeof({ return T.init != T.init; })); 464 465 unittest 466 { 467 static assert(isComparable!int); 468 static assert(isComparable!string); 469 static assert(!isComparable!creal); 470 static struct Foo {} 471 static assert(!isComparable!Foo); 472 static struct Bar { bool opCmp(Bar) { return true; } } 473 static assert(isComparable!Bar); 474 } 475 476 // TODO Make variadic 477 enum areComparable(T, U) = is(typeof({ return T.init < U.init; })); 478 enum areEquable (T, U) = is(typeof({ return T.init == U.init; })); 479 enum areNotEquable(T, U) = is(typeof({ return T.init != U.init; })); 480 481 unittest 482 { 483 static assert(areComparable!(int, float)); 484 static assert(areEquable!(int, float)); 485 static assert(areNotEquable!(int, float)); 486 487 static assert(!areComparable!(int, string)); 488 static assert(!areEquable!(int, string)); 489 static assert(!areNotEquable!(int, string)); 490 } 491 492 enum isValueType(T) = !hasIndirections!T; 493 // enum isValueType(T) = isScalarType!T || isStaticArray!T || isStruct!T; 494 enum hasValueSemantics(T) = !hasIndirections!T; // TODO merge with isValueType 495 496 /* See also: http://forum.dlang.org/thread/hsfkgcmkjgvrfuyjoujj@forum.dlang.org#post-hsfkgcmkjgvrfuyjoujj:40forum.dlang.org */ 497 enum isReferenceType(T) = isDynamicArray!T || isSomeString!T || isClass!T; 498 499 enum arityMin0(alias fun) = __traits(compiles, fun()); 500 501 /** TODO Unite into a variadic. 502 See also: http://forum.dlang.org/thread/bfjwbhkyehcloqcjzxck@forum.dlang.org#post-atjmewbffdzeixrviyoa:40forum.dlang.org 503 */ 504 enum isCallableWith(alias fun, T) = (is(typeof(fun(T.init))) || 505 is(typeof(T.init.fun))); // TODO Are both these needed? 506 unittest 507 { 508 auto sqr(T)(T x) { return x*x; } 509 assert(isCallableWith!(sqr, int)); 510 assert(!isCallableWith!(sqr, string)); 511 } 512 513 /* TODO Unite into a variadic. 514 See also: http://forum.dlang.org/thread/bfjwbhkyehcloqcjzxck@forum.dlang.org#post-atjmewbffdzeixrviyoa:40forum.dlang.org 515 */ 516 enum isCallableWith(alias fun, T, U) = (is(typeof(fun(T.init, 517 U.init))) || 518 is(typeof(T.init.fun(U)))); // TODO Are both these needed? 519 unittest 520 { 521 auto sqr2(T)(T x, T y) { return x*x + y*y; } 522 assert(isCallableWith!(sqr2, int, int)); 523 assert(!isCallableWith!(sqr2, int, string)); 524 } 525 526 /** Check if $(D T) is a Sorted Range. 527 See also: http://forum.dlang.org/thread/lt1g3q$15fe$1@digitalmars.com 528 */ 529 template isSortedRange(T) 530 { 531 import std.traits : isInstanceOf; 532 import std.range: SortedRange; 533 enum isSortedRange = isInstanceOf!(SortedRange, T); // TODO Or use: __traits(isSame, TemplateOf!R, SortedRange) 534 } 535 536 /** Check if Function $(D expr) is callable at compile-time. 537 See also: http://forum.dlang.org/thread/owlwzvidwwpsrelpkbok@forum.dlang.org 538 */ 539 template isCTFEable(alias fun) 540 { 541 template isCTFEable_aux(alias T) 542 { 543 enum isCTFEable_aux = T; 544 } 545 enum isCTFEable = __traits(compiles, isCTFEable_aux!(fun())); 546 } 547 548 template isCTFEable2(fun...) 549 { 550 enum isCTFEable2 = true; 551 } 552 553 unittest 554 { 555 int fun1() { return 1; } 556 auto fun1_N() 557 { 558 import std.array; 559 //would return Error: gc_malloc cannot be interpreted at compile time, 560 /* because it has no available source code due to a bug */ 561 return [1].array; 562 } 563 int fun2(int x) 564 { 565 return 1; 566 } 567 auto fun2_N(int x){ 568 import std.array; 569 //same as fun1_N 570 return [1].array; 571 } 572 573 int a1; 574 enum a2=0; 575 576 static assert(!isCTFEable!(()=>a1)); 577 static assert(isCTFEable!(()=>a2)); 578 579 static assert(isCTFEable!fun1); 580 /* static assert(!isCTFEable!fun1_N); */ 581 582 static assert(isCTFEable!(()=>fun2(0))); 583 /* static assert(!isCTFEable!(()=>fun2_N(0))); */ 584 //NOTE:an alternate syntax which could be implemented would be: static 585 /* assert(!isCTFEable!(fun2_N,0)); */ 586 } 587 588 /** Check if the value of $(D expr) is known at compile-time. 589 See also: http://forum.dlang.org/thread/owlwzvidwwpsrelpkbok@forum.dlang.org 590 */ 591 enum isCTEable(alias expr) = __traits(compiles, { enum id = expr; }); 592 593 unittest 594 { 595 static assert(isCTEable!11); 596 enum x = 11; 597 static assert(isCTEable!x); 598 auto y = 11; 599 static assert(!isCTEable!y); 600 } 601 602 import std.traits: functionAttributes, FunctionAttribute, isCallable, ParameterTypeTuple, Unqual; 603 604 /** Returns $(D true) if $(D T) is not $(D const) or $(D immutable). 605 Note that isConst is true for string, or immutable(char)[], because the 606 'head' is mutable. 607 */ 608 import std.traits : isMutable; 609 enum isConst(T) = !isMutable!T; 610 611 unittest 612 { 613 static assert(isConst!(const(int))); 614 static assert(!isConst!int); 615 } 616 617 import std.traits : CommonType; 618 619 enum bool haveCommonType(Types...) = !is(CommonType!Types == void); 620 unittest 621 { 622 static assert(haveCommonType!(bool, int, long)); 623 static assert(!haveCommonType!(bool, int, string)); 624 } 625 626 /** Check if $(D fun) is a pure function. */ 627 enum bool isPure(alias fun) = (isCallable!fun && 628 (functionAttributes!fun & 629 FunctionAttribute.pure_)); 630 631 /** Check if $(D fun) is a function purely callable with arguments T. */ 632 enum bool isPurelyCallableWith(alias fun, T...) = (isPure!fun && 633 is(T == ParameterTypeTuple!fun)); 634 635 unittest 636 { 637 int foo(int x) @safe pure nothrow { return x; } 638 static assert(isPure!foo); 639 static assert(isPurelyCallableWith!(foo, int)); 640 } 641 642 /** Persistently Call Function $(D fun) with arguments $(D args). 643 644 Hash Id Build-Timestamp (Code-Id because we currently have stable way of hashing-algorithms) is Constructed from Data Structure: 645 - Hierarchically Mangled Unqual!typeof(instance) 646 - Use msgpack in combination with sha1Of or only sha1Of (with extended 647 overloads for sha1Of) if available. 648 649 Extend std.functional : memoize to accept pure functions that takes an 650 immutable mmap as input. Create wrapper that converts file to immutable mmap 651 and performs memoization on the pure function. 652 653 */ 654 auto persistentlyMemoizedCall(alias fun, T...)(T args) 655 if (isPure!fun && 656 isCallable!(fun, args)) 657 { 658 import std.functional: memoize; 659 return fun(args); 660 } 661 662 /** Move std.uni.newLine? 663 TODO What to do with Windows style endings? 664 See also: https://en.wikipedia.org/wiki/Newline 665 */ 666 bool isNewline(C)(C c) @safe pure nothrow @nogc 667 if (isSomeChar!C) 668 { 669 import std.ascii: newline; // TODO Probably not useful. 670 static if (newline == "\n") 671 { 672 return (c == '\n' || c == '\r'); // optimized for systems with \n as default 673 } 674 else static if (newline == "\r") 675 { 676 return (c == '\r' || c == '\n'); // optimized for systems with \r as default 677 } 678 else 679 { 680 static assert(false, "Support Windows?"); 681 } 682 } 683 684 bool isNewline(S)(S s) @safe pure nothrow @nogc 685 if (isSomeString!S) 686 { 687 import std.ascii: newline; // TODO Probably not useful. 688 static if (newline == "\n") 689 { 690 return (s == '\n' || s == '\r'); // optimized for systems with \n as default 691 } 692 else static if (newline == "\r") 693 { 694 return (s == '\r' || s == '\n'); // optimized for systems with \r as default 695 } 696 else static if (newline == "\r\n") 697 { 698 return (s == "\r\n" || s == '\r' || s == '\n'); // optimized for systems with \r\n as default 699 } 700 else static if (newline == "\n\r") 701 { 702 return (s == "\n\r" || s == '\r' || s == '\n'); // optimized for systems with \n\r as default 703 } 704 else 705 { 706 static assert(false, "Support windows?"); 707 } 708 } 709 710 /** Dynamic Variant of $(D EnumMembers). 711 See also: http://forum.dlang.org/thread/bspwlfypfishykezzocx@forum.dlang.org#post-dguqnroxbfewerepomwq:40forum.dlang.org 712 */ 713 auto enumMembers(T)() 714 { 715 import std.traits: EnumMembers; 716 return [EnumMembers!T]; 717 } 718 719 /** Dynamic Variant of $(D EnumMembers) without Enumerator Aliases. 720 See also: http://forum.dlang.org/thread/bspwlfypfishykezzocx@forum.dlang.org#post-dguqnroxbfewerepomwq:40forum.dlang.org 721 */ 722 auto uniqueEnumMembers(T)() 723 { 724 import std.traits: EnumMembers; 725 import std.algorithm: sort, uniq; 726 return [EnumMembers!T].sort().uniq; 727 } 728 729 enum sizeOf(T) = T.sizeof; // TODO Add to Phobos 730 template sizesOf(T...) // TODO Add to Phobos 731 { 732 import std.meta : staticMap; 733 enum sizesOf = staticMap!(sizeOf, T); 734 } 735 736 enum stringOf(T) = T.stringof; // TODO Add to Phobos 737 template stringsOf(T...) // TODO Add to Phobos 738 { 739 import std.meta : staticMap; 740 enum stringsOf = staticMap!(stringOf, T); 741 } 742 743 unittest 744 { 745 enum sizes = sizesOf!(bool, short, int, long); 746 747 // static use 748 static assert(sizes[0] == 1); 749 static assert(sizes[1] == 2); 750 static assert(sizes[2] == 4); 751 static assert(sizes[3] == 8); 752 753 // dynamic use 754 const i = 0; 755 assert([sizes][i] == 1); 756 } 757 758 /** Get Number of Bits Required to store an instance of $(D T). 759 See also: http://forum.dlang.org/thread/okonqhnxzqlqtxijxsfg@forum.dlang.org 760 */ 761 template packedBitSizeOf(T) 762 { 763 static if (is(T == enum)) 764 { 765 static assert(T.min != T.max, "enum T must have at least two enumerators"); 766 import core.bitop : bsr; 767 enum range = T.max - T.min; 768 enum packedBitSizeOf = range.bsr + 1; 769 } 770 // TODO 771 // else static if (isAggregate!T) 772 // { 773 // foreach (E; T.tupleof) 774 // { 775 // ....; 776 // } 777 // } 778 else 779 { 780 enum packedBitSizeOf = 8*T.sizeof; 781 } 782 } 783 784 unittest 785 { 786 static assert(packedBitSizeOf!ubyte == 8); 787 static assert(!__traits(compiles, { enum E1 { x } static assert(packedBitSizeOf!E1 == 1);})); 788 enum E2 { x, y } 789 static assert(packedBitSizeOf!E2 == 1); 790 enum E3 { x, y, z } 791 static assert(packedBitSizeOf!E3 == 2); 792 enum E4 { x, y, z, w } 793 static assert(packedBitSizeOf!E4 == 2); 794 enum E5 { a, b, c, d, e } 795 static assert(packedBitSizeOf!E5 == 3); 796 enum E6 { a, b, c, d, e, f } 797 static assert(packedBitSizeOf!E6 == 3); 798 enum E7 { a, b, c, d, e, f, g } 799 static assert(packedBitSizeOf!E7 == 3); 800 enum E8 { a, b, c, d, e, f, g, h } 801 static assert(packedBitSizeOf!E8 == 3); 802 enum E9 { a, b, c, d, e, f, g, h, i } 803 static assert(packedBitSizeOf!E9 == 4); 804 } 805 806 /** Get Dimensionality of Type $(D T). 807 See also: http://forum.dlang.org/thread/hiuhqdxtpifhzwebewjh@forum.dlang.org?page=2 808 */ 809 810 template dimensionality (T) 811 { 812 template count_dim (uint i = 0) 813 { 814 static if (is(typeof(T.init.opSlice!i(0, 0)))) 815 { 816 enum count_dim = count_dim!(i+1); 817 } 818 else static if (i == 0 && 819 (isInputRange!T || 820 is(typeof(T.init[0])))) 821 { 822 enum count_dim = 1; 823 } 824 else 825 { 826 enum count_dim = i; 827 } 828 } 829 alias dimensionality = count_dim!(); 830 } 831 832 unittest 833 { 834 static assert(dimensionality!(int[]) == 1); 835 }