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