1 // Written in the D programming language.
4 This module defines functions related to exceptions and general error
5 handling. It also defines functions intended to aid in unit testing.
7 $(SCRIPT inhibitQuickIndex = 1;)
10 $(TR $(TH Category) $(TH Functions))
11 $(TR $(TD Assumptions) $(TD
12 $(LREF assertNotThrown)
15 $(LREF assumeWontThrow)
18 $(TR $(TD Enforce) $(TD
23 $(TR $(TD Handlers) $(TD
24 $(LREF collectException)
25 $(LREF collectExceptionMsg)
30 $(LREF basicExceptionCtors)
31 $(LREF emptyExceptionMsg)
32 $(LREF ErrnoException)
33 $(LREF RangePrimitive)
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)
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
;
56 // use enforce like assert
58 enforce(a
> 2, "a needs to be higher than 2.");
60 // enforce can throw a custom exception
61 enforce
!ConvException(a
> 2, "a needs to be higher than 2.");
63 // enforce will return it's input
65 auto memory
= enforce(malloc(size
), "malloc failed")[0 .. size
];
66 scope(exit
) free(memory
.ptr
);
68 // collectException can be used to test for exceptions
69 Exception e
= collectException("abc".to
!int);
70 assert(e
.file
.endsWith("conv.d"));
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");
76 // assertThrown can be used to assert that an exception is thrown
77 assertThrown
!ConvException("abc".to
!int);
79 // ifThrown can be used to provide a default value if an exception is thrown
80 assert("x".to
!int().ifThrown(0) == 0);
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]));
88 // basicExceptionCtors avoids the boilerplate when creating custom exceptions
89 static class MeaCulpa
: Exception
91 mixin basicExceptionCtors
;
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);
98 // assumeWontThrow can be used to cast throwing code into `nothrow`
99 void exceptionFreeCode() nothrow
101 // auto-decoding only throws if an invalid UTF char is given
102 assumeWontThrow("abc".front
);
105 // assumeUnique can be used to cast mutable instance to an `immutable` one
107 char[] str = " mutable".dup
;
109 immutable res
= assumeUnique(str);
110 assert(res
== "immutable");
113 import std
.range
.primitives
;
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.
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__`.
135 `AssertError` if the given `Throwable` is thrown.
138 the result of `expression`.
140 auto assertNotThrown(T
: Throwable
= Exception
, E
)
143 string file
= __FILE__
,
144 size_t line
= __LINE__
)
146 import core
.exception
: AssertError
;
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
);
161 import core
.exception
: AssertError
;
164 assertNotThrown
!StringException(enforce
!StringException(true, "Error!"));
166 //Exception is the default.
167 assertNotThrown(enforce
!StringException(true, "Error!"));
169 assert(collectExceptionMsg
!AssertError(assertNotThrown
!StringException(
170 enforce
!StringException(false, "Error!"))) ==
171 `assertNotThrown failed: StringException was thrown: Error!`);
175 import core
.exception
: AssertError
;
177 assert(collectExceptionMsg
!AssertError(assertNotThrown
!StringException(
178 enforce
!StringException(false, ""), "Error!")) ==
179 `assertNotThrown failed: StringException was thrown: Error!`);
181 assert(collectExceptionMsg
!AssertError(assertNotThrown
!StringException(
182 enforce
!StringException(false, ""))) ==
183 `assertNotThrown failed: StringException was thrown.`);
185 assert(collectExceptionMsg
!AssertError(assertNotThrown
!StringException(
186 enforce
!StringException(false, ""), "")) ==
187 `assertNotThrown failed: StringException was thrown.`);
192 import core
.exception
: AssertError
;
194 static noreturn
throwEx(Throwable t
) { throw t
; }
195 bool nothrowEx() { return true; }
199 assert(assertNotThrown
!Exception(nothrowEx()));
201 catch (AssertError
) assert(0);
205 assert(assertNotThrown
!Exception(nothrowEx(), "It's a message"));
207 catch (AssertError
) assert(0);
211 assert(assertNotThrown
!AssertError(nothrowEx()));
213 catch (AssertError
) assert(0);
217 assert(assertNotThrown
!AssertError(nothrowEx(), "It's a message"));
219 catch (AssertError
) assert(0);
225 assertNotThrown
!Exception(
226 throwEx(new Exception("It's an Exception")));
228 catch (AssertError
) thrown
= true;
236 assertNotThrown
!Exception(
237 throwEx(new Exception("It's an Exception")), "It's a message");
239 catch (AssertError
) thrown
= true;
247 assertNotThrown
!AssertError(
248 throwEx(new AssertError("It's an AssertError", __FILE__
, __LINE__
)));
250 catch (AssertError
) thrown
= true;
258 assertNotThrown
!AssertError(
259 throwEx(new AssertError("It's an AssertError", __FILE__
, __LINE__
)),
262 catch (AssertError
) thrown
= true;
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.
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__`.
283 `AssertError` if the given `Throwable` is not thrown.
285 void assertThrown(T
: Throwable
= Exception
, E
)
288 string file
= __FILE__
,
289 size_t line
= __LINE__
)
291 import core
.exception
: AssertError
;
298 static if (!is(immutable E
== immutable noreturn
))
299 throw new AssertError("assertThrown failed: No " ~ T
.stringof
~ " was thrown"
300 ~ (msg
.length
== 0 ?
"." : ": ") ~ msg
,
306 import core
.exception
: AssertError
;
309 assertThrown
!StringException(enforce
!StringException(false, "Error!"));
311 //Exception is the default.
312 assertThrown(enforce
!StringException(false, "Error!"));
314 assert(collectExceptionMsg
!AssertError(assertThrown
!StringException(
315 enforce
!StringException(true, "Error!"))) ==
316 `assertThrown failed: No StringException was thrown.`);
321 import core
.exception
: AssertError
;
323 static noreturn
throwEx(Throwable t
) { throw t
; }
328 assertThrown
!Exception(throwEx(new Exception("It's an Exception")));
330 catch (AssertError
) assert(0);
334 assertThrown
!Exception(throwEx(new Exception("It's an Exception")),
337 catch (AssertError
) assert(0);
341 assertThrown
!AssertError(throwEx(new AssertError("It's an AssertError",
342 __FILE__
, __LINE__
)));
344 catch (AssertError
) assert(0);
348 assertThrown
!AssertError(throwEx(new AssertError("It's an AssertError",
349 __FILE__
, __LINE__
)),
352 catch (AssertError
) assert(0);
358 assertThrown
!Exception(nothrowEx());
368 assertThrown
!Exception(nothrowEx(), "It's a message");
378 assertThrown
!AssertError(nothrowEx());
388 assertThrown
!AssertError(nothrowEx(), "It's a message");
398 Enforces that the given value is true.
399 If the given value is false, an exception is thrown.
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)
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.
416 Returns: `value`, if `cast(bool) value` is true. Otherwise,
417 depending on the chosen overload, `new Exception(msg)`, `dg()` or `ex` is thrown.
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.)
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).
430 If a delegate is passed, the safety and purity of this function are inferred
431 from `Dg`'s safety and purity.
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
))
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
) {} })))
442 if (!value
) bailOut
!E(file
, line
, msg
);
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
) {} })))
458 T
enforce(T
)(T value
, lazy Throwable ex
)
460 if (!value
) throw ex();
467 import core
.stdc
.stdlib
: malloc
, free
;
468 import std
.conv
: ConvException
, to
;
470 // use enforce like assert
472 enforce(a
> 2, "a needs to be higher than 2.");
474 // enforce can throw a custom exception
475 enforce
!ConvException(a
> 2, "a needs to be higher than 2.");
477 // enforce will return it's input
479 auto memory
= enforce(malloc(size
), "malloc failed")[0 .. size
];
480 scope(exit
) free(memory
.ptr
);
486 assertNotThrown(enforce(true, new Exception("this should not be thrown")));
487 assertThrown(enforce(false, new Exception("this should be thrown")));
493 assert(enforce(123) == 123);
497 enforce(false, "error");
502 assert(e
.msg
== "error");
503 assert(e
.file
== __FILE__
);
504 assert(e
.line
== __LINE__
-7);
508 /// Alias your own enforce function
511 import std
.conv
: ConvException
;
512 alias convEnforce
= enforce
!ConvException
;
513 assertNotThrown(convEnforce(true));
514 assertThrown
!ConvException(convEnforce(false, "blah"));
517 private noreturn
bailOut(E
: Throwable
= Exception
)(string file
, size_t line
, scope const(char)[] msg
)
519 static if (is(typeof(new E(string
.init
, string
.init
, size_t
.init
))))
521 throw new E(msg ? msg
.idup
: "Enforcement failed", file
, line
);
523 else static if (is(typeof(new E(string
.init
, size_t
.init
))))
525 throw new E(file
, line
);
529 static assert(0, "Expected this(string, string, size_t) or this(string, size_t)" ~
530 " constructor for " ~ __traits(identifier
, E
));
534 // https://issues.dlang.org/show_bug.cgi?id=10510
537 extern(C
) void cFoo() { }
538 enforce(false, &cFoo
);
541 // purity and safety inference test
544 static foreach (EncloseSafe
; [false, true])
545 static foreach (EnclosePure
; [false, true])
547 static foreach (BodySafe
; [false, true])
548 static foreach (BodyPure
; [false, true])
552 (EncloseSafe ?
"@safe " : "") ~
553 (EnclosePure ?
"pure " : "") ~
554 "{ enforce(true, { " ~
556 (BodySafe ?
"" : "auto p = &n + 10; " ) ~ // unsafe code
557 (BodyPure ?
"" : "static int g; g = 10; ") ~ // impure code
561 (BodySafe ||
!EncloseSafe
) && (!EnclosePure || BodyPure
);
564 pragma(msg
, "safe = ", EncloseSafe?
1:0, "/", BodySafe?
1:0, ", ",
565 "pure = ", EnclosePure?
1:0, "/", BodyPure?
1:0, ", ",
566 "expect = ", expect?
"OK":"NG", ", ",
569 static assert(__traits(compiles
, mixin(code
)()) == expect
);
574 // Test for https://issues.dlang.org/show_bug.cgi?id=8637
580 ~this() {} // impure & unsafe destructor
581 bool opCast(T
:bool)() {
582 int* p
= cast(int*) 0; // unsafe operation
583 int n
= g
; // impure operation
591 enforce(s
, new Exception(""));
595 alias E1
= Exception
;
596 static class E2
: Exception
598 this(string fn
, size_t ln
) { super("", fn
, ln
); }
600 static class E3
: Exception
602 this(string msg
) { super(msg
, __FILE__
, __LINE__
); }
608 // https://issues.dlang.org/show_bug.cgi?id=14685
613 this() { super("Not found"); }
615 static assert(!__traits(compiles
, { enforce
!E(false); }));
619 Enforces that the given value is true, throwing an `ErrnoException` if it
623 value = The value to test.
624 msg = The message to include in the `ErrnoException` if it is thrown.
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
631 alias errnoEnforce
= enforce
!ErrnoException
;
636 import core
.stdc
.stdio
: fclose
, fgets
, fopen
;
637 import std
.file
: thisExePath
;
638 import std
.string
: toStringz
;
640 auto f
= fopen(thisExePath
.toStringz
, "r").errnoEnforce
;
641 scope(exit
) fclose(f
);
643 auto line
= fgets(buf
.ptr
, buf
.length
, f
);
644 enforce(line
!is null); // expect a non-empty line
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.
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
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.
664 T
collectException(T
= Exception
, E
)(lazy E expression
, ref E result
)
668 result
= expression();
674 // Avoid "statement not reachable" warning
675 static if (!is(immutable E
== immutable noreturn
))
682 int foo() { throw new Exception("blah"); }
683 assert(collectException(foo(), b
));
685 version (D_NoBoundsChecks
) {}
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
));
696 Catches and returns the exception thrown from the given expression.
697 If no exception is thrown, then null is returned. `E` can be
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
708 T = The type of exception to catch.
709 expression = The expression which may throw an exception.
711 T
collectException(T
: Throwable
= Exception
, E
)(lazy E expression
)
721 // Avoid "statement not reachable" warning
722 static if (!is(immutable E
== immutable noreturn
))
729 int foo() { throw new Exception("blah"); }
730 assert(collectException(foo()).msg
== "blah");
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`.
738 If an exception is thrown but it has an empty message, then
739 `emptyExceptionMsg` is returned.
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
749 T = The type of exception to catch.
750 expression = The expression which may throw an exception.
752 string
collectExceptionMsg(T
= Exception
, E
)(lazy E expression
)
754 import std
.array
: empty
;
759 // Avoid "statement not reachable" warning
760 static if (!is(immutable E
== immutable noreturn
))
761 return cast(string
) null;
764 return e
.msg
.empty ? emptyExceptionMsg
: e
.msg
;
769 void throwFunc() { throw new Exception("My Message."); }
770 assert(collectExceptionMsg(throwFunc()) == "My Message.");
772 void nothrowFunc() {}
773 assert(collectExceptionMsg(nothrowFunc()) is null);
775 void throwEmptyFunc() { throw new Exception(""); }
776 assert(collectExceptionMsg(throwEmptyFunc()) == emptyExceptionMsg
);
780 Value that collectExceptionMsg returns when it catches an exception
781 with an empty exception message.
783 enum emptyExceptionMsg
= "<Empty Exception Message>";
785 // https://issues.dlang.org/show_bug.cgi?id=22364
788 static noreturn
foo() { throw new Exception(""); }
790 const ex
= collectException
!(Exception
, noreturn
)(foo());
793 const msg
= collectExceptionMsg
!(Exception
, noreturn
)(foo());
798 // Triggers a backend assertion failure
799 // collectException!(Exception, noreturn)(foo(), n);
801 static assert(__traits(compiles
, collectException
!(Exception
, noreturn
)(foo(), n
)));
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`.
817 Typically, `assumeUnique` is used to return arrays from
818 functions that have allocated and built them.
821 array = The array to cast to immutable.
823 Returns: The immutable array.
831 char[] result = new char['z' - 'a' + 1];
832 foreach (i, ref e; result)
834 e = cast(char)('a' + i);
836 return assumeUnique(result);
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`.
851 string letters(char first, char last)
853 if (first >= last) return null; // fine
854 auto sneaky = buffer;
855 sneaky.length = last - first + 1;
856 foreach (i, ref e; sneaky)
858 e = cast(char)('a' + i);
860 return assumeUnique(sneaky); // BAD
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
871 return to!(string)(sneaky); // not that sneaky anymore
874 The `to` call will duplicate the array appropriately.
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:)
885 static string letters() pure
887 char[] result = new char['z' - 'a' + 1];
888 foreach (i, ref e; result)
890 e = cast(char)('a' + i);
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)
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.
909 immutable(T
)[] assumeUnique(T
)(T
[] array
) pure nothrow
911 return .assumeUnique(array
); // call ref version
914 immutable(T
)[] assumeUnique(T
)(ref T
[] array
) pure nothrow
916 auto result
= cast(immutable(T
)[]) array
;
921 immutable(T
[U
]) assumeUnique(T
, U
)(ref T
[U
] array
) pure nothrow
923 auto result
= cast(immutable(T
[U
])) array
;
931 int[] arr
= new int[1];
932 auto arr1
= arr
.assumeUnique
;
933 static assert(is(typeof(arr1
) == immutable(int)[]));
941 int[string
] arr
= ["a":1];
942 auto arr1
= arr
.assumeUnique
;
943 static assert(is(typeof(arr1
) == immutable(int[string
])));
945 assert(arr1
.keys
== ["a"]);
949 * Wraps a possibly-throwing expression in a `nothrow` wrapper so that it
950 * can be called by a `nothrow` function.
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
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
964 * expr = The expression asserted not to throw.
965 * msg = The message to include in the `AssertError` if the assumption turns
967 * file = The source file name of the caller.
968 * line = The line number of the caller.
971 * The value of `expr`, if any.
973 T
assumeWontThrow(T
)(lazy T expr
,
975 string file
= __FILE__
,
976 size_t line
= __LINE__
) nothrow
978 import core
.exception
: AssertError
;
985 import std
.range
.primitives
: empty
;
986 immutable tail
= msg
.empty ?
"." : ": " ~ msg
;
987 throw new AssertError("assumeWontThrow failed: Expression did throw" ~
995 import std
.math
.algebraic
: sqrt
;
997 // This function may throw.
998 int squareRoot(int x
)
1001 throw new Exception("Tried to take root of negative number");
1002 return cast(int) sqrt(cast(double) x
);
1005 // This function never throws.
1006 int computeLength(int x
, int y
) nothrow
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
));
1015 assert(computeLength(3, 4) == 5);
1020 import core
.exception
: AssertError
;
1024 throw new Exception("I threw up");
1028 assumeWontThrow(alwaysThrows());
1030 assertThrown
!AssertError(bad());
1034 Checks whether a given source object contains pointers or references to a given
1038 source = The source object
1039 target = The target object
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).
1045 Returns: `true` if `source`'s representation embeds a pointer
1046 that points to `target`'s representation or somewhere inside
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.
1052 If `source` is a class, then it will be handled as a pointer.
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.
1057 If `source` is or contains a union or `void[n]`, then there may be either false positives or
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
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
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
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))
1079 static if (is(S
== U
*, U
) ||
is(S
== class) ||
is(S
== interface))
1081 const m
= *cast(void**) &source
;
1082 const b
= cast(void*) &target
;
1083 const e
= b
+ target
.sizeof
;
1084 return b
<= m
&& m
< e
;
1086 else static if (is(S
== struct) ||
is(S
== union))
1088 foreach (i
, Subobj
; typeof(source
.tupleof
))
1089 static if (!isUnionAliased
!(S
, i
))
1090 if (doesPointTo(source
.tupleof
[i
], target
)) return true;
1093 else static if (isStaticArray
!S
)
1095 static if (!is(S
== void[n
], size_t n
))
1097 foreach (ref s
; source
)
1098 if (doesPointTo(s
, target
)) return true;
1102 else static if (isDynamicArray
!S
)
1104 import std
.array
: overlap
;
1105 return overlap(cast(void[]) source
, cast(void[])(&target
)[0 .. 1]).length
!= 0;
1113 // for shared objects
1115 bool doesPointTo(S
, T
)(auto ref const shared S source
, ref const shared T target
) @trusted pure nothrow
1117 return doesPointTo
!(shared S
, shared T
, void)(source
, target
);
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))
1125 static if (is(S
== U
*, U
) ||
is(S
== class) ||
is(S
== interface))
1127 const m
= *cast(void**) &source
;
1128 const b
= cast(void*) &target
;
1129 const e
= b
+ target
.sizeof
;
1130 return b
<= m
&& m
< e
;
1132 else static if (is(S
== struct) ||
is(S
== union))
1134 foreach (i
, Subobj
; typeof(source
.tupleof
))
1135 if (mayPointTo(source
.tupleof
[i
], target
)) return true;
1138 else static if (isStaticArray
!S
)
1140 static if (is(S
== void[n
], size_t n
))
1142 static if (n
>= (void[]).sizeof
)
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
[]))
1150 else static if (n
>= (void*).sizeof
)
1152 // Reinterpreting cast is impossible during ctfe
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
;
1161 if ((n
- (alBase
- base
)) >= (void*).sizeof
&&
1162 mayPointTo(*(cast(void**) alBase
), target
))
1168 foreach (size_t i
; 0 .. S
.length
)
1169 if (mayPointTo(source
[i
], target
)) return true;
1174 else static if (isDynamicArray
!S
)
1176 import std
.array
: overlap
;
1177 return overlap(cast(void[]) source
, cast(void[])(&target
)[0 .. 1]).length
!= 0;
1185 // for shared objects
1187 bool mayPointTo(S
, T
)(auto ref const shared S source
, ref const shared T target
) @trusted pure nothrow
1189 return mayPointTo
!(shared S
, shared T
, void)(source
, target
);
1197 assert(!p
.doesPointTo(i
));
1199 assert( p
.doesPointTo(i
));
1202 /// Structs and Unions
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.
1219 // Unions will behave exactly the same. Points to will check each "member"
1220 // individually, even if they share the same memory
1223 /// Arrays (dynamic and static)
1227 // trick the compiler when initializing slice
1228 // https://issues.dlang.org/show_bug.cgi?id=18637
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
];
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
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
));
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
1247 assert( arrp
[0].doesPointTo(i
)); // i is pointed by arrp[0].
1248 assert( arrp
.doesPointTo(i
)); // which means i is pointed by arrp
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
));
1263 this(int* p
){this.p
= p
;}
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.
1275 //To check the class payload itself, iterate on its members:
1278 import std
.traits
: Fields
;
1280 foreach (index
, _
; Fields
!C
)
1281 if (doesPointTo(a
.tupleof
[index
], i
))
1286 // To check if a class points a specific payload, a direct memmory check
1288 auto aLoc
= cast(ubyte[__traits(classInstanceSize
, C
)]*) a
;
1289 assert(b
.doesPointTo(*aLoc
)); // b points to where a is pointing
1293 version (StdUnittest
)
1295 // https://issues.dlang.org/show_bug.cgi?id=17084
1296 // the bug doesn't happen if these declarations are in the unittest block
1298 private struct Page17084
1301 int opCmp(P
)(P
) { return 0; }
1302 int opCmp(P
)(shared(P
)) shared { return 0; }
1305 private struct URL17084
1308 string
toString()() const { return ""; }
1309 alias toString
this;
1313 // https://issues.dlang.org/show_bug.cgi?id=17084
1316 import std
.algorithm
.sorting
: sort
;
1319 shared(Page17084
)[] p
;
1325 struct S1
{ int a
; S1
* b
; }
1328 assert(doesPointTo(p
, a1
));
1332 assert(doesPointTo(a2
, a1
));
1334 struct S3
{ int[10] a
; }
1336 auto a4
= a3
.a
[2 .. 3];
1337 assert(doesPointTo(a4
, a3
));
1339 auto a5
= new double[4];
1340 auto a6
= a5
[1 .. 2];
1341 assert(!doesPointTo(a5
, a6
));
1343 auto a7
= new double[3];
1344 auto a8
= new double[][1];
1346 assert(!doesPointTo(a8
[0], a8
[0]));
1348 // don't invoke postblit on subobjects
1350 static struct NoCopy
{ this(this) { assert(0); } }
1351 static struct Holder
{ NoCopy a
, b
, c
; }
1353 cast(void) doesPointTo(h
, h
);
1357 shared sh3sub
= sh3
.a
[];
1358 assert(doesPointTo(sh3sub
, sh3
));
1360 int[] darr
= [1, 2, 3, 4];
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
));
1366 //But they do point their elements
1368 assert(doesPointTo(darr
, darr
[i
]));
1369 assert(doesPointTo(darr
[0 .. 3], darr
[2]));
1370 assert(!doesPointTo(darr
[0 .. 3], darr
[3]));
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.
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]));
1390 //An array of pointers
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
1399 //A struct containing a static array of pointers
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.
1410 //An array containing structs that have pointers
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.
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
1424 // zeroed void ranges can't point at anything
1425 assert(!mayPointTo(voidArr
, a
));
1426 assert(!mayPointTo(voidArr
, b
));
1428 *cast(void**) &voidArr
[16] = &a
; // Pointers should be found
1430 alias SA
= void[size_t
.sizeof
+ 3];
1431 SA
*smallArr1
= cast(SA
*)&voidArr
;
1432 SA
*smallArr2
= cast(SA
*)&(voidArr
[16]);
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
[];
1440 assert( mayPointTo(*smallArr2
, a
));
1441 assert(!mayPointTo(*smallArr1
, b
));
1443 assert(!doesPointTo(voidArr
, a
)); // Value might be a false pointer
1444 assert(!doesPointTo(voidArr
, b
));
1446 SA
*smallArr3
= cast(SA
*) &voidArr
[13]; // Works for weird sizes/alignments
1447 assert( mayPointTo(*smallArr3
, a
));
1448 assert(!mayPointTo(*smallArr3
, b
));
1450 assert(!doesPointTo(*smallArr3
, a
));
1451 assert(!doesPointTo(*smallArr3
, b
));
1453 auto v3
= cast(void[3]*) &voidArr
[16]; // Arrays smaller than pointers are ignored
1454 assert(!mayPointTo(*v3
, a
));
1455 assert(!mayPointTo(*v3
, b
));
1457 assert(!doesPointTo(*v3
, a
));
1458 assert(!doesPointTo(*v3
, b
));
1460 assert(mayPointTo(voidArr
, a
)); // slice-contiaining void[N] might point at anything
1461 assert(mayPointTo(voidArr
, b
));
1464 void[16] arr1
= void;
1465 void[size_t
.sizeof
] arr2
= void;
1467 return mayPointTo(arr1
, var
) && !doesPointTo(arr1
, var
) &&
1468 mayPointTo(arr2
, var
) && !doesPointTo(arr2
, var
);
1473 @system unittest //Unions
1476 union U
//Named union
1483 union //Anonymous union
1492 assert(!doesPointTo(u
, i
));
1493 assert(!doesPointTo(s
, i
));
1494 assert(!mayPointTo(u
, i
));
1495 assert(!mayPointTo(s
, i
));
1499 assert(!doesPointTo(u
, i
));
1500 assert(!doesPointTo(s
, i
));
1501 assert( mayPointTo(u
, i
));
1502 assert( mayPointTo(s
, i
));
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
));
1512 @system unittest //Classes
1520 assert(!doesPointTo(a
, b
)); //a does not point to b
1522 assert(!doesPointTo(a
, i
)); //a does not point to i
1524 @safe unittest //alias this test
1531 @property int* foo(){return &i
;}
1534 assert(is(S
: int*));
1536 assert(!doesPointTo(s
, i
));
1537 assert( doesPointTo(s
, j
));
1538 assert( doesPointTo(cast(int*) s
, i
));
1539 assert(!doesPointTo(cast(int*) s
, j
));
1543 Returns true if the field at index `i` in $(D T) shares its address with another field.
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.
1548 package enum isUnionAliased(T
, size_t i
) = isUnionAliasedImpl
!T(T
.tupleof
[i
].offsetof
);
1549 private bool isUnionAliasedImpl(T
)(size_t offset
)
1552 foreach (i
, U
; typeof(T
.tupleof
))
1553 if (T
.tupleof
[i
].offsetof
== offset
)
1562 int a0
; //Not aliased
1565 int a1
; //Not aliased
1574 int b0
; //Not aliased
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;
1596 version (CRuntime_Glibc
) version = GNU_STRERROR
;
1597 version (CRuntime_UClibc
) version = GNU_STRERROR
;
1599 package string
errnoString(int errno
) nothrow @trusted
1601 import core
.stdc
.string
: strlen
;
1602 version (GNU_STRERROR
)
1604 import core
.stdc
.string
: strerror_r
;
1605 char[1024] buf
= void;
1606 auto s
= strerror_r(errno
, buf
.ptr
, buf
.length
);
1608 else version (Posix
)
1611 import core
.stdc
.string
: strerror_r
;
1612 char[1024] buf
= void;
1614 if (strerror_r(errno
, buf
.ptr
, buf
.length
) == 0)
1617 return "Unknown error";
1621 import core
.stdc
.string
: strerror
;
1622 auto s
= strerror(errno
);
1624 return s
[0 .. s
.strlen
].idup
;
1627 /*********************
1628 * Thrown if errors that set `errno` occur.
1630 class ErrnoException
: Exception
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
1641 import core
.stdc
.errno
: errno
;
1642 this(msg
, errno
, file
, line
);
1644 /// Constructor which takes an error message and error code.
1645 this(string msg
, int errno
, string file
= null, size_t line
= 0) @safe
1648 _errnoMsg
= errnoString(errno
);
1649 super(msg
~ " (" ~ errnoMsg
~ ")", file
, line
);
1656 import core
.stdc
.errno
: EAGAIN
;
1657 auto ex
= new ErrnoException("oh no", EAGAIN
);
1658 assert(ex
.errno
== EAGAIN
);
1661 /// errno is used by default if no explicit error code is provided
1664 import core
.stdc
.errno
: errno
, EAGAIN
;
1667 scope(exit
) errno
= old
;
1669 // fake that errno got set by the callee
1671 auto ex
= new ErrnoException("oh no");
1672 assert(ex
.errno
== EAGAIN
);
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.
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.
1689 expression, if it does not throw. Otherwise, returns the result of
1693 CommonType
!(T1
, T2
) ifThrown(E
: Throwable
= Exception
, T1
, T2
)(lazy scope T1 expression
, lazy scope T2 errorHandler
)
1695 static assert(!is(typeof(return) == void),
1696 "The error handler's return value("
1698 ") does not have a common type with the expression("
1704 return expression();
1708 return errorHandler();
1714 CommonType
!(T1
, T2
) ifThrown(E
: Throwable
, T1
, T2
)(lazy scope T1 expression
, scope T2
delegate(E
) errorHandler
)
1716 static assert(!is(typeof(return) == void),
1717 "The error handler's return value("
1719 ") does not have a common type with the expression("
1725 return expression();
1729 return errorHandler(e
);
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
)
1737 static assert(!is(typeof(return) == void),
1738 "The error handler's return value("
1740 ") does not have a common type with the expression("
1746 return expression();
1750 return errorHandler(e
);
1754 /// Revert to a default value upon an error:
1757 import std
.conv
: to
;
1758 assert("x".to
!int.ifThrown(0) == 0);
1762 Chain multiple calls to ifThrown, each capturing errors from the
1763 entire preceding expression.
1767 import std
.conv
: ConvException
, to
;
1769 assert(s
.to
!int.ifThrown(cast(int) s
.to
!double)
1770 .ifThrown(cast(int) s
.to
!bool) == 1);
1773 assert(s
.to
!int.ifThrown(cast(int) s
.to
!double)
1774 .ifThrown(cast(int) s
.to
!bool) == 2);
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");
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");
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
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
));
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)));
1800 /// Use a lambda to get the thrown object.
1803 import std
.format
: format
;
1804 assert("%s".format
.ifThrown
!Exception(e
=> typeid(e
).name
) == "std.format.FormatException");
1812 //Revert to a default value upon an error:
1813 assert("x".to
!int().ifThrown(0) == 0);
1815 //Chaining multiple calls to ifThrown to attempt multiple things in a row:
1818 ifThrown(cast(int) s
.to
!double()).
1819 ifThrown(cast(int) s
.to
!bool())
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")
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
));
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)));
1836 //Use a lambda to get the thrown object.
1837 assert("%s".format().ifThrown(e
=> typeid(e
).name
) == "std.format.FormatException");
1842 import core
.exception
;
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
1854 assert("1".to
!int().ifThrown
!ConvException(e
=>0) == 1);
1855 assert("x".to
!int().ifThrown
!ConvException(e
=>0) == 0);
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
1862 assert("x".to
!int().ifThrown
!StringException(e
=>0).collectException
!ConvException() !is null);
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);
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)));
1877 version (StdUnittest
) package
1878 void assertCTFEable(alias dg
)()
1880 static assert({ cast(void) dg(); return true; }());
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.
1888 `RangePrimitive.access` is a shortcut for the access primitives; `front`,
1889 `back` and `opIndex`.
1891 `RangePrimitive.pop` is a shortcut for the mutating primitives;
1892 `popFront` and `popBack`.
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
1913 import std
.algorithm
.comparison
: equal
;
1914 import std
.algorithm
.iteration
: map
, splitter
;
1915 import std
.conv
: to
, ConvException
;
1917 auto s
= "12,1337z32,54,2,7,9,1z,6,8";
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
));
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]));
1931 import std
.algorithm
.comparison
: equal
;
1932 import std
.range
: retro
;
1933 import std
.utf
: UTFException
;
1935 auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit
1937 auto handled
= str.handle
!(UTFException
, RangePrimitive
.access
,
1938 (e
, r
) => ' '); // Replace invalid code points with spaces
1940 assert(handled
.equal("hello world")); // `front` is handled,
1941 assert(handled
.retro
.equal("dlrow olleh")); // as well as `back`
1944 /** Handle exceptions thrown from range primitives.
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.
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.
1962 Returns: A wrapper `struct` that preserves the range interface of `input`.
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.
1971 auto handle(E
: Throwable
, RangePrimitive primitivesToHandle
, alias handler
, Range
)(Range input
)
1972 if (isInputRange
!Range
)
1974 static struct Handler
1976 private Range range
;
1978 static if (isForwardRange
!Range
)
1980 @property typeof(this) save()
1982 static if (primitivesToHandle
& RangePrimitive
.save
)
1986 return typeof(this)(range
.save
);
1990 return typeof(this)(handler(exception
, this.range
));
1994 return typeof(this)(range
.save
);
1998 static if (isInfinite
!Range
)
2000 enum bool empty
= false;
2004 @property bool empty()
2006 static if (primitivesToHandle
& RangePrimitive
.empty
)
2010 return this.range
.empty
;
2014 return handler(exception
, this.range
);
2018 return this.range
.empty
;
2022 @property auto ref front()
2024 static if (primitivesToHandle
& RangePrimitive
.front
)
2028 return this.range
.front
;
2032 return handler(exception
, this.range
);
2036 return this.range
.front
;
2041 static if (primitivesToHandle
& RangePrimitive
.popFront
)
2045 this.range
.popFront();
2049 handler(exception
, this.range
);
2053 this.range
.popFront();
2056 static if (isBidirectionalRange
!Range
)
2058 @property auto ref back()
2060 static if (primitivesToHandle
& RangePrimitive
.back
)
2064 return this.range
.back
;
2068 return handler(exception
, this.range
);
2072 return this.range
.back
;
2077 static if (primitivesToHandle
& RangePrimitive
.popBack
)
2081 this.range
.popBack();
2085 handler(exception
, this.range
);
2089 this.range
.popBack();
2093 static if (isRandomAccessRange
!Range
)
2095 auto ref opIndex(size_t index
)
2097 static if (primitivesToHandle
& RangePrimitive
.opIndex
)
2101 return this.range
[index
];
2105 static if (__traits(compiles
, handler(exception
, this.range
, index
)))
2106 return handler(exception
, this.range
, index
);
2108 return handler(exception
, this.range
);
2112 return this.range
[index
];
2116 static if (hasLength
!Range
)
2118 @property auto length()
2120 static if (primitivesToHandle
& RangePrimitive
.length
)
2124 return this.range
.length
;
2128 return handler(exception
, this.range
);
2132 return this.range
.length
;
2136 static if (hasSlicing
!Range
)
2138 static if (hasLength
!Range
)
2140 typeof(this) opSlice(size_t lower
, size_t upper
)
2142 static if (primitivesToHandle
& RangePrimitive
.opSlice
)
2146 return typeof(this)(this.range
[lower
.. upper
]);
2150 return typeof(this)(handler(exception
, this.range
));
2154 return typeof(this)(this.range
[lower
.. upper
]);
2157 else static if (is(typeof(Range
.init
[size_t
.init
.. $])))
2159 import std
.range
: Take
, takeExactly
;
2160 static struct DollarToken
{}
2161 enum opDollar
= DollarToken
.init
;
2163 typeof(this) opSlice(size_t lower
, DollarToken
)
2165 static if (primitivesToHandle
& RangePrimitive
.opSlice
)
2169 return typeof(this)(this.range
[lower
.. $]);
2173 return typeof(this)(handler(exception
, this.range
));
2177 return typeof(this)(this.range
[lower
.. $]);
2180 Take
!Handler
opSlice(size_t lower
, size_t upper
)
2182 static if (primitivesToHandle
& RangePrimitive
.opSlice
)
2186 return takeExactly(typeof(this)(this.range
[lower
.. $]), upper
- 1);
2190 return takeExactly(typeof(this)(handler(exception
, this.range
)), 0);
2194 return takeExactly(typeof(this)(this.range
[lower
.. $]), upper
- 1);
2200 return Handler(input
);
2206 import std
.algorithm
.comparison
: equal
;
2207 import std
.algorithm
.iteration
: map
, splitter
;
2208 import std
.conv
: to
, ConvException
;
2210 auto s
= "12,1337z32,54,2,7,9,1z,6,8";
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
));
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]));
2224 import std
.algorithm
.comparison
: equal
;
2225 import std
.range
: retro
;
2226 import std
.utf
: UTFException
;
2228 auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit
2230 auto handled
= str.handle
!(UTFException
, RangePrimitive
.access
,
2231 (e
, r
) => ' '); // Replace invalid code points with spaces
2233 assert(handled
.equal("hello world")); // `front` is handled,
2234 assert(handled
.retro
.equal("dlrow olleh")); // as well as `back`
2237 pure nothrow @safe unittest
2239 static struct ThrowingRange
2242 @property bool empty()
2244 throw new Exception("empty has thrown");
2247 @property int front()
2249 throw new Exception("front has thrown");
2252 @property int back()
2254 throw new Exception("back has thrown");
2259 throw new Exception("popFront has thrown");
2264 throw new Exception("popBack has thrown");
2269 throw new Exception("opIndex has thrown");
2272 ThrowingRange
opSlice(size_t
, size_t
)
2274 throw new Exception("opSlice has thrown");
2277 @property size_t
length()
2279 throw new Exception("length has thrown");
2282 alias opDollar
= length
;
2284 @property ThrowingRange
save()
2286 throw new Exception("save has thrown");
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
);
2296 auto f
= ThrowingRange();
2297 auto fb
= f
.handle
!(Exception
, RangePrimitive
.front | RangePrimitive
.back
,
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]);
2307 auto accessRange
= f
.handle
!(Exception
, RangePrimitive
.access
,
2309 assert(accessRange
.front
== -1);
2310 assert(accessRange
.back
== -1);
2311 assert(accessRange
[0] == -1);
2312 assertThrown(accessRange
.popFront());
2313 assertThrown(accessRange
.popBack());
2315 auto pfb
= f
.handle
!(Exception
, RangePrimitive
.pop, (e
, r
) => -1)();
2317 pfb
.popFront(); // this would throw otherwise
2318 pfb
.popBack(); // this would throw otherwise
2320 auto em
= f
.handle
!(Exception
,
2321 RangePrimitive
.empty
, (e
, r
) => false)();
2325 auto arr
= f
.handle
!(Exception
,
2326 RangePrimitive
.opIndex
, (e
, r
) => 1337)();
2328 assert(arr
[0] == 1337);
2330 auto arr2
= f
.handle
!(Exception
,
2331 RangePrimitive
.opIndex
, (e
, r
, i
) => i
)();
2333 assert(arr2
[0] == 0);
2334 assert(arr2
[1337] == 1337);
2336 auto save
= f
.handle
!(Exception
,
2337 RangePrimitive
.save
,
2338 function(Exception e
, ref ThrowingRange r
) {
2339 return ThrowingRange();
2344 auto slice
= f
.handle
!(Exception
,
2345 RangePrimitive
.opSlice
, (e
, r
) => ThrowingRange())();
2347 auto sliced
= slice
[0 .. 1337]; // this would throw otherwise
2349 static struct Infinite
2351 import std
.range
: Take
;
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
)
2362 throw new Exception("opSlice has thrown");
2366 static assert(isInputRange
!Infinite
);
2367 static assert(isInfinite
!Infinite
);
2368 static assert(hasSlicing
!Infinite
);
2370 assertThrown(Infinite()[0 .. $]);
2372 auto infinite
= Infinite
.init
.handle
!(Exception
,
2373 RangePrimitive
.opSlice
, (e
, r
) => Infinite())();
2375 auto infSlice
= infinite
[0 .. $]; // this would throw otherwise
2380 Convenience mixin for trivially sub-classing exceptions
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.
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.
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.
2398 mixin template basicExceptionCtors()
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.
2407 this(string msg
, string file
= __FILE__
, size_t line
= __LINE__
,
2408 Throwable next
= null) @nogc @safe pure nothrow
2410 super(msg
, file
, line
, next
);
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.
2420 this(string msg
, Throwable next
, string file
= __FILE__
,
2421 size_t line
= __LINE__
) @nogc @safe pure nothrow
2423 super(msg
, file
, line
, next
);
2430 class MeaCulpa
: Exception
2433 mixin basicExceptionCtors
;
2437 throw new MeaCulpa("test");
2440 assert(e
.msg
== "test");
2441 assert(e
.file
== __FILE__
);
2442 assert(e
.line
== __LINE__
- 5);
2446 @safe pure nothrow unittest
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
);
2456 class TestException
: Exception
{ mixin basicExceptionCtors
; }
2457 auto e
= new Exception("!!!");
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
);
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
);
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);
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
);