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 /// Localized error message generated through $(REF strerror_r, core,stdc,string) or $(REF strerror, core,stdc,string). 1637 final @property string errnoMsg() nothrow pure scope @nogc @safe { return _errnoMsg; } 1638 private string _errnoMsg; 1639 /// Constructor which takes an error message. The current global $(REF errno, core,stdc,errno) value is used as error code. 1640 this(string msg, string file = null, size_t line = 0) @safe 1641 { 1642 import core.stdc.errno : errno; 1643 this(msg, errno, file, line); 1644 } 1645 /// Constructor which takes an error message and error code. 1646 this(string msg, int errno, string file = null, size_t line = 0) @safe 1647 { 1648 _errno = errno; 1649 _errnoMsg = errnoString(errno); 1650 super(msg ~ " (" ~ errnoMsg ~ ")", file, line); 1651 } 1652 } 1653 1654 /// 1655 @safe unittest 1656 { 1657 import core.stdc.errno : EAGAIN; 1658 auto ex = new ErrnoException("oh no", EAGAIN); 1659 assert(ex.errno == EAGAIN); 1660 } 1661 1662 /// errno is used by default if no explicit error code is provided 1663 @safe unittest 1664 { 1665 import core.stdc.errno : errno, EAGAIN; 1666 1667 auto old = errno; 1668 scope(exit) errno = old; 1669 1670 // fake that errno got set by the callee 1671 errno = EAGAIN; 1672 auto ex = new ErrnoException("oh no"); 1673 assert(ex.errno == EAGAIN); 1674 } 1675 1676 /++ 1677 ML-style functional exception handling. Runs the supplied expression and 1678 returns its result. If the expression throws a `Throwable`, runs the 1679 supplied error handler instead and return its result. The error handler's 1680 type must be the same as the expression's type. 1681 1682 Params: 1683 E = The type of `Throwable`s to catch. Defaults to `Exception` 1684 T1 = The type of the expression. 1685 T2 = The return type of the error handler. 1686 expression = The expression to run and return its result. 1687 errorHandler = The handler to run if the expression throwed. 1688 1689 Returns: 1690 expression, if it does not throw. Otherwise, returns the result of 1691 errorHandler. 1692 +/ 1693 //lazy version 1694 CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, lazy scope T2 errorHandler) 1695 { 1696 static assert(!is(typeof(return) == void), 1697 "The error handler's return value(" 1698 ~ T2.stringof ~ 1699 ") does not have a common type with the expression(" 1700 ~ T1.stringof ~ 1701 ")." 1702 ); 1703 try 1704 { 1705 return expression(); 1706 } 1707 catch (E) 1708 { 1709 return errorHandler(); 1710 } 1711 } 1712 1713 ///ditto 1714 //delegate version 1715 CommonType!(T1, T2) ifThrown(E : Throwable, T1, T2)(lazy scope T1 expression, scope T2 delegate(E) errorHandler) 1716 { 1717 static assert(!is(typeof(return) == void), 1718 "The error handler's return value(" 1719 ~ T2.stringof ~ 1720 ") does not have a common type with the expression(" 1721 ~ T1.stringof ~ 1722 ")." 1723 ); 1724 try 1725 { 1726 return expression(); 1727 } 1728 catch (E e) 1729 { 1730 return errorHandler(e); 1731 } 1732 } 1733 1734 ///ditto 1735 //delegate version, general overload to catch any Exception 1736 CommonType!(T1, T2) ifThrown(T1, T2)(lazy scope T1 expression, scope T2 delegate(Exception) errorHandler) 1737 { 1738 static assert(!is(typeof(return) == void), 1739 "The error handler's return value(" 1740 ~ T2.stringof ~ 1741 ") does not have a common type with the expression(" 1742 ~ T1.stringof ~ 1743 ")." 1744 ); 1745 try 1746 { 1747 return expression(); 1748 } 1749 catch (Exception e) 1750 { 1751 return errorHandler(e); 1752 } 1753 } 1754 1755 /// Revert to a default value upon an error: 1756 @safe unittest 1757 { 1758 import std.conv : to; 1759 assert("x".to!int.ifThrown(0) == 0); 1760 } 1761 1762 /** 1763 Chain multiple calls to ifThrown, each capturing errors from the 1764 entire preceding expression. 1765 */ 1766 @safe unittest 1767 { 1768 import std.conv : ConvException, to; 1769 string s = "true"; 1770 assert(s.to!int.ifThrown(cast(int) s.to!double) 1771 .ifThrown(cast(int) s.to!bool) == 1); 1772 1773 s = "2.0"; 1774 assert(s.to!int.ifThrown(cast(int) s.to!double) 1775 .ifThrown(cast(int) s.to!bool) == 2); 1776 1777 // Respond differently to different types of errors 1778 alias orFallback = (lazy a) => a.ifThrown!ConvException("not a number") 1779 .ifThrown!Exception("number too small"); 1780 1781 assert(orFallback(enforce("x".to!int < 1).to!string) == "not a number"); 1782 assert(orFallback(enforce("2".to!int < 1).to!string) == "number too small"); 1783 } 1784 1785 /** 1786 The expression and the errorHandler must have a common type they can both 1787 be implicitly casted to, and that type will be the type of the compound 1788 expression. 1789 */ 1790 @safe unittest 1791 { 1792 // null and new Object have a common type(Object). 1793 static assert(is(typeof(null.ifThrown(new Object())) == Object)); 1794 static assert(is(typeof((new Object()).ifThrown(null)) == Object)); 1795 1796 // 1 and new Object do not have a common type. 1797 static assert(!__traits(compiles, 1.ifThrown(new Object()))); 1798 static assert(!__traits(compiles, (new Object()).ifThrown(1))); 1799 } 1800 1801 /// Use a lambda to get the thrown object. 1802 @system unittest 1803 { 1804 import std.format : format; 1805 assert("%s".format.ifThrown!Exception(e => e.classinfo.name) == "std.format.FormatException"); 1806 } 1807 1808 //Verify Examples 1809 @system unittest 1810 { 1811 import std.conv; 1812 import std.string; 1813 //Revert to a default value upon an error: 1814 assert("x".to!int().ifThrown(0) == 0); 1815 1816 //Chaining multiple calls to ifThrown to attempt multiple things in a row: 1817 string s="true"; 1818 assert(s.to!int(). 1819 ifThrown(cast(int) s.to!double()). 1820 ifThrown(cast(int) s.to!bool()) 1821 == 1); 1822 1823 //Respond differently to different types of errors 1824 assert(enforce("x".to!int() < 1).to!string() 1825 .ifThrown!ConvException("not a number") 1826 .ifThrown!Exception("number too small") 1827 == "not a number"); 1828 1829 //null and new Object have a common type(Object). 1830 static assert(is(typeof(null.ifThrown(new Object())) == Object)); 1831 static assert(is(typeof((new Object()).ifThrown(null)) == Object)); 1832 1833 //1 and new Object do not have a common type. 1834 static assert(!__traits(compiles, 1.ifThrown(new Object()))); 1835 static assert(!__traits(compiles, (new Object()).ifThrown(1))); 1836 1837 //Use a lambda to get the thrown object. 1838 assert("%s".format().ifThrown(e => e.classinfo.name) == "std.format.FormatException"); 1839 } 1840 1841 @system unittest 1842 { 1843 import core.exception; 1844 import std.conv; 1845 import std.string; 1846 //Basic behaviour - all versions. 1847 assert("1".to!int().ifThrown(0) == 1); 1848 assert("x".to!int().ifThrown(0) == 0); 1849 assert("1".to!int().ifThrown!ConvException(0) == 1); 1850 assert("x".to!int().ifThrown!ConvException(0) == 0); 1851 assert("1".to!int().ifThrown(e=>0) == 1); 1852 assert("x".to!int().ifThrown(e=>0) == 0); 1853 static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled 1854 { 1855 assert("1".to!int().ifThrown!ConvException(e=>0) == 1); 1856 assert("x".to!int().ifThrown!ConvException(e=>0) == 0); 1857 } 1858 1859 //Exceptions other than stated not caught. 1860 assert("x".to!int().ifThrown!StringException(0).collectException!ConvException() !is null); 1861 static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled 1862 { 1863 assert("x".to!int().ifThrown!StringException(e=>0).collectException!ConvException() !is null); 1864 } 1865 1866 //Default does not include errors. 1867 int throwRangeError() { throw new RangeError; } 1868 assert(throwRangeError().ifThrown(0).collectException!RangeError() !is null); 1869 assert(throwRangeError().ifThrown(e=>0).collectException!RangeError() !is null); 1870 1871 //Incompatible types are not accepted. 1872 static assert(!__traits(compiles, 1.ifThrown(new Object()))); 1873 static assert(!__traits(compiles, (new Object()).ifThrown(1))); 1874 static assert(!__traits(compiles, 1.ifThrown(e=>new Object()))); 1875 static assert(!__traits(compiles, (new Object()).ifThrown(e=>1))); 1876 } 1877 1878 version (StdUnittest) package 1879 void assertCTFEable(alias dg)() 1880 { 1881 static assert({ cast(void) dg(); return true; }()); 1882 cast(void) dg(); 1883 } 1884 1885 /** This `enum` is used to select the primitives of the range to handle by the 1886 $(LREF handle) range wrapper. The values of the `enum` can be `OR`'d to 1887 select multiple primitives to be handled. 1888 1889 `RangePrimitive.access` is a shortcut for the access primitives; `front`, 1890 `back` and `opIndex`. 1891 1892 `RangePrimitive.pop` is a shortcut for the mutating primitives; 1893 `popFront` and `popBack`. 1894 */ 1895 enum RangePrimitive 1896 { 1897 front = 0b00_0000_0001, /// 1898 back = 0b00_0000_0010, /// Ditto 1899 popFront = 0b00_0000_0100, /// Ditto 1900 popBack = 0b00_0000_1000, /// Ditto 1901 empty = 0b00_0001_0000, /// Ditto 1902 save = 0b00_0010_0000, /// Ditto 1903 length = 0b00_0100_0000, /// Ditto 1904 opDollar = 0b00_1000_0000, /// Ditto 1905 opIndex = 0b01_0000_0000, /// Ditto 1906 opSlice = 0b10_0000_0000, /// Ditto 1907 access = front | back | opIndex, /// Ditto 1908 pop = popFront | popBack, /// Ditto 1909 } 1910 1911 /// 1912 pure @safe unittest 1913 { 1914 import std.algorithm.comparison : equal; 1915 import std.algorithm.iteration : map, splitter; 1916 import std.conv : to, ConvException; 1917 1918 auto s = "12,1337z32,54,2,7,9,1z,6,8"; 1919 1920 // The next line composition will throw when iterated 1921 // as some elements of the input do not convert to integer 1922 auto r = s.splitter(',').map!(a => to!int(a)); 1923 1924 // Substitute 0 for cases of ConvException 1925 auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); 1926 assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8])); 1927 } 1928 1929 /// 1930 pure @safe unittest 1931 { 1932 import std.algorithm.comparison : equal; 1933 import std.range : retro; 1934 import std.utf : UTFException; 1935 1936 auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit 1937 1938 auto handled = str.handle!(UTFException, RangePrimitive.access, 1939 (e, r) => ' '); // Replace invalid code points with spaces 1940 1941 assert(handled.equal("hello world")); // `front` is handled, 1942 assert(handled.retro.equal("dlrow olleh")); // as well as `back` 1943 } 1944 1945 /** Handle exceptions thrown from range primitives. 1946 1947 Use the $(LREF RangePrimitive) enum to specify which primitives to _handle. 1948 Multiple range primitives can be handled at once by using the `OR` operator 1949 or the pseudo-primitives `RangePrimitive.access` and `RangePrimitive.pop`. 1950 All handled primitives must have return types or values compatible with the 1951 user-supplied handler. 1952 1953 Params: 1954 E = The type of `Throwable` to _handle. 1955 primitivesToHandle = Set of range primitives to _handle. 1956 handler = The callable that is called when a handled primitive throws a 1957 `Throwable` of type `E`. The handler must accept arguments of 1958 the form $(D E, ref IRange) and its return value is used as the primitive's 1959 return value whenever `E` is thrown. For `opIndex`, the handler can 1960 optionally recieve a third argument; the index that caused the exception. 1961 input = The range to _handle. 1962 1963 Returns: A wrapper `struct` that preserves the range interface of `input`. 1964 1965 Note: 1966 Infinite ranges with slicing support must return an instance of 1967 $(REF Take, std,range) when sliced with a specific lower and upper 1968 bound (see $(REF hasSlicing, std,range,primitives)); `handle` deals with 1969 this by `take`ing 0 from the return value of the handler function and 1970 returning that when an exception is caught. 1971 */ 1972 auto handle(E : Throwable, RangePrimitive primitivesToHandle, alias handler, Range)(Range input) 1973 if (isInputRange!Range) 1974 { 1975 static struct Handler 1976 { 1977 private Range range; 1978 1979 static if (isForwardRange!Range) 1980 { 1981 @property typeof(this) save() 1982 { 1983 static if (primitivesToHandle & RangePrimitive.save) 1984 { 1985 try 1986 { 1987 return typeof(this)(range.save); 1988 } 1989 catch (E exception) 1990 { 1991 return typeof(this)(handler(exception, this.range)); 1992 } 1993 } 1994 else 1995 return typeof(this)(range.save); 1996 } 1997 } 1998 1999 static if (isInfinite!Range) 2000 { 2001 enum bool empty = false; 2002 } 2003 else 2004 { 2005 @property bool empty() 2006 { 2007 static if (primitivesToHandle & RangePrimitive.empty) 2008 { 2009 try 2010 { 2011 return this.range.empty; 2012 } 2013 catch (E exception) 2014 { 2015 return handler(exception, this.range); 2016 } 2017 } 2018 else 2019 return this.range.empty; 2020 } 2021 } 2022 2023 @property auto ref front() 2024 { 2025 static if (primitivesToHandle & RangePrimitive.front) 2026 { 2027 try 2028 { 2029 return this.range.front; 2030 } 2031 catch (E exception) 2032 { 2033 return handler(exception, this.range); 2034 } 2035 } 2036 else 2037 return this.range.front; 2038 } 2039 2040 void popFront() 2041 { 2042 static if (primitivesToHandle & RangePrimitive.popFront) 2043 { 2044 try 2045 { 2046 this.range.popFront(); 2047 } 2048 catch (E exception) 2049 { 2050 handler(exception, this.range); 2051 } 2052 } 2053 else 2054 this.range.popFront(); 2055 } 2056 2057 static if (isBidirectionalRange!Range) 2058 { 2059 @property auto ref back() 2060 { 2061 static if (primitivesToHandle & RangePrimitive.back) 2062 { 2063 try 2064 { 2065 return this.range.back; 2066 } 2067 catch (E exception) 2068 { 2069 return handler(exception, this.range); 2070 } 2071 } 2072 else 2073 return this.range.back; 2074 } 2075 2076 void popBack() 2077 { 2078 static if (primitivesToHandle & RangePrimitive.popBack) 2079 { 2080 try 2081 { 2082 this.range.popBack(); 2083 } 2084 catch (E exception) 2085 { 2086 handler(exception, this.range); 2087 } 2088 } 2089 else 2090 this.range.popBack(); 2091 } 2092 } 2093 2094 static if (isRandomAccessRange!Range) 2095 { 2096 auto ref opIndex(size_t index) 2097 { 2098 static if (primitivesToHandle & RangePrimitive.opIndex) 2099 { 2100 try 2101 { 2102 return this.range[index]; 2103 } 2104 catch (E exception) 2105 { 2106 static if (__traits(compiles, handler(exception, this.range, index))) 2107 return handler(exception, this.range, index); 2108 else 2109 return handler(exception, this.range); 2110 } 2111 } 2112 else 2113 return this.range[index]; 2114 } 2115 } 2116 2117 static if (hasLength!Range) 2118 { 2119 @property auto length() 2120 { 2121 static if (primitivesToHandle & RangePrimitive.length) 2122 { 2123 try 2124 { 2125 return this.range.length; 2126 } 2127 catch (E exception) 2128 { 2129 return handler(exception, this.range); 2130 } 2131 } 2132 else 2133 return this.range.length; 2134 } 2135 } 2136 2137 static if (hasSlicing!Range) 2138 { 2139 static if (hasLength!Range) 2140 { 2141 typeof(this) opSlice(size_t lower, size_t upper) 2142 { 2143 static if (primitivesToHandle & RangePrimitive.opSlice) 2144 { 2145 try 2146 { 2147 return typeof(this)(this.range[lower .. upper]); 2148 } 2149 catch (E exception) 2150 { 2151 return typeof(this)(handler(exception, this.range)); 2152 } 2153 } 2154 else 2155 return typeof(this)(this.range[lower .. upper]); 2156 } 2157 } 2158 else static if (is(typeof(Range.init[size_t.init .. $]))) 2159 { 2160 import std.range : Take, takeExactly; 2161 static struct DollarToken {} 2162 enum opDollar = DollarToken.init; 2163 2164 typeof(this) opSlice(size_t lower, DollarToken) 2165 { 2166 static if (primitivesToHandle & RangePrimitive.opSlice) 2167 { 2168 try 2169 { 2170 return typeof(this)(this.range[lower .. $]); 2171 } 2172 catch (E exception) 2173 { 2174 return typeof(this)(handler(exception, this.range)); 2175 } 2176 } 2177 else 2178 return typeof(this)(this.range[lower .. $]); 2179 } 2180 2181 Take!Handler opSlice(size_t lower, size_t upper) 2182 { 2183 static if (primitivesToHandle & RangePrimitive.opSlice) 2184 { 2185 try 2186 { 2187 return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1); 2188 } 2189 catch (E exception) 2190 { 2191 return takeExactly(typeof(this)(handler(exception, this.range)), 0); 2192 } 2193 } 2194 else 2195 return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1); 2196 } 2197 } 2198 } 2199 } 2200 2201 return Handler(input); 2202 } 2203 2204 /// 2205 pure @safe unittest 2206 { 2207 import std.algorithm.comparison : equal; 2208 import std.algorithm.iteration : map, splitter; 2209 import std.conv : to, ConvException; 2210 2211 auto s = "12,1337z32,54,2,7,9,1z,6,8"; 2212 2213 // The next line composition will throw when iterated 2214 // as some elements of the input do not convert to integer 2215 auto r = s.splitter(',').map!(a => to!int(a)); 2216 2217 // Substitute 0 for cases of ConvException 2218 auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); 2219 assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8])); 2220 } 2221 2222 /// 2223 pure @safe unittest 2224 { 2225 import std.algorithm.comparison : equal; 2226 import std.range : retro; 2227 import std.utf : UTFException; 2228 2229 auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit 2230 2231 auto handled = str.handle!(UTFException, RangePrimitive.access, 2232 (e, r) => ' '); // Replace invalid code points with spaces 2233 2234 assert(handled.equal("hello world")); // `front` is handled, 2235 assert(handled.retro.equal("dlrow olleh")); // as well as `back` 2236 } 2237 2238 pure nothrow @safe unittest 2239 { 2240 static struct ThrowingRange 2241 { 2242 pure @safe: 2243 @property bool empty() 2244 { 2245 throw new Exception("empty has thrown"); 2246 } 2247 2248 @property int front() 2249 { 2250 throw new Exception("front has thrown"); 2251 } 2252 2253 @property int back() 2254 { 2255 throw new Exception("back has thrown"); 2256 } 2257 2258 void popFront() 2259 { 2260 throw new Exception("popFront has thrown"); 2261 } 2262 2263 void popBack() 2264 { 2265 throw new Exception("popBack has thrown"); 2266 } 2267 2268 int opIndex(size_t) 2269 { 2270 throw new Exception("opIndex has thrown"); 2271 } 2272 2273 ThrowingRange opSlice(size_t, size_t) 2274 { 2275 throw new Exception("opSlice has thrown"); 2276 } 2277 2278 @property size_t length() 2279 { 2280 throw new Exception("length has thrown"); 2281 } 2282 2283 alias opDollar = length; 2284 2285 @property ThrowingRange save() 2286 { 2287 throw new Exception("save has thrown"); 2288 } 2289 } 2290 2291 static assert(isInputRange!ThrowingRange); 2292 static assert(isForwardRange!ThrowingRange); 2293 static assert(isBidirectionalRange!ThrowingRange); 2294 static assert(hasSlicing!ThrowingRange); 2295 static assert(hasLength!ThrowingRange); 2296 2297 auto f = ThrowingRange(); 2298 auto fb = f.handle!(Exception, RangePrimitive.front | RangePrimitive.back, 2299 (e, r) => -1)(); 2300 assert(fb.front == -1); 2301 assert(fb.back == -1); 2302 assertThrown(fb.popFront()); 2303 assertThrown(fb.popBack()); 2304 assertThrown(fb.empty); 2305 assertThrown(fb.save); 2306 assertThrown(fb[0]); 2307 2308 auto accessRange = f.handle!(Exception, RangePrimitive.access, 2309 (e, r) => -1); 2310 assert(accessRange.front == -1); 2311 assert(accessRange.back == -1); 2312 assert(accessRange[0] == -1); 2313 assertThrown(accessRange.popFront()); 2314 assertThrown(accessRange.popBack()); 2315 2316 auto pfb = f.handle!(Exception, RangePrimitive.pop, (e, r) => -1)(); 2317 2318 pfb.popFront(); // this would throw otherwise 2319 pfb.popBack(); // this would throw otherwise 2320 2321 auto em = f.handle!(Exception, 2322 RangePrimitive.empty, (e, r) => false)(); 2323 2324 assert(!em.empty); 2325 2326 auto arr = f.handle!(Exception, 2327 RangePrimitive.opIndex, (e, r) => 1337)(); 2328 2329 assert(arr[0] == 1337); 2330 2331 auto arr2 = f.handle!(Exception, 2332 RangePrimitive.opIndex, (e, r, i) => i)(); 2333 2334 assert(arr2[0] == 0); 2335 assert(arr2[1337] == 1337); 2336 2337 auto save = f.handle!(Exception, 2338 RangePrimitive.save, 2339 function(Exception e, ref ThrowingRange r) { 2340 return ThrowingRange(); 2341 })(); 2342 2343 save.save; 2344 2345 auto slice = f.handle!(Exception, 2346 RangePrimitive.opSlice, (e, r) => ThrowingRange())(); 2347 2348 auto sliced = slice[0 .. 1337]; // this would throw otherwise 2349 2350 static struct Infinite 2351 { 2352 import std.range : Take; 2353 pure @safe: 2354 enum bool empty = false; 2355 int front() { assert(false); } 2356 void popFront() { assert(false); } 2357 Infinite save() @property { assert(false); } 2358 static struct DollarToken {} 2359 enum opDollar = DollarToken.init; 2360 Take!Infinite opSlice(size_t, size_t) { assert(false); } 2361 Infinite opSlice(size_t, DollarToken) 2362 { 2363 throw new Exception("opSlice has thrown"); 2364 } 2365 } 2366 2367 static assert(isInputRange!Infinite); 2368 static assert(isInfinite!Infinite); 2369 static assert(hasSlicing!Infinite); 2370 2371 assertThrown(Infinite()[0 .. $]); 2372 2373 auto infinite = Infinite.init.handle!(Exception, 2374 RangePrimitive.opSlice, (e, r) => Infinite())(); 2375 2376 auto infSlice = infinite[0 .. $]; // this would throw otherwise 2377 } 2378 2379 2380 /++ 2381 Convenience mixin for trivially sub-classing exceptions 2382 2383 Even trivially sub-classing an exception involves writing boilerplate code 2384 for the constructor to: 1$(RPAREN) correctly pass in the source file and line number 2385 the exception was thrown from; 2$(RPAREN) be usable with $(LREF enforce) which 2386 expects exception constructors to take arguments in a fixed order. This 2387 mixin provides that boilerplate code. 2388 2389 Note however that you need to mark the $(B mixin) line with at least a 2390 minimal (i.e. just $(B ///)) DDoc comment if you want the mixed-in 2391 constructors to be documented in the newly created Exception subclass. 2392 2393 $(RED Current limitation): Due to 2394 $(LINK2 https://issues.dlang.org/show_bug.cgi?id=11500, bug #11500), 2395 currently the constructors specified in this mixin cannot be overloaded with 2396 any other custom constructors. Thus this mixin can currently only be used 2397 when no such custom constructors need to be explicitly specified. 2398 +/ 2399 mixin template basicExceptionCtors() 2400 { 2401 /++ 2402 Params: 2403 msg = The message for the exception. 2404 file = The file where the exception occurred. 2405 line = The line number where the exception occurred. 2406 next = The previous exception in the chain of exceptions, if any. 2407 +/ 2408 this(string msg, string file = __FILE__, size_t line = __LINE__, 2409 Throwable next = null) @nogc @safe pure nothrow 2410 { 2411 super(msg, file, line, next); 2412 } 2413 2414 /++ 2415 Params: 2416 msg = The message for the exception. 2417 next = The previous exception in the chain of exceptions. 2418 file = The file where the exception occurred. 2419 line = The line number where the exception occurred. 2420 +/ 2421 this(string msg, Throwable next, string file = __FILE__, 2422 size_t line = __LINE__) @nogc @safe pure nothrow 2423 { 2424 super(msg, file, line, next); 2425 } 2426 } 2427 2428 /// 2429 @safe unittest 2430 { 2431 class MeaCulpa: Exception 2432 { 2433 /// 2434 mixin basicExceptionCtors; 2435 } 2436 2437 try 2438 throw new MeaCulpa("test"); 2439 catch (MeaCulpa e) 2440 { 2441 assert(e.msg == "test"); 2442 assert(e.file == __FILE__); 2443 assert(e.line == __LINE__ - 5); 2444 } 2445 } 2446 2447 @safe pure nothrow unittest 2448 { 2449 class TestException : Exception { mixin basicExceptionCtors; } 2450 auto e = new Exception("msg"); 2451 auto te1 = new TestException("foo"); 2452 auto te2 = new TestException("foo", e); 2453 } 2454 2455 @safe unittest 2456 { 2457 class TestException : Exception { mixin basicExceptionCtors; } 2458 auto e = new Exception("!!!"); 2459 2460 auto te1 = new TestException("message", "file", 42, e); 2461 assert(te1.msg == "message"); 2462 assert(te1.file == "file"); 2463 assert(te1.line == 42); 2464 assert(te1.next is e); 2465 2466 auto te2 = new TestException("message", e, "file", 42); 2467 assert(te2.msg == "message"); 2468 assert(te2.file == "file"); 2469 assert(te2.line == 42); 2470 assert(te2.next is e); 2471 2472 auto te3 = new TestException("foo"); 2473 assert(te3.msg == "foo"); 2474 assert(te3.file == __FILE__); 2475 assert(te3.line == __LINE__ - 3); 2476 assert(te3.next is null); 2477 2478 auto te4 = new TestException("foo", e); 2479 assert(te4.msg == "foo"); 2480 assert(te4.file == __FILE__); 2481 assert(te4.line == __LINE__ - 3); 2482 assert(te4.next is e); 2483 }