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