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 `enforce` is used to throw exceptions and is therefore intended to
421 aid in error handling. It is $(I not) intended for verifying the logic
422 of your program. That is what `assert` is for. Also, do not use
423 `enforce` inside of contracts (i.e. inside of `in` and `out`
424 blocks and `invariant`s), because contracts are compiled out when
425 compiling with $(I -release).
427 If a delegate is passed, the safety and purity of this function are inferred
428 from `Dg`'s safety and purity.
430 template enforce(E : Throwable = Exception)
431 if (is(typeof(new E("", string.init, size_t.init)) : Throwable) ||
432 is(typeof(new E(string.init, size_t.init)) : Throwable))
435 T enforce(T)(T value, lazy const(char)[] msg = null,
436 string file = __FILE__, size_t line = __LINE__)
437 if (is(typeof({ if (!value) {} })))
439 if (!value) bailOut!E(file, line, msg);
445 T enforce(T, Dg, string file = __FILE__, size_t line = __LINE__)
446 (T value, scope Dg dg)
447 if (isSomeFunction!Dg && is(typeof( dg() )) &&
448 is(typeof({ if (!value) {} })))
455 T enforce(T)(T value, lazy Throwable ex)
457 if (!value) throw ex();
464 import core.stdc.stdlib : malloc, free;
465 import std.conv : ConvException, to;
467 // use enforce like assert
469 enforce(a > 2, "a needs to be higher than 2.");
471 // enforce can throw a custom exception
472 enforce!ConvException(a > 2, "a needs to be higher than 2.");
474 // enforce will return it's input
476 auto memory = enforce(malloc(size), "malloc failed")[0 .. size];
477 scope(exit) free(memory.ptr);
483 assertNotThrown(enforce(true, new Exception("this should not be thrown")));
484 assertThrown(enforce(false, new Exception("this should be thrown")));
490 assert(enforce(123) == 123);
494 enforce(false, "error");
499 assert(e.msg == "error");
500 assert(e.file == __FILE__);
501 assert(e.line == __LINE__-7);
505 /// Alias your own enforce function
508 import std.conv : ConvException;
509 alias convEnforce = enforce!ConvException;
510 assertNotThrown(convEnforce(true));
511 assertThrown!ConvException(convEnforce(false, "blah"));
514 private noreturn bailOut(E : Throwable = Exception)(string file, size_t line, scope const(char)[] msg)
516 static if (is(typeof(new E(string.init, string.init, size_t.init))))
518 throw new E(msg ? msg.idup : "Enforcement failed", file, line);
520 else static if (is(typeof(new E(string.init, size_t.init))))
522 throw new E(file, line);
526 static assert(0, "Expected this(string, string, size_t) or this(string, size_t)" ~
527 " constructor for " ~ __traits(identifier, E));
531 // https://issues.dlang.org/show_bug.cgi?id=10510
534 extern(C) void cFoo() { }
535 enforce(false, &cFoo);
538 // purity and safety inference test
541 static foreach (EncloseSafe; [false, true])
542 static foreach (EnclosePure; [false, true])
544 static foreach (BodySafe; [false, true])
545 static foreach (BodyPure; [false, true])
549 (EncloseSafe ? "@safe " : "") ~
550 (EnclosePure ? "pure " : "") ~
551 "{ enforce(true, { " ~
553 (BodySafe ? "" : "auto p = &n + 10; " ) ~ // unsafe code
554 (BodyPure ? "" : "static int g; g = 10; ") ~ // impure code
558 (BodySafe || !EncloseSafe) && (!EnclosePure || BodyPure);
561 pragma(msg, "safe = ", EncloseSafe?1:0, "/", BodySafe?1:0, ", ",
562 "pure = ", EnclosePure?1:0, "/", BodyPure?1:0, ", ",
563 "expect = ", expect?"OK":"NG", ", ",
566 static assert(__traits(compiles, mixin(code)()) == expect);
571 // Test for https://issues.dlang.org/show_bug.cgi?id=8637
577 ~this() {} // impure & unsafe destructor
578 bool opCast(T:bool)() {
579 int* p = cast(int*) 0; // unsafe operation
580 int n = g; // impure operation
588 enforce(s, new Exception(""));
592 alias E1 = Exception;
593 static class E2 : Exception
595 this(string fn, size_t ln) { super("", fn, ln); }
597 static class E3 : Exception
599 this(string msg) { super(msg, __FILE__, __LINE__); }
605 // https://issues.dlang.org/show_bug.cgi?id=14685
610 this() { super("Not found"); }
612 static assert(!__traits(compiles, { enforce!E(false); }));
616 Enforces that the given value is true, throwing an `ErrnoException` if it
620 value = The value to test.
621 msg = The message to include in the `ErrnoException` if it is thrown.
623 Returns: `value`, if `cast(bool) value` is true. Otherwise,
624 $(D new ErrnoException(msg)) is thrown. It is assumed that the last
625 operation set `errno` to an error code corresponding with the failed
628 alias errnoEnforce = enforce!ErrnoException;
633 import core.stdc.stdio : fclose, fgets, fopen;
634 import std.file : thisExePath;
635 import std.string : toStringz;
637 auto f = fopen(thisExePath.toStringz, "r").errnoEnforce;
638 scope(exit) fclose(f);
640 auto line = fgets(buf.ptr, buf.length, f);
641 enforce(line !is null); // expect a non-empty line
645 Catches and returns the exception thrown from the given expression.
646 If no exception is thrown, then null is returned and `result` is
647 set to the result of the expression.
649 Note that while `collectException` $(I can) be used to collect any
650 `Throwable` and not just `Exception`s, it is generally ill-advised to
651 catch anything that is neither an `Exception` nor a type derived from
652 `Exception`. So, do not use `collectException` to collect
653 non-`Exception`s unless you're sure that that's what you really want to
657 T = The type of exception to catch.
658 expression = The expression which may throw an exception.
659 result = The result of the expression if no exception is thrown.
661 T collectException(T = Exception, E)(lazy E expression, ref E result)
665 result = expression();
671 // Avoid "statement not reachable" warning
672 static if (!is(immutable E == immutable noreturn))
679 int foo() { throw new Exception("blah"); }
680 assert(collectException(foo(), b));
682 version (D_NoBoundsChecks) {}
685 // check for out of bounds error
686 int[] a = new int[3];
687 import core.exception : RangeError;
688 assert(collectException!RangeError(a[4], b));
693 Catches and returns the exception thrown from the given expression.
694 If no exception is thrown, then null is returned. `E` can be
697 Note that while `collectException` $(I can) be used to collect any
698 `Throwable` and not just `Exception`s, it is generally ill-advised to
699 catch anything that is neither an `Exception` nor a type derived from
700 `Exception`. So, do not use `collectException` to collect
701 non-`Exception`s unless you're sure that that's what you really want to
705 T = The type of exception to catch.
706 expression = The expression which may throw an exception.
708 T collectException(T : Throwable = Exception, E)(lazy E expression)
718 // Avoid "statement not reachable" warning
719 static if (!is(immutable E == immutable noreturn))
726 int foo() { throw new Exception("blah"); }
727 assert(collectException(foo()).msg == "blah");
731 Catches the exception thrown from the given expression and returns the
732 msg property of that exception. If no exception is thrown, then null is
733 returned. `E` can be `void`.
735 If an exception is thrown but it has an empty message, then
736 `emptyExceptionMsg` is returned.
738 Note that while `collectExceptionMsg` $(I can) be used to collect any
739 `Throwable` and not just `Exception`s, it is generally ill-advised to
740 catch anything that is neither an `Exception` nor a type derived from
741 `Exception`. So, do not use `collectExceptionMsg` to collect
742 non-`Exception`s unless you're sure that that's what you really want to
746 T = The type of exception to catch.
747 expression = The expression which may throw an exception.
749 string collectExceptionMsg(T = Exception, E)(lazy E expression)
751 import std.array : empty;
756 // Avoid "statement not reachable" warning
757 static if (!is(immutable E == immutable noreturn))
758 return cast(string) null;
761 return e.msg.empty ? emptyExceptionMsg : e.msg;
766 void throwFunc() { throw new Exception("My Message."); }
767 assert(collectExceptionMsg(throwFunc()) == "My Message.");
769 void nothrowFunc() {}
770 assert(collectExceptionMsg(nothrowFunc()) is null);
772 void throwEmptyFunc() { throw new Exception(""); }
773 assert(collectExceptionMsg(throwEmptyFunc()) == emptyExceptionMsg);
777 Value that collectExceptionMsg returns when it catches an exception
778 with an empty exception message.
780 enum emptyExceptionMsg = "<Empty Exception Message>";
782 // https://issues.dlang.org/show_bug.cgi?id=22364
785 static noreturn foo() { throw new Exception(""); }
787 const ex = collectException!(Exception, noreturn)(foo());
790 const msg = collectExceptionMsg!(Exception, noreturn)(foo());
795 // Triggers a backend assertion failure
796 // collectException!(Exception, noreturn)(foo(), n);
798 static assert(__traits(compiles, collectException!(Exception, noreturn)(foo(), n)));
802 Casts a mutable array to an immutable array in an idiomatic
803 manner. Technically, `assumeUnique` just inserts a cast,
804 but its name documents assumptions on the part of the
805 caller. `assumeUnique(arr)` should only be called when
806 there are no more active mutable aliases to elements of $(D
807 arr). To strengthen this assumption, `assumeUnique(arr)`
808 also clears `arr` before returning. Essentially $(D
809 assumeUnique(arr)) indicates commitment from the caller that there
810 is no more mutable access to any of `arr`'s elements
811 (transitively), and that all future accesses will be done through
812 the immutable array returned by `assumeUnique`.
814 Typically, `assumeUnique` is used to return arrays from
815 functions that have allocated and built them.
818 array = The array to cast to immutable.
820 Returns: The immutable array.
828 char[] result = new char['z' - 'a' + 1];
829 foreach (i, ref e; result)
831 e = cast(char)('a' + i);
833 return assumeUnique(result);
838 The use in the example above is correct because `result`
839 was private to `letters` and is inaccessible in writing
840 after the function returns. The following example shows an
841 incorrect use of `assumeUnique`.
848 string letters(char first, char last)
850 if (first >= last) return null; // fine
851 auto sneaky = buffer;
852 sneaky.length = last - first + 1;
853 foreach (i, ref e; sneaky)
855 e = cast(char)('a' + i);
857 return assumeUnique(sneaky); // BAD
862 The example above wreaks havoc on client code because it is
863 modifying arrays that callers considered immutable. To obtain an
864 immutable array from the writable array `buffer`, replace
868 return to!(string)(sneaky); // not that sneaky anymore
871 The call will duplicate the array appropriately.
873 Note that checking for uniqueness during compilation is
874 possible in certain cases, especially when a function is
875 marked as a pure function. The following example does not
876 need to call `assumeUnique` because the compiler can infer the
877 uniqueness of the array in the pure function:
881 static string letters() pure
883 char[] result = new char['z' - 'a' + 1];
884 foreach (i, ref e; result)
886 e = cast(char)('a' + i);
893 For more on infering uniqueness see the $(B unique) and
894 $(B lent) keywords in the
895 $(HTTP www.cs.cmu.edu/~aldrich/papers/aldrich-dissertation.pdf, ArchJava)
898 The downside of using `assumeUnique`'s
899 convention-based usage is that at this time there is no
900 formal checking of the correctness of the assumption;
901 on the upside, the idiomatic use of `assumeUnique` is
902 simple and rare enough to be tolerable.
904 immutable(T)[] assumeUnique(T)(T[] array) pure nothrow
906 return .assumeUnique(array); // call ref version
909 immutable(T)[] assumeUnique(T)(ref T[] array) pure nothrow
911 auto result = cast(immutable(T)[]) array;
916 immutable(T[U]) assumeUnique(T, U)(ref T[U] array) pure nothrow
918 auto result = cast(immutable(T[U])) array;
926 int[] arr = new int[1];
927 auto arr1 = arr.assumeUnique;
928 static assert(is(typeof(arr1) == immutable(int)[]));
936 int[string] arr = ["a":1];
937 auto arr1 = arr.assumeUnique;
938 static assert(is(typeof(arr1) == immutable(int[string])));
940 assert(arr1.keys == ["a"]);
944 * Wraps a possibly-throwing expression in a `nothrow` wrapper so that it
945 * can be called by a `nothrow` function.
947 * This wrapper function documents commitment on the part of the caller that
948 * the appropriate steps have been taken to avoid whatever conditions may
949 * trigger an exception during the evaluation of `expr`. If it turns out
950 * that the expression $(I does) throw at runtime, the wrapper will throw an
953 * (Note that `Throwable` objects such as `AssertError` that do not
954 * subclass `Exception` may be thrown even from `nothrow` functions,
955 * since they are considered to be serious runtime problems that cannot be
959 * expr = The expression asserted not to throw.
960 * msg = The message to include in the `AssertError` if the assumption turns
962 * file = The source file name of the caller.
963 * line = The line number of the caller.
966 * The value of `expr`, if any.
968 T assumeWontThrow(T)(lazy T expr,
970 string file = __FILE__,
971 size_t line = __LINE__) nothrow
973 import core.exception : AssertError;
980 import std.range.primitives : empty;
981 immutable tail = msg.empty ? "." : ": " ~ msg;
982 throw new AssertError("assumeWontThrow failed: Expression did throw" ~
990 import std.math.algebraic : sqrt;
992 // This function may throw.
993 int squareRoot(int x)
996 throw new Exception("Tried to take root of negative number");
997 return cast(int) sqrt(cast(double) x);
1000 // This function never throws.
1001 int computeLength(int x, int y) nothrow
1003 // Since x*x + y*y is always positive, we can safely assume squareRoot
1004 // won't throw, and use it to implement this nothrow function. If it
1005 // does throw (e.g., if x*x + y*y overflows a 32-bit value), then the
1006 // program will terminate.
1007 return assumeWontThrow(squareRoot(x*x + y*y));
1010 assert(computeLength(3, 4) == 5);
1015 import core.exception : AssertError;
1019 throw new Exception("I threw up");
1023 assumeWontThrow(alwaysThrows());
1025 assertThrown!AssertError(bad());
1029 Checks whether a given source object contains pointers or references to a given
1033 source = The source object
1034 target = The target object
1037 The function is explicitly annotated `@nogc` because inference could fail,
1038 see $(LINK2 https://issues.dlang.org/show_bug.cgi?id=17084, issue 17084).
1040 Returns: `true` if `source`'s representation embeds a pointer
1041 that points to `target`'s representation or somewhere inside
1044 If `source` is or contains a dynamic array, then, then these functions will check
1045 if there is overlap between the dynamic array and `target`'s representation.
1047 If `source` is a class, then it will be handled as a pointer.
1049 If `target` is a pointer, a dynamic array or a class, then these functions will only
1050 check if `source` points to `target`, $(I not) what `target` references.
1052 If `source` is or contains a union or `void[n]`, then there may be either false positives or
1055 `doesPointTo` will return `true` if it is absolutely certain
1056 `source` points to `target`. It may produce false negatives, but never
1057 false positives. This function should be prefered when trying to validate
1060 `mayPointTo` will return `false` if it is absolutely certain
1061 `source` does not point to `target`. It may produce false positives, but never
1062 false negatives. This function should be prefered for defensively choosing a
1065 Note: Evaluating $(D doesPointTo(x, x)) checks whether `x` has
1066 internal pointers. This should only be done as an assertive test,
1067 as the language is free to assume objects don't have internal pointers
1070 bool doesPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @nogc @trusted pure nothrow
1071 if (__traits(isRef, source) || isDynamicArray!S ||
1072 is(S : U*, U) || is(S == class))
1074 static if (is(S : U*, U) || is(S == class) || is(S == interface))
1076 const m = *cast(void**) &source;
1077 const b = cast(void*) ⌖
1078 const e = b + target.sizeof;
1079 return b <= m && m < e;
1081 else static if (is(S == struct) || is(S == union))
1083 foreach (i, Subobj; typeof(source.tupleof))
1084 static if (!isUnionAliased!(S, i))
1085 if (doesPointTo(source.tupleof[i], target)) return true;
1088 else static if (isStaticArray!S)
1090 static if (!is(S == void[n], size_t n))
1092 foreach (ref s; source)
1093 if (doesPointTo(s, target)) return true;
1097 else static if (isDynamicArray!S)
1099 import std.array : overlap;
1100 return overlap(cast(void[]) source, cast(void[])(&target)[0 .. 1]).length != 0;
1108 // for shared objects
1110 bool doesPointTo(S, T)(auto ref const shared S source, ref const shared T target) @trusted pure nothrow
1112 return doesPointTo!(shared S, shared T, void)(source, target);
1116 bool mayPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @trusted pure nothrow
1117 if (__traits(isRef, source) || isDynamicArray!S ||
1118 is(S : U*, U) || is(S == class))
1120 static if (is(S : U*, U) || is(S == class) || is(S == interface))
1122 const m = *cast(void**) &source;
1123 const b = cast(void*) ⌖
1124 const e = b + target.sizeof;
1125 return b <= m && m < e;
1127 else static if (is(S == struct) || is(S == union))
1129 foreach (i, Subobj; typeof(source.tupleof))
1130 if (mayPointTo(source.tupleof[i], target)) return true;
1133 else static if (isStaticArray!S)
1135 static if (is(S == void[n], size_t n))
1137 static if (n >= (void[]).sizeof)
1139 // could contain a slice, which could point at anything.
1140 // But a void[N] that is all 0 cannot point anywhere
1141 import std.algorithm.searching : any;
1142 if (__ctfe || any(cast(ubyte[]) source[]))
1145 else static if (n >= (void*).sizeof)
1147 // Reinterpreting cast is impossible during ctfe
1151 // Only check for properly aligned pointers
1152 enum al = (void*).alignof - 1;
1153 const base = cast(size_t) &source;
1154 const alBase = (base + al) & ~al;
1156 if ((n - (alBase - base)) >= (void*).sizeof &&
1157 mayPointTo(*(cast(void**) alBase), target))
1163 foreach (size_t i; 0 .. S.length)
1164 if (mayPointTo(source[i], target)) return true;
1169 else static if (isDynamicArray!S)
1171 import std.array : overlap;
1172 return overlap(cast(void[]) source, cast(void[])(&target)[0 .. 1]).length != 0;
1180 // for shared objects
1182 bool mayPointTo(S, T)(auto ref const shared S source, ref const shared T target) @trusted pure nothrow
1184 return mayPointTo!(shared S, shared T, void)(source, target);
1192 assert(!p.doesPointTo(i));
1194 assert( p.doesPointTo(i));
1197 /// Structs and Unions
1208 // structs and unions "own" their members
1209 // pointsTo will answer true if one of the members pointsTo.
1210 assert(!s.doesPointTo(s.v)); //s.v is just v member of s, so not pointed.
1211 assert( s.p.doesPointTo(i)); //i is pointed by s.p.
1212 assert( s .doesPointTo(i)); //which means i is pointed by s itself.
1214 // Unions will behave exactly the same. Points to will check each "member"
1215 // individually, even if they share the same memory
1218 /// Arrays (dynamic and static)
1222 // trick the compiler when initializing slice
1223 // https://issues.dlang.org/show_bug.cgi?id=18637
1225 int[] slice = [0, 1, 2, 3, 4];
1226 int[5] arr = [0, 1, 2, 3, 4];
1227 int*[] slicep = [p];
1228 int*[1] arrp = [&i];
1230 // A slice points to all of its members:
1231 assert( slice.doesPointTo(slice[3]));
1232 assert(!slice[0 .. 2].doesPointTo(slice[3])); // Object 3 is outside of the
1235 // Note that a slice will not take into account what its members point to.
1236 assert( slicep[0].doesPointTo(i));
1237 assert(!slicep .doesPointTo(i));
1239 // static arrays are objects that own their members, just like structs:
1240 assert(!arr.doesPointTo(arr[0])); // arr[0] is just a member of arr, so not
1242 assert( arrp[0].doesPointTo(i)); // i is pointed by arrp[0].
1243 assert( arrp .doesPointTo(i)); // which means i is pointed by arrp
1246 // Notice the difference between static and dynamic arrays:
1247 assert(!arr .doesPointTo(arr[0]));
1248 assert( arr[].doesPointTo(arr[0]));
1249 assert( arrp .doesPointTo(i));
1250 assert(!arrp[].doesPointTo(i));
1258 this(int* p){this.p = p;}
1265 // Classes are a bit particular, as they are treated like simple pointers
1266 // to a class payload.
1267 assert( a.p.doesPointTo(i)); // a.p points to i.
1268 assert(!a .doesPointTo(i)); // Yet a itself does not point i.
1270 //To check the class payload itself, iterate on its members:
1273 import std.traits : Fields;
1275 foreach (index, _; Fields!C)
1276 if (doesPointTo(a.tupleof[index], i))
1281 // To check if a class points a specific payload, a direct memmory check
1283 auto aLoc = cast(ubyte[__traits(classInstanceSize, C)]*) a;
1284 assert(b.doesPointTo(*aLoc)); // b points to where a is pointing
1288 version (StdUnittest)
1290 // https://issues.dlang.org/show_bug.cgi?id=17084
1291 // the bug doesn't happen if these declarations are in the unittest block
1293 private struct Page17084
1296 int opCmp(P)(P) { return 0; }
1297 int opCmp(P)(shared(P)) shared { return 0; }
1300 private struct URL17084
1303 string toString()() const { return ""; }
1304 alias toString this;
1308 // https://issues.dlang.org/show_bug.cgi?id=17084
1311 import std.algorithm.sorting : sort;
1314 shared(Page17084)[] p;
1320 struct S1 { int a; S1 * b; }
1323 assert(doesPointTo(p, a1));
1327 assert(doesPointTo(a2, a1));
1329 struct S3 { int[10] a; }
1331 auto a4 = a3.a[2 .. 3];
1332 assert(doesPointTo(a4, a3));
1334 auto a5 = new double[4];
1335 auto a6 = a5[1 .. 2];
1336 assert(!doesPointTo(a5, a6));
1338 auto a7 = new double[3];
1339 auto a8 = new double[][1];
1341 assert(!doesPointTo(a8[0], a8[0]));
1343 // don't invoke postblit on subobjects
1345 static struct NoCopy { this(this) { assert(0); } }
1346 static struct Holder { NoCopy a, b, c; }
1348 cast(void) doesPointTo(h, h);
1352 shared sh3sub = sh3.a[];
1353 assert(doesPointTo(sh3sub, sh3));
1355 int[] darr = [1, 2, 3, 4];
1357 //dynamic arrays don't point to each other, or slices of themselves
1358 assert(!doesPointTo(darr, darr));
1359 assert(!doesPointTo(darr[0 .. 1], darr));
1361 //But they do point their elements
1363 assert(doesPointTo(darr, darr[i]));
1364 assert(doesPointTo(darr[0 .. 3], darr[2]));
1365 assert(!doesPointTo(darr[0 .. 3], darr[3]));
1370 //tests with static arrays
1371 //Static arrays themselves are just objects, and don't really *point* to anything.
1372 //They aggregate their contents, much the same way a structure aggregates its attributes.
1373 //*However* The elements inside the static array may themselves point to stuff.
1377 assert(!doesPointTo(k, k)); //an array doesn't point to itself
1378 //Technically, k doesn't point its elements, although it does alias them
1379 assert(!doesPointTo(k, k[0]));
1380 assert(!doesPointTo(k, k[1]));
1381 //But an extracted slice will point to the same array.
1382 assert(doesPointTo(k[], k));
1383 assert(doesPointTo(k[], k[1]));
1385 //An array of pointers
1390 assert( doesPointTo(pp, a)); //The array contains a pointer to a
1391 assert(!doesPointTo(pp, b)); //The array does NOT contain a pointer to b
1392 assert(!doesPointTo(pp, pp)); //The array does not point itslef
1394 //A struct containing a static array of pointers
1401 assert( doesPointTo(s, a)); //The struct contains an array that points a
1402 assert(!doesPointTo(s, b)); //But doesn't point b
1403 assert(!doesPointTo(s, s)); //The struct doesn't actually point itslef.
1405 //An array containing structs that have pointers
1410 SS[2] ss = [SS(&a), SS(null)];
1411 assert( doesPointTo(ss, a)); //The array contains a struct that points to a
1412 assert(!doesPointTo(ss, b)); //The array doesn't contains a struct that points to b
1413 assert(!doesPointTo(ss, ss)); //The array doesn't point itself.
1415 // https://issues.dlang.org/show_bug.cgi?id=20426
1416 align((void*).alignof) void[32] voidArr = void;
1417 (cast(void*[]) voidArr[])[] = null; // Ensure no false pointers
1419 // zeroed void ranges can't point at anything
1420 assert(!mayPointTo(voidArr, a));
1421 assert(!mayPointTo(voidArr, b));
1423 *cast(void**) &voidArr[16] = &a; // Pointers should be found
1425 alias SA = void[size_t.sizeof + 3];
1426 SA *smallArr1 = cast(SA*)&voidArr;
1427 SA *smallArr2 = cast(SA*)&(voidArr[16]);
1429 // But it should only consider properly aligned pointers
1430 // Write single bytes to avoid issues due to misaligned writes
1431 void*[1] tmp = [&b];
1432 (cast(ubyte[]) voidArr[3 .. 3 + (void*).sizeof])[] = cast(ubyte[]) tmp[];
1435 assert( mayPointTo(*smallArr2, a));
1436 assert(!mayPointTo(*smallArr1, b));
1438 assert(!doesPointTo(voidArr, a)); // Value might be a false pointer
1439 assert(!doesPointTo(voidArr, b));
1441 SA *smallArr3 = cast(SA *) &voidArr[13]; // Works for weird sizes/alignments
1442 assert( mayPointTo(*smallArr3, a));
1443 assert(!mayPointTo(*smallArr3, b));
1445 assert(!doesPointTo(*smallArr3, a));
1446 assert(!doesPointTo(*smallArr3, b));
1448 auto v3 = cast(void[3]*) &voidArr[16]; // Arrays smaller than pointers are ignored
1449 assert(!mayPointTo(*v3, a));
1450 assert(!mayPointTo(*v3, b));
1452 assert(!doesPointTo(*v3, a));
1453 assert(!doesPointTo(*v3, b));
1455 assert(mayPointTo(voidArr, a)); // slice-contiaining void[N] might point at anything
1456 assert(mayPointTo(voidArr, b));
1459 void[16] arr1 = void;
1460 void[size_t.sizeof] arr2 = void;
1462 return mayPointTo(arr1, var) && !doesPointTo(arr1, var) &&
1463 mayPointTo(arr2, var) && !doesPointTo(arr2, var);
1468 @system unittest //Unions
1471 union U //Named union
1478 union //Anonymous union
1487 assert(!doesPointTo(u, i));
1488 assert(!doesPointTo(s, i));
1489 assert(!mayPointTo(u, i));
1490 assert(!mayPointTo(s, i));
1494 assert(!doesPointTo(u, i));
1495 assert(!doesPointTo(s, i));
1496 assert( mayPointTo(u, i));
1497 assert( mayPointTo(s, i));
1499 u.asInt = cast(size_t)&i;
1500 s.asInt = cast(size_t)&i;
1501 assert(!doesPointTo(u, i));
1502 assert(!doesPointTo(s, i));
1503 assert( mayPointTo(u, i));
1504 assert( mayPointTo(s, i));
1507 @system unittest //Classes
1515 assert(!doesPointTo(a, b)); //a does not point to b
1517 assert(!doesPointTo(a, i)); //a does not point to i
1519 @safe unittest //alias this test
1526 @property int* foo(){return &i;}
1529 assert(is(S : int*));
1531 assert(!doesPointTo(s, i));
1532 assert( doesPointTo(s, j));
1533 assert( doesPointTo(cast(int*) s, i));
1534 assert(!doesPointTo(cast(int*) s, j));
1536 @safe unittest //more alias this opCast
1541 void* opCast(T)() if (is(T == void*))
1545 alias foo = opCast!(void*);
1548 assert(!doesPointTo(A.init, p));
1549 assert(!mayPointTo(A.init, p));
1553 Returns true if the field at index `i` in ($D T) shares its address with another field.
1555 Note: This does not merelly check if the field is a member of an union, but also that
1556 it is not a single child.
1558 package enum isUnionAliased(T, size_t i) = isUnionAliasedImpl!T(T.tupleof[i].offsetof);
1559 private bool isUnionAliasedImpl(T)(size_t offset)
1562 foreach (i, U; typeof(T.tupleof))
1563 if (T.tupleof[i].offsetof == offset)
1572 int a0; //Not aliased
1575 int a1; //Not aliased
1584 int b0; //Not aliased
1595 static assert(!isUnionAliased!(S, 0)); //a0;
1596 static assert(!isUnionAliased!(S, 1)); //a1;
1597 static assert( isUnionAliased!(S, 2)); //a2;
1598 static assert( isUnionAliased!(S, 3)); //a3;
1599 static assert(!isUnionAliased!(S, 4)); //a4;
1600 static assert(!isUnionAliased!(S.A4, 0)); //a4.b0;
1601 static assert(!isUnionAliased!(S, 5)); //a5;
1602 static assert( isUnionAliased!(S.A5, 0)); //a5.b0;
1603 static assert( isUnionAliased!(S.A5, 1)); //a5.b1;
1606 version (CRuntime_Glibc) version = GNU_STRERROR;
1607 version (CRuntime_UClibc) version = GNU_STRERROR;
1609 package string errnoString(int errno) nothrow @trusted
1611 import core.stdc.string : strlen;
1612 version (GNU_STRERROR)
1614 import core.stdc.string : strerror_r;
1615 char[1024] buf = void;
1616 auto s = strerror_r(errno, buf.ptr, buf.length);
1618 else version (Posix)
1621 import core.stdc.string : strerror_r;
1622 char[1024] buf = void;
1624 if (strerror_r(errno, buf.ptr, buf.length) == 0)
1627 return "Unknown error";
1631 import core.stdc.string : strerror;
1632 auto s = strerror(errno);
1634 return s[0 .. s.strlen].idup;
1637 /*********************
1638 * Thrown if errors that set `errno` occur.
1640 class ErrnoException : Exception
1642 /// Operating system error code.
1643 final @property uint errno() nothrow pure scope @nogc @safe { return _errno; }
1644 private uint _errno;
1645 /// Constructor which takes an error message. The current global $(REF errno, core,stdc,errno) value is used as error code.
1646 this(string msg, string file = null, size_t line = 0) @safe
1648 import core.stdc.errno : errno;
1649 this(msg, errno, file, line);
1651 /// Constructor which takes an error message and error code.
1652 this(string msg, int errno, string file = null, size_t line = 0) @safe
1655 super(msg ~ " (" ~ errnoString(errno) ~ ")", file, line);
1662 import core.stdc.errno : EAGAIN;
1663 auto ex = new ErrnoException("oh no", EAGAIN);
1664 assert(ex.errno == EAGAIN);
1667 /// errno is used by default if no explicit error code is provided
1670 import core.stdc.errno : errno, EAGAIN;
1673 scope(exit) errno = old;
1675 // fake that errno got set by the callee
1677 auto ex = new ErrnoException("oh no");
1678 assert(ex.errno == EAGAIN);
1682 ML-style functional exception handling. Runs the supplied expression and
1683 returns its result. If the expression throws a `Throwable`, runs the
1684 supplied error handler instead and return its result. The error handler's
1685 type must be the same as the expression's type.
1688 E = The type of `Throwable`s to catch. Defaults to `Exception`
1689 T1 = The type of the expression.
1690 T2 = The return type of the error handler.
1691 expression = The expression to run and return its result.
1692 errorHandler = The handler to run if the expression throwed.
1695 expression, if it does not throw. Otherwise, returns the result of
1699 CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, lazy scope T2 errorHandler)
1701 static assert(!is(typeof(return) == void),
1702 "The error handler's return value("
1704 ") does not have a common type with the expression("
1710 return expression();
1714 return errorHandler();
1720 CommonType!(T1, T2) ifThrown(E : Throwable, T1, T2)(lazy scope T1 expression, scope T2 delegate(E) errorHandler)
1722 static assert(!is(typeof(return) == void),
1723 "The error handler's return value("
1725 ") does not have a common type with the expression("
1731 return expression();
1735 return errorHandler(e);
1740 //delegate version, general overload to catch any Exception
1741 CommonType!(T1, T2) ifThrown(T1, T2)(lazy scope T1 expression, scope T2 delegate(Exception) errorHandler)
1743 static assert(!is(typeof(return) == void),
1744 "The error handler's return value("
1746 ") does not have a common type with the expression("
1752 return expression();
1756 return errorHandler(e);
1760 /// Revert to a default value upon an error:
1763 import std.conv : to;
1764 assert("x".to!int.ifThrown(0) == 0);
1768 Chain multiple calls to ifThrown, each capturing errors from the
1769 entire preceding expression.
1773 import std.conv : ConvException, to;
1775 assert(s.to!int.ifThrown(cast(int) s.to!double)
1776 .ifThrown(cast(int) s.to!bool) == 1);
1779 assert(s.to!int.ifThrown(cast(int) s.to!double)
1780 .ifThrown(cast(int) s.to!bool) == 2);
1782 // Respond differently to different types of errors
1783 alias orFallback = (lazy a) => a.ifThrown!ConvException("not a number")
1784 .ifThrown!Exception("number too small");
1786 assert(orFallback(enforce("x".to!int < 1).to!string) == "not a number");
1787 assert(orFallback(enforce("2".to!int < 1).to!string) == "number too small");
1791 The expression and the errorHandler must have a common type they can both
1792 be implicitly casted to, and that type will be the type of the compound
1797 // null and new Object have a common type(Object).
1798 static assert(is(typeof(null.ifThrown(new Object())) == Object));
1799 static assert(is(typeof((new Object()).ifThrown(null)) == Object));
1801 // 1 and new Object do not have a common type.
1802 static assert(!__traits(compiles, 1.ifThrown(new Object())));
1803 static assert(!__traits(compiles, (new Object()).ifThrown(1)));
1806 /// Use a lambda to get the thrown object.
1809 import std.format : format;
1810 assert("%s".format.ifThrown!Exception(e => e.classinfo.name) == "std.format.FormatException");
1818 //Revert to a default value upon an error:
1819 assert("x".to!int().ifThrown(0) == 0);
1821 //Chaining multiple calls to ifThrown to attempt multiple things in a row:
1824 ifThrown(cast(int) s.to!double()).
1825 ifThrown(cast(int) s.to!bool())
1828 //Respond differently to different types of errors
1829 assert(enforce("x".to!int() < 1).to!string()
1830 .ifThrown!ConvException("not a number")
1831 .ifThrown!Exception("number too small")
1834 //null and new Object have a common type(Object).
1835 static assert(is(typeof(null.ifThrown(new Object())) == Object));
1836 static assert(is(typeof((new Object()).ifThrown(null)) == Object));
1838 //1 and new Object do not have a common type.
1839 static assert(!__traits(compiles, 1.ifThrown(new Object())));
1840 static assert(!__traits(compiles, (new Object()).ifThrown(1)));
1842 //Use a lambda to get the thrown object.
1843 assert("%s".format().ifThrown(e => e.classinfo.name) == "std.format.FormatException");
1848 import core.exception;
1851 //Basic behaviour - all versions.
1852 assert("1".to!int().ifThrown(0) == 1);
1853 assert("x".to!int().ifThrown(0) == 0);
1854 assert("1".to!int().ifThrown!ConvException(0) == 1);
1855 assert("x".to!int().ifThrown!ConvException(0) == 0);
1856 assert("1".to!int().ifThrown(e=>0) == 1);
1857 assert("x".to!int().ifThrown(e=>0) == 0);
1858 static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled
1860 assert("1".to!int().ifThrown!ConvException(e=>0) == 1);
1861 assert("x".to!int().ifThrown!ConvException(e=>0) == 0);
1864 //Exceptions other than stated not caught.
1865 assert("x".to!int().ifThrown!StringException(0).collectException!ConvException() !is null);
1866 static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled
1868 assert("x".to!int().ifThrown!StringException(e=>0).collectException!ConvException() !is null);
1871 //Default does not include errors.
1872 int throwRangeError() { throw new RangeError; }
1873 assert(throwRangeError().ifThrown(0).collectException!RangeError() !is null);
1874 assert(throwRangeError().ifThrown(e=>0).collectException!RangeError() !is null);
1876 //Incompatible types are not accepted.
1877 static assert(!__traits(compiles, 1.ifThrown(new Object())));
1878 static assert(!__traits(compiles, (new Object()).ifThrown(1)));
1879 static assert(!__traits(compiles, 1.ifThrown(e=>new Object())));
1880 static assert(!__traits(compiles, (new Object()).ifThrown(e=>1)));
1883 version (StdUnittest) package
1884 void assertCTFEable(alias dg)()
1886 static assert({ cast(void) dg(); return true; }());
1890 /** This `enum` is used to select the primitives of the range to handle by the
1891 $(LREF handle) range wrapper. The values of the `enum` can be `OR`'d to
1892 select multiple primitives to be handled.
1894 `RangePrimitive.access` is a shortcut for the access primitives; `front`,
1895 `back` and `opIndex`.
1897 `RangePrimitive.pop` is a shortcut for the mutating primitives;
1898 `popFront` and `popBack`.
1902 front = 0b00_0000_0001, ///
1903 back = 0b00_0000_0010, /// Ditto
1904 popFront = 0b00_0000_0100, /// Ditto
1905 popBack = 0b00_0000_1000, /// Ditto
1906 empty = 0b00_0001_0000, /// Ditto
1907 save = 0b00_0010_0000, /// Ditto
1908 length = 0b00_0100_0000, /// Ditto
1909 opDollar = 0b00_1000_0000, /// Ditto
1910 opIndex = 0b01_0000_0000, /// Ditto
1911 opSlice = 0b10_0000_0000, /// Ditto
1912 access = front | back | opIndex, /// Ditto
1913 pop = popFront | popBack, /// Ditto
1919 import std.algorithm.comparison : equal;
1920 import std.algorithm.iteration : map, splitter;
1921 import std.conv : to, ConvException;
1923 auto s = "12,1337z32,54,2,7,9,1z,6,8";
1925 // The next line composition will throw when iterated
1926 // as some elements of the input do not convert to integer
1927 auto r = s.splitter(',').map!(a => to!int(a));
1929 // Substitute 0 for cases of ConvException
1930 auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0);
1931 assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8]));
1937 import std.algorithm.comparison : equal;
1938 import std.range : retro;
1939 import std.utf : UTFException;
1941 auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit
1943 auto handled = str.handle!(UTFException, RangePrimitive.access,
1944 (e, r) => ' '); // Replace invalid code points with spaces
1946 assert(handled.equal("hello world")); // `front` is handled,
1947 assert(handled.retro.equal("dlrow olleh")); // as well as `back`
1950 /** Handle exceptions thrown from range primitives.
1952 Use the $(LREF RangePrimitive) enum to specify which primitives to _handle.
1953 Multiple range primitives can be handled at once by using the `OR` operator
1954 or the pseudo-primitives `RangePrimitive.access` and `RangePrimitive.pop`.
1955 All handled primitives must have return types or values compatible with the
1956 user-supplied handler.
1959 E = The type of `Throwable` to _handle.
1960 primitivesToHandle = Set of range primitives to _handle.
1961 handler = The callable that is called when a handled primitive throws a
1962 `Throwable` of type `E`. The handler must accept arguments of
1963 the form $(D E, ref IRange) and its return value is used as the primitive's
1964 return value whenever `E` is thrown. For `opIndex`, the handler can
1965 optionally recieve a third argument; the index that caused the exception.
1966 input = The range to _handle.
1968 Returns: A wrapper `struct` that preserves the range interface of `input`.
1971 Infinite ranges with slicing support must return an instance of
1972 $(REF Take, std,range) when sliced with a specific lower and upper
1973 bound (see $(REF hasSlicing, std,range,primitives)); `handle` deals with
1974 this by `take`ing 0 from the return value of the handler function and
1975 returning that when an exception is caught.
1977 auto handle(E : Throwable, RangePrimitive primitivesToHandle, alias handler, Range)(Range input)
1978 if (isInputRange!Range)
1980 static struct Handler
1982 private Range range;
1984 static if (isForwardRange!Range)
1986 @property typeof(this) save()
1988 static if (primitivesToHandle & RangePrimitive.save)
1992 return typeof(this)(range.save);
1996 return typeof(this)(handler(exception, this.range));
2000 return typeof(this)(range.save);
2004 static if (isInfinite!Range)
2006 enum bool empty = false;
2010 @property bool empty()
2012 static if (primitivesToHandle & RangePrimitive.empty)
2016 return this.range.empty;
2020 return handler(exception, this.range);
2024 return this.range.empty;
2028 @property auto ref front()
2030 static if (primitivesToHandle & RangePrimitive.front)
2034 return this.range.front;
2038 return handler(exception, this.range);
2042 return this.range.front;
2047 static if (primitivesToHandle & RangePrimitive.popFront)
2051 this.range.popFront();
2055 handler(exception, this.range);
2059 this.range.popFront();
2062 static if (isBidirectionalRange!Range)
2064 @property auto ref back()
2066 static if (primitivesToHandle & RangePrimitive.back)
2070 return this.range.back;
2074 return handler(exception, this.range);
2078 return this.range.back;
2083 static if (primitivesToHandle & RangePrimitive.popBack)
2087 this.range.popBack();
2091 handler(exception, this.range);
2095 this.range.popBack();
2099 static if (isRandomAccessRange!Range)
2101 auto ref opIndex(size_t index)
2103 static if (primitivesToHandle & RangePrimitive.opIndex)
2107 return this.range[index];
2111 static if (__traits(compiles, handler(exception, this.range, index)))
2112 return handler(exception, this.range, index);
2114 return handler(exception, this.range);
2118 return this.range[index];
2122 static if (hasLength!Range)
2124 @property auto length()
2126 static if (primitivesToHandle & RangePrimitive.length)
2130 return this.range.length;
2134 return handler(exception, this.range);
2138 return this.range.length;
2142 static if (hasSlicing!Range)
2144 static if (hasLength!Range)
2146 typeof(this) opSlice(size_t lower, size_t upper)
2148 static if (primitivesToHandle & RangePrimitive.opSlice)
2152 return typeof(this)(this.range[lower .. upper]);
2156 return typeof(this)(handler(exception, this.range));
2160 return typeof(this)(this.range[lower .. upper]);
2163 else static if (is(typeof(Range.init[size_t.init .. $])))
2165 import std.range : Take, takeExactly;
2166 static struct DollarToken {}
2167 enum opDollar = DollarToken.init;
2169 typeof(this) opSlice(size_t lower, DollarToken)
2171 static if (primitivesToHandle & RangePrimitive.opSlice)
2175 return typeof(this)(this.range[lower .. $]);
2179 return typeof(this)(handler(exception, this.range));
2183 return typeof(this)(this.range[lower .. $]);
2186 Take!Handler opSlice(size_t lower, size_t upper)
2188 static if (primitivesToHandle & RangePrimitive.opSlice)
2192 return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1);
2196 return takeExactly(typeof(this)(handler(exception, this.range)), 0);
2200 return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1);
2206 return Handler(input);
2212 import std.algorithm.comparison : equal;
2213 import std.algorithm.iteration : map, splitter;
2214 import std.conv : to, ConvException;
2216 auto s = "12,1337z32,54,2,7,9,1z,6,8";
2218 // The next line composition will throw when iterated
2219 // as some elements of the input do not convert to integer
2220 auto r = s.splitter(',').map!(a => to!int(a));
2222 // Substitute 0 for cases of ConvException
2223 auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0);
2224 assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8]));
2230 import std.algorithm.comparison : equal;
2231 import std.range : retro;
2232 import std.utf : UTFException;
2234 auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit
2236 auto handled = str.handle!(UTFException, RangePrimitive.access,
2237 (e, r) => ' '); // Replace invalid code points with spaces
2239 assert(handled.equal("hello world")); // `front` is handled,
2240 assert(handled.retro.equal("dlrow olleh")); // as well as `back`
2243 pure nothrow @safe unittest
2245 static struct ThrowingRange
2248 @property bool empty()
2250 throw new Exception("empty has thrown");
2253 @property int front()
2255 throw new Exception("front has thrown");
2258 @property int back()
2260 throw new Exception("back has thrown");
2265 throw new Exception("popFront has thrown");
2270 throw new Exception("popBack has thrown");
2275 throw new Exception("opIndex has thrown");
2278 ThrowingRange opSlice(size_t, size_t)
2280 throw new Exception("opSlice has thrown");
2283 @property size_t length()
2285 throw new Exception("length has thrown");
2288 alias opDollar = length;
2290 @property ThrowingRange save()
2292 throw new Exception("save has thrown");
2296 static assert(isInputRange!ThrowingRange);
2297 static assert(isForwardRange!ThrowingRange);
2298 static assert(isBidirectionalRange!ThrowingRange);
2299 static assert(hasSlicing!ThrowingRange);
2300 static assert(hasLength!ThrowingRange);
2302 auto f = ThrowingRange();
2303 auto fb = f.handle!(Exception, RangePrimitive.front | RangePrimitive.back,
2305 assert(fb.front == -1);
2306 assert(fb.back == -1);
2307 assertThrown(fb.popFront());
2308 assertThrown(fb.popBack());
2309 assertThrown(fb.empty);
2310 assertThrown(fb.save);
2311 assertThrown(fb[0]);
2313 auto accessRange = f.handle!(Exception, RangePrimitive.access,
2315 assert(accessRange.front == -1);
2316 assert(accessRange.back == -1);
2317 assert(accessRange[0] == -1);
2318 assertThrown(accessRange.popFront());
2319 assertThrown(accessRange.popBack());
2321 auto pfb = f.handle!(Exception, RangePrimitive.pop, (e, r) => -1)();
2323 pfb.popFront(); // this would throw otherwise
2324 pfb.popBack(); // this would throw otherwise
2326 auto em = f.handle!(Exception,
2327 RangePrimitive.empty, (e, r) => false)();
2331 auto arr = f.handle!(Exception,
2332 RangePrimitive.opIndex, (e, r) => 1337)();
2334 assert(arr[0] == 1337);
2336 auto arr2 = f.handle!(Exception,
2337 RangePrimitive.opIndex, (e, r, i) => i)();
2339 assert(arr2[0] == 0);
2340 assert(arr2[1337] == 1337);
2342 auto save = f.handle!(Exception,
2343 RangePrimitive.save,
2344 function(Exception e, ref ThrowingRange r) {
2345 return ThrowingRange();
2350 auto slice = f.handle!(Exception,
2351 RangePrimitive.opSlice, (e, r) => ThrowingRange())();
2353 auto sliced = slice[0 .. 1337]; // this would throw otherwise
2355 static struct Infinite
2357 import std.range : Take;
2359 enum bool empty = false;
2360 int front() { assert(false); }
2361 void popFront() { assert(false); }
2362 Infinite save() @property { assert(false); }
2363 static struct DollarToken {}
2364 enum opDollar = DollarToken.init;
2365 Take!Infinite opSlice(size_t, size_t) { assert(false); }
2366 Infinite opSlice(size_t, DollarToken)
2368 throw new Exception("opSlice has thrown");
2372 static assert(isInputRange!Infinite);
2373 static assert(isInfinite!Infinite);
2374 static assert(hasSlicing!Infinite);
2376 assertThrown(Infinite()[0 .. $]);
2378 auto infinite = Infinite.init.handle!(Exception,
2379 RangePrimitive.opSlice, (e, r) => Infinite())();
2381 auto infSlice = infinite[0 .. $]; // this would throw otherwise
2386 Convenience mixin for trivially sub-classing exceptions
2388 Even trivially sub-classing an exception involves writing boilerplate code
2389 for the constructor to: 1$(RPAREN) correctly pass in the source file and line number
2390 the exception was thrown from; 2$(RPAREN) be usable with $(LREF enforce) which
2391 expects exception constructors to take arguments in a fixed order. This
2392 mixin provides that boilerplate code.
2394 Note however that you need to mark the $(B mixin) line with at least a
2395 minimal (i.e. just $(B ///)) DDoc comment if you want the mixed-in
2396 constructors to be documented in the newly created Exception subclass.
2398 $(RED Current limitation): Due to
2399 $(LINK2 https://issues.dlang.org/show_bug.cgi?id=11500, bug #11500),
2400 currently the constructors specified in this mixin cannot be overloaded with
2401 any other custom constructors. Thus this mixin can currently only be used
2402 when no such custom constructors need to be explicitly specified.
2404 mixin template basicExceptionCtors()
2408 msg = The message for the exception.
2409 file = The file where the exception occurred.
2410 line = The line number where the exception occurred.
2411 next = The previous exception in the chain of exceptions, if any.
2413 this(string msg, string file = __FILE__, size_t line = __LINE__,
2414 Throwable next = null) @nogc @safe pure nothrow
2416 super(msg, file, line, next);
2421 msg = The message for the exception.
2422 next = The previous exception in the chain of exceptions.
2423 file = The file where the exception occurred.
2424 line = The line number where the exception occurred.
2426 this(string msg, Throwable next, string file = __FILE__,
2427 size_t line = __LINE__) @nogc @safe pure nothrow
2429 super(msg, file, line, next);
2436 class MeaCulpa: Exception
2439 mixin basicExceptionCtors;
2443 throw new MeaCulpa("test");
2446 assert(e.msg == "test");
2447 assert(e.file == __FILE__);
2448 assert(e.line == __LINE__ - 5);
2452 @safe pure nothrow unittest
2454 class TestException : Exception { mixin basicExceptionCtors; }
2455 auto e = new Exception("msg");
2456 auto te1 = new TestException("foo");
2457 auto te2 = new TestException("foo", e);
2462 class TestException : Exception { mixin basicExceptionCtors; }
2463 auto e = new Exception("!!!");
2465 auto te1 = new TestException("message", "file", 42, e);
2466 assert(te1.msg == "message");
2467 assert(te1.file == "file");
2468 assert(te1.line == 42);
2469 assert(te1.next is e);
2471 auto te2 = new TestException("message", e, "file", 42);
2472 assert(te2.msg == "message");
2473 assert(te2.file == "file");
2474 assert(te2.line == 42);
2475 assert(te2.next is e);
2477 auto te3 = new TestException("foo");
2478 assert(te3.msg == "foo");
2479 assert(te3.file == __FILE__);
2480 assert(te3.line == __LINE__ - 3);
2481 assert(te3.next is null);
2483 auto te4 = new TestException("foo", e);
2484 assert(te4.msg == "foo");
2485 assert(te4.file == __FILE__);
2486 assert(te4.line == __LINE__ - 3);
2487 assert(te4.next is e);