1 // Written in the D programming language.
2
3 /++
4 This module defines functions related to exceptions and general error
5 handling. It also defines functions intended to aid in unit testing.
6
7 $(SCRIPT inhibitQuickIndex = 1;)
8 $(BOOKTABLE,
9 $(TR $(TH Category) $(TH Functions))
10 $(TR $(TD Assumptions) $(TD
11 $(LREF assertNotThrown)
12 $(LREF assertThrown)
13 $(LREF assumeUnique)
14 $(LREF assumeWontThrow)
15 $(LREF mayPointTo)
16 ))
17 $(TR $(TD Enforce) $(TD
18 $(LREF doesPointTo)
19 $(LREF enforce)
20 $(LREF enforceEx)
21 $(LREF errnoEnforce)
22 ))
23 $(TR $(TD Handlers) $(TD
24 $(LREF collectException)
25 $(LREF collectExceptionMsg)
26 $(LREF ifThrown)
27 $(LREF handle)
28 ))
29 $(TR $(TD Other) $(TD
30 $(LREF basicExceptionCtors)
31 $(LREF emptyExceptionMsg)
32 $(LREF ErrnoException)
33 $(LREF RangePrimitive)
34 ))
35 )
36
37 Synopsis of some of std.exception's functions:
38 --------------------
39 string synopsis()
40 {
41 FILE* f = enforce(fopen("some/file"));
42 // f is not null from here on
43 FILE* g = enforce!WriteException(fopen("some/other/file", "w"));
44 // g is not null from here on
45
46 Exception e = collectException(write(g, readln(f)));
47 if (e)
48 {
49 ... an exception occurred...
50 ... We have the exception to play around with...
51 }
52
53 string msg = collectExceptionMsg(write(g, readln(f)));
54 if (msg)
55 {
56 ... an exception occurred...
57 ... We have the message from the exception but not the exception...
58 }
59
60 char[] line;
61 enforce(readln(f, line));
62 return assumeUnique(line);
63 }
64 --------------------
65
66 Copyright: Copyright Andrei Alexandrescu 2008-, Jonathan M Davis 2011-.
67 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0)
68 Authors: $(HTTP erdani.org, Andrei Alexandrescu) and Jonathan M Davis
69 Source: $(PHOBOSSRC std/_exception.d)
70
71 +/
72 module std.exception;
73
74 import std.range.primitives;
75 import std.traits;
76
77 /++
78 Asserts that the given expression does $(I not) throw the given type
79 of $(D Throwable). If a $(D Throwable) of the given type is thrown,
80 it is caught and does not escape assertNotThrown. Rather, an
81 $(D AssertError) is thrown. However, any other $(D Throwable)s will escape.
82
83 Params:
84 T = The $(D Throwable) to test for.
85 expression = The expression to test.
86 msg = Optional message to output on test failure.
87 If msg is empty, and the thrown exception has a
88 non-empty msg field, the exception's msg field
89 will be output on test failure.
90 file = The file where the error occurred.
91 Defaults to $(D __FILE__).
92 line = The line where the error occurred.
93 Defaults to $(D __LINE__).
94
95 Throws:
96 $(D AssertError) if the given $(D Throwable) is thrown.
97
98 Returns:
99 the result of `expression`.
100 +/
101 auto assertNotThrown(T : Throwable = Exception, E)
102 (lazy E expression,
103 string msg = null,
104 string file = __FILE__,
105 size_t line = __LINE__)
106 {
107 import core.exception : AssertError;
108 try
109 {
110 return expression();
111 }
catch(T t)112 catch (T t)
113 {
114 immutable message = msg.length == 0 ? t.msg : msg;
115 immutable tail = message.length == 0 ? "." : ": " ~ message;
116 throw new AssertError("assertNotThrown failed: " ~ T.stringof ~ " was thrown" ~ tail, file, line, t);
117 }
118 }
119 ///
120 @system unittest
121 {
122 import core.exception : AssertError;
123
124 import std.string;
125 assertNotThrown!StringException(enforce!StringException(true, "Error!"));
126
127 //Exception is the default.
128 assertNotThrown(enforce!StringException(true, "Error!"));
129
130 assert(collectExceptionMsg!AssertError(assertNotThrown!StringException(
131 enforce!StringException(false, "Error!"))) ==
132 `assertNotThrown failed: StringException was thrown: Error!`);
133 }
134 @system unittest
135 {
136 import core.exception : AssertError;
137 import std.string;
138 assert(collectExceptionMsg!AssertError(assertNotThrown!StringException(
139 enforce!StringException(false, ""), "Error!")) ==
140 `assertNotThrown failed: StringException was thrown: Error!`);
141
142 assert(collectExceptionMsg!AssertError(assertNotThrown!StringException(
143 enforce!StringException(false, ""))) ==
144 `assertNotThrown failed: StringException was thrown.`);
145
146 assert(collectExceptionMsg!AssertError(assertNotThrown!StringException(
147 enforce!StringException(false, ""), "")) ==
148 `assertNotThrown failed: StringException was thrown.`);
149 }
150
151 @system unittest
152 {
153 import core.exception : AssertError;
154
throwEx(Throwable t)155 void throwEx(Throwable t) { throw t; }
nothrowEx()156 bool nothrowEx() { return true; }
157
158 try
159 {
160 assert(assertNotThrown!Exception(nothrowEx()));
161 }
162 catch (AssertError) assert(0);
163
164 try
165 {
166 assert(assertNotThrown!Exception(nothrowEx(), "It's a message"));
167 }
168 catch (AssertError) assert(0);
169
170 try
171 {
172 assert(assertNotThrown!AssertError(nothrowEx()));
173 }
174 catch (AssertError) assert(0);
175
176 try
177 {
178 assert(assertNotThrown!AssertError(nothrowEx(), "It's a message"));
179 }
180 catch (AssertError) assert(0);
181
182 {
183 bool thrown = false;
184 try
185 {
186 assertNotThrown!Exception(
187 throwEx(new Exception("It's an Exception")));
188 }
189 catch (AssertError) thrown = true;
190 assert(thrown);
191 }
192
193 {
194 bool thrown = false;
195 try
196 {
197 assertNotThrown!Exception(
198 throwEx(new Exception("It's an Exception")), "It's a message");
199 }
200 catch (AssertError) thrown = true;
201 assert(thrown);
202 }
203
204 {
205 bool thrown = false;
206 try
207 {
208 assertNotThrown!AssertError(
209 throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)));
210 }
211 catch (AssertError) thrown = true;
212 assert(thrown);
213 }
214
215 {
216 bool thrown = false;
217 try
218 {
219 assertNotThrown!AssertError(
220 throwEx(new AssertError("It's an AssertError", __FILE__, __LINE__)),
221 "It's a message");
222 }
223 catch (AssertError) thrown = true;
224 assert(thrown);
225 }
226 }
227
228 /++
229 Asserts that the given expression throws the given type of $(D Throwable).
230 The $(D Throwable) is caught and does not escape assertThrown. However,
231 any other $(D Throwable)s $(I will) escape, and if no $(D Throwable)
232 of the given type is thrown, then an $(D AssertError) is thrown.
233
234 Params:
235 T = The $(D Throwable) to test for.
236 expression = The expression to test.
237 msg = Optional message to output on test failure.
238 file = The file where the error occurred.
239 Defaults to $(D __FILE__).
240 line = The line where the error occurred.
241 Defaults to $(D __LINE__).
242
243 Throws:
244 $(D AssertError) if the given $(D Throwable) is not thrown.
245 +/
246 void assertThrown(T : Throwable = Exception, E)
247 (lazy E expression,
248 string msg = null,
249 string file = __FILE__,
250 size_t line = __LINE__)
251 {
252 import core.exception : AssertError;
253
254 try
255 expression();
256 catch (T)
257 return;
258 throw new AssertError("assertThrown failed: No " ~ T.stringof ~ " was thrown"
259 ~ (msg.length == 0 ? "." : ": ") ~ msg,
260 file, line);
261 }
262 ///
263 @system unittest
264 {
265 import core.exception : AssertError;
266 import std.string;
267
268 assertThrown!StringException(enforce!StringException(false, "Error!"));
269
270 //Exception is the default.
271 assertThrown(enforce!StringException(false, "Error!"));
272
273 assert(collectExceptionMsg!AssertError(assertThrown!StringException(
274 enforce!StringException(true, "Error!"))) ==
275 `assertThrown failed: No StringException was thrown.`);
276 }
277
278 @system unittest
279 {
280 import core.exception : AssertError;
281
throwEx(Throwable t)282 void throwEx(Throwable t) { throw t; }
nothrowEx()283 void nothrowEx() { }
284
285 try
286 {
287 assertThrown!Exception(throwEx(new Exception("It's an Exception")));
288 }
289 catch (AssertError) assert(0);
290
291 try
292 {
293 assertThrown!Exception(throwEx(new Exception("It's an Exception")),
294 "It's a message");
295 }
296 catch (AssertError) assert(0);
297
298 try
299 {
300 assertThrown!AssertError(throwEx(new AssertError("It's an AssertError",
301 __FILE__, __LINE__)));
302 }
303 catch (AssertError) assert(0);
304
305 try
306 {
307 assertThrown!AssertError(throwEx(new AssertError("It's an AssertError",
308 __FILE__, __LINE__)),
309 "It's a message");
310 }
311 catch (AssertError) assert(0);
312
313
314 {
315 bool thrown = false;
316 try
317 assertThrown!Exception(nothrowEx());
318 catch (AssertError)
319 thrown = true;
320
321 assert(thrown);
322 }
323
324 {
325 bool thrown = false;
326 try
327 assertThrown!Exception(nothrowEx(), "It's a message");
328 catch (AssertError)
329 thrown = true;
330
331 assert(thrown);
332 }
333
334 {
335 bool thrown = false;
336 try
337 assertThrown!AssertError(nothrowEx());
338 catch (AssertError)
339 thrown = true;
340
341 assert(thrown);
342 }
343
344 {
345 bool thrown = false;
346 try
347 assertThrown!AssertError(nothrowEx(), "It's a message");
348 catch (AssertError)
349 thrown = true;
350
351 assert(thrown);
352 }
353 }
354
355
356 /++
357 Enforces that the given value is true.
358
359 Params:
360 value = The value to test.
361 E = Exception type to throw if the value evalues to false.
362 msg = The error message to put in the exception if it is thrown.
363 file = The source file of the caller.
364 line = The line number of the caller.
365
366 Returns: $(D value), if `cast(bool) value` is true. Otherwise,
367 $(D new Exception(msg)) is thrown.
368
369 Note:
370 $(D enforce) is used to throw exceptions and is therefore intended to
371 aid in error handling. It is $(I not) intended for verifying the logic
372 of your program. That is what $(D assert) is for. Also, do not use
373 $(D enforce) inside of contracts (i.e. inside of $(D in) and $(D out)
374 blocks and $(D invariant)s), because they will be compiled out when
375 compiling with $(I -release). Use $(D assert) in contracts.
376
377 Example:
378 --------------------
379 auto f = enforce(fopen("data.txt"));
380 auto line = readln(f);
381 enforce(line.length, "Expected a non-empty line.");
382 --------------------
383 +/
384 T enforce(E : Throwable = Exception, T)(T value, lazy const(char)[] msg = null,
385 string file = __FILE__, size_t line = __LINE__)
386 if (is(typeof({ if (!value) {} })))
387 {
388 if (!value) bailOut!E(file, line, msg);
389 return value;
390 }
391
392 /++
393 Enforces that the given value is true.
394
395 Params:
396 value = The value to test.
397 dg = The delegate to be called if the value evaluates to false.
398 file = The source file of the caller.
399 line = The line number of the caller.
400
401 Returns: $(D value), if `cast(bool) value` is true. Otherwise, the given
402 delegate is called.
403
404 The safety and purity of this function are inferred from $(D Dg)'s safety
405 and purity.
406 +/
407 T enforce(T, Dg, string file = __FILE__, size_t line = __LINE__)
408 (T value, scope Dg dg)
409 if (isSomeFunction!Dg && is(typeof( dg() )) &&
410 is(typeof({ if (!value) {} })))
411 {
412 if (!value) dg();
413 return value;
414 }
415
416 private void bailOut(E : Throwable = Exception)(string file, size_t line, in char[] msg)
417 {
418 static if (is(typeof(new E(string.init, string.init, size_t.init))))
419 {
420 throw new E(msg ? msg.idup : "Enforcement failed", file, line);
421 }
422 else static if (is(typeof(new E(string.init, size_t.init))))
423 {
424 throw new E(file, line);
425 }
426 else
427 {
428 static assert(0, "Expected this(string, string, size_t) or this(string, size_t)" ~
429 " constructor for " ~ __traits(identifier, E));
430 }
431 }
432
433 @safe unittest
434 {
435 assert(enforce(123) == 123);
436
437 try
438 {
439 enforce(false, "error");
440 assert(false);
441 }
catch(Exception e)442 catch (Exception e)
443 {
444 assert(e.msg == "error");
445 assert(e.file == __FILE__);
446 assert(e.line == __LINE__-7);
447 }
448 }
449
450 @safe unittest
451 {
452 // Issue 10510
453 extern(C) void cFoo() { }
454 enforce(false, &cFoo);
455 }
456
457 // purity and safety inference test
458 @system unittest
459 {
460 import std.meta : AliasSeq;
461
462 foreach (EncloseSafe; AliasSeq!(false, true))
463 foreach (EnclosePure; AliasSeq!(false, true))
464 {
465 foreach (BodySafe; AliasSeq!(false, true))
466 foreach (BodyPure; AliasSeq!(false, true))
467 {
468 enum code =
469 "delegate void() " ~
470 (EncloseSafe ? "@safe " : "") ~
471 (EnclosePure ? "pure " : "") ~
472 "{ enforce(true, { " ~
473 "int n; " ~
474 (BodySafe ? "" : "auto p = &n + 10; " ) ~ // unsafe code
475 (BodyPure ? "" : "static int g; g = 10; ") ~ // impure code
476 "}); " ~
477 "}";
478 enum expect =
479 (BodySafe || !EncloseSafe) && (!EnclosePure || BodyPure);
480
481 version (none)
482 pragma(msg, "safe = ", EncloseSafe?1:0, "/", BodySafe?1:0, ", ",
483 "pure = ", EnclosePure?1:0, "/", BodyPure?1:0, ", ",
484 "expect = ", expect?"OK":"NG", ", ",
485 "code = ", code);
486
487 static assert(__traits(compiles, mixin(code)()) == expect);
488 }
489 }
490 }
491
492 // Test for bugzilla 8637
493 @system unittest
494 {
495 struct S
496 {
497 static int g;
498 ~this() {} // impure & unsafe destructor
499 bool opCast(T:bool)() {
500 int* p = cast(int*) 0; // unsafe operation
501 int n = g; // impure operation
502 return true;
503 }
504 }
505 S s;
506
507 enforce(s);
508 enforce(s, {});
509 enforce(s, new Exception(""));
510
511 errnoEnforce(s);
512
513 alias E1 = Exception;
514 static class E2 : Exception
515 {
516 this(string fn, size_t ln) { super("", fn, ln); }
517 }
518 static class E3 : Exception
519 {
520 this(string msg) { super(msg, __FILE__, __LINE__); }
521 }
522 enforce!E1(s);
523 enforce!E2(s);
524 }
525
526 @safe unittest
527 {
528 // Issue 14685
529
530 class E : Exception
531 {
532 this() { super("Not found"); }
533 }
534 static assert(!__traits(compiles, { enforce!E(false); }));
535 }
536
537 /++
538 Enforces that the given value is true.
539
540 Params:
541 value = The value to test.
542 ex = The exception to throw if the value evaluates to false.
543
544 Returns: $(D value), if `cast(bool) value` is true. Otherwise, $(D ex) is
545 thrown.
546
547 Example:
548 --------------------
549 auto f = enforce(fopen("data.txt"));
550 auto line = readln(f);
551 enforce(line.length, new IOException); // expect a non-empty line
552 --------------------
553 +/
554 T enforce(T)(T value, lazy Throwable ex)
555 {
556 if (!value) throw ex();
557 return value;
558 }
559
560 @safe unittest
561 {
562 assertNotThrown(enforce(true, new Exception("this should not be thrown")));
563 assertThrown(enforce(false, new Exception("this should be thrown")));
564 }
565
566 /++
567 Enforces that the given value is true, throwing an `ErrnoException` if it
568 is not.
569
570 Params:
571 value = The value to test.
572 msg = The message to include in the `ErrnoException` if it is thrown.
573
574 Returns: $(D value), if `cast(bool) value` is true. Otherwise,
575 $(D new ErrnoException(msg)) is thrown. It is assumed that the last
576 operation set $(D errno) to an error code corresponding with the failed
577 condition.
578
579 Example:
580 --------------------
581 auto f = errnoEnforce(fopen("data.txt"));
582 auto line = readln(f);
583 enforce(line.length); // expect a non-empty line
584 --------------------
585 +/
586 T errnoEnforce(T, string file = __FILE__, size_t line = __LINE__)
587 (T value, lazy string msg = null)
588 {
589 if (!value) throw new ErrnoException(msg, file, line);
590 return value;
591 }
592
593
594 /++
595 If $(D !value) is $(D false), $(D value) is returned. Otherwise,
596 $(D new E(msg, file, line)) is thrown. Or if $(D E) doesn't take a message
597 and can be constructed with $(D new E(file, line)), then
598 $(D new E(file, line)) will be thrown.
599
600 This is legacy name, it is recommended to use $(D enforce!E) instead.
601
602 Example:
603 --------------------
604 auto f = enforceEx!FileMissingException(fopen("data.txt"));
605 auto line = readln(f);
606 enforceEx!DataCorruptionException(line.length);
607 --------------------
608 +/
609 template enforceEx(E : Throwable)
610 if (is(typeof(new E("", __FILE__, __LINE__))))
611 {
612 /++ Ditto +/
enforceEx(T)613 T enforceEx(T)(T value, lazy string msg = "", string file = __FILE__, size_t line = __LINE__)
614 {
615 if (!value) throw new E(msg, file, line);
616 return value;
617 }
618 }
619
620 /++ Ditto +/
621 template enforceEx(E : Throwable)
622 if (is(typeof(new E(__FILE__, __LINE__))) && !is(typeof(new E("", __FILE__, __LINE__))))
623 {
624 /++ Ditto +/
enforceEx(T)625 T enforceEx(T)(T value, string file = __FILE__, size_t line = __LINE__)
626 {
627 if (!value) throw new E(file, line);
628 return value;
629 }
630 }
631
632 @system unittest
633 {
634 import core.exception : OutOfMemoryError;
635 import std.array : empty;
636 assertNotThrown(enforceEx!Exception(true));
637 assertNotThrown(enforceEx!Exception(true, "blah"));
638 assertNotThrown(enforceEx!OutOfMemoryError(true));
639
640 {
641 auto e = collectException(enforceEx!Exception(false));
642 assert(e !is null);
643 assert(e.msg.empty);
644 assert(e.file == __FILE__);
645 assert(e.line == __LINE__ - 4);
646 }
647
648 {
649 auto e = collectException(enforceEx!Exception(false, "hello", "file", 42));
650 assert(e !is null);
651 assert(e.msg == "hello");
652 assert(e.file == "file");
653 assert(e.line == 42);
654 }
655
656 {
657 auto e = collectException!Error(enforceEx!OutOfMemoryError(false));
658 assert(e !is null);
659 assert(e.msg == "Memory allocation failed");
660 assert(e.file == __FILE__);
661 assert(e.line == __LINE__ - 4);
662 }
663
664 {
665 auto e = collectException!Error(enforceEx!OutOfMemoryError(false, "file", 42));
666 assert(e !is null);
667 assert(e.msg == "Memory allocation failed");
668 assert(e.file == "file");
669 assert(e.line == 42);
670 }
671
672 static assert(!is(typeof(enforceEx!int(true))));
673 }
674
675 @safe unittest
676 {
677 alias enf = enforceEx!Exception;
678 assertNotThrown(enf(true));
679 assertThrown(enf(false, "blah"));
680 }
681
682
683 /++
684 Catches and returns the exception thrown from the given expression.
685 If no exception is thrown, then null is returned and $(D result) is
686 set to the result of the expression.
687
688 Note that while $(D collectException) $(I can) be used to collect any
689 $(D Throwable) and not just $(D Exception)s, it is generally ill-advised to
690 catch anything that is neither an $(D Exception) nor a type derived from
691 $(D Exception). So, do not use $(D collectException) to collect
692 non-$(D Exception)s unless you're sure that that's what you really want to
693 do.
694
695 Params:
696 T = The type of exception to catch.
697 expression = The expression which may throw an exception.
698 result = The result of the expression if no exception is thrown.
699 +/
700 T collectException(T = Exception, E)(lazy E expression, ref E result)
701 {
702 try
703 {
704 result = expression();
705 }
catch(T e)706 catch (T e)
707 {
708 return e;
709 }
710 return null;
711 }
712 ///
713 @system unittest
714 {
715 int b;
foo()716 int foo() { throw new Exception("blah"); }
717 assert(collectException(foo(), b));
718
719 int[] a = new int[3];
720 import core.exception : RangeError;
721 assert(collectException!RangeError(a[4], b));
722 }
723
724 /++
725 Catches and returns the exception thrown from the given expression.
726 If no exception is thrown, then null is returned. $(D E) can be
727 $(D void).
728
729 Note that while $(D collectException) $(I can) be used to collect any
730 $(D Throwable) and not just $(D Exception)s, it is generally ill-advised to
731 catch anything that is neither an $(D Exception) nor a type derived from
732 $(D Exception). So, do not use $(D collectException) to collect
733 non-$(D Exception)s unless you're sure that that's what you really want to
734 do.
735
736 Params:
737 T = The type of exception to catch.
738 expression = The expression which may throw an exception.
739 +/
740 T collectException(T : Throwable = Exception, E)(lazy E expression)
741 {
742 try
743 {
744 expression();
745 }
catch(T t)746 catch (T t)
747 {
748 return t;
749 }
750 return null;
751 }
752
753 @safe unittest
754 {
foo()755 int foo() { throw new Exception("blah"); }
756 assert(collectException(foo()));
757 }
758
759 /++
760 Catches the exception thrown from the given expression and returns the
761 msg property of that exception. If no exception is thrown, then null is
762 returned. $(D E) can be $(D void).
763
764 If an exception is thrown but it has an empty message, then
765 $(D emptyExceptionMsg) is returned.
766
767 Note that while $(D collectExceptionMsg) $(I can) be used to collect any
768 $(D Throwable) and not just $(D Exception)s, it is generally ill-advised to
769 catch anything that is neither an $(D Exception) nor a type derived from
770 $(D Exception). So, do not use $(D collectExceptionMsg) to collect
771 non-$(D Exception)s unless you're sure that that's what you really want to
772 do.
773
774 Params:
775 T = The type of exception to catch.
776 expression = The expression which may throw an exception.
777 +/
778 string collectExceptionMsg(T = Exception, E)(lazy E expression)
779 {
780 import std.array : empty;
781 try
782 {
783 expression();
784
785 return cast(string) null;
786 }
787 catch (T e)
788 return e.msg.empty ? emptyExceptionMsg : e.msg;
789 }
790 ///
791 @safe unittest
792 {
throwFunc()793 void throwFunc() { throw new Exception("My Message."); }
794 assert(collectExceptionMsg(throwFunc()) == "My Message.");
795
nothrowFunc()796 void nothrowFunc() {}
797 assert(collectExceptionMsg(nothrowFunc()) is null);
798
throwEmptyFunc()799 void throwEmptyFunc() { throw new Exception(""); }
800 assert(collectExceptionMsg(throwEmptyFunc()) == emptyExceptionMsg);
801 }
802
803 /++
804 Value that collectExceptionMsg returns when it catches an exception
805 with an empty exception message.
806 +/
807 enum emptyExceptionMsg = "<Empty Exception Message>";
808
809 /**
810 * Casts a mutable array to an immutable array in an idiomatic
811 * manner. Technically, $(D assumeUnique) just inserts a cast,
812 * but its name documents assumptions on the part of the
813 * caller. $(D assumeUnique(arr)) should only be called when
814 * there are no more active mutable aliases to elements of $(D
815 * arr). To strengthen this assumption, $(D assumeUnique(arr))
816 * also clears $(D arr) before returning. Essentially $(D
817 * assumeUnique(arr)) indicates commitment from the caller that there
818 * is no more mutable access to any of $(D arr)'s elements
819 * (transitively), and that all future accesses will be done through
820 * the immutable array returned by $(D assumeUnique).
821 *
822 * Typically, $(D assumeUnique) is used to return arrays from
823 * functions that have allocated and built them.
824 *
825 * Params:
826 * array = The array to cast to immutable.
827 *
828 * Returns: The immutable array.
829 *
830 * Example:
831 *
832 * ----
833 * string letters()
834 * {
835 * char[] result = new char['z' - 'a' + 1];
836 * foreach (i, ref e; result)
837 * {
838 * e = cast(char)('a' + i);
839 * }
840 * return assumeUnique(result);
841 * }
842 * ----
843 *
844 * The use in the example above is correct because $(D result)
845 * was private to $(D letters) and is inaccessible in writing
846 * after the function returns. The following example shows an
847 * incorrect use of $(D assumeUnique).
848 *
849 * Bad:
850 *
851 * ----
852 * private char[] buffer;
853 * string letters(char first, char last)
854 * {
855 * if (first >= last) return null; // fine
856 * auto sneaky = buffer;
857 * sneaky.length = last - first + 1;
858 * foreach (i, ref e; sneaky)
859 * {
860 * e = cast(char)('a' + i);
861 * }
862 * return assumeUnique(sneaky); // BAD
863 * }
864 * ----
865 *
866 * The example above wreaks havoc on client code because it is
867 * modifying arrays that callers considered immutable. To obtain an
868 * immutable array from the writable array $(D buffer), replace
869 * the last line with:
870 * ----
871 * return to!(string)(sneaky); // not that sneaky anymore
872 * ----
873 *
874 * The call will duplicate the array appropriately.
875 *
876 * Note that checking for uniqueness during compilation is
877 * possible in certain cases, especially when a function is
878 * marked as a pure function. The following example does not
879 * need to call assumeUnique because the compiler can infer the
880 * uniqueness of the array in the pure function:
881 * ----
882 * string letters() pure
883 * {
884 * char[] result = new char['z' - 'a' + 1];
885 * foreach (i, ref e; result)
886 * {
887 * e = cast(char)('a' + i);
888 * }
889 * return result;
890 * }
891 * ----
892 *
893 * For more on infering uniqueness see the $(B unique) and
894 * $(B lent) keywords in the
895 * $(HTTP archjava.fluid.cs.cmu.edu/papers/oopsla02.pdf, ArchJava)
896 * language.
897 *
898 * The downside of using $(D 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 $(D assumeUnique) is
902 * simple and rare enough to be tolerable.
903 *
904 */
immutable(T)905 immutable(T)[] assumeUnique(T)(T[] array) pure nothrow
906 {
907 return .assumeUnique(array); // call ref version
908 }
909 /// ditto
immutable(T)910 immutable(T)[] assumeUnique(T)(ref T[] array) pure nothrow
911 {
912 auto result = cast(immutable(T)[]) array;
913 array = null;
914 return result;
915 }
916 /// ditto
assumeUnique(T,U)917 immutable(T[U]) assumeUnique(T, U)(ref T[U] array) pure nothrow
918 {
919 auto result = cast(immutable(T[U])) array;
920 array = null;
921 return result;
922 }
923
924 @system unittest
925 {
926 // @system due to assumeUnique
927 int[] arr = new int[1];
928 auto arr1 = assumeUnique(arr);
929 assert(is(typeof(arr1) == immutable(int)[]) && arr == null);
930 }
931
932 // @@@BUG@@@
version(none)933 version (none) @system unittest
934 {
935 int[string] arr = ["a":1];
936 auto arr1 = assumeUnique(arr);
937 assert(is(typeof(arr1) == immutable(int[string])) && arr == null);
938 }
939
940 /**
941 * Wraps a possibly-throwing expression in a $(D nothrow) wrapper so that it
942 * can be called by a $(D nothrow) function.
943 *
944 * This wrapper function documents commitment on the part of the caller that
945 * the appropriate steps have been taken to avoid whatever conditions may
946 * trigger an exception during the evaluation of $(D expr). If it turns out
947 * that the expression $(I does) throw at runtime, the wrapper will throw an
948 * $(D AssertError).
949 *
950 * (Note that $(D Throwable) objects such as $(D AssertError) that do not
951 * subclass $(D Exception) may be thrown even from $(D nothrow) functions,
952 * since they are considered to be serious runtime problems that cannot be
953 * recovered from.)
954 *
955 * Params:
956 * expr = The expression asserted not to throw.
957 * msg = The message to include in the `AssertError` if the assumption turns
958 * out to be false.
959 * file = The source file name of the caller.
960 * line = The line number of the caller.
961 *
962 * Returns:
963 * The value of `expr`, if any.
964 */
assumeWontThrow(T)965 T assumeWontThrow(T)(lazy T expr,
966 string msg = null,
967 string file = __FILE__,
968 size_t line = __LINE__) nothrow
969 {
970 import core.exception : AssertError;
971 try
972 {
973 return expr;
974 }
975 catch (Exception e)
976 {
977 import std.range.primitives : empty;
978 immutable tail = msg.empty ? "." : ": " ~ msg;
979 throw new AssertError("assumeWontThrow failed: Expression did throw" ~
980 tail, file, line);
981 }
982 }
983
984 ///
985 @safe unittest
986 {
987 import std.math : sqrt;
988
989 // This function may throw.
squareRoot(int x)990 int squareRoot(int x)
991 {
992 if (x < 0)
993 throw new Exception("Tried to take root of negative number");
994 return cast(int) sqrt(cast(double) x);
995 }
996
997 // This function never throws.
computeLength(int x,int y)998 int computeLength(int x, int y) nothrow
999 {
1000 // Since x*x + y*y is always positive, we can safely assume squareRoot
1001 // won't throw, and use it to implement this nothrow function. If it
1002 // does throw (e.g., if x*x + y*y overflows a 32-bit value), then the
1003 // program will terminate.
1004 return assumeWontThrow(squareRoot(x*x + y*y));
1005 }
1006
1007 assert(computeLength(3, 4) == 5);
1008 }
1009
1010 @system unittest
1011 {
1012 import core.exception : AssertError;
1013
alwaysThrows()1014 void alwaysThrows()
1015 {
1016 throw new Exception("I threw up");
1017 }
bad()1018 void bad() nothrow
1019 {
1020 assumeWontThrow(alwaysThrows());
1021 }
1022 assertThrown!AssertError(bad());
1023 }
1024
1025 /**
1026 Checks whether a given source object contains pointers or references to a given
1027 target object.
1028
1029 Params:
1030 source = The source object
1031 target = The target object
1032
1033 Returns: $(D true) if $(D source)'s representation embeds a pointer
1034 that points to $(D target)'s representation or somewhere inside
1035 it.
1036
1037 If $(D source) is or contains a dynamic array, then, then these functions will check
1038 if there is overlap between the dynamic array and $(D target)'s representation.
1039
1040 If $(D source) is a class, then it will be handled as a pointer.
1041
1042 If $(D target) is a pointer, a dynamic array or a class, then these functions will only
1043 check if $(D source) points to $(D target), $(I not) what $(D target) references.
1044
1045 If $(D source) is or contains a union, then there may be either false positives or
1046 false negatives:
1047
1048 $(D doesPointTo) will return $(D true) if it is absolutely certain
1049 $(D source) points to $(D target). It may produce false negatives, but never
1050 false positives. This function should be prefered when trying to validate
1051 input data.
1052
1053 $(D mayPointTo) will return $(D false) if it is absolutely certain
1054 $(D source) does not point to $(D target). It may produce false positives, but never
1055 false negatives. This function should be prefered for defensively choosing a
1056 code path.
1057
1058 Note: Evaluating $(D doesPointTo(x, x)) checks whether $(D x) has
1059 internal pointers. This should only be done as an assertive test,
1060 as the language is free to assume objects don't have internal pointers
1061 (TDPL 7.1.3.5).
1062 */
1063 bool doesPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @trusted pure nothrow
1064 if (__traits(isRef, source) || isDynamicArray!S ||
1065 isPointer!S || is(S == class))
1066 {
1067 static if (isPointer!S || is(S == class) || is(S == interface))
1068 {
1069 const m = *cast(void**) &source;
1070 const b = cast(void*) ⌖
1071 const e = b + target.sizeof;
1072 return b <= m && m < e;
1073 }
1074 else static if (is(S == struct) || is(S == union))
1075 {
1076 foreach (i, Subobj; typeof(source.tupleof))
1077 static if (!isUnionAliased!(S, i))
1078 if (doesPointTo(source.tupleof[i], target)) return true;
1079 return false;
1080 }
1081 else static if (isStaticArray!S)
1082 {
1083 foreach (size_t i; 0 .. S.length)
1084 if (doesPointTo(source[i], target)) return true;
1085 return false;
1086 }
1087 else static if (isDynamicArray!S)
1088 {
1089 import std.array : overlap;
1090 return overlap(cast(void[]) source, cast(void[])(&target)[0 .. 1]).length != 0;
1091 }
1092 else
1093 {
1094 return false;
1095 }
1096 }
1097
1098 // for shared objects
1099 /// ditto
doesPointTo(S,T)1100 bool doesPointTo(S, T)(auto ref const shared S source, ref const shared T target) @trusted pure nothrow
1101 {
1102 return doesPointTo!(shared S, shared T, void)(source, target);
1103 }
1104
1105 /// ditto
1106 bool mayPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @trusted pure nothrow
1107 if (__traits(isRef, source) || isDynamicArray!S ||
1108 isPointer!S || is(S == class))
1109 {
1110 static if (isPointer!S || is(S == class) || is(S == interface))
1111 {
1112 const m = *cast(void**) &source;
1113 const b = cast(void*) ⌖
1114 const e = b + target.sizeof;
1115 return b <= m && m < e;
1116 }
1117 else static if (is(S == struct) || is(S == union))
1118 {
1119 foreach (i, Subobj; typeof(source.tupleof))
1120 if (mayPointTo(source.tupleof[i], target)) return true;
1121 return false;
1122 }
1123 else static if (isStaticArray!S)
1124 {
1125 foreach (size_t i; 0 .. S.length)
1126 if (mayPointTo(source[i], target)) return true;
1127 return false;
1128 }
1129 else static if (isDynamicArray!S)
1130 {
1131 import std.array : overlap;
1132 return overlap(cast(void[]) source, cast(void[])(&target)[0 .. 1]).length != 0;
1133 }
1134 else
1135 {
1136 return false;
1137 }
1138 }
1139
1140 // for shared objects
1141 /// ditto
mayPointTo(S,T)1142 bool mayPointTo(S, T)(auto ref const shared S source, ref const shared T target) @trusted pure nothrow
1143 {
1144 return mayPointTo!(shared S, shared T, void)(source, target);
1145 }
1146
1147 /// Pointers
1148 @system unittest
1149 {
1150 int i = 0;
1151 int* p = null;
1152 assert(!p.doesPointTo(i));
1153 p = &i;
1154 assert( p.doesPointTo(i));
1155 }
1156
1157 /// Structs and Unions
1158 @system unittest
1159 {
1160 struct S
1161 {
1162 int v;
1163 int* p;
1164 }
1165 int i;
1166 auto s = S(0, &i);
1167
1168 // structs and unions "own" their members
1169 // pointsTo will answer true if one of the members pointsTo.
1170 assert(!s.doesPointTo(s.v)); //s.v is just v member of s, so not pointed.
1171 assert( s.p.doesPointTo(i)); //i is pointed by s.p.
1172 assert( s .doesPointTo(i)); //which means i is pointed by s itself.
1173
1174 // Unions will behave exactly the same. Points to will check each "member"
1175 // individually, even if they share the same memory
1176 }
1177
1178 /// Arrays (dynamic and static)
1179 @system unittest
1180 {
1181 int i;
1182 int[] slice = [0, 1, 2, 3, 4];
1183 int[5] arr = [0, 1, 2, 3, 4];
1184 int*[] slicep = [&i];
1185 int*[1] arrp = [&i];
1186
1187 // A slice points to all of its members:
1188 assert( slice.doesPointTo(slice[3]));
1189 assert(!slice[0 .. 2].doesPointTo(slice[3])); // Object 3 is outside of the
1190 // slice [0 .. 2]
1191
1192 // Note that a slice will not take into account what its members point to.
1193 assert( slicep[0].doesPointTo(i));
1194 assert(!slicep .doesPointTo(i));
1195
1196 // static arrays are objects that own their members, just like structs:
1197 assert(!arr.doesPointTo(arr[0])); // arr[0] is just a member of arr, so not
1198 // pointed.
1199 assert( arrp[0].doesPointTo(i)); // i is pointed by arrp[0].
1200 assert( arrp .doesPointTo(i)); // which means i is pointed by arrp
1201 // itself.
1202
1203 // Notice the difference between static and dynamic arrays:
1204 assert(!arr .doesPointTo(arr[0]));
1205 assert( arr[].doesPointTo(arr[0]));
1206 assert( arrp .doesPointTo(i));
1207 assert(!arrp[].doesPointTo(i));
1208 }
1209
1210 /// Classes
1211 @system unittest
1212 {
1213 class C
1214 {
this(int * p)1215 this(int* p){this.p = p;}
1216 int* p;
1217 }
1218 int i;
1219 C a = new C(&i);
1220 C b = a;
1221
1222 // Classes are a bit particular, as they are treated like simple pointers
1223 // to a class payload.
1224 assert( a.p.doesPointTo(i)); // a.p points to i.
1225 assert(!a .doesPointTo(i)); // Yet a itself does not point i.
1226
1227 //To check the class payload itself, iterate on its members:
1228 ()
1229 {
1230 import std.traits : Fields;
1231
1232 foreach (index, _; Fields!C)
1233 if (doesPointTo(a.tupleof[index], i))
1234 return;
1235 assert(0);
1236 }();
1237
1238 // To check if a class points a specific payload, a direct memmory check
1239 // can be done:
1240 auto aLoc = cast(ubyte[__traits(classInstanceSize, C)]*) a;
1241 assert(b.doesPointTo(*aLoc)); // b points to where a is pointing
1242 }
1243
1244 @system unittest
1245 {
1246 struct S1 { int a; S1 * b; }
1247 S1 a1;
1248 S1 * p = &a1;
1249 assert(doesPointTo(p, a1));
1250
1251 S1 a2;
1252 a2.b = &a1;
1253 assert(doesPointTo(a2, a1));
1254
1255 struct S3 { int[10] a; }
1256 S3 a3;
1257 auto a4 = a3.a[2 .. 3];
1258 assert(doesPointTo(a4, a3));
1259
1260 auto a5 = new double[4];
1261 auto a6 = a5[1 .. 2];
1262 assert(!doesPointTo(a5, a6));
1263
1264 auto a7 = new double[3];
1265 auto a8 = new double[][1];
1266 a8[0] = a7;
1267 assert(!doesPointTo(a8[0], a8[0]));
1268
1269 // don't invoke postblit on subobjects
1270 {
thisNoCopy1271 static struct NoCopy { this(this) { assert(0); } }
1272 static struct Holder { NoCopy a, b, c; }
1273 Holder h;
1274 cast(void) doesPointTo(h, h);
1275 }
1276
1277 shared S3 sh3;
1278 shared sh3sub = sh3.a[];
1279 assert(doesPointTo(sh3sub, sh3));
1280
1281 int[] darr = [1, 2, 3, 4];
1282
1283 //dynamic arrays don't point to each other, or slices of themselves
1284 assert(!doesPointTo(darr, darr));
1285 assert(!doesPointTo(darr[0 .. 1], darr));
1286
1287 //But they do point their elements
1288 foreach (i; 0 .. 4)
1289 assert(doesPointTo(darr, darr[i]));
1290 assert(doesPointTo(darr[0 .. 3], darr[2]));
1291 assert(!doesPointTo(darr[0 .. 3], darr[3]));
1292 }
1293
1294 @system unittest
1295 {
1296 //tests with static arrays
1297 //Static arrays themselves are just objects, and don't really *point* to anything.
1298 //They aggregate their contents, much the same way a structure aggregates its attributes.
1299 //*However* The elements inside the static array may themselves point to stuff.
1300
1301 //Standard array
1302 int[2] k;
1303 assert(!doesPointTo(k, k)); //an array doesn't point to itself
1304 //Technically, k doesn't point its elements, although it does alias them
1305 assert(!doesPointTo(k, k[0]));
1306 assert(!doesPointTo(k, k[1]));
1307 //But an extracted slice will point to the same array.
1308 assert(doesPointTo(k[], k));
1309 assert(doesPointTo(k[], k[1]));
1310
1311 //An array of pointers
1312 int*[2] pp;
1313 int a;
1314 int b;
1315 pp[0] = &a;
1316 assert( doesPointTo(pp, a)); //The array contains a pointer to a
1317 assert(!doesPointTo(pp, b)); //The array does NOT contain a pointer to b
1318 assert(!doesPointTo(pp, pp)); //The array does not point itslef
1319
1320 //A struct containing a static array of pointers
1321 static struct S
1322 {
1323 int*[2] p;
1324 }
1325 S s;
1326 s.p[0] = &a;
1327 assert( doesPointTo(s, a)); //The struct contains an array that points a
1328 assert(!doesPointTo(s, b)); //But doesn't point b
1329 assert(!doesPointTo(s, s)); //The struct doesn't actually point itslef.
1330
1331 //An array containing structs that have pointers
1332 static struct SS
1333 {
1334 int* p;
1335 }
1336 SS[2] ss = [SS(&a), SS(null)];
1337 assert( doesPointTo(ss, a)); //The array contains a struct that points to a
1338 assert(!doesPointTo(ss, b)); //The array doesn't contains a struct that points to b
1339 assert(!doesPointTo(ss, ss)); //The array doesn't point itself.
1340 }
1341
1342
1343 @system unittest //Unions
1344 {
1345 int i;
1346 union U //Named union
1347 {
1348 size_t asInt = 0;
1349 int* asPointer;
1350 }
1351 struct S
1352 {
1353 union //Anonymous union
1354 {
1355 size_t asInt = 0;
1356 int* asPointer;
1357 }
1358 }
1359
1360 U u;
1361 S s;
1362 assert(!doesPointTo(u, i));
1363 assert(!doesPointTo(s, i));
1364 assert(!mayPointTo(u, i));
1365 assert(!mayPointTo(s, i));
1366
1367 u.asPointer = &i;
1368 s.asPointer = &i;
1369 assert(!doesPointTo(u, i));
1370 assert(!doesPointTo(s, i));
1371 assert( mayPointTo(u, i));
1372 assert( mayPointTo(s, i));
1373
1374 u.asInt = cast(size_t)&i;
1375 s.asInt = cast(size_t)&i;
1376 assert(!doesPointTo(u, i));
1377 assert(!doesPointTo(s, i));
1378 assert( mayPointTo(u, i));
1379 assert( mayPointTo(s, i));
1380 }
1381
1382 @system unittest //Classes
1383 {
1384 int i;
1385 static class A
1386 {
1387 int* p;
1388 }
1389 A a = new A, b = a;
1390 assert(!doesPointTo(a, b)); //a does not point to b
1391 a.p = &i;
1392 assert(!doesPointTo(a, i)); //a does not point to i
1393 }
1394 @safe unittest //alias this test
1395 {
1396 static int i;
1397 static int j;
1398 struct S
1399 {
1400 int* p;
1401 @property int* foo(){return &i;}
1402 alias foo this;
1403 }
1404 assert(is(S : int*));
1405 S s = S(&j);
1406 assert(!doesPointTo(s, i));
1407 assert( doesPointTo(s, j));
1408 assert( doesPointTo(cast(int*) s, i));
1409 assert(!doesPointTo(cast(int*) s, j));
1410 }
1411 @safe unittest //more alias this opCast
1412 {
1413 void* p;
1414 class A
1415 {
1416 void* opCast(T)() if (is(T == void*))
1417 {
1418 return p;
1419 }
1420 alias foo = opCast!(void*);
1421 alias foo this;
1422 }
1423 assert(!doesPointTo(A.init, p));
1424 assert(!mayPointTo(A.init, p));
1425 }
1426
1427 /+
1428 Returns true if the field at index $(D i) in ($D T) shares its address with another field.
1429
1430 Note: This does not merelly check if the field is a member of an union, but also that
1431 it is not a single child.
1432 +/
1433 package enum isUnionAliased(T, size_t i) = isUnionAliasedImpl!T(T.tupleof[i].offsetof);
1434 private bool isUnionAliasedImpl(T)(size_t offset)
1435 {
1436 int count = 0;
1437 foreach (i, U; typeof(T.tupleof))
1438 if (T.tupleof[i].offsetof == offset)
1439 ++count;
1440 return count >= 2;
1441 }
1442 //
1443 @safe unittest
1444 {
1445 static struct S
1446 {
1447 int a0; //Not aliased
1448 union
1449 {
1450 int a1; //Not aliased
1451 }
1452 union
1453 {
1454 int a2; //Aliased
1455 int a3; //Aliased
1456 }
1457 union A4
1458 {
1459 int b0; //Not aliased
1460 }
1461 A4 a4;
1462 union A5
1463 {
1464 int b0; //Aliased
1465 int b1; //Aliased
1466 }
1467 A5 a5;
1468 }
1469
1470 static assert(!isUnionAliased!(S, 0)); //a0;
1471 static assert(!isUnionAliased!(S, 1)); //a1;
1472 static assert( isUnionAliased!(S, 2)); //a2;
1473 static assert( isUnionAliased!(S, 3)); //a3;
1474 static assert(!isUnionAliased!(S, 4)); //a4;
1475 static assert(!isUnionAliased!(S.A4, 0)); //a4.b0;
1476 static assert(!isUnionAliased!(S, 5)); //a5;
1477 static assert( isUnionAliased!(S.A5, 0)); //a5.b0;
1478 static assert( isUnionAliased!(S.A5, 1)); //a5.b1;
1479 }
1480
1481 version (CRuntime_Glibc) version = GNU_STRERROR;
1482 version (CRuntime_UClibc) version = GNU_STRERROR;
1483
1484 package string errnoString(int errno) nothrow @trusted
1485 {
1486 import core.stdc.string : strlen;
1487 version (GNU_STRERROR)
1488 {
1489 import core.stdc.string : strerror_r;
1490 char[1024] buf = void;
1491 auto s = strerror_r(errno, buf.ptr, buf.length);
1492 }
1493 else version (Posix)
1494 {
1495 // XSI-compliant
1496 import core.stdc.string : strerror_r;
1497 char[1024] buf = void;
1498 const(char)* s;
1499 if (strerror_r(errno, buf.ptr, buf.length) == 0)
1500 s = buf.ptr;
1501 else
1502 return "Unknown error";
1503 }
1504 else
1505 {
1506 import core.stdc.string : strerror;
1507 auto s = strerror(errno);
1508 }
1509 return s[0 .. s.strlen].idup;
1510 }
1511
1512 /*********************
1513 * Thrown if errors that set $(D errno) occur.
1514 */
1515 class ErrnoException : Exception
1516 {
1517 final @property uint errno() { return _errno; } /// Operating system error code.
1518 private uint _errno;
1519 /// Constructor which takes an error message. The current global $(REF errno, core,stdc,errno) value is used as error code.
1520 this(string msg, string file = null, size_t line = 0) @trusted
1521 {
1522 import core.stdc.errno : errno;
1523 this(msg, errno, file, line);
1524 }
1525 /// Constructor which takes an error message and error code.
1526 this(string msg, int errno, string file = null, size_t line = 0) @trusted
1527 {
1528 _errno = errno;
1529 super(msg ~ " (" ~ errnoString(errno) ~ ")", file, line);
1530 }
1531
1532 @system unittest
1533 {
1534 import core.stdc.errno : errno, EAGAIN;
1535
1536 auto old = errno;
1537 scope(exit) errno = old;
1538
1539 errno = EAGAIN;
1540 auto ex = new ErrnoException("oh no");
1541 assert(ex.errno == EAGAIN);
1542 }
1543
1544 @system unittest
1545 {
1546 import core.stdc.errno : EAGAIN;
1547 auto ex = new ErrnoException("oh no", EAGAIN);
1548 assert(ex.errno == EAGAIN);
1549 }
1550 }
1551
1552 /++
1553 ML-style functional exception handling. Runs the supplied expression and
1554 returns its result. If the expression throws a $(D Throwable), runs the
1555 supplied error handler instead and return its result. The error handler's
1556 type must be the same as the expression's type.
1557
1558 Params:
1559 E = The type of $(D Throwable)s to catch. Defaults to $(D Exception)
1560 T1 = The type of the expression.
1561 T2 = The return type of the error handler.
1562 expression = The expression to run and return its result.
1563 errorHandler = The handler to run if the expression throwed.
1564
1565 Returns:
1566 expression, if it does not throw. Otherwise, returns the result of
1567 errorHandler.
1568
1569 Example:
1570 --------------------
1571 //Revert to a default value upon an error:
1572 assert("x".to!int().ifThrown(0) == 0);
1573 --------------------
1574
1575 You can also chain multiple calls to ifThrown, each capturing errors from the
1576 entire preceding expression.
1577
1578 Example:
1579 --------------------
1580 //Chaining multiple calls to ifThrown to attempt multiple things in a row:
1581 string s="true";
1582 assert(s.to!int().
1583 ifThrown(cast(int) s.to!double()).
1584 ifThrown(cast(int) s.to!bool())
1585 == 1);
1586
1587 //Respond differently to different types of errors
1588 assert(enforce("x".to!int() < 1).to!string()
1589 .ifThrown!ConvException("not a number")
1590 .ifThrown!Exception("number too small")
1591 == "not a number");
1592 --------------------
1593
1594 The expression and the errorHandler must have a common type they can both
1595 be implicitly casted to, and that type will be the type of the compound
1596 expression.
1597
1598 Example:
1599 --------------------
1600 //null and new Object have a common type(Object).
1601 static assert(is(typeof(null.ifThrown(new Object())) == Object));
1602 static assert(is(typeof((new Object()).ifThrown(null)) == Object));
1603
1604 //1 and new Object do not have a common type.
1605 static assert(!__traits(compiles, 1.ifThrown(new Object())));
1606 static assert(!__traits(compiles, (new Object()).ifThrown(1)));
1607 --------------------
1608
1609 If you need to use the actual thrown exception, you can use a delegate.
1610 Example:
1611 --------------------
1612 //Use a lambda to get the thrown object.
1613 assert("%s".format().ifThrown!Exception(e => e.classinfo.name) == "std.format.FormatException");
1614 --------------------
1615 +/
1616 //lazy version
1617 CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, lazy scope T2 errorHandler)
1618 {
1619 static assert(!is(typeof(return) == void),
1620 "The error handler's return value("
1621 ~ T2.stringof ~
1622 ") does not have a common type with the expression("
1623 ~ T1.stringof ~
1624 ")."
1625 );
1626 try
1627 {
1628 return expression();
1629 }
1630 catch (E)
1631 {
1632 return errorHandler();
1633 }
1634 }
1635
1636 ///ditto
1637 //delegate version
1638 CommonType!(T1, T2) ifThrown(E : Throwable, T1, T2)(lazy scope T1 expression, scope T2 delegate(E) errorHandler)
1639 {
1640 static assert(!is(typeof(return) == void),
1641 "The error handler's return value("
1642 ~ T2.stringof ~
1643 ") does not have a common type with the expression("
1644 ~ T1.stringof ~
1645 ")."
1646 );
1647 try
1648 {
1649 return expression();
1650 }
1651 catch (E e)
1652 {
1653 return errorHandler(e);
1654 }
1655 }
1656
1657 ///ditto
1658 //delegate version, general overload to catch any Exception
1659 CommonType!(T1, T2) ifThrown(T1, T2)(lazy scope T1 expression, scope T2 delegate(Exception) errorHandler)
1660 {
1661 static assert(!is(typeof(return) == void),
1662 "The error handler's return value("
1663 ~ T2.stringof ~
1664 ") does not have a common type with the expression("
1665 ~ T1.stringof ~
1666 ")."
1667 );
1668 try
1669 {
1670 return expression();
1671 }
1672 catch (Exception e)
1673 {
1674 return errorHandler(e);
1675 }
1676 }
1677
1678 //Verify Examples
1679 @system unittest
1680 {
1681 import std.conv;
1682 import std.string;
1683 //Revert to a default value upon an error:
1684 assert("x".to!int().ifThrown(0) == 0);
1685
1686 //Chaining multiple calls to ifThrown to attempt multiple things in a row:
1687 string s="true";
1688 assert(s.to!int().
1689 ifThrown(cast(int) s.to!double()).
1690 ifThrown(cast(int) s.to!bool())
1691 == 1);
1692
1693 //Respond differently to different types of errors
1694 assert(enforce("x".to!int() < 1).to!string()
1695 .ifThrown!ConvException("not a number")
1696 .ifThrown!Exception("number too small")
1697 == "not a number");
1698
1699 //null and new Object have a common type(Object).
1700 static assert(is(typeof(null.ifThrown(new Object())) == Object));
1701 static assert(is(typeof((new Object()).ifThrown(null)) == Object));
1702
1703 //1 and new Object do not have a common type.
1704 static assert(!__traits(compiles, 1.ifThrown(new Object())));
1705 static assert(!__traits(compiles, (new Object()).ifThrown(1)));
1706
1707 //Use a lambda to get the thrown object.
1708 assert("%s".format().ifThrown(e => e.classinfo.name) == "std.format.FormatException");
1709 }
1710
1711 @system unittest
1712 {
1713 import core.exception;
1714 import std.conv;
1715 import std.string;
1716 //Basic behaviour - all versions.
1717 assert("1".to!int().ifThrown(0) == 1);
1718 assert("x".to!int().ifThrown(0) == 0);
1719 assert("1".to!int().ifThrown!ConvException(0) == 1);
1720 assert("x".to!int().ifThrown!ConvException(0) == 0);
1721 assert("1".to!int().ifThrown(e=>0) == 1);
1722 assert("x".to!int().ifThrown(e=>0) == 0);
1723 static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled
1724 {
1725 assert("1".to!int().ifThrown!ConvException(e=>0) == 1);
1726 assert("x".to!int().ifThrown!ConvException(e=>0) == 0);
1727 }
1728
1729 //Exceptions other than stated not caught.
1730 assert("x".to!int().ifThrown!StringException(0).collectException!ConvException() !is null);
1731 static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled
1732 {
1733 assert("x".to!int().ifThrown!StringException(e=>0).collectException!ConvException() !is null);
1734 }
1735
1736 //Default does not include errors.
1737 int throwRangeError() { throw new RangeError; }
1738 assert(throwRangeError().ifThrown(0).collectException!RangeError() !is null);
1739 assert(throwRangeError().ifThrown(e=>0).collectException!RangeError() !is null);
1740
1741 //Incompatible types are not accepted.
1742 static assert(!__traits(compiles, 1.ifThrown(new Object())));
1743 static assert(!__traits(compiles, (new Object()).ifThrown(1)));
1744 static assert(!__traits(compiles, 1.ifThrown(e=>new Object())));
1745 static assert(!__traits(compiles, (new Object()).ifThrown(e=>1)));
1746 }
1747
1748 version (unittest) package
1749 @property void assertCTFEable(alias dg)()
1750 {
1751 static assert({ cast(void) dg(); return true; }());
1752 cast(void) dg();
1753 }
1754
1755 /** This $(D enum) is used to select the primitives of the range to handle by the
1756 $(LREF handle) range wrapper. The values of the $(D enum) can be $(D OR)'d to
1757 select multiple primitives to be handled.
1758
1759 $(D RangePrimitive.access) is a shortcut for the access primitives; $(D front),
1760 $(D back) and $(D opIndex).
1761
1762 $(D RangePrimitive.pop) is a shortcut for the mutating primitives;
1763 $(D popFront) and $(D popBack).
1764 */
1765 enum RangePrimitive
1766 {
1767 front = 0b00_0000_0001, ///
1768 back = 0b00_0000_0010, /// Ditto
1769 popFront = 0b00_0000_0100, /// Ditto
1770 popBack = 0b00_0000_1000, /// Ditto
1771 empty = 0b00_0001_0000, /// Ditto
1772 save = 0b00_0010_0000, /// Ditto
1773 length = 0b00_0100_0000, /// Ditto
1774 opDollar = 0b00_1000_0000, /// Ditto
1775 opIndex = 0b01_0000_0000, /// Ditto
1776 opSlice = 0b10_0000_0000, /// Ditto
1777 access = front | back | opIndex, /// Ditto
1778 pop = popFront | popBack, /// Ditto
1779 }
1780
1781 /** Handle exceptions thrown from range primitives.
1782
1783 Use the $(LREF RangePrimitive) enum to specify which primitives to _handle.
1784 Multiple range primitives can be handled at once by using the $(D OR) operator
1785 or the pseudo-primitives $(D RangePrimitive.access) and $(D RangePrimitive.pop).
1786 All handled primitives must have return types or values compatible with the
1787 user-supplied handler.
1788
1789 Params:
1790 E = The type of $(D Throwable) to _handle.
1791 primitivesToHandle = Set of range primitives to _handle.
1792 handler = The callable that is called when a handled primitive throws a
1793 $(D Throwable) of type $(D E). The handler must accept arguments of
1794 the form $(D E, ref IRange) and its return value is used as the primitive's
1795 return value whenever $(D E) is thrown. For $(D opIndex), the handler can
1796 optionally recieve a third argument; the index that caused the exception.
1797 input = The range to _handle.
1798
1799 Returns: A wrapper $(D struct) that preserves the range interface of $(D input).
1800
1801 Note:
1802 Infinite ranges with slicing support must return an instance of
1803 $(REF Take, std,range) when sliced with a specific lower and upper
1804 bound (see $(REF hasSlicing, std,range,primitives)); $(D handle) deals with
1805 this by $(D take)ing 0 from the return value of the handler function and
1806 returning that when an exception is caught.
1807 */
1808 auto handle(E : Throwable, RangePrimitive primitivesToHandle, alias handler, Range)(Range input)
1809 if (isInputRange!Range)
1810 {
1811 static struct Handler
1812 {
1813 private Range range;
1814
1815 static if (isForwardRange!Range)
1816 {
1817 @property typeof(this) save()
1818 {
1819 static if (primitivesToHandle & RangePrimitive.save)
1820 {
1821 try
1822 {
1823 return typeof(this)(range.save);
1824 }
1825 catch (E exception)
1826 {
1827 return typeof(this)(handler(exception, this.range));
1828 }
1829 }
1830 else
1831 return typeof(this)(range.save);
1832 }
1833 }
1834
1835 static if (isInfinite!Range)
1836 {
1837 enum bool empty = false;
1838 }
1839 else
1840 {
1841 @property bool empty()
1842 {
1843 static if (primitivesToHandle & RangePrimitive.empty)
1844 {
1845 try
1846 {
1847 return this.range.empty;
1848 }
1849 catch (E exception)
1850 {
1851 return handler(exception, this.range);
1852 }
1853 }
1854 else
1855 return this.range.empty;
1856 }
1857 }
1858
1859 @property auto ref front()
1860 {
1861 static if (primitivesToHandle & RangePrimitive.front)
1862 {
1863 try
1864 {
1865 return this.range.front;
1866 }
1867 catch (E exception)
1868 {
1869 return handler(exception, this.range);
1870 }
1871 }
1872 else
1873 return this.range.front;
1874 }
1875
1876 void popFront()
1877 {
1878 static if (primitivesToHandle & RangePrimitive.popFront)
1879 {
1880 try
1881 {
1882 this.range.popFront();
1883 }
1884 catch (E exception)
1885 {
1886 handler(exception, this.range);
1887 }
1888 }
1889 else
1890 this.range.popFront();
1891 }
1892
1893 static if (isBidirectionalRange!Range)
1894 {
1895 @property auto ref back()
1896 {
1897 static if (primitivesToHandle & RangePrimitive.back)
1898 {
1899 try
1900 {
1901 return this.range.back;
1902 }
1903 catch (E exception)
1904 {
1905 return handler(exception, this.range);
1906 }
1907 }
1908 else
1909 return this.range.back;
1910 }
1911
1912 void popBack()
1913 {
1914 static if (primitivesToHandle & RangePrimitive.popBack)
1915 {
1916 try
1917 {
1918 this.range.popBack();
1919 }
1920 catch (E exception)
1921 {
1922 handler(exception, this.range);
1923 }
1924 }
1925 else
1926 this.range.popBack();
1927 }
1928 }
1929
1930 static if (isRandomAccessRange!Range)
1931 {
1932 auto ref opIndex(size_t index)
1933 {
1934 static if (primitivesToHandle & RangePrimitive.opIndex)
1935 {
1936 try
1937 {
1938 return this.range[index];
1939 }
1940 catch (E exception)
1941 {
1942 static if (__traits(compiles, handler(exception, this.range, index)))
1943 return handler(exception, this.range, index);
1944 else
1945 return handler(exception, this.range);
1946 }
1947 }
1948 else
1949 return this.range[index];
1950 }
1951 }
1952
1953 static if (hasLength!Range)
1954 {
1955 @property auto length()
1956 {
1957 static if (primitivesToHandle & RangePrimitive.length)
1958 {
1959 try
1960 {
1961 return this.range.length;
1962 }
1963 catch (E exception)
1964 {
1965 return handler(exception, this.range);
1966 }
1967 }
1968 else
1969 return this.range.length;
1970 }
1971 }
1972
1973 static if (hasSlicing!Range)
1974 {
1975 static if (hasLength!Range)
1976 {
1977 typeof(this) opSlice(size_t lower, size_t upper)
1978 {
1979 static if (primitivesToHandle & RangePrimitive.opSlice)
1980 {
1981 try
1982 {
1983 return typeof(this)(this.range[lower .. upper]);
1984 }
1985 catch (E exception)
1986 {
1987 return typeof(this)(handler(exception, this.range));
1988 }
1989 }
1990 else
1991 return typeof(this)(this.range[lower .. upper]);
1992 }
1993 }
1994 else static if (is(typeof(Range.init[size_t.init .. $])))
1995 {
1996 import std.range : Take, takeExactly;
1997 static struct DollarToken {}
1998 enum opDollar = DollarToken.init;
1999
2000 typeof(this) opSlice(size_t lower, DollarToken)
2001 {
2002 static if (primitivesToHandle & RangePrimitive.opSlice)
2003 {
2004 try
2005 {
2006 return typeof(this)(this.range[lower .. $]);
2007 }
2008 catch (E exception)
2009 {
2010 return typeof(this)(handler(exception, this.range));
2011 }
2012 }
2013 else
2014 return typeof(this)(this.range[lower .. $]);
2015 }
2016
2017 Take!Handler opSlice(size_t lower, size_t upper)
2018 {
2019 static if (primitivesToHandle & RangePrimitive.opSlice)
2020 {
2021 try
2022 {
2023 return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1);
2024 }
2025 catch (E exception)
2026 {
2027 return takeExactly(typeof(this)(handler(exception, this.range)), 0);
2028 }
2029 }
2030 else
2031 return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1);
2032 }
2033 }
2034 }
2035 }
2036
2037 return Handler(input);
2038 }
2039
2040 ///
2041 pure @safe unittest
2042 {
2043 import std.algorithm.comparison : equal;
2044 import std.algorithm.iteration : map, splitter;
2045 import std.conv : to, ConvException;
2046
2047 auto s = "12,1337z32,54,2,7,9,1z,6,8";
2048
2049 // The next line composition will throw when iterated
2050 // as some elements of the input do not convert to integer
2051 auto r = s.splitter(',').map!(a => to!int(a));
2052
2053 // Substitute 0 for cases of ConvException
2054 auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0);
2055 assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8]));
2056 }
2057
2058 ///
2059 pure @safe unittest
2060 {
2061 import std.algorithm.comparison : equal;
2062 import std.range : retro;
2063 import std.utf : UTFException;
2064
2065 auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit
2066
2067 auto handled = str.handle!(UTFException, RangePrimitive.access,
2068 (e, r) => ' '); // Replace invalid code points with spaces
2069
2070 assert(handled.equal("hello world")); // `front` is handled,
2071 assert(handled.retro.equal("dlrow olleh")); // as well as `back`
2072 }
2073
2074 pure nothrow @safe unittest
2075 {
2076 static struct ThrowingRange
2077 {
2078 pure @safe:
2079 @property bool empty()
2080 {
2081 throw new Exception("empty has thrown");
2082 }
2083
2084 @property int front()
2085 {
2086 throw new Exception("front has thrown");
2087 }
2088
2089 @property int back()
2090 {
2091 throw new Exception("back has thrown");
2092 }
2093
2094 void popFront()
2095 {
2096 throw new Exception("popFront has thrown");
2097 }
2098
2099 void popBack()
2100 {
2101 throw new Exception("popBack has thrown");
2102 }
2103
2104 int opIndex(size_t)
2105 {
2106 throw new Exception("opIndex has thrown");
2107 }
2108
2109 ThrowingRange opSlice(size_t, size_t)
2110 {
2111 throw new Exception("opSlice has thrown");
2112 }
2113
2114 @property size_t length()
2115 {
2116 throw new Exception("length has thrown");
2117 }
2118
2119 alias opDollar = length;
2120
2121 @property ThrowingRange save()
2122 {
2123 throw new Exception("save has thrown");
2124 }
2125 }
2126
2127 static assert(isInputRange!ThrowingRange);
2128 static assert(isForwardRange!ThrowingRange);
2129 static assert(isBidirectionalRange!ThrowingRange);
2130 static assert(hasSlicing!ThrowingRange);
2131 static assert(hasLength!ThrowingRange);
2132
2133 auto f = ThrowingRange();
2134 auto fb = f.handle!(Exception, RangePrimitive.front | RangePrimitive.back,
2135 (e, r) => -1)();
2136 assert(fb.front == -1);
2137 assert(fb.back == -1);
2138 assertThrown(fb.popFront());
2139 assertThrown(fb.popBack());
2140 assertThrown(fb.empty);
2141 assertThrown(fb.save);
2142 assertThrown(fb[0]);
2143
2144 auto accessRange = f.handle!(Exception, RangePrimitive.access,
2145 (e, r) => -1);
2146 assert(accessRange.front == -1);
2147 assert(accessRange.back == -1);
2148 assert(accessRange[0] == -1);
2149 assertThrown(accessRange.popFront());
2150 assertThrown(accessRange.popBack());
2151
2152 auto pfb = f.handle!(Exception, RangePrimitive.pop, (e, r) => -1)();
2153
2154 pfb.popFront(); // this would throw otherwise
2155 pfb.popBack(); // this would throw otherwise
2156
2157 auto em = f.handle!(Exception,
2158 RangePrimitive.empty, (e, r) => false)();
2159
2160 assert(!em.empty);
2161
2162 auto arr = f.handle!(Exception,
2163 RangePrimitive.opIndex, (e, r) => 1337)();
2164
2165 assert(arr[0] == 1337);
2166
2167 auto arr2 = f.handle!(Exception,
2168 RangePrimitive.opIndex, (e, r, i) => i)();
2169
2170 assert(arr2[0] == 0);
2171 assert(arr2[1337] == 1337);
2172
2173 auto save = f.handle!(Exception,
2174 RangePrimitive.save,
2175 function(Exception e, ref ThrowingRange r) {
2176 return ThrowingRange();
2177 })();
2178
2179 save.save;
2180
2181 auto slice = f.handle!(Exception,
2182 RangePrimitive.opSlice, (e, r) => ThrowingRange())();
2183
2184 auto sliced = slice[0 .. 1337]; // this would throw otherwise
2185
2186 static struct Infinite
2187 {
2188 import std.range : Take;
2189 pure @safe:
2190 enum bool empty = false;
2191 int front() { assert(false); }
2192 void popFront() { assert(false); }
2193 Infinite save() @property { assert(false); }
2194 static struct DollarToken {}
2195 enum opDollar = DollarToken.init;
2196 Take!Infinite opSlice(size_t, size_t) { assert(false); }
2197 Infinite opSlice(size_t, DollarToken)
2198 {
2199 throw new Exception("opSlice has thrown");
2200 }
2201 }
2202
2203 static assert(isInputRange!Infinite);
2204 static assert(isInfinite!Infinite);
2205 static assert(hasSlicing!Infinite);
2206
2207 assertThrown(Infinite()[0 .. $]);
2208
2209 auto infinite = Infinite.init.handle!(Exception,
2210 RangePrimitive.opSlice, (e, r) => Infinite())();
2211
2212 auto infSlice = infinite[0 .. $]; // this would throw otherwise
2213 }
2214
2215
2216 /++
2217 Convenience mixin for trivially sub-classing exceptions
2218
2219 Even trivially sub-classing an exception involves writing boilerplate code
2220 for the constructor to: 1$(RPAREN) correctly pass in the source file and line number
2221 the exception was thrown from; 2$(RPAREN) be usable with $(LREF enforce) which
2222 expects exception constructors to take arguments in a fixed order. This
2223 mixin provides that boilerplate code.
2224
2225 Note however that you need to mark the $(B mixin) line with at least a
2226 minimal (i.e. just $(B ///)) DDoc comment if you want the mixed-in
2227 constructors to be documented in the newly created Exception subclass.
2228
2229 $(RED Current limitation): Due to
2230 $(LINK2 https://issues.dlang.org/show_bug.cgi?id=11500, bug #11500),
2231 currently the constructors specified in this mixin cannot be overloaded with
2232 any other custom constructors. Thus this mixin can currently only be used
2233 when no such custom constructors need to be explicitly specified.
2234 +/
2235 mixin template basicExceptionCtors()
2236 {
2237 /++
2238 Params:
2239 msg = The message for the exception.
2240 file = The file where the exception occurred.
2241 line = The line number where the exception occurred.
2242 next = The previous exception in the chain of exceptions, if any.
2243 +/
2244 this(string msg, string file = __FILE__, size_t line = __LINE__,
2245 Throwable next = null) @nogc @safe pure nothrow
2246 {
2247 super(msg, file, line, next);
2248 }
2249
2250 /++
2251 Params:
2252 msg = The message for the exception.
2253 next = The previous exception in the chain of exceptions.
2254 file = The file where the exception occurred.
2255 line = The line number where the exception occurred.
2256 +/
2257 this(string msg, Throwable next, string file = __FILE__,
2258 size_t line = __LINE__) @nogc @safe pure nothrow
2259 {
2260 super(msg, file, line, next);
2261 }
2262 }
2263
2264 ///
2265 @safe unittest
2266 {
2267 class MeaCulpa: Exception
2268 {
2269 ///
2270 mixin basicExceptionCtors;
2271 }
2272
2273 try
2274 throw new MeaCulpa("test");
2275 catch (MeaCulpa e)
2276 {
2277 assert(e.msg == "test");
2278 assert(e.file == __FILE__);
2279 assert(e.line == __LINE__ - 5);
2280 }
2281 }
2282
2283 @safe pure nothrow unittest
2284 {
2285 class TestException : Exception { mixin basicExceptionCtors; }
2286 auto e = new Exception("msg");
2287 auto te1 = new TestException("foo");
2288 auto te2 = new TestException("foo", e);
2289 }
2290
2291 @safe unittest
2292 {
2293 class TestException : Exception { mixin basicExceptionCtors; }
2294 auto e = new Exception("!!!");
2295
2296 auto te1 = new TestException("message", "file", 42, e);
2297 assert(te1.msg == "message");
2298 assert(te1.file == "file");
2299 assert(te1.line == 42);
2300 assert(te1.next is e);
2301
2302 auto te2 = new TestException("message", e, "file", 42);
2303 assert(te2.msg == "message");
2304 assert(te2.file == "file");
2305 assert(te2.line == 42);
2306 assert(te2.next is e);
2307
2308 auto te3 = new TestException("foo");
2309 assert(te3.msg == "foo");
2310 assert(te3.file == __FILE__);
2311 assert(te3.line == __LINE__ - 3);
2312 assert(te3.next is null);
2313
2314 auto te4 = new TestException("foo", e);
2315 assert(te4.msg == "foo");
2316 assert(te4.file == __FILE__);
2317 assert(te4.line == __LINE__ - 3);
2318 assert(te4.next is e);
2319 }
2320