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