1 // Written in the D programming language. 2 3 /++ 4 This module defines functions related to exceptions and general error 5 handling. It also defines functions intended to aid in unit testing. 6 7 $(SCRIPT inhibitQuickIndex = 1;) 8 $(DIVC quickindex, 9 $(BOOKTABLE, 10 $(TR $(TH Category) $(TH Functions)) 11 $(TR $(TD Assumptions) $(TD 12 $(LREF assertNotThrown) 13 $(LREF assertThrown) 14 $(LREF assumeUnique) 15 $(LREF assumeWontThrow) 16 $(LREF mayPointTo) 17 )) 18 $(TR $(TD Enforce) $(TD 19 $(LREF doesPointTo) 20 $(LREF enforce) 21 $(LREF errnoEnforce) 22 )) 23 $(TR $(TD Handlers) $(TD 24 $(LREF collectException) 25 $(LREF collectExceptionMsg) 26 $(LREF ifThrown) 27 $(LREF handle) 28 )) 29 $(TR $(TD Other) $(TD 30 $(LREF basicExceptionCtors) 31 $(LREF emptyExceptionMsg) 32 $(LREF ErrnoException) 33 $(LREF RangePrimitive) 34 )) 35 )) 36 37 Copyright: Copyright Andrei Alexandrescu 2008-, Jonathan M Davis 2011-. 38 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0) 39 Authors: $(HTTP erdani.org, Andrei Alexandrescu) and 40 $(HTTP jmdavisprog.com, Jonathan M Davis) 41 Source: $(PHOBOSSRC std/exception.d) 42 43 +/ 44 module std.exception; 45 46 /// Synopis 47 @system unittest 48 { 49 import core.stdc.stdlib : malloc, free; 50 import std.algorithm.comparison : equal; 51 import std.algorithm.iteration : map, splitter; 52 import std.algorithm.searching : endsWith; 53 import std.conv : ConvException, to; 54 import std.range : front, retro; 55 56 // use enforce like assert 57 int a = 3; 58 enforce(a > 2, "a needs to be higher than 2."); 59 60 // enforce can throw a custom exception 61 enforce!ConvException(a > 2, "a needs to be higher than 2."); 62 63 // enforce will return it's input 64 enum size = 42; 65 auto memory = enforce(malloc(size), "malloc failed")[0 .. size]; 66 scope(exit) free(memory.ptr); 67 68 // collectException can be used to test for exceptions 69 Exception e = collectException("abc".to!int); 70 assert(e.file.endsWith("conv.d")); 71 72 // and just for the exception message 73 string msg = collectExceptionMsg("abc".to!int); 74 assert(msg == "Unexpected 'a' when converting from type string to type int"); 75 76 // assertThrown can be used to assert that an exception is thrown 77 assertThrown!ConvException("abc".to!int); 78 79 // ifThrown can be used to provide a default value if an exception is thrown 80 assert("x".to!int().ifThrown(0) == 0); 81 82 // handle is a more advanced version of ifThrown for ranges 83 auto r = "12,1337z32,54".splitter(',').map!(a => to!int(a)); 84 auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); 85 assert(h.equal([12, 0, 54])); 86 assertThrown!ConvException(h.retro.equal([54, 0, 12])); 87 88 // basicExceptionCtors avoids the boilerplate when creating custom exceptions 89 static class MeaCulpa : Exception 90 { 91 mixin basicExceptionCtors; 92 } 93 e = collectException((){throw new MeaCulpa("diagnostic message");}()); 94 assert(e.msg == "diagnostic message"); 95 assert(e.file == __FILE__); 96 assert(e.line == __LINE__ - 3); 97 98 // assumeWontThrow can be used to cast throwing code into `nothrow` 99 void exceptionFreeCode() nothrow 100 { 101 // auto-decoding only throws if an invalid UTF char is given 102 assumeWontThrow("abc".front); 103 } 104 105 // assumeUnique can be used to cast mutable instance to an `immutable` one 106 // use with care 107 char[] str = " mutable".dup; 108 str[0 .. 2] = "im"; 109 immutable res = assumeUnique(str); 110 assert(res == "immutable"); 111 } 112 113 import std.range.primitives; 114 import std.traits; 115 116 /++ 117 Asserts that the given expression does $(I not) throw the given type 118 of `Throwable`. If a `Throwable` of the given type is thrown, 119 it is caught and does not escape assertNotThrown. Rather, an 120 `AssertError` is thrown. However, any other `Throwable`s will escape. 121 122 Params: 123 T = The `Throwable` to test for. 124 expression = The expression to test. 125 msg = Optional message to output on test failure. 126 If msg is empty, and the thrown exception has a 127 non-empty msg field, the exception's msg field 128 will be output on test failure. 129 file = The file where the error occurred. 130 Defaults to `__FILE__`. 131 line = The line where the error occurred. 132 Defaults to `__LINE__`. 133 134 Throws: 135 `AssertError` if the given `Throwable` is thrown. 136 137 Returns: 138 the result of `expression`. 139 +/ 140 auto assertNotThrown(T : Throwable = Exception, E) 141 (lazy E expression, 142 string msg = null, 143 string file = __FILE__, 144 size_t line = __LINE__) 145 { 146 import core.exception : AssertError; 147 try 148 { 149 return expression(); 150 } 151 catch (T t) 152 { 153 immutable message = msg.length == 0 ? t.msg : msg; 154 immutable tail = message.length == 0 ? "." : ": " ~ message; 155 throw new AssertError("assertNotThrown failed: " ~ T.stringof ~ " was thrown" ~ tail, file, line, t); 156 } 157 } 158 /// 159 @system unittest 160 { 161 import core.exception : AssertError; 162 163 import std..string; 164 assertNotThrown!StringException(enforce!StringException(true, "Error!")); 165 166 //Exception is the default. 167 assertNotThrown(enforce!StringException(true, "Error!")); 168 169 assert(collectExceptionMsg!AssertError(assertNotThrown!StringException( 170 enforce!StringException(false, "Error!"))) == 171 `assertNotThrown failed: StringException was thrown: Error!`); 172 } 173 @system unittest 174 { 175 import core.exception : AssertError; 176 import std..string; 177 assert(collectExceptionMsg!AssertError(assertNotThrown!StringException( 178 enforce!StringException(false, ""), "Error!")) == 179 `assertNotThrown failed: StringException was thrown: Error!`); 180 181 assert(collectExceptionMsg!AssertError(assertNotThrown!StringException( 182 enforce!StringException(false, ""))) == 183 `assertNotThrown failed: StringException was thrown.`); 184 185 assert(collectExceptionMsg!AssertError(assertNotThrown!StringException( 186 enforce!StringException(false, ""), "")) == 187 `assertNotThrown failed: StringException was thrown.`); 188 } 189 190 @system unittest 191 { 192 import core.exception : AssertError; 193 194 void throwEx(Throwable t) { throw t; } 195 bool nothrowEx() { return true; } 196 197 try 198 { 199 assert(assertNotThrown!Exception(nothrowEx())); 200 } 201 catch (AssertError) assert(0); 202 203 try 204 { 205 assert(assertNotThrown!Exception(nothrowEx(), "It's a message")); 206 } 207 catch (AssertError) assert(0); 208 209 try 210 { 211 assert(assertNotThrown!AssertError(nothrowEx())); 212 } 213 catch (AssertError) assert(0); 214 215 try 216 { 217 assert(assertNotThrown!AssertError(nothrowEx(), "It's a message")); 218 } 219 catch (AssertError) assert(0); 220 221 { 222 bool thrown = false; 223 try 224 { 225 assertNotThrown!Exception( 226 throwEx(new Exception("It's an Exception"))); 227 } 228 catch (AssertError) thrown = true; 229 assert(thrown); 230 } 231 232 { 233 bool thrown = false; 234 try 235 { 236 assertNotThrown!Exception( 237 throwEx(new Exception("It's an Exception")), "It's a message"); 238 } 239 catch (AssertError) thrown = true; 240 assert(thrown); 241 } 242 243 { 244 bool thrown = false; 245 try 246 { 247 assertNotThrown!AssertError( 248 throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__))); 249 } 250 catch (AssertError) thrown = true; 251 assert(thrown); 252 } 253 254 { 255 bool thrown = false; 256 try 257 { 258 assertNotThrown!AssertError( 259 throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)), 260 "It's a message"); 261 } 262 catch (AssertError) thrown = true; 263 assert(thrown); 264 } 265 } 266 267 /++ 268 Asserts that the given expression throws the given type of `Throwable`. 269 The `Throwable` is caught and does not escape assertThrown. However, 270 any other `Throwable`s $(I will) escape, and if no `Throwable` 271 of the given type is thrown, then an `AssertError` is thrown. 272 273 Params: 274 T = The `Throwable` to test for. 275 expression = The expression to test. 276 msg = Optional message to output on test failure. 277 file = The file where the error occurred. 278 Defaults to `__FILE__`. 279 line = The line where the error occurred. 280 Defaults to `__LINE__`. 281 282 Throws: 283 `AssertError` if the given `Throwable` is not thrown. 284 +/ 285 void assertThrown(T : Throwable = Exception, E) 286 (lazy E expression, 287 string msg = null, 288 string file = __FILE__, 289 size_t line = __LINE__) 290 { 291 import core.exception : AssertError; 292 293 try 294 expression(); 295 catch (T) 296 return; 297 throw new AssertError("assertThrown failed: No " ~ T.stringof ~ " was thrown" 298 ~ (msg.length == 0 ? "." : ": ") ~ msg, 299 file, line); 300 } 301 /// 302 @system unittest 303 { 304 import core.exception : AssertError; 305 import std..string; 306 307 assertThrown!StringException(enforce!StringException(false, "Error!")); 308 309 //Exception is the default. 310 assertThrown(enforce!StringException(false, "Error!")); 311 312 assert(collectExceptionMsg!AssertError(assertThrown!StringException( 313 enforce!StringException(true, "Error!"))) == 314 `assertThrown failed: No StringException was thrown.`); 315 } 316 317 @system unittest 318 { 319 import core.exception : AssertError; 320 321 void throwEx(Throwable t) { throw t; } 322 void nothrowEx() { } 323 324 try 325 { 326 assertThrown!Exception(throwEx(new Exception("It's an Exception"))); 327 } 328 catch (AssertError) assert(0); 329 330 try 331 { 332 assertThrown!Exception(throwEx(new Exception("It's an Exception")), 333 "It's a message"); 334 } 335 catch (AssertError) assert(0); 336 337 try 338 { 339 assertThrown!AssertError(throwEx(new AssertError("It's an AssertError", 340 __FILE__, __LINE__))); 341 } 342 catch (AssertError) assert(0); 343 344 try 345 { 346 assertThrown!AssertError(throwEx(new AssertError("It's an AssertError", 347 __FILE__, __LINE__)), 348 "It's a message"); 349 } 350 catch (AssertError) assert(0); 351 352 353 { 354 bool thrown = false; 355 try 356 assertThrown!Exception(nothrowEx()); 357 catch (AssertError) 358 thrown = true; 359 360 assert(thrown); 361 } 362 363 { 364 bool thrown = false; 365 try 366 assertThrown!Exception(nothrowEx(), "It's a message"); 367 catch (AssertError) 368 thrown = true; 369 370 assert(thrown); 371 } 372 373 { 374 bool thrown = false; 375 try 376 assertThrown!AssertError(nothrowEx()); 377 catch (AssertError) 378 thrown = true; 379 380 assert(thrown); 381 } 382 383 { 384 bool thrown = false; 385 try 386 assertThrown!AssertError(nothrowEx(), "It's a message"); 387 catch (AssertError) 388 thrown = true; 389 390 assert(thrown); 391 } 392 } 393 394 395 /++ 396 Enforces that the given value is true. 397 If the given value is false, an exception is thrown. 398 The 399 $(UL 400 $(LI `msg` - error message as a `string`) 401 $(LI `dg` - custom delegate that return a string and is only called if an exception occurred) 402 $(LI `ex` - custom exception to be thrown. It is `lazy` and is only created if an exception occurred) 403 ) 404 405 Params: 406 value = The value to test. 407 E = Exception type to throw if the value evaluates to false. 408 msg = The error message to put in the exception if it is thrown. 409 dg = The delegate to be called if the value evaluates to false. 410 ex = The exception to throw if the value evaluates to false. 411 file = The source file of the caller. 412 line = The line number of the caller. 413 414 Returns: `value`, if `cast(bool) value` is true. Otherwise, 415 depending on the chosen overload, `new Exception(msg)`, `dg()` or `ex` is thrown. 416 417 Note: 418 `enforce` is used to throw exceptions and is therefore intended to 419 aid in error handling. It is $(I not) intended for verifying the logic 420 of your program. That is what `assert` is for. Also, do not use 421 `enforce` inside of contracts (i.e. inside of `in` and `out` 422 blocks and `invariant`s), because contracts are compiled out when 423 compiling with $(I -release). 424 425 If a delegate is passed, the safety and purity of this function are inferred 426 from `Dg`'s safety and purity. 427 +/ 428 template enforce(E : Throwable = Exception) 429 if (is(typeof(new E("", string.init, size_t.init)) : Throwable) || 430 is(typeof(new E(string.init, size_t.init)) : Throwable)) 431 { 432 /// 433 T enforce(T)(T value, lazy const(char)[] msg = null, 434 string file = __FILE__, size_t line = __LINE__) 435 if (is(typeof({ if (!value) {} }))) 436 { 437 if (!value) bailOut!E(file, line, msg); 438 return value; 439 } 440 } 441 442 /// ditto 443 T enforce(T, Dg, string file = __FILE__, size_t line = __LINE__) 444 (T value, scope Dg dg) 445 if (isSomeFunction!Dg && is(typeof( dg() )) && 446 is(typeof({ if (!value) {} }))) 447 { 448 if (!value) dg(); 449 return value; 450 } 451 452 /// ditto 453 T enforce(T)(T value, lazy Throwable ex) 454 { 455 if (!value) throw ex(); 456 return value; 457 } 458 459 /// 460 @system unittest 461 { 462 import core.stdc.stdlib : malloc, free; 463 import std.conv : ConvException, to; 464 465 // use enforce like assert 466 int a = 3; 467 enforce(a > 2, "a needs to be higher than 2."); 468 469 // enforce can throw a custom exception 470 enforce!ConvException(a > 2, "a needs to be higher than 2."); 471 472 // enforce will return it's input 473 enum size = 42; 474 auto memory = enforce(malloc(size), "malloc failed")[0 .. size]; 475 scope(exit) free(memory.ptr); 476 } 477 478 /// 479 @safe unittest 480 { 481 assertNotThrown(enforce(true, new Exception("this should not be thrown"))); 482 assertThrown(enforce(false, new Exception("this should be thrown"))); 483 } 484 485 /// 486 @safe unittest 487 { 488 assert(enforce(123) == 123); 489 490 try 491 { 492 enforce(false, "error"); 493 assert(false); 494 } 495 catch (Exception e) 496 { 497 assert(e.msg == "error"); 498 assert(e.file == __FILE__); 499 assert(e.line == __LINE__-7); 500 } 501 } 502 503 /// Alias your own enforce function 504 @safe unittest 505 { 506 import std.conv : ConvException; 507 alias convEnforce = enforce!ConvException; 508 assertNotThrown(convEnforce(true)); 509 assertThrown!ConvException(convEnforce(false, "blah")); 510 } 511 512 private void bailOut(E : Throwable = Exception)(string file, size_t line, scope const(char)[] msg) 513 { 514 static if (is(typeof(new E(string.init, string.init, size_t.init)))) 515 { 516 throw new E(msg ? msg.idup : "Enforcement failed", file, line); 517 } 518 else static if (is(typeof(new E(string.init, size_t.init)))) 519 { 520 throw new E(file, line); 521 } 522 else 523 { 524 static assert(0, "Expected this(string, string, size_t) or this(string, size_t)" ~ 525 " constructor for " ~ __traits(identifier, E)); 526 } 527 } 528 529 // https://issues.dlang.org/show_bug.cgi?id=10510 530 @safe unittest 531 { 532 extern(C) void cFoo() { } 533 enforce(false, &cFoo); 534 } 535 536 // purity and safety inference test 537 @system unittest 538 { 539 static foreach (EncloseSafe; [false, true]) 540 static foreach (EnclosePure; [false, true]) 541 { 542 static foreach (BodySafe; [false, true]) 543 static foreach (BodyPure; [false, true]) 544 {{ 545 enum code = 546 "delegate void() " ~ 547 (EncloseSafe ? "@safe " : "") ~ 548 (EnclosePure ? "pure " : "") ~ 549 "{ enforce(true, { " ~ 550 "int n; " ~ 551 (BodySafe ? "" : "auto p = &n + 10; " ) ~ // unsafe code 552 (BodyPure ? "" : "static int g; g = 10; ") ~ // impure code 553 "}); " ~ 554 "}"; 555 enum expect = 556 (BodySafe || !EncloseSafe) && (!EnclosePure || BodyPure); 557 558 version (none) 559 pragma(msg, "safe = ", EncloseSafe?1:0, "/", BodySafe?1:0, ", ", 560 "pure = ", EnclosePure?1:0, "/", BodyPure?1:0, ", ", 561 "expect = ", expect?"OK":"NG", ", ", 562 "code = ", code); 563 564 static assert(__traits(compiles, mixin(code)()) == expect); 565 }} 566 } 567 } 568 569 // Test for https://issues.dlang.org/show_bug.cgi?id=8637 570 @system unittest 571 { 572 struct S 573 { 574 static int g; 575 ~this() {} // impure & unsafe destructor 576 bool opCast(T:bool)() { 577 int* p = cast(int*) 0; // unsafe operation 578 int n = g; // impure operation 579 return true; 580 } 581 } 582 S s; 583 584 enforce(s); 585 enforce(s, {}); 586 enforce(s, new Exception("")); 587 588 errnoEnforce(s); 589 590 alias E1 = Exception; 591 static class E2 : Exception 592 { 593 this(string fn, size_t ln) { super("", fn, ln); } 594 } 595 static class E3 : Exception 596 { 597 this(string msg) { super(msg, __FILE__, __LINE__); } 598 } 599 enforce!E1(s); 600 enforce!E2(s); 601 } 602 603 // https://issues.dlang.org/show_bug.cgi?id=14685 604 @safe unittest 605 { 606 class E : Exception 607 { 608 this() { super("Not found"); } 609 } 610 static assert(!__traits(compiles, { enforce!E(false); })); 611 } 612 613 /++ 614 Enforces that the given value is true, throwing an `ErrnoException` if it 615 is not. 616 617 Params: 618 value = The value to test. 619 msg = The message to include in the `ErrnoException` if it is thrown. 620 621 Returns: `value`, if `cast(bool) value` is true. Otherwise, 622 $(D new ErrnoException(msg)) is thrown. It is assumed that the last 623 operation set `errno` to an error code corresponding with the failed 624 condition. 625 +/ 626 alias errnoEnforce = enforce!ErrnoException; 627 628 /// 629 @system unittest 630 { 631 import core.stdc.stdio : fclose, fgets, fopen; 632 import std.file : thisExePath; 633 import std..string : toStringz; 634 635 auto f = fopen(thisExePath.toStringz, "r").errnoEnforce; 636 scope(exit) fclose(f); 637 char[100] buf; 638 auto line = fgets(buf.ptr, buf.length, f); 639 enforce(line !is null); // expect a non-empty line 640 } 641 642 // @@@DEPRECATED_2.089@@@ 643 /++ 644 $(RED Deprecated. Please use $(LREF enforce) instead. This function will be removed 2.089.) 645 646 If `!value` is `false`, `value` is returned. Otherwise, 647 $(D new E(msg, file, line)) is thrown. Or if `E` doesn't take a message 648 and can be constructed with $(D new E(file, line)), then 649 $(D new E(file, line)) will be thrown. 650 651 Example: 652 -------------------- 653 auto f = enforceEx!FileMissingException(fopen("data.txt")); 654 auto line = readln(f); 655 enforceEx!DataCorruptionException(line.length); 656 -------------------- 657 +/ 658 deprecated("Use `enforce`. `enforceEx` will be removed with 2.089.") 659 template enforceEx(E : Throwable) 660 if (is(typeof(new E("", string.init, size_t.init)))) 661 { 662 /++ Ditto +/ 663 T enforceEx(T)(T value, lazy string msg = "", string file = __FILE__, size_t line = __LINE__) 664 { 665 if (!value) throw new E(msg, file, line); 666 return value; 667 } 668 } 669 670 /+ Ditto +/ 671 deprecated("Use `enforce`. `enforceEx` will be removed with 2.089.") 672 template enforceEx(E : Throwable) 673 if (is(typeof(new E(string.init, size_t.init))) && !is(typeof(new E("", string.init, size_t.init)))) 674 { 675 /++ Ditto +/ 676 T enforceEx(T)(T value, string file = __FILE__, size_t line = __LINE__) 677 { 678 if (!value) throw new E(file, line); 679 return value; 680 } 681 } 682 683 deprecated 684 @system unittest 685 { 686 import core.exception : OutOfMemoryError; 687 import std.array : empty; 688 assertNotThrown(enforceEx!Exception(true)); 689 assertNotThrown(enforceEx!Exception(true, "blah")); 690 assertNotThrown(enforceEx!OutOfMemoryError(true)); 691 692 { 693 auto e = collectException(enforceEx!Exception(false)); 694 assert(e !is null); 695 assert(e.msg.empty); 696 assert(e.file == __FILE__); 697 assert(e.line == __LINE__ - 4); 698 } 699 700 { 701 auto e = collectException(enforceEx!Exception(false, "hello", "file", 42)); 702 assert(e !is null); 703 assert(e.msg == "hello"); 704 assert(e.file == "file"); 705 assert(e.line == 42); 706 } 707 708 { 709 auto e = collectException!Error(enforceEx!OutOfMemoryError(false)); 710 assert(e !is null); 711 assert(e.msg == "Memory allocation failed"); 712 assert(e.file == __FILE__); 713 assert(e.line == __LINE__ - 4); 714 } 715 716 { 717 auto e = collectException!Error(enforceEx!OutOfMemoryError(false, "file", 42)); 718 assert(e !is null); 719 assert(e.msg == "Memory allocation failed"); 720 assert(e.file == "file"); 721 assert(e.line == 42); 722 } 723 724 static assert(!is(typeof(enforceEx!int(true)))); 725 } 726 727 deprecated 728 @safe unittest 729 { 730 alias enf = enforceEx!Exception; 731 assertNotThrown(enf(true)); 732 assertThrown(enf(false, "blah")); 733 } 734 735 /++ 736 Catches and returns the exception thrown from the given expression. 737 If no exception is thrown, then null is returned and `result` is 738 set to the result of the expression. 739 740 Note that while `collectException` $(I can) be used to collect any 741 `Throwable` and not just `Exception`s, it is generally ill-advised to 742 catch anything that is neither an `Exception` nor a type derived from 743 `Exception`. So, do not use `collectException` to collect 744 non-`Exception`s unless you're sure that that's what you really want to 745 do. 746 747 Params: 748 T = The type of exception to catch. 749 expression = The expression which may throw an exception. 750 result = The result of the expression if no exception is thrown. 751 +/ 752 T collectException(T = Exception, E)(lazy E expression, ref E result) 753 { 754 try 755 { 756 result = expression(); 757 } 758 catch (T e) 759 { 760 return e; 761 } 762 return null; 763 } 764 /// 765 @system unittest 766 { 767 int b; 768 int foo() { throw new Exception("blah"); } 769 assert(collectException(foo(), b)); 770 771 int[] a = new int[3]; 772 import core.exception : RangeError; 773 assert(collectException!RangeError(a[4], b)); 774 } 775 776 /++ 777 Catches and returns the exception thrown from the given expression. 778 If no exception is thrown, then null is returned. `E` can be 779 `void`. 780 781 Note that while `collectException` $(I can) be used to collect any 782 `Throwable` and not just `Exception`s, it is generally ill-advised to 783 catch anything that is neither an `Exception` nor a type derived from 784 `Exception`. So, do not use `collectException` to collect 785 non-`Exception`s unless you're sure that that's what you really want to 786 do. 787 788 Params: 789 T = The type of exception to catch. 790 expression = The expression which may throw an exception. 791 +/ 792 T collectException(T : Throwable = Exception, E)(lazy E expression) 793 { 794 try 795 { 796 expression(); 797 } 798 catch (T t) 799 { 800 return t; 801 } 802 return null; 803 } 804 805 /// 806 @safe unittest 807 { 808 int foo() { throw new Exception("blah"); } 809 assert(collectException(foo()).msg == "blah"); 810 } 811 812 /++ 813 Catches the exception thrown from the given expression and returns the 814 msg property of that exception. If no exception is thrown, then null is 815 returned. `E` can be `void`. 816 817 If an exception is thrown but it has an empty message, then 818 `emptyExceptionMsg` is returned. 819 820 Note that while `collectExceptionMsg` $(I can) be used to collect any 821 `Throwable` and not just `Exception`s, it is generally ill-advised to 822 catch anything that is neither an `Exception` nor a type derived from 823 `Exception`. So, do not use `collectExceptionMsg` to collect 824 non-`Exception`s unless you're sure that that's what you really want to 825 do. 826 827 Params: 828 T = The type of exception to catch. 829 expression = The expression which may throw an exception. 830 +/ 831 string collectExceptionMsg(T = Exception, E)(lazy E expression) 832 { 833 import std.array : empty; 834 try 835 { 836 expression(); 837 838 return cast(string) null; 839 } 840 catch (T e) 841 return e.msg.empty ? emptyExceptionMsg : e.msg; 842 } 843 /// 844 @safe unittest 845 { 846 void throwFunc() { throw new Exception("My Message."); } 847 assert(collectExceptionMsg(throwFunc()) == "My Message."); 848 849 void nothrowFunc() {} 850 assert(collectExceptionMsg(nothrowFunc()) is null); 851 852 void throwEmptyFunc() { throw new Exception(""); } 853 assert(collectExceptionMsg(throwEmptyFunc()) == emptyExceptionMsg); 854 } 855 856 /++ 857 Value that collectExceptionMsg returns when it catches an exception 858 with an empty exception message. 859 +/ 860 enum emptyExceptionMsg = "<Empty Exception Message>"; 861 862 /** 863 * Casts a mutable array to an immutable array in an idiomatic 864 * manner. Technically, `assumeUnique` just inserts a cast, 865 * but its name documents assumptions on the part of the 866 * caller. `assumeUnique(arr)` should only be called when 867 * there are no more active mutable aliases to elements of $(D 868 * arr). To strengthen this assumption, `assumeUnique(arr)` 869 * also clears `arr` before returning. Essentially $(D 870 * assumeUnique(arr)) indicates commitment from the caller that there 871 * is no more mutable access to any of `arr`'s elements 872 * (transitively), and that all future accesses will be done through 873 * the immutable array returned by `assumeUnique`. 874 * 875 * Typically, `assumeUnique` is used to return arrays from 876 * functions that have allocated and built them. 877 * 878 * Params: 879 * array = The array to cast to immutable. 880 * 881 * Returns: The immutable array. 882 * 883 * Example: 884 * 885 * $(RUNNABLE_EXAMPLE 886 * ---- 887 * string letters() 888 * { 889 * char[] result = new char['z' - 'a' + 1]; 890 * foreach (i, ref e; result) 891 * { 892 * e = cast(char)('a' + i); 893 * } 894 * return assumeUnique(result); 895 * } 896 * ---- 897 * ) 898 * 899 * The use in the example above is correct because `result` 900 * was private to `letters` and is inaccessible in writing 901 * after the function returns. The following example shows an 902 * incorrect use of `assumeUnique`. 903 * 904 * Bad: 905 * 906 * $(RUNNABLE_EXAMPLE 907 * ---- 908 * private char[] buffer; 909 * string letters(char first, char last) 910 * { 911 * if (first >= last) return null; // fine 912 * auto sneaky = buffer; 913 * sneaky.length = last - first + 1; 914 * foreach (i, ref e; sneaky) 915 * { 916 * e = cast(char)('a' + i); 917 * } 918 * return assumeUnique(sneaky); // BAD 919 * } 920 * ---- 921 * ) 922 * 923 * The example above wreaks havoc on client code because it is 924 * modifying arrays that callers considered immutable. To obtain an 925 * immutable array from the writable array `buffer`, replace 926 * the last line with: 927 * 928 * ---- 929 * return to!(string)(sneaky); // not that sneaky anymore 930 * ---- 931 * 932 * The call will duplicate the array appropriately. 933 * 934 * Note that checking for uniqueness during compilation is 935 * possible in certain cases, especially when a function is 936 * marked as a pure function. The following example does not 937 * need to call assumeUnique because the compiler can infer the 938 * uniqueness of the array in the pure function: 939 * 940 * $(RUNNABLE_EXAMPLE 941 * ---- 942 * string letters() pure 943 * { 944 * char[] result = new char['z' - 'a' + 1]; 945 * foreach (i, ref e; result) 946 * { 947 * e = cast(char)('a' + i); 948 * } 949 * return result; 950 * } 951 * ---- 952 * ) 953 * 954 * For more on infering uniqueness see the $(B unique) and 955 * $(B lent) keywords in the 956 * $(HTTP www.cs.cmu.edu/~aldrich/papers/aldrich-dissertation.pdf, ArchJava) 957 * language. 958 * 959 * The downside of using `assumeUnique`'s 960 * convention-based usage is that at this time there is no 961 * formal checking of the correctness of the assumption; 962 * on the upside, the idiomatic use of `assumeUnique` is 963 * simple and rare enough to be tolerable. 964 * 965 */ 966 immutable(T)[] assumeUnique(T)(T[] array) pure nothrow 967 { 968 return .assumeUnique(array); // call ref version 969 } 970 /// ditto 971 immutable(T)[] assumeUnique(T)(ref T[] array) pure nothrow 972 { 973 auto result = cast(immutable(T)[]) array; 974 array = null; 975 return result; 976 } 977 /// ditto 978 immutable(T[U]) assumeUnique(T, U)(ref T[U] array) pure nothrow 979 { 980 auto result = cast(immutable(T[U])) array; 981 array = null; 982 return result; 983 } 984 985 /// 986 @system unittest 987 { 988 int[] arr = new int[1]; 989 auto arr1 = arr.assumeUnique; 990 static assert(is(typeof(arr1) == immutable(int)[])); 991 assert(arr == null); 992 assert(arr1 == [0]); 993 } 994 995 /// 996 @system unittest 997 { 998 int[string] arr = ["a":1]; 999 auto arr1 = arr.assumeUnique; 1000 static assert(is(typeof(arr1) == immutable(int[string]))); 1001 assert(arr == null); 1002 assert(arr1.keys == ["a"]); 1003 } 1004 1005 /** 1006 * Wraps a possibly-throwing expression in a `nothrow` wrapper so that it 1007 * can be called by a `nothrow` function. 1008 * 1009 * This wrapper function documents commitment on the part of the caller that 1010 * the appropriate steps have been taken to avoid whatever conditions may 1011 * trigger an exception during the evaluation of `expr`. If it turns out 1012 * that the expression $(I does) throw at runtime, the wrapper will throw an 1013 * `AssertError`. 1014 * 1015 * (Note that `Throwable` objects such as `AssertError` that do not 1016 * subclass `Exception` may be thrown even from `nothrow` functions, 1017 * since they are considered to be serious runtime problems that cannot be 1018 * recovered from.) 1019 * 1020 * Params: 1021 * expr = The expression asserted not to throw. 1022 * msg = The message to include in the `AssertError` if the assumption turns 1023 * out to be false. 1024 * file = The source file name of the caller. 1025 * line = The line number of the caller. 1026 * 1027 * Returns: 1028 * The value of `expr`, if any. 1029 */ 1030 T assumeWontThrow(T)(lazy T expr, 1031 string msg = null, 1032 string file = __FILE__, 1033 size_t line = __LINE__) nothrow 1034 { 1035 import core.exception : AssertError; 1036 try 1037 { 1038 return expr; 1039 } 1040 catch (Exception e) 1041 { 1042 import std.range.primitives : empty; 1043 immutable tail = msg.empty ? "." : ": " ~ msg; 1044 throw new AssertError("assumeWontThrow failed: Expression did throw" ~ 1045 tail, file, line); 1046 } 1047 } 1048 1049 /// 1050 @safe unittest 1051 { 1052 import std.math : sqrt; 1053 1054 // This function may throw. 1055 int squareRoot(int x) 1056 { 1057 if (x < 0) 1058 throw new Exception("Tried to take root of negative number"); 1059 return cast(int) sqrt(cast(double) x); 1060 } 1061 1062 // This function never throws. 1063 int computeLength(int x, int y) nothrow 1064 { 1065 // Since x*x + y*y is always positive, we can safely assume squareRoot 1066 // won't throw, and use it to implement this nothrow function. If it 1067 // does throw (e.g., if x*x + y*y overflows a 32-bit value), then the 1068 // program will terminate. 1069 return assumeWontThrow(squareRoot(x*x + y*y)); 1070 } 1071 1072 assert(computeLength(3, 4) == 5); 1073 } 1074 1075 @system unittest 1076 { 1077 import core.exception : AssertError; 1078 1079 void alwaysThrows() 1080 { 1081 throw new Exception("I threw up"); 1082 } 1083 void bad() nothrow 1084 { 1085 assumeWontThrow(alwaysThrows()); 1086 } 1087 assertThrown!AssertError(bad()); 1088 } 1089 1090 /** 1091 Checks whether a given source object contains pointers or references to a given 1092 target object. 1093 1094 Params: 1095 source = The source object 1096 target = The target object 1097 1098 Bugs: 1099 The function is explicitly annotated `@nogc` because inference could fail, 1100 see $(LINK2 https://issues.dlang.org/show_bug.cgi?id=17084, issue 17084). 1101 1102 Returns: `true` if `source`'s representation embeds a pointer 1103 that points to `target`'s representation or somewhere inside 1104 it. 1105 1106 If `source` is or contains a dynamic array, then, then these functions will check 1107 if there is overlap between the dynamic array and `target`'s representation. 1108 1109 If `source` is a class, then it will be handled as a pointer. 1110 1111 If `target` is a pointer, a dynamic array or a class, then these functions will only 1112 check if `source` points to `target`, $(I not) what `target` references. 1113 1114 If `source` is or contains a union or `void[n]`, then there may be either false positives or 1115 false negatives: 1116 1117 `doesPointTo` will return `true` if it is absolutely certain 1118 `source` points to `target`. It may produce false negatives, but never 1119 false positives. This function should be prefered when trying to validate 1120 input data. 1121 1122 `mayPointTo` will return `false` if it is absolutely certain 1123 `source` does not point to `target`. It may produce false positives, but never 1124 false negatives. This function should be prefered for defensively choosing a 1125 code path. 1126 1127 Note: Evaluating $(D doesPointTo(x, x)) checks whether `x` has 1128 internal pointers. This should only be done as an assertive test, 1129 as the language is free to assume objects don't have internal pointers 1130 (TDPL 7.1.3.5). 1131 */ 1132 bool doesPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @nogc @trusted pure nothrow 1133 if (__traits(isRef, source) || isDynamicArray!S || 1134 isPointer!S || is(S == class)) 1135 { 1136 static if (isPointer!S || is(S == class) || is(S == interface)) 1137 { 1138 const m = *cast(void**) &source; 1139 const b = cast(void*) ⌖ 1140 const e = b + target.sizeof; 1141 return b <= m && m < e; 1142 } 1143 else static if (is(S == struct) || is(S == union)) 1144 { 1145 foreach (i, Subobj; typeof(source.tupleof)) 1146 static if (!isUnionAliased!(S, i)) 1147 if (doesPointTo(source.tupleof[i], target)) return true; 1148 return false; 1149 } 1150 else static if (isStaticArray!S) 1151 { 1152 static if (!is(S == void[n], size_t n)) 1153 { 1154 foreach (ref s; source) 1155 if (doesPointTo(s, target)) return true; 1156 } 1157 return false; 1158 } 1159 else static if (isDynamicArray!S) 1160 { 1161 import std.array : overlap; 1162 return overlap(cast(void[]) source, cast(void[])(&target)[0 .. 1]).length != 0; 1163 } 1164 else 1165 { 1166 return false; 1167 } 1168 } 1169 1170 // for shared objects 1171 /// ditto 1172 bool doesPointTo(S, T)(auto ref const shared S source, ref const shared T target) @trusted pure nothrow 1173 { 1174 return doesPointTo!(shared S, shared T, void)(source, target); 1175 } 1176 1177 /// ditto 1178 bool mayPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @trusted pure nothrow 1179 if (__traits(isRef, source) || isDynamicArray!S || 1180 isPointer!S || is(S == class)) 1181 { 1182 static if (isPointer!S || is(S == class) || is(S == interface)) 1183 { 1184 const m = *cast(void**) &source; 1185 const b = cast(void*) ⌖ 1186 const e = b + target.sizeof; 1187 return b <= m && m < e; 1188 } 1189 else static if (is(S == struct) || is(S == union)) 1190 { 1191 foreach (i, Subobj; typeof(source.tupleof)) 1192 if (mayPointTo(source.tupleof[i], target)) return true; 1193 return false; 1194 } 1195 else static if (isStaticArray!S) 1196 { 1197 static if (is(S == void[n], size_t n)) 1198 { 1199 static if (n >= (void[]).sizeof) 1200 { 1201 // could contain a slice, which could point at anything. 1202 // But a void[N] that is all 0 cannot point anywhere 1203 import std.algorithm.searching : any; 1204 if (__ctfe || any(cast(ubyte[]) source[])) 1205 return true; 1206 } 1207 else static if (n >= (void*).sizeof) 1208 { 1209 // Reinterpreting cast is impossible during ctfe 1210 if (__ctfe) 1211 return true; 1212 1213 // Only check for properly aligned pointers 1214 enum al = (void*).alignof - 1; 1215 const base = cast(size_t) &source; 1216 const alBase = (base + al) & ~al; 1217 1218 if ((n - (alBase - base)) >= (void*).sizeof && 1219 mayPointTo(*(cast(void**) alBase), target)) 1220 return true; 1221 } 1222 } 1223 else 1224 { 1225 foreach (size_t i; 0 .. S.length) 1226 if (mayPointTo(source[i], target)) return true; 1227 } 1228 1229 return false; 1230 } 1231 else static if (isDynamicArray!S) 1232 { 1233 import std.array : overlap; 1234 return overlap(cast(void[]) source, cast(void[])(&target)[0 .. 1]).length != 0; 1235 } 1236 else 1237 { 1238 return false; 1239 } 1240 } 1241 1242 // for shared objects 1243 /// ditto 1244 bool mayPointTo(S, T)(auto ref const shared S source, ref const shared T target) @trusted pure nothrow 1245 { 1246 return mayPointTo!(shared S, shared T, void)(source, target); 1247 } 1248 1249 /// Pointers 1250 @system unittest 1251 { 1252 int i = 0; 1253 int* p = null; 1254 assert(!p.doesPointTo(i)); 1255 p = &i; 1256 assert( p.doesPointTo(i)); 1257 } 1258 1259 /// Structs and Unions 1260 @system unittest 1261 { 1262 struct S 1263 { 1264 int v; 1265 int* p; 1266 } 1267 int i; 1268 auto s = S(0, &i); 1269 1270 // structs and unions "own" their members 1271 // pointsTo will answer true if one of the members pointsTo. 1272 assert(!s.doesPointTo(s.v)); //s.v is just v member of s, so not pointed. 1273 assert( s.p.doesPointTo(i)); //i is pointed by s.p. 1274 assert( s .doesPointTo(i)); //which means i is pointed by s itself. 1275 1276 // Unions will behave exactly the same. Points to will check each "member" 1277 // individually, even if they share the same memory 1278 } 1279 1280 /// Arrays (dynamic and static) 1281 @system unittest 1282 { 1283 int i; 1284 // trick the compiler when initializing slice 1285 // https://issues.dlang.org/show_bug.cgi?id=18637 1286 int* p = &i; 1287 int[] slice = [0, 1, 2, 3, 4]; 1288 int[5] arr = [0, 1, 2, 3, 4]; 1289 int*[] slicep = [p]; 1290 int*[1] arrp = [&i]; 1291 1292 // A slice points to all of its members: 1293 assert( slice.doesPointTo(slice[3])); 1294 assert(!slice[0 .. 2].doesPointTo(slice[3])); // Object 3 is outside of the 1295 // slice [0 .. 2] 1296 1297 // Note that a slice will not take into account what its members point to. 1298 assert( slicep[0].doesPointTo(i)); 1299 assert(!slicep .doesPointTo(i)); 1300 1301 // static arrays are objects that own their members, just like structs: 1302 assert(!arr.doesPointTo(arr[0])); // arr[0] is just a member of arr, so not 1303 // pointed. 1304 assert( arrp[0].doesPointTo(i)); // i is pointed by arrp[0]. 1305 assert( arrp .doesPointTo(i)); // which means i is pointed by arrp 1306 // itself. 1307 1308 // Notice the difference between static and dynamic arrays: 1309 assert(!arr .doesPointTo(arr[0])); 1310 assert( arr[].doesPointTo(arr[0])); 1311 assert( arrp .doesPointTo(i)); 1312 assert(!arrp[].doesPointTo(i)); 1313 } 1314 1315 /// Classes 1316 @system unittest 1317 { 1318 class C 1319 { 1320 this(int* p){this.p = p;} 1321 int* p; 1322 } 1323 int i; 1324 C a = new C(&i); 1325 C b = a; 1326 1327 // Classes are a bit particular, as they are treated like simple pointers 1328 // to a class payload. 1329 assert( a.p.doesPointTo(i)); // a.p points to i. 1330 assert(!a .doesPointTo(i)); // Yet a itself does not point i. 1331 1332 //To check the class payload itself, iterate on its members: 1333 () 1334 { 1335 import std.traits : Fields; 1336 1337 foreach (index, _; Fields!C) 1338 if (doesPointTo(a.tupleof[index], i)) 1339 return; 1340 assert(0); 1341 }(); 1342 1343 // To check if a class points a specific payload, a direct memmory check 1344 // can be done: 1345 auto aLoc = cast(ubyte[__traits(classInstanceSize, C)]*) a; 1346 assert(b.doesPointTo(*aLoc)); // b points to where a is pointing 1347 } 1348 1349 1350 version (StdUnittest) 1351 { 1352 // https://issues.dlang.org/show_bug.cgi?id=17084 1353 // the bug doesn't happen if these declarations are in the unittest block 1354 // (static or not). 1355 private struct Page17084 1356 { 1357 URL17084 url; 1358 int opCmp(P)(P) { return 0; } 1359 int opCmp(P)(shared(P)) shared { return 0; } 1360 } 1361 1362 private struct URL17084 1363 { 1364 int[] queryParams; 1365 string toString()() const { return ""; } 1366 alias toString this; 1367 } 1368 } 1369 1370 // https://issues.dlang.org/show_bug.cgi?id=17084 1371 @system unittest 1372 { 1373 import std.algorithm.sorting : sort; 1374 Page17084[] s; 1375 sort(s); 1376 shared(Page17084)[] p; 1377 sort(p); 1378 } 1379 1380 @system unittest 1381 { 1382 struct S1 { int a; S1 * b; } 1383 S1 a1; 1384 S1 * p = &a1; 1385 assert(doesPointTo(p, a1)); 1386 1387 S1 a2; 1388 a2.b = &a1; 1389 assert(doesPointTo(a2, a1)); 1390 1391 struct S3 { int[10] a; } 1392 S3 a3; 1393 auto a4 = a3.a[2 .. 3]; 1394 assert(doesPointTo(a4, a3)); 1395 1396 auto a5 = new double[4]; 1397 auto a6 = a5[1 .. 2]; 1398 assert(!doesPointTo(a5, a6)); 1399 1400 auto a7 = new double[3]; 1401 auto a8 = new double[][1]; 1402 a8[0] = a7; 1403 assert(!doesPointTo(a8[0], a8[0])); 1404 1405 // don't invoke postblit on subobjects 1406 { 1407 static struct NoCopy { this(this) { assert(0); } } 1408 static struct Holder { NoCopy a, b, c; } 1409 Holder h; 1410 cast(void) doesPointTo(h, h); 1411 } 1412 1413 shared S3 sh3; 1414 shared sh3sub = sh3.a[]; 1415 assert(doesPointTo(sh3sub, sh3)); 1416 1417 int[] darr = [1, 2, 3, 4]; 1418 1419 //dynamic arrays don't point to each other, or slices of themselves 1420 assert(!doesPointTo(darr, darr)); 1421 assert(!doesPointTo(darr[0 .. 1], darr)); 1422 1423 //But they do point their elements 1424 foreach (i; 0 .. 4) 1425 assert(doesPointTo(darr, darr[i])); 1426 assert(doesPointTo(darr[0 .. 3], darr[2])); 1427 assert(!doesPointTo(darr[0 .. 3], darr[3])); 1428 } 1429 1430 @system unittest 1431 { 1432 //tests with static arrays 1433 //Static arrays themselves are just objects, and don't really *point* to anything. 1434 //They aggregate their contents, much the same way a structure aggregates its attributes. 1435 //*However* The elements inside the static array may themselves point to stuff. 1436 1437 //Standard array 1438 int[2] k; 1439 assert(!doesPointTo(k, k)); //an array doesn't point to itself 1440 //Technically, k doesn't point its elements, although it does alias them 1441 assert(!doesPointTo(k, k[0])); 1442 assert(!doesPointTo(k, k[1])); 1443 //But an extracted slice will point to the same array. 1444 assert(doesPointTo(k[], k)); 1445 assert(doesPointTo(k[], k[1])); 1446 1447 //An array of pointers 1448 int*[2] pp; 1449 int a; 1450 int b; 1451 pp[0] = &a; 1452 assert( doesPointTo(pp, a)); //The array contains a pointer to a 1453 assert(!doesPointTo(pp, b)); //The array does NOT contain a pointer to b 1454 assert(!doesPointTo(pp, pp)); //The array does not point itslef 1455 1456 //A struct containing a static array of pointers 1457 static struct S 1458 { 1459 int*[2] p; 1460 } 1461 S s; 1462 s.p[0] = &a; 1463 assert( doesPointTo(s, a)); //The struct contains an array that points a 1464 assert(!doesPointTo(s, b)); //But doesn't point b 1465 assert(!doesPointTo(s, s)); //The struct doesn't actually point itslef. 1466 1467 //An array containing structs that have pointers 1468 static struct SS 1469 { 1470 int* p; 1471 } 1472 SS[2] ss = [SS(&a), SS(null)]; 1473 assert( doesPointTo(ss, a)); //The array contains a struct that points to a 1474 assert(!doesPointTo(ss, b)); //The array doesn't contains a struct that points to b 1475 assert(!doesPointTo(ss, ss)); //The array doesn't point itself. 1476 1477 // https://issues.dlang.org/show_bug.cgi?id=20426 1478 align((void*).alignof) void[32] voidArr = void; 1479 (cast(void*[]) voidArr[])[] = null; // Ensure no false pointers 1480 1481 // zeroed void ranges can't point at anything 1482 assert(!mayPointTo(voidArr, a)); 1483 assert(!mayPointTo(voidArr, b)); 1484 1485 *cast(void**) &voidArr[16] = &a; // Pointers should be found 1486 1487 alias SA = void[size_t.sizeof + 3]; 1488 SA *smallArr1 = cast(SA*)&voidArr; 1489 SA *smallArr2 = cast(SA*)&(voidArr[16]); 1490 1491 // But it should only consider properly aligned pointers 1492 // Write single bytes to avoid issues due to misaligned writes 1493 void*[1] tmp = [&b]; 1494 (cast(ubyte[]) voidArr[3 .. 3 + (void*).sizeof])[] = cast(ubyte[]) tmp[]; 1495 1496 1497 assert( mayPointTo(*smallArr2, a)); 1498 assert(!mayPointTo(*smallArr1, b)); 1499 1500 assert(!doesPointTo(voidArr, a)); // Value might be a false pointer 1501 assert(!doesPointTo(voidArr, b)); 1502 1503 SA *smallArr3 = cast(SA *) &voidArr[13]; // Works for weird sizes/alignments 1504 assert( mayPointTo(*smallArr3, a)); 1505 assert(!mayPointTo(*smallArr3, b)); 1506 1507 assert(!doesPointTo(*smallArr3, a)); 1508 assert(!doesPointTo(*smallArr3, b)); 1509 1510 auto v3 = cast(void[3]*) &voidArr[16]; // Arrays smaller than pointers are ignored 1511 assert(!mayPointTo(*v3, a)); 1512 assert(!mayPointTo(*v3, b)); 1513 1514 assert(!doesPointTo(*v3, a)); 1515 assert(!doesPointTo(*v3, b)); 1516 1517 assert(mayPointTo(voidArr, a)); // slice-contiaining void[N] might point at anything 1518 assert(mayPointTo(voidArr, b)); 1519 1520 static assert(() { 1521 void[16] arr1 = void; 1522 void[size_t.sizeof] arr2 = void; 1523 int var; 1524 return mayPointTo(arr1, var) && !doesPointTo(arr1, var) && 1525 mayPointTo(arr2, var) && !doesPointTo(arr2, var); 1526 }()); 1527 } 1528 1529 1530 @system unittest //Unions 1531 { 1532 int i; 1533 union U //Named union 1534 { 1535 size_t asInt = 0; 1536 int* asPointer; 1537 } 1538 struct S 1539 { 1540 union //Anonymous union 1541 { 1542 size_t asInt = 0; 1543 int* asPointer; 1544 } 1545 } 1546 1547 U u; 1548 S s; 1549 assert(!doesPointTo(u, i)); 1550 assert(!doesPointTo(s, i)); 1551 assert(!mayPointTo(u, i)); 1552 assert(!mayPointTo(s, i)); 1553 1554 u.asPointer = &i; 1555 s.asPointer = &i; 1556 assert(!doesPointTo(u, i)); 1557 assert(!doesPointTo(s, i)); 1558 assert( mayPointTo(u, i)); 1559 assert( mayPointTo(s, i)); 1560 1561 u.asInt = cast(size_t)&i; 1562 s.asInt = cast(size_t)&i; 1563 assert(!doesPointTo(u, i)); 1564 assert(!doesPointTo(s, i)); 1565 assert( mayPointTo(u, i)); 1566 assert( mayPointTo(s, i)); 1567 } 1568 1569 @system unittest //Classes 1570 { 1571 int i; 1572 static class A 1573 { 1574 int* p; 1575 } 1576 A a = new A, b = a; 1577 assert(!doesPointTo(a, b)); //a does not point to b 1578 a.p = &i; 1579 assert(!doesPointTo(a, i)); //a does not point to i 1580 } 1581 @safe unittest //alias this test 1582 { 1583 static int i; 1584 static int j; 1585 struct S 1586 { 1587 int* p; 1588 @property int* foo(){return &i;} 1589 alias foo this; 1590 } 1591 assert(is(S : int*)); 1592 S s = S(&j); 1593 assert(!doesPointTo(s, i)); 1594 assert( doesPointTo(s, j)); 1595 assert( doesPointTo(cast(int*) s, i)); 1596 assert(!doesPointTo(cast(int*) s, j)); 1597 } 1598 @safe unittest //more alias this opCast 1599 { 1600 void* p; 1601 class A 1602 { 1603 void* opCast(T)() if (is(T == void*)) 1604 { 1605 return p; 1606 } 1607 alias foo = opCast!(void*); 1608 alias foo this; 1609 } 1610 assert(!doesPointTo(A.init, p)); 1611 assert(!mayPointTo(A.init, p)); 1612 } 1613 1614 /+ 1615 Returns true if the field at index `i` in ($D T) shares its address with another field. 1616 1617 Note: This does not merelly check if the field is a member of an union, but also that 1618 it is not a single child. 1619 +/ 1620 package enum isUnionAliased(T, size_t i) = isUnionAliasedImpl!T(T.tupleof[i].offsetof); 1621 private bool isUnionAliasedImpl(T)(size_t offset) 1622 { 1623 int count = 0; 1624 foreach (i, U; typeof(T.tupleof)) 1625 if (T.tupleof[i].offsetof == offset) 1626 ++count; 1627 return count >= 2; 1628 } 1629 // 1630 @safe unittest 1631 { 1632 static struct S 1633 { 1634 int a0; //Not aliased 1635 union 1636 { 1637 int a1; //Not aliased 1638 } 1639 union 1640 { 1641 int a2; //Aliased 1642 int a3; //Aliased 1643 } 1644 union A4 1645 { 1646 int b0; //Not aliased 1647 } 1648 A4 a4; 1649 union A5 1650 { 1651 int b0; //Aliased 1652 int b1; //Aliased 1653 } 1654 A5 a5; 1655 } 1656 1657 static assert(!isUnionAliased!(S, 0)); //a0; 1658 static assert(!isUnionAliased!(S, 1)); //a1; 1659 static assert( isUnionAliased!(S, 2)); //a2; 1660 static assert( isUnionAliased!(S, 3)); //a3; 1661 static assert(!isUnionAliased!(S, 4)); //a4; 1662 static assert(!isUnionAliased!(S.A4, 0)); //a4.b0; 1663 static assert(!isUnionAliased!(S, 5)); //a5; 1664 static assert( isUnionAliased!(S.A5, 0)); //a5.b0; 1665 static assert( isUnionAliased!(S.A5, 1)); //a5.b1; 1666 } 1667 1668 version (CRuntime_Glibc) version = GNU_STRERROR; 1669 version (CRuntime_UClibc) version = GNU_STRERROR; 1670 1671 package string errnoString(int errno) nothrow @trusted 1672 { 1673 import core.stdc..string : strlen; 1674 version (GNU_STRERROR) 1675 { 1676 import core.stdc..string : strerror_r; 1677 char[1024] buf = void; 1678 auto s = strerror_r(errno, buf.ptr, buf.length); 1679 } 1680 else version (Posix) 1681 { 1682 // XSI-compliant 1683 import core.stdc..string : strerror_r; 1684 char[1024] buf = void; 1685 const(char)* s; 1686 if (strerror_r(errno, buf.ptr, buf.length) == 0) 1687 s = buf.ptr; 1688 else 1689 return "Unknown error"; 1690 } 1691 else 1692 { 1693 import core.stdc..string : strerror; 1694 auto s = strerror(errno); 1695 } 1696 return s[0 .. s.strlen].idup; 1697 } 1698 1699 /********************* 1700 * Thrown if errors that set `errno` occur. 1701 */ 1702 class ErrnoException : Exception 1703 { 1704 /// Operating system error code. 1705 final @property uint errno() nothrow pure @nogc @safe { return _errno; } 1706 private uint _errno; 1707 /// Constructor which takes an error message. The current global $(REF errno, core,stdc,errno) value is used as error code. 1708 this(string msg, string file = null, size_t line = 0) @safe 1709 { 1710 import core.stdc.errno : errno; 1711 this(msg, errno, file, line); 1712 } 1713 /// Constructor which takes an error message and error code. 1714 this(string msg, int errno, string file = null, size_t line = 0) @safe 1715 { 1716 _errno = errno; 1717 super(msg ~ " (" ~ errnoString(errno) ~ ")", file, line); 1718 } 1719 } 1720 1721 /// 1722 @safe unittest 1723 { 1724 import core.stdc.errno : EAGAIN; 1725 auto ex = new ErrnoException("oh no", EAGAIN); 1726 assert(ex.errno == EAGAIN); 1727 } 1728 1729 /// errno is used by default if no explicit error code is provided 1730 @safe unittest 1731 { 1732 import core.stdc.errno : errno, EAGAIN; 1733 1734 auto old = errno; 1735 scope(exit) errno = old; 1736 1737 // fake that errno got set by the callee 1738 errno = EAGAIN; 1739 auto ex = new ErrnoException("oh no"); 1740 assert(ex.errno == EAGAIN); 1741 } 1742 1743 /++ 1744 ML-style functional exception handling. Runs the supplied expression and 1745 returns its result. If the expression throws a `Throwable`, runs the 1746 supplied error handler instead and return its result. The error handler's 1747 type must be the same as the expression's type. 1748 1749 Params: 1750 E = The type of `Throwable`s to catch. Defaults to `Exception` 1751 T1 = The type of the expression. 1752 T2 = The return type of the error handler. 1753 expression = The expression to run and return its result. 1754 errorHandler = The handler to run if the expression throwed. 1755 1756 Returns: 1757 expression, if it does not throw. Otherwise, returns the result of 1758 errorHandler. 1759 +/ 1760 //lazy version 1761 CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, lazy scope T2 errorHandler) 1762 { 1763 static assert(!is(typeof(return) == void), 1764 "The error handler's return value(" 1765 ~ T2.stringof ~ 1766 ") does not have a common type with the expression(" 1767 ~ T1.stringof ~ 1768 ")." 1769 ); 1770 try 1771 { 1772 return expression(); 1773 } 1774 catch (E) 1775 { 1776 return errorHandler(); 1777 } 1778 } 1779 1780 ///ditto 1781 //delegate version 1782 CommonType!(T1, T2) ifThrown(E : Throwable, T1, T2)(lazy scope T1 expression, scope T2 delegate(E) errorHandler) 1783 { 1784 static assert(!is(typeof(return) == void), 1785 "The error handler's return value(" 1786 ~ T2.stringof ~ 1787 ") does not have a common type with the expression(" 1788 ~ T1.stringof ~ 1789 ")." 1790 ); 1791 try 1792 { 1793 return expression(); 1794 } 1795 catch (E e) 1796 { 1797 return errorHandler(e); 1798 } 1799 } 1800 1801 ///ditto 1802 //delegate version, general overload to catch any Exception 1803 CommonType!(T1, T2) ifThrown(T1, T2)(lazy scope T1 expression, scope T2 delegate(Exception) errorHandler) 1804 { 1805 static assert(!is(typeof(return) == void), 1806 "The error handler's return value(" 1807 ~ T2.stringof ~ 1808 ") does not have a common type with the expression(" 1809 ~ T1.stringof ~ 1810 ")." 1811 ); 1812 try 1813 { 1814 return expression(); 1815 } 1816 catch (Exception e) 1817 { 1818 return errorHandler(e); 1819 } 1820 } 1821 1822 /// Revert to a default value upon an error: 1823 @safe unittest 1824 { 1825 import std.conv : to; 1826 assert("x".to!int.ifThrown(0) == 0); 1827 } 1828 1829 /** 1830 Chain multiple calls to ifThrown, each capturing errors from the 1831 entire preceding expression. 1832 */ 1833 @safe unittest 1834 { 1835 import std.conv : ConvException, to; 1836 string s = "true"; 1837 assert(s.to!int.ifThrown(cast(int) s.to!double) 1838 .ifThrown(cast(int) s.to!bool) == 1); 1839 1840 s = "2.0"; 1841 assert(s.to!int.ifThrown(cast(int) s.to!double) 1842 .ifThrown(cast(int) s.to!bool) == 2); 1843 1844 // Respond differently to different types of errors 1845 alias orFallback = (lazy a) => a.ifThrown!ConvException("not a number") 1846 .ifThrown!Exception("number too small"); 1847 1848 assert(orFallback(enforce("x".to!int < 1).to!string) == "not a number"); 1849 assert(orFallback(enforce("2".to!int < 1).to!string) == "number too small"); 1850 } 1851 1852 /** 1853 The expression and the errorHandler must have a common type they can both 1854 be implicitly casted to, and that type will be the type of the compound 1855 expression. 1856 */ 1857 @safe unittest 1858 { 1859 // null and new Object have a common type(Object). 1860 static assert(is(typeof(null.ifThrown(new Object())) == Object)); 1861 static assert(is(typeof((new Object()).ifThrown(null)) == Object)); 1862 1863 // 1 and new Object do not have a common type. 1864 static assert(!__traits(compiles, 1.ifThrown(new Object()))); 1865 static assert(!__traits(compiles, (new Object()).ifThrown(1))); 1866 } 1867 1868 /// Use a lambda to get the thrown object. 1869 @system unittest 1870 { 1871 import std.format : format; 1872 assert("%s".format.ifThrown!Exception(e => e.classinfo.name) == "std.format.FormatException"); 1873 } 1874 1875 //Verify Examples 1876 @system unittest 1877 { 1878 import std.conv; 1879 import std..string; 1880 //Revert to a default value upon an error: 1881 assert("x".to!int().ifThrown(0) == 0); 1882 1883 //Chaining multiple calls to ifThrown to attempt multiple things in a row: 1884 string s="true"; 1885 assert(s.to!int(). 1886 ifThrown(cast(int) s.to!double()). 1887 ifThrown(cast(int) s.to!bool()) 1888 == 1); 1889 1890 //Respond differently to different types of errors 1891 assert(enforce("x".to!int() < 1).to!string() 1892 .ifThrown!ConvException("not a number") 1893 .ifThrown!Exception("number too small") 1894 == "not a number"); 1895 1896 //null and new Object have a common type(Object). 1897 static assert(is(typeof(null.ifThrown(new Object())) == Object)); 1898 static assert(is(typeof((new Object()).ifThrown(null)) == Object)); 1899 1900 //1 and new Object do not have a common type. 1901 static assert(!__traits(compiles, 1.ifThrown(new Object()))); 1902 static assert(!__traits(compiles, (new Object()).ifThrown(1))); 1903 1904 //Use a lambda to get the thrown object. 1905 assert("%s".format().ifThrown(e => e.classinfo.name) == "std.format.FormatException"); 1906 } 1907 1908 @system unittest 1909 { 1910 import core.exception; 1911 import std.conv; 1912 import std..string; 1913 //Basic behaviour - all versions. 1914 assert("1".to!int().ifThrown(0) == 1); 1915 assert("x".to!int().ifThrown(0) == 0); 1916 assert("1".to!int().ifThrown!ConvException(0) == 1); 1917 assert("x".to!int().ifThrown!ConvException(0) == 0); 1918 assert("1".to!int().ifThrown(e=>0) == 1); 1919 assert("x".to!int().ifThrown(e=>0) == 0); 1920 static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled 1921 { 1922 assert("1".to!int().ifThrown!ConvException(e=>0) == 1); 1923 assert("x".to!int().ifThrown!ConvException(e=>0) == 0); 1924 } 1925 1926 //Exceptions other than stated not caught. 1927 assert("x".to!int().ifThrown!StringException(0).collectException!ConvException() !is null); 1928 static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled 1929 { 1930 assert("x".to!int().ifThrown!StringException(e=>0).collectException!ConvException() !is null); 1931 } 1932 1933 //Default does not include errors. 1934 int throwRangeError() { throw new RangeError; } 1935 assert(throwRangeError().ifThrown(0).collectException!RangeError() !is null); 1936 assert(throwRangeError().ifThrown(e=>0).collectException!RangeError() !is null); 1937 1938 //Incompatible types are not accepted. 1939 static assert(!__traits(compiles, 1.ifThrown(new Object()))); 1940 static assert(!__traits(compiles, (new Object()).ifThrown(1))); 1941 static assert(!__traits(compiles, 1.ifThrown(e=>new Object()))); 1942 static assert(!__traits(compiles, (new Object()).ifThrown(e=>1))); 1943 } 1944 1945 version (StdUnittest) package 1946 void assertCTFEable(alias dg)() 1947 { 1948 static assert({ cast(void) dg(); return true; }()); 1949 cast(void) dg(); 1950 } 1951 1952 /** This `enum` is used to select the primitives of the range to handle by the 1953 $(LREF handle) range wrapper. The values of the `enum` can be `OR`'d to 1954 select multiple primitives to be handled. 1955 1956 `RangePrimitive.access` is a shortcut for the access primitives; `front`, 1957 `back` and `opIndex`. 1958 1959 `RangePrimitive.pop` is a shortcut for the mutating primitives; 1960 `popFront` and `popBack`. 1961 */ 1962 enum RangePrimitive 1963 { 1964 front = 0b00_0000_0001, /// 1965 back = 0b00_0000_0010, /// Ditto 1966 popFront = 0b00_0000_0100, /// Ditto 1967 popBack = 0b00_0000_1000, /// Ditto 1968 empty = 0b00_0001_0000, /// Ditto 1969 save = 0b00_0010_0000, /// Ditto 1970 length = 0b00_0100_0000, /// Ditto 1971 opDollar = 0b00_1000_0000, /// Ditto 1972 opIndex = 0b01_0000_0000, /// Ditto 1973 opSlice = 0b10_0000_0000, /// Ditto 1974 access = front | back | opIndex, /// Ditto 1975 pop = popFront | popBack, /// Ditto 1976 } 1977 1978 /// 1979 pure @safe unittest 1980 { 1981 import std.algorithm.comparison : equal; 1982 import std.algorithm.iteration : map, splitter; 1983 import std.conv : to, ConvException; 1984 1985 auto s = "12,1337z32,54,2,7,9,1z,6,8"; 1986 1987 // The next line composition will throw when iterated 1988 // as some elements of the input do not convert to integer 1989 auto r = s.splitter(',').map!(a => to!int(a)); 1990 1991 // Substitute 0 for cases of ConvException 1992 auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); 1993 assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8])); 1994 } 1995 1996 /// 1997 pure @safe unittest 1998 { 1999 import std.algorithm.comparison : equal; 2000 import std.range : retro; 2001 import std.utf : UTFException; 2002 2003 auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit 2004 2005 auto handled = str.handle!(UTFException, RangePrimitive.access, 2006 (e, r) => ' '); // Replace invalid code points with spaces 2007 2008 assert(handled.equal("hello world")); // `front` is handled, 2009 assert(handled.retro.equal("dlrow olleh")); // as well as `back` 2010 } 2011 2012 /** Handle exceptions thrown from range primitives. 2013 2014 Use the $(LREF RangePrimitive) enum to specify which primitives to _handle. 2015 Multiple range primitives can be handled at once by using the `OR` operator 2016 or the pseudo-primitives `RangePrimitive.access` and `RangePrimitive.pop`. 2017 All handled primitives must have return types or values compatible with the 2018 user-supplied handler. 2019 2020 Params: 2021 E = The type of `Throwable` to _handle. 2022 primitivesToHandle = Set of range primitives to _handle. 2023 handler = The callable that is called when a handled primitive throws a 2024 `Throwable` of type `E`. The handler must accept arguments of 2025 the form $(D E, ref IRange) and its return value is used as the primitive's 2026 return value whenever `E` is thrown. For `opIndex`, the handler can 2027 optionally recieve a third argument; the index that caused the exception. 2028 input = The range to _handle. 2029 2030 Returns: A wrapper `struct` that preserves the range interface of `input`. 2031 2032 Note: 2033 Infinite ranges with slicing support must return an instance of 2034 $(REF Take, std,range) when sliced with a specific lower and upper 2035 bound (see $(REF hasSlicing, std,range,primitives)); `handle` deals with 2036 this by `take`ing 0 from the return value of the handler function and 2037 returning that when an exception is caught. 2038 */ 2039 auto handle(E : Throwable, RangePrimitive primitivesToHandle, alias handler, Range)(Range input) 2040 if (isInputRange!Range) 2041 { 2042 static struct Handler 2043 { 2044 private Range range; 2045 2046 static if (isForwardRange!Range) 2047 { 2048 @property typeof(this) save() 2049 { 2050 static if (primitivesToHandle & RangePrimitive.save) 2051 { 2052 try 2053 { 2054 return typeof(this)(range.save); 2055 } 2056 catch (E exception) 2057 { 2058 return typeof(this)(handler(exception, this.range)); 2059 } 2060 } 2061 else 2062 return typeof(this)(range.save); 2063 } 2064 } 2065 2066 static if (isInfinite!Range) 2067 { 2068 enum bool empty = false; 2069 } 2070 else 2071 { 2072 @property bool empty() 2073 { 2074 static if (primitivesToHandle & RangePrimitive.empty) 2075 { 2076 try 2077 { 2078 return this.range.empty; 2079 } 2080 catch (E exception) 2081 { 2082 return handler(exception, this.range); 2083 } 2084 } 2085 else 2086 return this.range.empty; 2087 } 2088 } 2089 2090 @property auto ref front() 2091 { 2092 static if (primitivesToHandle & RangePrimitive.front) 2093 { 2094 try 2095 { 2096 return this.range.front; 2097 } 2098 catch (E exception) 2099 { 2100 return handler(exception, this.range); 2101 } 2102 } 2103 else 2104 return this.range.front; 2105 } 2106 2107 void popFront() 2108 { 2109 static if (primitivesToHandle & RangePrimitive.popFront) 2110 { 2111 try 2112 { 2113 this.range.popFront(); 2114 } 2115 catch (E exception) 2116 { 2117 handler(exception, this.range); 2118 } 2119 } 2120 else 2121 this.range.popFront(); 2122 } 2123 2124 static if (isBidirectionalRange!Range) 2125 { 2126 @property auto ref back() 2127 { 2128 static if (primitivesToHandle & RangePrimitive.back) 2129 { 2130 try 2131 { 2132 return this.range.back; 2133 } 2134 catch (E exception) 2135 { 2136 return handler(exception, this.range); 2137 } 2138 } 2139 else 2140 return this.range.back; 2141 } 2142 2143 void popBack() 2144 { 2145 static if (primitivesToHandle & RangePrimitive.popBack) 2146 { 2147 try 2148 { 2149 this.range.popBack(); 2150 } 2151 catch (E exception) 2152 { 2153 handler(exception, this.range); 2154 } 2155 } 2156 else 2157 this.range.popBack(); 2158 } 2159 } 2160 2161 static if (isRandomAccessRange!Range) 2162 { 2163 auto ref opIndex(size_t index) 2164 { 2165 static if (primitivesToHandle & RangePrimitive.opIndex) 2166 { 2167 try 2168 { 2169 return this.range[index]; 2170 } 2171 catch (E exception) 2172 { 2173 static if (__traits(compiles, handler(exception, this.range, index))) 2174 return handler(exception, this.range, index); 2175 else 2176 return handler(exception, this.range); 2177 } 2178 } 2179 else 2180 return this.range[index]; 2181 } 2182 } 2183 2184 static if (hasLength!Range) 2185 { 2186 @property auto length() 2187 { 2188 static if (primitivesToHandle & RangePrimitive.length) 2189 { 2190 try 2191 { 2192 return this.range.length; 2193 } 2194 catch (E exception) 2195 { 2196 return handler(exception, this.range); 2197 } 2198 } 2199 else 2200 return this.range.length; 2201 } 2202 } 2203 2204 static if (hasSlicing!Range) 2205 { 2206 static if (hasLength!Range) 2207 { 2208 typeof(this) opSlice(size_t lower, size_t upper) 2209 { 2210 static if (primitivesToHandle & RangePrimitive.opSlice) 2211 { 2212 try 2213 { 2214 return typeof(this)(this.range[lower .. upper]); 2215 } 2216 catch (E exception) 2217 { 2218 return typeof(this)(handler(exception, this.range)); 2219 } 2220 } 2221 else 2222 return typeof(this)(this.range[lower .. upper]); 2223 } 2224 } 2225 else static if (is(typeof(Range.init[size_t.init .. $]))) 2226 { 2227 import std.range : Take, takeExactly; 2228 static struct DollarToken {} 2229 enum opDollar = DollarToken.init; 2230 2231 typeof(this) opSlice(size_t lower, DollarToken) 2232 { 2233 static if (primitivesToHandle & RangePrimitive.opSlice) 2234 { 2235 try 2236 { 2237 return typeof(this)(this.range[lower .. $]); 2238 } 2239 catch (E exception) 2240 { 2241 return typeof(this)(handler(exception, this.range)); 2242 } 2243 } 2244 else 2245 return typeof(this)(this.range[lower .. $]); 2246 } 2247 2248 Take!Handler opSlice(size_t lower, size_t upper) 2249 { 2250 static if (primitivesToHandle & RangePrimitive.opSlice) 2251 { 2252 try 2253 { 2254 return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1); 2255 } 2256 catch (E exception) 2257 { 2258 return takeExactly(typeof(this)(handler(exception, this.range)), 0); 2259 } 2260 } 2261 else 2262 return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1); 2263 } 2264 } 2265 } 2266 } 2267 2268 return Handler(input); 2269 } 2270 2271 /// 2272 pure @safe unittest 2273 { 2274 import std.algorithm.comparison : equal; 2275 import std.algorithm.iteration : map, splitter; 2276 import std.conv : to, ConvException; 2277 2278 auto s = "12,1337z32,54,2,7,9,1z,6,8"; 2279 2280 // The next line composition will throw when iterated 2281 // as some elements of the input do not convert to integer 2282 auto r = s.splitter(',').map!(a => to!int(a)); 2283 2284 // Substitute 0 for cases of ConvException 2285 auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); 2286 assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8])); 2287 } 2288 2289 /// 2290 pure @safe unittest 2291 { 2292 import std.algorithm.comparison : equal; 2293 import std.range : retro; 2294 import std.utf : UTFException; 2295 2296 auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit 2297 2298 auto handled = str.handle!(UTFException, RangePrimitive.access, 2299 (e, r) => ' '); // Replace invalid code points with spaces 2300 2301 assert(handled.equal("hello world")); // `front` is handled, 2302 assert(handled.retro.equal("dlrow olleh")); // as well as `back` 2303 } 2304 2305 pure nothrow @safe unittest 2306 { 2307 static struct ThrowingRange 2308 { 2309 pure @safe: 2310 @property bool empty() 2311 { 2312 throw new Exception("empty has thrown"); 2313 } 2314 2315 @property int front() 2316 { 2317 throw new Exception("front has thrown"); 2318 } 2319 2320 @property int back() 2321 { 2322 throw new Exception("back has thrown"); 2323 } 2324 2325 void popFront() 2326 { 2327 throw new Exception("popFront has thrown"); 2328 } 2329 2330 void popBack() 2331 { 2332 throw new Exception("popBack has thrown"); 2333 } 2334 2335 int opIndex(size_t) 2336 { 2337 throw new Exception("opIndex has thrown"); 2338 } 2339 2340 ThrowingRange opSlice(size_t, size_t) 2341 { 2342 throw new Exception("opSlice has thrown"); 2343 } 2344 2345 @property size_t length() 2346 { 2347 throw new Exception("length has thrown"); 2348 } 2349 2350 alias opDollar = length; 2351 2352 @property ThrowingRange save() 2353 { 2354 throw new Exception("save has thrown"); 2355 } 2356 } 2357 2358 static assert(isInputRange!ThrowingRange); 2359 static assert(isForwardRange!ThrowingRange); 2360 static assert(isBidirectionalRange!ThrowingRange); 2361 static assert(hasSlicing!ThrowingRange); 2362 static assert(hasLength!ThrowingRange); 2363 2364 auto f = ThrowingRange(); 2365 auto fb = f.handle!(Exception, RangePrimitive.front | RangePrimitive.back, 2366 (e, r) => -1)(); 2367 assert(fb.front == -1); 2368 assert(fb.back == -1); 2369 assertThrown(fb.popFront()); 2370 assertThrown(fb.popBack()); 2371 assertThrown(fb.empty); 2372 assertThrown(fb.save); 2373 assertThrown(fb[0]); 2374 2375 auto accessRange = f.handle!(Exception, RangePrimitive.access, 2376 (e, r) => -1); 2377 assert(accessRange.front == -1); 2378 assert(accessRange.back == -1); 2379 assert(accessRange[0] == -1); 2380 assertThrown(accessRange.popFront()); 2381 assertThrown(accessRange.popBack()); 2382 2383 auto pfb = f.handle!(Exception, RangePrimitive.pop, (e, r) => -1)(); 2384 2385 pfb.popFront(); // this would throw otherwise 2386 pfb.popBack(); // this would throw otherwise 2387 2388 auto em = f.handle!(Exception, 2389 RangePrimitive.empty, (e, r) => false)(); 2390 2391 assert(!em.empty); 2392 2393 auto arr = f.handle!(Exception, 2394 RangePrimitive.opIndex, (e, r) => 1337)(); 2395 2396 assert(arr[0] == 1337); 2397 2398 auto arr2 = f.handle!(Exception, 2399 RangePrimitive.opIndex, (e, r, i) => i)(); 2400 2401 assert(arr2[0] == 0); 2402 assert(arr2[1337] == 1337); 2403 2404 auto save = f.handle!(Exception, 2405 RangePrimitive.save, 2406 function(Exception e, ref ThrowingRange r) { 2407 return ThrowingRange(); 2408 })(); 2409 2410 save.save; 2411 2412 auto slice = f.handle!(Exception, 2413 RangePrimitive.opSlice, (e, r) => ThrowingRange())(); 2414 2415 auto sliced = slice[0 .. 1337]; // this would throw otherwise 2416 2417 static struct Infinite 2418 { 2419 import std.range : Take; 2420 pure @safe: 2421 enum bool empty = false; 2422 int front() { assert(false); } 2423 void popFront() { assert(false); } 2424 Infinite save() @property { assert(false); } 2425 static struct DollarToken {} 2426 enum opDollar = DollarToken.init; 2427 Take!Infinite opSlice(size_t, size_t) { assert(false); } 2428 Infinite opSlice(size_t, DollarToken) 2429 { 2430 throw new Exception("opSlice has thrown"); 2431 } 2432 } 2433 2434 static assert(isInputRange!Infinite); 2435 static assert(isInfinite!Infinite); 2436 static assert(hasSlicing!Infinite); 2437 2438 assertThrown(Infinite()[0 .. $]); 2439 2440 auto infinite = Infinite.init.handle!(Exception, 2441 RangePrimitive.opSlice, (e, r) => Infinite())(); 2442 2443 auto infSlice = infinite[0 .. $]; // this would throw otherwise 2444 } 2445 2446 2447 /++ 2448 Convenience mixin for trivially sub-classing exceptions 2449 2450 Even trivially sub-classing an exception involves writing boilerplate code 2451 for the constructor to: 1$(RPAREN) correctly pass in the source file and line number 2452 the exception was thrown from; 2$(RPAREN) be usable with $(LREF enforce) which 2453 expects exception constructors to take arguments in a fixed order. This 2454 mixin provides that boilerplate code. 2455 2456 Note however that you need to mark the $(B mixin) line with at least a 2457 minimal (i.e. just $(B ///)) DDoc comment if you want the mixed-in 2458 constructors to be documented in the newly created Exception subclass. 2459 2460 $(RED Current limitation): Due to 2461 $(LINK2 https://issues.dlang.org/show_bug.cgi?id=11500, bug #11500), 2462 currently the constructors specified in this mixin cannot be overloaded with 2463 any other custom constructors. Thus this mixin can currently only be used 2464 when no such custom constructors need to be explicitly specified. 2465 +/ 2466 mixin template basicExceptionCtors() 2467 { 2468 /++ 2469 Params: 2470 msg = The message for the exception. 2471 file = The file where the exception occurred. 2472 line = The line number where the exception occurred. 2473 next = The previous exception in the chain of exceptions, if any. 2474 +/ 2475 this(string msg, string file = __FILE__, size_t line = __LINE__, 2476 Throwable next = null) @nogc @safe pure nothrow 2477 { 2478 super(msg, file, line, next); 2479 } 2480 2481 /++ 2482 Params: 2483 msg = The message for the exception. 2484 next = The previous exception in the chain of exceptions. 2485 file = The file where the exception occurred. 2486 line = The line number where the exception occurred. 2487 +/ 2488 this(string msg, Throwable next, string file = __FILE__, 2489 size_t line = __LINE__) @nogc @safe pure nothrow 2490 { 2491 super(msg, file, line, next); 2492 } 2493 } 2494 2495 /// 2496 @safe unittest 2497 { 2498 class MeaCulpa: Exception 2499 { 2500 /// 2501 mixin basicExceptionCtors; 2502 } 2503 2504 try 2505 throw new MeaCulpa("test"); 2506 catch (MeaCulpa e) 2507 { 2508 assert(e.msg == "test"); 2509 assert(e.file == __FILE__); 2510 assert(e.line == __LINE__ - 5); 2511 } 2512 } 2513 2514 @safe pure nothrow unittest 2515 { 2516 class TestException : Exception { mixin basicExceptionCtors; } 2517 auto e = new Exception("msg"); 2518 auto te1 = new TestException("foo"); 2519 auto te2 = new TestException("foo", e); 2520 } 2521 2522 @safe unittest 2523 { 2524 class TestException : Exception { mixin basicExceptionCtors; } 2525 auto e = new Exception("!!!"); 2526 2527 auto te1 = new TestException("message", "file", 42, e); 2528 assert(te1.msg == "message"); 2529 assert(te1.file == "file"); 2530 assert(te1.line == 42); 2531 assert(te1.next is e); 2532 2533 auto te2 = new TestException("message", e, "file", 42); 2534 assert(te2.msg == "message"); 2535 assert(te2.file == "file"); 2536 assert(te2.line == 42); 2537 assert(te2.next is e); 2538 2539 auto te3 = new TestException("foo"); 2540 assert(te3.msg == "foo"); 2541 assert(te3.file == __FILE__); 2542 assert(te3.line == __LINE__ - 3); 2543 assert(te3.next is null); 2544 2545 auto te4 = new TestException("foo", e); 2546 assert(te4.msg == "foo"); 2547 assert(te4.file == __FILE__); 2548 assert(te4.line == __LINE__ - 3); 2549 assert(te4.next is e); 2550 }