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