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