]> git.ipfire.org Git - thirdparty/gcc.git/blob - libphobos/src/std/exception.d
Add D front-end, libphobos library, and D2 testsuite.
[thirdparty/gcc.git] / libphobos / src / std / exception.d
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 }
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
155 void throwEx(Throwable t) { throw t; }
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
282 void throwEx(Throwable t) { throw t; }
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 }
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 +/
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 +/
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 }
706 catch (T e)
707 {
708 return e;
709 }
710 return null;
711 }
712 ///
713 @system unittest
714 {
715 int b;
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 }
746 catch (T t)
747 {
748 return t;
749 }
750 return null;
751 }
752
753 @safe unittest
754 {
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 {
793 void throwFunc() { throw new Exception("My Message."); }
794 assert(collectExceptionMsg(throwFunc()) == "My Message.");
795
796 void nothrowFunc() {}
797 assert(collectExceptionMsg(nothrowFunc()) is null);
798
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 */
905 immutable(T)[] assumeUnique(T)(T[] array) pure nothrow
906 {
907 return .assumeUnique(array); // call ref version
908 }
909 /// ditto
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
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@@@
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 */
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.
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.
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
1014 void alwaysThrows()
1015 {
1016 throw new Exception("I threw up");
1017 }
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*) &target;
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
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*) &target;
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
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 {
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 {
1271 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 package string errnoString(int errno) nothrow @trusted
1482 {
1483 import core.stdc.string : strlen;
1484 version (CRuntime_Glibc)
1485 {
1486 import core.stdc.string : strerror_r;
1487 char[1024] buf = void;
1488 auto s = strerror_r(errno, buf.ptr, buf.length);
1489 }
1490 else version (Posix)
1491 {
1492 // XSI-compliant
1493 import core.stdc.string : strerror_r;
1494 char[1024] buf = void;
1495 const(char)* s;
1496 if (strerror_r(errno, buf.ptr, buf.length) == 0)
1497 s = buf.ptr;
1498 else
1499 return "Unknown error";
1500 }
1501 else
1502 {
1503 import core.stdc.string : strerror;
1504 auto s = strerror(errno);
1505 }
1506 return s[0 .. s.strlen].idup;
1507 }
1508
1509 /*********************
1510 * Thrown if errors that set $(D errno) occur.
1511 */
1512 class ErrnoException : Exception
1513 {
1514 final @property uint errno() { return _errno; } /// Operating system error code.
1515 private uint _errno;
1516 /// Constructor which takes an error message. The current global $(REF errno, core,stdc,errno) value is used as error code.
1517 this(string msg, string file = null, size_t line = 0) @trusted
1518 {
1519 import core.stdc.errno : errno;
1520 this(msg, errno, file, line);
1521 }
1522 /// Constructor which takes an error message and error code.
1523 this(string msg, int errno, string file = null, size_t line = 0) @trusted
1524 {
1525 _errno = errno;
1526 super(msg ~ " (" ~ errnoString(errno) ~ ")", file, line);
1527 }
1528
1529 @system unittest
1530 {
1531 import core.stdc.errno : errno, EAGAIN;
1532
1533 auto old = errno;
1534 scope(exit) errno = old;
1535
1536 errno = EAGAIN;
1537 auto ex = new ErrnoException("oh no");
1538 assert(ex.errno == EAGAIN);
1539 }
1540
1541 @system unittest
1542 {
1543 import core.stdc.errno : EAGAIN;
1544 auto ex = new ErrnoException("oh no", EAGAIN);
1545 assert(ex.errno == EAGAIN);
1546 }
1547 }
1548
1549 /++
1550 ML-style functional exception handling. Runs the supplied expression and
1551 returns its result. If the expression throws a $(D Throwable), runs the
1552 supplied error handler instead and return its result. The error handler's
1553 type must be the same as the expression's type.
1554
1555 Params:
1556 E = The type of $(D Throwable)s to catch. Defaults to $(D Exception)
1557 T1 = The type of the expression.
1558 T2 = The return type of the error handler.
1559 expression = The expression to run and return its result.
1560 errorHandler = The handler to run if the expression throwed.
1561
1562 Returns:
1563 expression, if it does not throw. Otherwise, returns the result of
1564 errorHandler.
1565
1566 Example:
1567 --------------------
1568 //Revert to a default value upon an error:
1569 assert("x".to!int().ifThrown(0) == 0);
1570 --------------------
1571
1572 You can also chain multiple calls to ifThrown, each capturing errors from the
1573 entire preceding expression.
1574
1575 Example:
1576 --------------------
1577 //Chaining multiple calls to ifThrown to attempt multiple things in a row:
1578 string s="true";
1579 assert(s.to!int().
1580 ifThrown(cast(int) s.to!double()).
1581 ifThrown(cast(int) s.to!bool())
1582 == 1);
1583
1584 //Respond differently to different types of errors
1585 assert(enforce("x".to!int() < 1).to!string()
1586 .ifThrown!ConvException("not a number")
1587 .ifThrown!Exception("number too small")
1588 == "not a number");
1589 --------------------
1590
1591 The expression and the errorHandler must have a common type they can both
1592 be implicitly casted to, and that type will be the type of the compound
1593 expression.
1594
1595 Example:
1596 --------------------
1597 //null and new Object have a common type(Object).
1598 static assert(is(typeof(null.ifThrown(new Object())) == Object));
1599 static assert(is(typeof((new Object()).ifThrown(null)) == Object));
1600
1601 //1 and new Object do not have a common type.
1602 static assert(!__traits(compiles, 1.ifThrown(new Object())));
1603 static assert(!__traits(compiles, (new Object()).ifThrown(1)));
1604 --------------------
1605
1606 If you need to use the actual thrown exception, you can use a delegate.
1607 Example:
1608 --------------------
1609 //Use a lambda to get the thrown object.
1610 assert("%s".format().ifThrown!Exception(e => e.classinfo.name) == "std.format.FormatException");
1611 --------------------
1612 +/
1613 //lazy version
1614 CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, lazy scope T2 errorHandler)
1615 {
1616 static assert(!is(typeof(return) == void),
1617 "The error handler's return value("
1618 ~ T2.stringof ~
1619 ") does not have a common type with the expression("
1620 ~ T1.stringof ~
1621 ")."
1622 );
1623 try
1624 {
1625 return expression();
1626 }
1627 catch (E)
1628 {
1629 return errorHandler();
1630 }
1631 }
1632
1633 ///ditto
1634 //delegate version
1635 CommonType!(T1, T2) ifThrown(E : Throwable, T1, T2)(lazy scope T1 expression, scope T2 delegate(E) errorHandler)
1636 {
1637 static assert(!is(typeof(return) == void),
1638 "The error handler's return value("
1639 ~ T2.stringof ~
1640 ") does not have a common type with the expression("
1641 ~ T1.stringof ~
1642 ")."
1643 );
1644 try
1645 {
1646 return expression();
1647 }
1648 catch (E e)
1649 {
1650 return errorHandler(e);
1651 }
1652 }
1653
1654 ///ditto
1655 //delegate version, general overload to catch any Exception
1656 CommonType!(T1, T2) ifThrown(T1, T2)(lazy scope T1 expression, scope T2 delegate(Exception) errorHandler)
1657 {
1658 static assert(!is(typeof(return) == void),
1659 "The error handler's return value("
1660 ~ T2.stringof ~
1661 ") does not have a common type with the expression("
1662 ~ T1.stringof ~
1663 ")."
1664 );
1665 try
1666 {
1667 return expression();
1668 }
1669 catch (Exception e)
1670 {
1671 return errorHandler(e);
1672 }
1673 }
1674
1675 //Verify Examples
1676 @system unittest
1677 {
1678 import std.conv;
1679 import std.string;
1680 //Revert to a default value upon an error:
1681 assert("x".to!int().ifThrown(0) == 0);
1682
1683 //Chaining multiple calls to ifThrown to attempt multiple things in a row:
1684 string s="true";
1685 assert(s.to!int().
1686 ifThrown(cast(int) s.to!double()).
1687 ifThrown(cast(int) s.to!bool())
1688 == 1);
1689
1690 //Respond differently to different types of errors
1691 assert(enforce("x".to!int() < 1).to!string()
1692 .ifThrown!ConvException("not a number")
1693 .ifThrown!Exception("number too small")
1694 == "not a number");
1695
1696 //null and new Object have a common type(Object).
1697 static assert(is(typeof(null.ifThrown(new Object())) == Object));
1698 static assert(is(typeof((new Object()).ifThrown(null)) == Object));
1699
1700 //1 and new Object do not have a common type.
1701 static assert(!__traits(compiles, 1.ifThrown(new Object())));
1702 static assert(!__traits(compiles, (new Object()).ifThrown(1)));
1703
1704 //Use a lambda to get the thrown object.
1705 assert("%s".format().ifThrown(e => e.classinfo.name) == "std.format.FormatException");
1706 }
1707
1708 @system unittest
1709 {
1710 import core.exception;
1711 import std.conv;
1712 import std.string;
1713 //Basic behaviour - all versions.
1714 assert("1".to!int().ifThrown(0) == 1);
1715 assert("x".to!int().ifThrown(0) == 0);
1716 assert("1".to!int().ifThrown!ConvException(0) == 1);
1717 assert("x".to!int().ifThrown!ConvException(0) == 0);
1718 assert("1".to!int().ifThrown(e=>0) == 1);
1719 assert("x".to!int().ifThrown(e=>0) == 0);
1720 static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled
1721 {
1722 assert("1".to!int().ifThrown!ConvException(e=>0) == 1);
1723 assert("x".to!int().ifThrown!ConvException(e=>0) == 0);
1724 }
1725
1726 //Exceptions other than stated not caught.
1727 assert("x".to!int().ifThrown!StringException(0).collectException!ConvException() !is null);
1728 static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled
1729 {
1730 assert("x".to!int().ifThrown!StringException(e=>0).collectException!ConvException() !is null);
1731 }
1732
1733 //Default does not include errors.
1734 int throwRangeError() { throw new RangeError; }
1735 assert(throwRangeError().ifThrown(0).collectException!RangeError() !is null);
1736 assert(throwRangeError().ifThrown(e=>0).collectException!RangeError() !is null);
1737
1738 //Incompatible types are not accepted.
1739 static assert(!__traits(compiles, 1.ifThrown(new Object())));
1740 static assert(!__traits(compiles, (new Object()).ifThrown(1)));
1741 static assert(!__traits(compiles, 1.ifThrown(e=>new Object())));
1742 static assert(!__traits(compiles, (new Object()).ifThrown(e=>1)));
1743 }
1744
1745 version (unittest) package
1746 @property void assertCTFEable(alias dg)()
1747 {
1748 static assert({ cast(void) dg(); return true; }());
1749 cast(void) dg();
1750 }
1751
1752 /** This $(D enum) is used to select the primitives of the range to handle by the
1753 $(LREF handle) range wrapper. The values of the $(D enum) can be $(D OR)'d to
1754 select multiple primitives to be handled.
1755
1756 $(D RangePrimitive.access) is a shortcut for the access primitives; $(D front),
1757 $(D back) and $(D opIndex).
1758
1759 $(D RangePrimitive.pop) is a shortcut for the mutating primitives;
1760 $(D popFront) and $(D popBack).
1761 */
1762 enum RangePrimitive
1763 {
1764 front = 0b00_0000_0001, ///
1765 back = 0b00_0000_0010, /// Ditto
1766 popFront = 0b00_0000_0100, /// Ditto
1767 popBack = 0b00_0000_1000, /// Ditto
1768 empty = 0b00_0001_0000, /// Ditto
1769 save = 0b00_0010_0000, /// Ditto
1770 length = 0b00_0100_0000, /// Ditto
1771 opDollar = 0b00_1000_0000, /// Ditto
1772 opIndex = 0b01_0000_0000, /// Ditto
1773 opSlice = 0b10_0000_0000, /// Ditto
1774 access = front | back | opIndex, /// Ditto
1775 pop = popFront | popBack, /// Ditto
1776 }
1777
1778 /** Handle exceptions thrown from range primitives.
1779
1780 Use the $(LREF RangePrimitive) enum to specify which primitives to _handle.
1781 Multiple range primitives can be handled at once by using the $(D OR) operator
1782 or the pseudo-primitives $(D RangePrimitive.access) and $(D RangePrimitive.pop).
1783 All handled primitives must have return types or values compatible with the
1784 user-supplied handler.
1785
1786 Params:
1787 E = The type of $(D Throwable) to _handle.
1788 primitivesToHandle = Set of range primitives to _handle.
1789 handler = The callable that is called when a handled primitive throws a
1790 $(D Throwable) of type $(D E). The handler must accept arguments of
1791 the form $(D E, ref IRange) and its return value is used as the primitive's
1792 return value whenever $(D E) is thrown. For $(D opIndex), the handler can
1793 optionally recieve a third argument; the index that caused the exception.
1794 input = The range to _handle.
1795
1796 Returns: A wrapper $(D struct) that preserves the range interface of $(D input).
1797
1798 Note:
1799 Infinite ranges with slicing support must return an instance of
1800 $(REF Take, std,range) when sliced with a specific lower and upper
1801 bound (see $(REF hasSlicing, std,range,primitives)); $(D handle) deals with
1802 this by $(D take)ing 0 from the return value of the handler function and
1803 returning that when an exception is caught.
1804 */
1805 auto handle(E : Throwable, RangePrimitive primitivesToHandle, alias handler, Range)(Range input)
1806 if (isInputRange!Range)
1807 {
1808 static struct Handler
1809 {
1810 private Range range;
1811
1812 static if (isForwardRange!Range)
1813 {
1814 @property typeof(this) save()
1815 {
1816 static if (primitivesToHandle & RangePrimitive.save)
1817 {
1818 try
1819 {
1820 return typeof(this)(range.save);
1821 }
1822 catch (E exception)
1823 {
1824 return typeof(this)(handler(exception, this.range));
1825 }
1826 }
1827 else
1828 return typeof(this)(range.save);
1829 }
1830 }
1831
1832 static if (isInfinite!Range)
1833 {
1834 enum bool empty = false;
1835 }
1836 else
1837 {
1838 @property bool empty()
1839 {
1840 static if (primitivesToHandle & RangePrimitive.empty)
1841 {
1842 try
1843 {
1844 return this.range.empty;
1845 }
1846 catch (E exception)
1847 {
1848 return handler(exception, this.range);
1849 }
1850 }
1851 else
1852 return this.range.empty;
1853 }
1854 }
1855
1856 @property auto ref front()
1857 {
1858 static if (primitivesToHandle & RangePrimitive.front)
1859 {
1860 try
1861 {
1862 return this.range.front;
1863 }
1864 catch (E exception)
1865 {
1866 return handler(exception, this.range);
1867 }
1868 }
1869 else
1870 return this.range.front;
1871 }
1872
1873 void popFront()
1874 {
1875 static if (primitivesToHandle & RangePrimitive.popFront)
1876 {
1877 try
1878 {
1879 this.range.popFront();
1880 }
1881 catch (E exception)
1882 {
1883 handler(exception, this.range);
1884 }
1885 }
1886 else
1887 this.range.popFront();
1888 }
1889
1890 static if (isBidirectionalRange!Range)
1891 {
1892 @property auto ref back()
1893 {
1894 static if (primitivesToHandle & RangePrimitive.back)
1895 {
1896 try
1897 {
1898 return this.range.back;
1899 }
1900 catch (E exception)
1901 {
1902 return handler(exception, this.range);
1903 }
1904 }
1905 else
1906 return this.range.back;
1907 }
1908
1909 void popBack()
1910 {
1911 static if (primitivesToHandle & RangePrimitive.popBack)
1912 {
1913 try
1914 {
1915 this.range.popBack();
1916 }
1917 catch (E exception)
1918 {
1919 handler(exception, this.range);
1920 }
1921 }
1922 else
1923 this.range.popBack();
1924 }
1925 }
1926
1927 static if (isRandomAccessRange!Range)
1928 {
1929 auto ref opIndex(size_t index)
1930 {
1931 static if (primitivesToHandle & RangePrimitive.opIndex)
1932 {
1933 try
1934 {
1935 return this.range[index];
1936 }
1937 catch (E exception)
1938 {
1939 static if (__traits(compiles, handler(exception, this.range, index)))
1940 return handler(exception, this.range, index);
1941 else
1942 return handler(exception, this.range);
1943 }
1944 }
1945 else
1946 return this.range[index];
1947 }
1948 }
1949
1950 static if (hasLength!Range)
1951 {
1952 @property auto length()
1953 {
1954 static if (primitivesToHandle & RangePrimitive.length)
1955 {
1956 try
1957 {
1958 return this.range.length;
1959 }
1960 catch (E exception)
1961 {
1962 return handler(exception, this.range);
1963 }
1964 }
1965 else
1966 return this.range.length;
1967 }
1968 }
1969
1970 static if (hasSlicing!Range)
1971 {
1972 static if (hasLength!Range)
1973 {
1974 typeof(this) opSlice(size_t lower, size_t upper)
1975 {
1976 static if (primitivesToHandle & RangePrimitive.opSlice)
1977 {
1978 try
1979 {
1980 return typeof(this)(this.range[lower .. upper]);
1981 }
1982 catch (E exception)
1983 {
1984 return typeof(this)(handler(exception, this.range));
1985 }
1986 }
1987 else
1988 return typeof(this)(this.range[lower .. upper]);
1989 }
1990 }
1991 else static if (is(typeof(Range.init[size_t.init .. $])))
1992 {
1993 import std.range : Take, takeExactly;
1994 static struct DollarToken {}
1995 enum opDollar = DollarToken.init;
1996
1997 typeof(this) opSlice(size_t lower, DollarToken)
1998 {
1999 static if (primitivesToHandle & RangePrimitive.opSlice)
2000 {
2001 try
2002 {
2003 return typeof(this)(this.range[lower .. $]);
2004 }
2005 catch (E exception)
2006 {
2007 return typeof(this)(handler(exception, this.range));
2008 }
2009 }
2010 else
2011 return typeof(this)(this.range[lower .. $]);
2012 }
2013
2014 Take!Handler opSlice(size_t lower, size_t upper)
2015 {
2016 static if (primitivesToHandle & RangePrimitive.opSlice)
2017 {
2018 try
2019 {
2020 return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1);
2021 }
2022 catch (E exception)
2023 {
2024 return takeExactly(typeof(this)(handler(exception, this.range)), 0);
2025 }
2026 }
2027 else
2028 return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1);
2029 }
2030 }
2031 }
2032 }
2033
2034 return Handler(input);
2035 }
2036
2037 ///
2038 pure @safe unittest
2039 {
2040 import std.algorithm.comparison : equal;
2041 import std.algorithm.iteration : map, splitter;
2042 import std.conv : to, ConvException;
2043
2044 auto s = "12,1337z32,54,2,7,9,1z,6,8";
2045
2046 // The next line composition will throw when iterated
2047 // as some elements of the input do not convert to integer
2048 auto r = s.splitter(',').map!(a => to!int(a));
2049
2050 // Substitute 0 for cases of ConvException
2051 auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0);
2052 assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8]));
2053 }
2054
2055 ///
2056 pure @safe unittest
2057 {
2058 import std.algorithm.comparison : equal;
2059 import std.range : retro;
2060 import std.utf : UTFException;
2061
2062 auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit
2063
2064 auto handled = str.handle!(UTFException, RangePrimitive.access,
2065 (e, r) => ' '); // Replace invalid code points with spaces
2066
2067 assert(handled.equal("hello world")); // `front` is handled,
2068 assert(handled.retro.equal("dlrow olleh")); // as well as `back`
2069 }
2070
2071 pure nothrow @safe unittest
2072 {
2073 static struct ThrowingRange
2074 {
2075 pure @safe:
2076 @property bool empty()
2077 {
2078 throw new Exception("empty has thrown");
2079 }
2080
2081 @property int front()
2082 {
2083 throw new Exception("front has thrown");
2084 }
2085
2086 @property int back()
2087 {
2088 throw new Exception("back has thrown");
2089 }
2090
2091 void popFront()
2092 {
2093 throw new Exception("popFront has thrown");
2094 }
2095
2096 void popBack()
2097 {
2098 throw new Exception("popBack has thrown");
2099 }
2100
2101 int opIndex(size_t)
2102 {
2103 throw new Exception("opIndex has thrown");
2104 }
2105
2106 ThrowingRange opSlice(size_t, size_t)
2107 {
2108 throw new Exception("opSlice has thrown");
2109 }
2110
2111 @property size_t length()
2112 {
2113 throw new Exception("length has thrown");
2114 }
2115
2116 alias opDollar = length;
2117
2118 @property ThrowingRange save()
2119 {
2120 throw new Exception("save has thrown");
2121 }
2122 }
2123
2124 static assert(isInputRange!ThrowingRange);
2125 static assert(isForwardRange!ThrowingRange);
2126 static assert(isBidirectionalRange!ThrowingRange);
2127 static assert(hasSlicing!ThrowingRange);
2128 static assert(hasLength!ThrowingRange);
2129
2130 auto f = ThrowingRange();
2131 auto fb = f.handle!(Exception, RangePrimitive.front | RangePrimitive.back,
2132 (e, r) => -1)();
2133 assert(fb.front == -1);
2134 assert(fb.back == -1);
2135 assertThrown(fb.popFront());
2136 assertThrown(fb.popBack());
2137 assertThrown(fb.empty);
2138 assertThrown(fb.save);
2139 assertThrown(fb[0]);
2140
2141 auto accessRange = f.handle!(Exception, RangePrimitive.access,
2142 (e, r) => -1);
2143 assert(accessRange.front == -1);
2144 assert(accessRange.back == -1);
2145 assert(accessRange[0] == -1);
2146 assertThrown(accessRange.popFront());
2147 assertThrown(accessRange.popBack());
2148
2149 auto pfb = f.handle!(Exception, RangePrimitive.pop, (e, r) => -1)();
2150
2151 pfb.popFront(); // this would throw otherwise
2152 pfb.popBack(); // this would throw otherwise
2153
2154 auto em = f.handle!(Exception,
2155 RangePrimitive.empty, (e, r) => false)();
2156
2157 assert(!em.empty);
2158
2159 auto arr = f.handle!(Exception,
2160 RangePrimitive.opIndex, (e, r) => 1337)();
2161
2162 assert(arr[0] == 1337);
2163
2164 auto arr2 = f.handle!(Exception,
2165 RangePrimitive.opIndex, (e, r, i) => i)();
2166
2167 assert(arr2[0] == 0);
2168 assert(arr2[1337] == 1337);
2169
2170 auto save = f.handle!(Exception,
2171 RangePrimitive.save,
2172 function(Exception e, ref ThrowingRange r) {
2173 return ThrowingRange();
2174 })();
2175
2176 save.save;
2177
2178 auto slice = f.handle!(Exception,
2179 RangePrimitive.opSlice, (e, r) => ThrowingRange())();
2180
2181 auto sliced = slice[0 .. 1337]; // this would throw otherwise
2182
2183 static struct Infinite
2184 {
2185 import std.range : Take;
2186 pure @safe:
2187 enum bool empty = false;
2188 int front() { assert(false); }
2189 void popFront() { assert(false); }
2190 Infinite save() @property { assert(false); }
2191 static struct DollarToken {}
2192 enum opDollar = DollarToken.init;
2193 Take!Infinite opSlice(size_t, size_t) { assert(false); }
2194 Infinite opSlice(size_t, DollarToken)
2195 {
2196 throw new Exception("opSlice has thrown");
2197 }
2198 }
2199
2200 static assert(isInputRange!Infinite);
2201 static assert(isInfinite!Infinite);
2202 static assert(hasSlicing!Infinite);
2203
2204 assertThrown(Infinite()[0 .. $]);
2205
2206 auto infinite = Infinite.init.handle!(Exception,
2207 RangePrimitive.opSlice, (e, r) => Infinite())();
2208
2209 auto infSlice = infinite[0 .. $]; // this would throw otherwise
2210 }
2211
2212
2213 /++
2214 Convenience mixin for trivially sub-classing exceptions
2215
2216 Even trivially sub-classing an exception involves writing boilerplate code
2217 for the constructor to: 1$(RPAREN) correctly pass in the source file and line number
2218 the exception was thrown from; 2$(RPAREN) be usable with $(LREF enforce) which
2219 expects exception constructors to take arguments in a fixed order. This
2220 mixin provides that boilerplate code.
2221
2222 Note however that you need to mark the $(B mixin) line with at least a
2223 minimal (i.e. just $(B ///)) DDoc comment if you want the mixed-in
2224 constructors to be documented in the newly created Exception subclass.
2225
2226 $(RED Current limitation): Due to
2227 $(LINK2 https://issues.dlang.org/show_bug.cgi?id=11500, bug #11500),
2228 currently the constructors specified in this mixin cannot be overloaded with
2229 any other custom constructors. Thus this mixin can currently only be used
2230 when no such custom constructors need to be explicitly specified.
2231 +/
2232 mixin template basicExceptionCtors()
2233 {
2234 /++
2235 Params:
2236 msg = The message for the exception.
2237 file = The file where the exception occurred.
2238 line = The line number where the exception occurred.
2239 next = The previous exception in the chain of exceptions, if any.
2240 +/
2241 this(string msg, string file = __FILE__, size_t line = __LINE__,
2242 Throwable next = null) @nogc @safe pure nothrow
2243 {
2244 super(msg, file, line, next);
2245 }
2246
2247 /++
2248 Params:
2249 msg = The message for the exception.
2250 next = The previous exception in the chain of exceptions.
2251 file = The file where the exception occurred.
2252 line = The line number where the exception occurred.
2253 +/
2254 this(string msg, Throwable next, string file = __FILE__,
2255 size_t line = __LINE__) @nogc @safe pure nothrow
2256 {
2257 super(msg, file, line, next);
2258 }
2259 }
2260
2261 ///
2262 @safe unittest
2263 {
2264 class MeaCulpa: Exception
2265 {
2266 ///
2267 mixin basicExceptionCtors;
2268 }
2269
2270 try
2271 throw new MeaCulpa("test");
2272 catch (MeaCulpa e)
2273 {
2274 assert(e.msg == "test");
2275 assert(e.file == __FILE__);
2276 assert(e.line == __LINE__ - 5);
2277 }
2278 }
2279
2280 @safe pure nothrow unittest
2281 {
2282 class TestException : Exception { mixin basicExceptionCtors; }
2283 auto e = new Exception("msg");
2284 auto te1 = new TestException("foo");
2285 auto te2 = new TestException("foo", e);
2286 }
2287
2288 @safe unittest
2289 {
2290 class TestException : Exception { mixin basicExceptionCtors; }
2291 auto e = new Exception("!!!");
2292
2293 auto te1 = new TestException("message", "file", 42, e);
2294 assert(te1.msg == "message");
2295 assert(te1.file == "file");
2296 assert(te1.line == 42);
2297 assert(te1.next is e);
2298
2299 auto te2 = new TestException("message", e, "file", 42);
2300 assert(te2.msg == "message");
2301 assert(te2.file == "file");
2302 assert(te2.line == 42);
2303 assert(te2.next is e);
2304
2305 auto te3 = new TestException("foo");
2306 assert(te3.msg == "foo");
2307 assert(te3.file == __FILE__);
2308 assert(te3.line == __LINE__ - 3);
2309 assert(te3.next is null);
2310
2311 auto te4 = new TestException("foo", e);
2312 assert(te4.msg == "foo");
2313 assert(te4.file == __FILE__);
2314 assert(te4.line == __LINE__ - 3);
2315 assert(te4.next is e);
2316 }