]> git.ipfire.org Git - people/ms/gcc.git/blob - libphobos/src/std/exception.d
b699a8edea36a272bc197ff825ecde141846fbdc
[people/ms/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 $(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`
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 }
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
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 }
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 {
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])
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;
577 ~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 {
595 this(string fn, size_t ln) { super("", fn, ln); }
596 }
597 static class E3 : Exception
598 {
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 {
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 }
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;
679 int foo() { throw new Exception("blah"); }
680 assert(collectException(foo(), b));
681
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 }
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 {
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 {
766 void throwFunc() { throw new Exception("My Message."); }
767 assert(collectExceptionMsg(throwFunc()) == "My Message.");
768
769 void nothrowFunc() {}
770 assert(collectExceptionMsg(nothrowFunc()) is null);
771
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 {
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 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 static 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)[] assumeUnique(T)(T[] array) pure nothrow
905 {
906 return .assumeUnique(array); // call ref version
907 }
908 /// ditto
909 immutable(T)[] assumeUnique(T)(ref T[] array) pure nothrow
910 {
911 auto result = cast(immutable(T)[]) array;
912 array = null;
913 return result;
914 }
915 /// ditto
916 immutable(T[U]) assumeUnique(T, U)(ref T[U] array) pure nothrow
917 {
918 auto result = cast(immutable(T[U])) array;
919 array = null;
920 return result;
921 }
922
923 ///
924 @system unittest
925 {
926 int[] arr = new int[1];
927 auto arr1 = arr.assumeUnique;
928 static assert(is(typeof(arr1) == immutable(int)[]));
929 assert(arr == null);
930 assert(arr1 == [0]);
931 }
932
933 ///
934 @system unittest
935 {
936 int[string] arr = ["a":1];
937 auto arr1 = arr.assumeUnique;
938 static assert(is(typeof(arr1) == immutable(int[string])));
939 assert(arr == null);
940 assert(arr1.keys == ["a"]);
941 }
942
943 /**
944 * Wraps a possibly-throwing expression in a `nothrow` wrapper so that it
945 * can be called by a `nothrow` function.
946 *
947 * This wrapper function documents commitment on the part of the caller that
948 * the appropriate steps have been taken to avoid whatever conditions may
949 * trigger an exception during the evaluation of `expr`. If it turns out
950 * that the expression $(I does) throw at runtime, the wrapper will throw an
951 * `AssertError`.
952 *
953 * (Note that `Throwable` objects such as `AssertError` that do not
954 * subclass `Exception` may be thrown even from `nothrow` functions,
955 * since they are considered to be serious runtime problems that cannot be
956 * recovered from.)
957 *
958 * Params:
959 * expr = The expression asserted not to throw.
960 * msg = The message to include in the `AssertError` if the assumption turns
961 * out to be false.
962 * file = The source file name of the caller.
963 * line = The line number of the caller.
964 *
965 * Returns:
966 * The value of `expr`, if any.
967 */
968 T assumeWontThrow(T)(lazy T expr,
969 string msg = null,
970 string file = __FILE__,
971 size_t line = __LINE__) nothrow
972 {
973 import core.exception : AssertError;
974 try
975 {
976 return expr;
977 }
978 catch (Exception e)
979 {
980 import std.range.primitives : empty;
981 immutable tail = msg.empty ? "." : ": " ~ msg;
982 throw new AssertError("assumeWontThrow failed: Expression did throw" ~
983 tail, file, line);
984 }
985 }
986
987 ///
988 @safe unittest
989 {
990 import std.math.algebraic : sqrt;
991
992 // This function may throw.
993 int squareRoot(int x)
994 {
995 if (x < 0)
996 throw new Exception("Tried to take root of negative number");
997 return cast(int) sqrt(cast(double) x);
998 }
999
1000 // This function never throws.
1001 int computeLength(int x, int y) nothrow
1002 {
1003 // Since x*x + y*y is always positive, we can safely assume squareRoot
1004 // won't throw, and use it to implement this nothrow function. If it
1005 // does throw (e.g., if x*x + y*y overflows a 32-bit value), then the
1006 // program will terminate.
1007 return assumeWontThrow(squareRoot(x*x + y*y));
1008 }
1009
1010 assert(computeLength(3, 4) == 5);
1011 }
1012
1013 @system unittest
1014 {
1015 import core.exception : AssertError;
1016
1017 void alwaysThrows()
1018 {
1019 throw new Exception("I threw up");
1020 }
1021 void bad() nothrow
1022 {
1023 assumeWontThrow(alwaysThrows());
1024 }
1025 assertThrown!AssertError(bad());
1026 }
1027
1028 /**
1029 Checks whether a given source object contains pointers or references to a given
1030 target object.
1031
1032 Params:
1033 source = The source object
1034 target = The target object
1035
1036 Bugs:
1037 The function is explicitly annotated `@nogc` because inference could fail,
1038 see $(LINK2 https://issues.dlang.org/show_bug.cgi?id=17084, issue 17084).
1039
1040 Returns: `true` if `source`'s representation embeds a pointer
1041 that points to `target`'s representation or somewhere inside
1042 it.
1043
1044 If `source` is or contains a dynamic array, then, then these functions will check
1045 if there is overlap between the dynamic array and `target`'s representation.
1046
1047 If `source` is a class, then it will be handled as a pointer.
1048
1049 If `target` is a pointer, a dynamic array or a class, then these functions will only
1050 check if `source` points to `target`, $(I not) what `target` references.
1051
1052 If `source` is or contains a union or `void[n]`, then there may be either false positives or
1053 false negatives:
1054
1055 `doesPointTo` will return `true` if it is absolutely certain
1056 `source` points to `target`. It may produce false negatives, but never
1057 false positives. This function should be prefered when trying to validate
1058 input data.
1059
1060 `mayPointTo` will return `false` if it is absolutely certain
1061 `source` does not point to `target`. It may produce false positives, but never
1062 false negatives. This function should be prefered for defensively choosing a
1063 code path.
1064
1065 Note: Evaluating $(D doesPointTo(x, x)) checks whether `x` has
1066 internal pointers. This should only be done as an assertive test,
1067 as the language is free to assume objects don't have internal pointers
1068 (TDPL 7.1.3.5).
1069 */
1070 bool doesPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @nogc @trusted pure nothrow
1071 if (__traits(isRef, source) || isDynamicArray!S ||
1072 is(S : U*, U) || is(S == class))
1073 {
1074 static if (is(S : U*, U) || is(S == class) || is(S == interface))
1075 {
1076 const m = *cast(void**) &source;
1077 const b = cast(void*) &target;
1078 const e = b + target.sizeof;
1079 return b <= m && m < e;
1080 }
1081 else static if (is(S == struct) || is(S == union))
1082 {
1083 foreach (i, Subobj; typeof(source.tupleof))
1084 static if (!isUnionAliased!(S, i))
1085 if (doesPointTo(source.tupleof[i], target)) return true;
1086 return false;
1087 }
1088 else static if (isStaticArray!S)
1089 {
1090 static if (!is(S == void[n], size_t n))
1091 {
1092 foreach (ref s; source)
1093 if (doesPointTo(s, target)) return true;
1094 }
1095 return false;
1096 }
1097 else static if (isDynamicArray!S)
1098 {
1099 import std.array : overlap;
1100 return overlap(cast(void[]) source, cast(void[])(&target)[0 .. 1]).length != 0;
1101 }
1102 else
1103 {
1104 return false;
1105 }
1106 }
1107
1108 // for shared objects
1109 /// ditto
1110 bool doesPointTo(S, T)(auto ref const shared S source, ref const shared T target) @trusted pure nothrow
1111 {
1112 return doesPointTo!(shared S, shared T, void)(source, target);
1113 }
1114
1115 /// ditto
1116 bool mayPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @trusted pure nothrow
1117 if (__traits(isRef, source) || isDynamicArray!S ||
1118 is(S : U*, U) || is(S == class))
1119 {
1120 static if (is(S : U*, U) || is(S == class) || is(S == interface))
1121 {
1122 const m = *cast(void**) &source;
1123 const b = cast(void*) &target;
1124 const e = b + target.sizeof;
1125 return b <= m && m < e;
1126 }
1127 else static if (is(S == struct) || is(S == union))
1128 {
1129 foreach (i, Subobj; typeof(source.tupleof))
1130 if (mayPointTo(source.tupleof[i], target)) return true;
1131 return false;
1132 }
1133 else static if (isStaticArray!S)
1134 {
1135 static if (is(S == void[n], size_t n))
1136 {
1137 static if (n >= (void[]).sizeof)
1138 {
1139 // could contain a slice, which could point at anything.
1140 // But a void[N] that is all 0 cannot point anywhere
1141 import std.algorithm.searching : any;
1142 if (__ctfe || any(cast(ubyte[]) source[]))
1143 return true;
1144 }
1145 else static if (n >= (void*).sizeof)
1146 {
1147 // Reinterpreting cast is impossible during ctfe
1148 if (__ctfe)
1149 return true;
1150
1151 // Only check for properly aligned pointers
1152 enum al = (void*).alignof - 1;
1153 const base = cast(size_t) &source;
1154 const alBase = (base + al) & ~al;
1155
1156 if ((n - (alBase - base)) >= (void*).sizeof &&
1157 mayPointTo(*(cast(void**) alBase), target))
1158 return true;
1159 }
1160 }
1161 else
1162 {
1163 foreach (size_t i; 0 .. S.length)
1164 if (mayPointTo(source[i], target)) return true;
1165 }
1166
1167 return false;
1168 }
1169 else static if (isDynamicArray!S)
1170 {
1171 import std.array : overlap;
1172 return overlap(cast(void[]) source, cast(void[])(&target)[0 .. 1]).length != 0;
1173 }
1174 else
1175 {
1176 return false;
1177 }
1178 }
1179
1180 // for shared objects
1181 /// ditto
1182 bool mayPointTo(S, T)(auto ref const shared S source, ref const shared T target) @trusted pure nothrow
1183 {
1184 return mayPointTo!(shared S, shared T, void)(source, target);
1185 }
1186
1187 /// Pointers
1188 @system unittest
1189 {
1190 int i = 0;
1191 int* p = null;
1192 assert(!p.doesPointTo(i));
1193 p = &i;
1194 assert( p.doesPointTo(i));
1195 }
1196
1197 /// Structs and Unions
1198 @system unittest
1199 {
1200 struct S
1201 {
1202 int v;
1203 int* p;
1204 }
1205 int i;
1206 auto s = S(0, &i);
1207
1208 // structs and unions "own" their members
1209 // pointsTo will answer true if one of the members pointsTo.
1210 assert(!s.doesPointTo(s.v)); //s.v is just v member of s, so not pointed.
1211 assert( s.p.doesPointTo(i)); //i is pointed by s.p.
1212 assert( s .doesPointTo(i)); //which means i is pointed by s itself.
1213
1214 // Unions will behave exactly the same. Points to will check each "member"
1215 // individually, even if they share the same memory
1216 }
1217
1218 /// Arrays (dynamic and static)
1219 @system unittest
1220 {
1221 int i;
1222 // trick the compiler when initializing slice
1223 // https://issues.dlang.org/show_bug.cgi?id=18637
1224 int* p = &i;
1225 int[] slice = [0, 1, 2, 3, 4];
1226 int[5] arr = [0, 1, 2, 3, 4];
1227 int*[] slicep = [p];
1228 int*[1] arrp = [&i];
1229
1230 // A slice points to all of its members:
1231 assert( slice.doesPointTo(slice[3]));
1232 assert(!slice[0 .. 2].doesPointTo(slice[3])); // Object 3 is outside of the
1233 // slice [0 .. 2]
1234
1235 // Note that a slice will not take into account what its members point to.
1236 assert( slicep[0].doesPointTo(i));
1237 assert(!slicep .doesPointTo(i));
1238
1239 // static arrays are objects that own their members, just like structs:
1240 assert(!arr.doesPointTo(arr[0])); // arr[0] is just a member of arr, so not
1241 // pointed.
1242 assert( arrp[0].doesPointTo(i)); // i is pointed by arrp[0].
1243 assert( arrp .doesPointTo(i)); // which means i is pointed by arrp
1244 // itself.
1245
1246 // Notice the difference between static and dynamic arrays:
1247 assert(!arr .doesPointTo(arr[0]));
1248 assert( arr[].doesPointTo(arr[0]));
1249 assert( arrp .doesPointTo(i));
1250 assert(!arrp[].doesPointTo(i));
1251 }
1252
1253 /// Classes
1254 @system unittest
1255 {
1256 class C
1257 {
1258 this(int* p){this.p = p;}
1259 int* p;
1260 }
1261 int i;
1262 C a = new C(&i);
1263 C b = a;
1264
1265 // Classes are a bit particular, as they are treated like simple pointers
1266 // to a class payload.
1267 assert( a.p.doesPointTo(i)); // a.p points to i.
1268 assert(!a .doesPointTo(i)); // Yet a itself does not point i.
1269
1270 //To check the class payload itself, iterate on its members:
1271 ()
1272 {
1273 import std.traits : Fields;
1274
1275 foreach (index, _; Fields!C)
1276 if (doesPointTo(a.tupleof[index], i))
1277 return;
1278 assert(0);
1279 }();
1280
1281 // To check if a class points a specific payload, a direct memmory check
1282 // can be done:
1283 auto aLoc = cast(ubyte[__traits(classInstanceSize, C)]*) a;
1284 assert(b.doesPointTo(*aLoc)); // b points to where a is pointing
1285 }
1286
1287
1288 version (StdUnittest)
1289 {
1290 // https://issues.dlang.org/show_bug.cgi?id=17084
1291 // the bug doesn't happen if these declarations are in the unittest block
1292 // (static or not).
1293 private struct Page17084
1294 {
1295 URL17084 url;
1296 int opCmp(P)(P) { return 0; }
1297 int opCmp(P)(shared(P)) shared { return 0; }
1298 }
1299
1300 private struct URL17084
1301 {
1302 int[] queryParams;
1303 string toString()() const { return ""; }
1304 alias toString this;
1305 }
1306 }
1307
1308 // https://issues.dlang.org/show_bug.cgi?id=17084
1309 @system unittest
1310 {
1311 import std.algorithm.sorting : sort;
1312 Page17084[] s;
1313 sort(s);
1314 shared(Page17084)[] p;
1315 sort(p);
1316 }
1317
1318 @system unittest
1319 {
1320 struct S1 { int a; S1 * b; }
1321 S1 a1;
1322 S1 * p = &a1;
1323 assert(doesPointTo(p, a1));
1324
1325 S1 a2;
1326 a2.b = &a1;
1327 assert(doesPointTo(a2, a1));
1328
1329 struct S3 { int[10] a; }
1330 S3 a3;
1331 auto a4 = a3.a[2 .. 3];
1332 assert(doesPointTo(a4, a3));
1333
1334 auto a5 = new double[4];
1335 auto a6 = a5[1 .. 2];
1336 assert(!doesPointTo(a5, a6));
1337
1338 auto a7 = new double[3];
1339 auto a8 = new double[][1];
1340 a8[0] = a7;
1341 assert(!doesPointTo(a8[0], a8[0]));
1342
1343 // don't invoke postblit on subobjects
1344 {
1345 static struct NoCopy { this(this) { assert(0); } }
1346 static struct Holder { NoCopy a, b, c; }
1347 Holder h;
1348 cast(void) doesPointTo(h, h);
1349 }
1350
1351 shared S3 sh3;
1352 shared sh3sub = sh3.a[];
1353 assert(doesPointTo(sh3sub, sh3));
1354
1355 int[] darr = [1, 2, 3, 4];
1356
1357 //dynamic arrays don't point to each other, or slices of themselves
1358 assert(!doesPointTo(darr, darr));
1359 assert(!doesPointTo(darr[0 .. 1], darr));
1360
1361 //But they do point their elements
1362 foreach (i; 0 .. 4)
1363 assert(doesPointTo(darr, darr[i]));
1364 assert(doesPointTo(darr[0 .. 3], darr[2]));
1365 assert(!doesPointTo(darr[0 .. 3], darr[3]));
1366 }
1367
1368 @system unittest
1369 {
1370 //tests with static arrays
1371 //Static arrays themselves are just objects, and don't really *point* to anything.
1372 //They aggregate their contents, much the same way a structure aggregates its attributes.
1373 //*However* The elements inside the static array may themselves point to stuff.
1374
1375 //Standard array
1376 int[2] k;
1377 assert(!doesPointTo(k, k)); //an array doesn't point to itself
1378 //Technically, k doesn't point its elements, although it does alias them
1379 assert(!doesPointTo(k, k[0]));
1380 assert(!doesPointTo(k, k[1]));
1381 //But an extracted slice will point to the same array.
1382 assert(doesPointTo(k[], k));
1383 assert(doesPointTo(k[], k[1]));
1384
1385 //An array of pointers
1386 int*[2] pp;
1387 int a;
1388 int b;
1389 pp[0] = &a;
1390 assert( doesPointTo(pp, a)); //The array contains a pointer to a
1391 assert(!doesPointTo(pp, b)); //The array does NOT contain a pointer to b
1392 assert(!doesPointTo(pp, pp)); //The array does not point itslef
1393
1394 //A struct containing a static array of pointers
1395 static struct S
1396 {
1397 int*[2] p;
1398 }
1399 S s;
1400 s.p[0] = &a;
1401 assert( doesPointTo(s, a)); //The struct contains an array that points a
1402 assert(!doesPointTo(s, b)); //But doesn't point b
1403 assert(!doesPointTo(s, s)); //The struct doesn't actually point itslef.
1404
1405 //An array containing structs that have pointers
1406 static struct SS
1407 {
1408 int* p;
1409 }
1410 SS[2] ss = [SS(&a), SS(null)];
1411 assert( doesPointTo(ss, a)); //The array contains a struct that points to a
1412 assert(!doesPointTo(ss, b)); //The array doesn't contains a struct that points to b
1413 assert(!doesPointTo(ss, ss)); //The array doesn't point itself.
1414
1415 // https://issues.dlang.org/show_bug.cgi?id=20426
1416 align((void*).alignof) void[32] voidArr = void;
1417 (cast(void*[]) voidArr[])[] = null; // Ensure no false pointers
1418
1419 // zeroed void ranges can't point at anything
1420 assert(!mayPointTo(voidArr, a));
1421 assert(!mayPointTo(voidArr, b));
1422
1423 *cast(void**) &voidArr[16] = &a; // Pointers should be found
1424
1425 alias SA = void[size_t.sizeof + 3];
1426 SA *smallArr1 = cast(SA*)&voidArr;
1427 SA *smallArr2 = cast(SA*)&(voidArr[16]);
1428
1429 // But it should only consider properly aligned pointers
1430 // Write single bytes to avoid issues due to misaligned writes
1431 void*[1] tmp = [&b];
1432 (cast(ubyte[]) voidArr[3 .. 3 + (void*).sizeof])[] = cast(ubyte[]) tmp[];
1433
1434
1435 assert( mayPointTo(*smallArr2, a));
1436 assert(!mayPointTo(*smallArr1, b));
1437
1438 assert(!doesPointTo(voidArr, a)); // Value might be a false pointer
1439 assert(!doesPointTo(voidArr, b));
1440
1441 SA *smallArr3 = cast(SA *) &voidArr[13]; // Works for weird sizes/alignments
1442 assert( mayPointTo(*smallArr3, a));
1443 assert(!mayPointTo(*smallArr3, b));
1444
1445 assert(!doesPointTo(*smallArr3, a));
1446 assert(!doesPointTo(*smallArr3, b));
1447
1448 auto v3 = cast(void[3]*) &voidArr[16]; // Arrays smaller than pointers are ignored
1449 assert(!mayPointTo(*v3, a));
1450 assert(!mayPointTo(*v3, b));
1451
1452 assert(!doesPointTo(*v3, a));
1453 assert(!doesPointTo(*v3, b));
1454
1455 assert(mayPointTo(voidArr, a)); // slice-contiaining void[N] might point at anything
1456 assert(mayPointTo(voidArr, b));
1457
1458 static assert(() {
1459 void[16] arr1 = void;
1460 void[size_t.sizeof] arr2 = void;
1461 int var;
1462 return mayPointTo(arr1, var) && !doesPointTo(arr1, var) &&
1463 mayPointTo(arr2, var) && !doesPointTo(arr2, var);
1464 }());
1465 }
1466
1467
1468 @system unittest //Unions
1469 {
1470 int i;
1471 union U //Named union
1472 {
1473 size_t asInt = 0;
1474 int* asPointer;
1475 }
1476 struct S
1477 {
1478 union //Anonymous union
1479 {
1480 size_t asInt = 0;
1481 int* asPointer;
1482 }
1483 }
1484
1485 U u;
1486 S s;
1487 assert(!doesPointTo(u, i));
1488 assert(!doesPointTo(s, i));
1489 assert(!mayPointTo(u, i));
1490 assert(!mayPointTo(s, i));
1491
1492 u.asPointer = &i;
1493 s.asPointer = &i;
1494 assert(!doesPointTo(u, i));
1495 assert(!doesPointTo(s, i));
1496 assert( mayPointTo(u, i));
1497 assert( mayPointTo(s, i));
1498
1499 u.asInt = cast(size_t)&i;
1500 s.asInt = cast(size_t)&i;
1501 assert(!doesPointTo(u, i));
1502 assert(!doesPointTo(s, i));
1503 assert( mayPointTo(u, i));
1504 assert( mayPointTo(s, i));
1505 }
1506
1507 @system unittest //Classes
1508 {
1509 int i;
1510 static class A
1511 {
1512 int* p;
1513 }
1514 A a = new A, b = a;
1515 assert(!doesPointTo(a, b)); //a does not point to b
1516 a.p = &i;
1517 assert(!doesPointTo(a, i)); //a does not point to i
1518 }
1519 @safe unittest //alias this test
1520 {
1521 static int i;
1522 static int j;
1523 struct S
1524 {
1525 int* p;
1526 @property int* foo(){return &i;}
1527 alias foo this;
1528 }
1529 assert(is(S : int*));
1530 S s = S(&j);
1531 assert(!doesPointTo(s, i));
1532 assert( doesPointTo(s, j));
1533 assert( doesPointTo(cast(int*) s, i));
1534 assert(!doesPointTo(cast(int*) s, j));
1535 }
1536 @safe unittest //more alias this opCast
1537 {
1538 void* p;
1539 class A
1540 {
1541 void* opCast(T)() if (is(T == void*))
1542 {
1543 return p;
1544 }
1545 alias foo = opCast!(void*);
1546 alias foo this;
1547 }
1548 assert(!doesPointTo(A.init, p));
1549 assert(!mayPointTo(A.init, p));
1550 }
1551
1552 /+
1553 Returns true if the field at index `i` in ($D T) shares its address with another field.
1554
1555 Note: This does not merelly check if the field is a member of an union, but also that
1556 it is not a single child.
1557 +/
1558 package enum isUnionAliased(T, size_t i) = isUnionAliasedImpl!T(T.tupleof[i].offsetof);
1559 private bool isUnionAliasedImpl(T)(size_t offset)
1560 {
1561 int count = 0;
1562 foreach (i, U; typeof(T.tupleof))
1563 if (T.tupleof[i].offsetof == offset)
1564 ++count;
1565 return count >= 2;
1566 }
1567 //
1568 @safe unittest
1569 {
1570 static struct S
1571 {
1572 int a0; //Not aliased
1573 union
1574 {
1575 int a1; //Not aliased
1576 }
1577 union
1578 {
1579 int a2; //Aliased
1580 int a3; //Aliased
1581 }
1582 union A4
1583 {
1584 int b0; //Not aliased
1585 }
1586 A4 a4;
1587 union A5
1588 {
1589 int b0; //Aliased
1590 int b1; //Aliased
1591 }
1592 A5 a5;
1593 }
1594
1595 static assert(!isUnionAliased!(S, 0)); //a0;
1596 static assert(!isUnionAliased!(S, 1)); //a1;
1597 static assert( isUnionAliased!(S, 2)); //a2;
1598 static assert( isUnionAliased!(S, 3)); //a3;
1599 static assert(!isUnionAliased!(S, 4)); //a4;
1600 static assert(!isUnionAliased!(S.A4, 0)); //a4.b0;
1601 static assert(!isUnionAliased!(S, 5)); //a5;
1602 static assert( isUnionAliased!(S.A5, 0)); //a5.b0;
1603 static assert( isUnionAliased!(S.A5, 1)); //a5.b1;
1604 }
1605
1606 version (CRuntime_Glibc) version = GNU_STRERROR;
1607 version (CRuntime_UClibc) version = GNU_STRERROR;
1608
1609 package string errnoString(int errno) nothrow @trusted
1610 {
1611 import core.stdc.string : strlen;
1612 version (GNU_STRERROR)
1613 {
1614 import core.stdc.string : strerror_r;
1615 char[1024] buf = void;
1616 auto s = strerror_r(errno, buf.ptr, buf.length);
1617 }
1618 else version (Posix)
1619 {
1620 // XSI-compliant
1621 import core.stdc.string : strerror_r;
1622 char[1024] buf = void;
1623 const(char)* s;
1624 if (strerror_r(errno, buf.ptr, buf.length) == 0)
1625 s = buf.ptr;
1626 else
1627 return "Unknown error";
1628 }
1629 else
1630 {
1631 import core.stdc.string : strerror;
1632 auto s = strerror(errno);
1633 }
1634 return s[0 .. s.strlen].idup;
1635 }
1636
1637 /*********************
1638 * Thrown if errors that set `errno` occur.
1639 */
1640 class ErrnoException : Exception
1641 {
1642 /// Operating system error code.
1643 final @property uint errno() nothrow pure scope @nogc @safe { return _errno; }
1644 private uint _errno;
1645 /// Constructor which takes an error message. The current global $(REF errno, core,stdc,errno) value is used as error code.
1646 this(string msg, string file = null, size_t line = 0) @safe
1647 {
1648 import core.stdc.errno : errno;
1649 this(msg, errno, file, line);
1650 }
1651 /// Constructor which takes an error message and error code.
1652 this(string msg, int errno, string file = null, size_t line = 0) @safe
1653 {
1654 _errno = errno;
1655 super(msg ~ " (" ~ errnoString(errno) ~ ")", file, line);
1656 }
1657 }
1658
1659 ///
1660 @safe unittest
1661 {
1662 import core.stdc.errno : EAGAIN;
1663 auto ex = new ErrnoException("oh no", EAGAIN);
1664 assert(ex.errno == EAGAIN);
1665 }
1666
1667 /// errno is used by default if no explicit error code is provided
1668 @safe unittest
1669 {
1670 import core.stdc.errno : errno, EAGAIN;
1671
1672 auto old = errno;
1673 scope(exit) errno = old;
1674
1675 // fake that errno got set by the callee
1676 errno = EAGAIN;
1677 auto ex = new ErrnoException("oh no");
1678 assert(ex.errno == EAGAIN);
1679 }
1680
1681 /++
1682 ML-style functional exception handling. Runs the supplied expression and
1683 returns its result. If the expression throws a `Throwable`, runs the
1684 supplied error handler instead and return its result. The error handler's
1685 type must be the same as the expression's type.
1686
1687 Params:
1688 E = The type of `Throwable`s to catch. Defaults to `Exception`
1689 T1 = The type of the expression.
1690 T2 = The return type of the error handler.
1691 expression = The expression to run and return its result.
1692 errorHandler = The handler to run if the expression throwed.
1693
1694 Returns:
1695 expression, if it does not throw. Otherwise, returns the result of
1696 errorHandler.
1697 +/
1698 //lazy version
1699 CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, lazy scope T2 errorHandler)
1700 {
1701 static assert(!is(typeof(return) == void),
1702 "The error handler's return value("
1703 ~ T2.stringof ~
1704 ") does not have a common type with the expression("
1705 ~ T1.stringof ~
1706 ")."
1707 );
1708 try
1709 {
1710 return expression();
1711 }
1712 catch (E)
1713 {
1714 return errorHandler();
1715 }
1716 }
1717
1718 ///ditto
1719 //delegate version
1720 CommonType!(T1, T2) ifThrown(E : Throwable, T1, T2)(lazy scope T1 expression, scope T2 delegate(E) errorHandler)
1721 {
1722 static assert(!is(typeof(return) == void),
1723 "The error handler's return value("
1724 ~ T2.stringof ~
1725 ") does not have a common type with the expression("
1726 ~ T1.stringof ~
1727 ")."
1728 );
1729 try
1730 {
1731 return expression();
1732 }
1733 catch (E e)
1734 {
1735 return errorHandler(e);
1736 }
1737 }
1738
1739 ///ditto
1740 //delegate version, general overload to catch any Exception
1741 CommonType!(T1, T2) ifThrown(T1, T2)(lazy scope T1 expression, scope T2 delegate(Exception) errorHandler)
1742 {
1743 static assert(!is(typeof(return) == void),
1744 "The error handler's return value("
1745 ~ T2.stringof ~
1746 ") does not have a common type with the expression("
1747 ~ T1.stringof ~
1748 ")."
1749 );
1750 try
1751 {
1752 return expression();
1753 }
1754 catch (Exception e)
1755 {
1756 return errorHandler(e);
1757 }
1758 }
1759
1760 /// Revert to a default value upon an error:
1761 @safe unittest
1762 {
1763 import std.conv : to;
1764 assert("x".to!int.ifThrown(0) == 0);
1765 }
1766
1767 /**
1768 Chain multiple calls to ifThrown, each capturing errors from the
1769 entire preceding expression.
1770 */
1771 @safe unittest
1772 {
1773 import std.conv : ConvException, to;
1774 string s = "true";
1775 assert(s.to!int.ifThrown(cast(int) s.to!double)
1776 .ifThrown(cast(int) s.to!bool) == 1);
1777
1778 s = "2.0";
1779 assert(s.to!int.ifThrown(cast(int) s.to!double)
1780 .ifThrown(cast(int) s.to!bool) == 2);
1781
1782 // Respond differently to different types of errors
1783 alias orFallback = (lazy a) => a.ifThrown!ConvException("not a number")
1784 .ifThrown!Exception("number too small");
1785
1786 assert(orFallback(enforce("x".to!int < 1).to!string) == "not a number");
1787 assert(orFallback(enforce("2".to!int < 1).to!string) == "number too small");
1788 }
1789
1790 /**
1791 The expression and the errorHandler must have a common type they can both
1792 be implicitly casted to, and that type will be the type of the compound
1793 expression.
1794 */
1795 @safe unittest
1796 {
1797 // null and new Object have a common type(Object).
1798 static assert(is(typeof(null.ifThrown(new Object())) == Object));
1799 static assert(is(typeof((new Object()).ifThrown(null)) == Object));
1800
1801 // 1 and new Object do not have a common type.
1802 static assert(!__traits(compiles, 1.ifThrown(new Object())));
1803 static assert(!__traits(compiles, (new Object()).ifThrown(1)));
1804 }
1805
1806 /// Use a lambda to get the thrown object.
1807 @system unittest
1808 {
1809 import std.format : format;
1810 assert("%s".format.ifThrown!Exception(e => e.classinfo.name) == "std.format.FormatException");
1811 }
1812
1813 //Verify Examples
1814 @system unittest
1815 {
1816 import std.conv;
1817 import std.string;
1818 //Revert to a default value upon an error:
1819 assert("x".to!int().ifThrown(0) == 0);
1820
1821 //Chaining multiple calls to ifThrown to attempt multiple things in a row:
1822 string s="true";
1823 assert(s.to!int().
1824 ifThrown(cast(int) s.to!double()).
1825 ifThrown(cast(int) s.to!bool())
1826 == 1);
1827
1828 //Respond differently to different types of errors
1829 assert(enforce("x".to!int() < 1).to!string()
1830 .ifThrown!ConvException("not a number")
1831 .ifThrown!Exception("number too small")
1832 == "not a number");
1833
1834 //null and new Object have a common type(Object).
1835 static assert(is(typeof(null.ifThrown(new Object())) == Object));
1836 static assert(is(typeof((new Object()).ifThrown(null)) == Object));
1837
1838 //1 and new Object do not have a common type.
1839 static assert(!__traits(compiles, 1.ifThrown(new Object())));
1840 static assert(!__traits(compiles, (new Object()).ifThrown(1)));
1841
1842 //Use a lambda to get the thrown object.
1843 assert("%s".format().ifThrown(e => e.classinfo.name) == "std.format.FormatException");
1844 }
1845
1846 @system unittest
1847 {
1848 import core.exception;
1849 import std.conv;
1850 import std.string;
1851 //Basic behaviour - all versions.
1852 assert("1".to!int().ifThrown(0) == 1);
1853 assert("x".to!int().ifThrown(0) == 0);
1854 assert("1".to!int().ifThrown!ConvException(0) == 1);
1855 assert("x".to!int().ifThrown!ConvException(0) == 0);
1856 assert("1".to!int().ifThrown(e=>0) == 1);
1857 assert("x".to!int().ifThrown(e=>0) == 0);
1858 static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled
1859 {
1860 assert("1".to!int().ifThrown!ConvException(e=>0) == 1);
1861 assert("x".to!int().ifThrown!ConvException(e=>0) == 0);
1862 }
1863
1864 //Exceptions other than stated not caught.
1865 assert("x".to!int().ifThrown!StringException(0).collectException!ConvException() !is null);
1866 static if (__traits(compiles, 0.ifThrown!Exception(e => 0))) //This will only work with a fix that was not yet pulled
1867 {
1868 assert("x".to!int().ifThrown!StringException(e=>0).collectException!ConvException() !is null);
1869 }
1870
1871 //Default does not include errors.
1872 int throwRangeError() { throw new RangeError; }
1873 assert(throwRangeError().ifThrown(0).collectException!RangeError() !is null);
1874 assert(throwRangeError().ifThrown(e=>0).collectException!RangeError() !is null);
1875
1876 //Incompatible types are not accepted.
1877 static assert(!__traits(compiles, 1.ifThrown(new Object())));
1878 static assert(!__traits(compiles, (new Object()).ifThrown(1)));
1879 static assert(!__traits(compiles, 1.ifThrown(e=>new Object())));
1880 static assert(!__traits(compiles, (new Object()).ifThrown(e=>1)));
1881 }
1882
1883 version (StdUnittest) package
1884 void assertCTFEable(alias dg)()
1885 {
1886 static assert({ cast(void) dg(); return true; }());
1887 cast(void) dg();
1888 }
1889
1890 /** This `enum` is used to select the primitives of the range to handle by the
1891 $(LREF handle) range wrapper. The values of the `enum` can be `OR`'d to
1892 select multiple primitives to be handled.
1893
1894 `RangePrimitive.access` is a shortcut for the access primitives; `front`,
1895 `back` and `opIndex`.
1896
1897 `RangePrimitive.pop` is a shortcut for the mutating primitives;
1898 `popFront` and `popBack`.
1899 */
1900 enum RangePrimitive
1901 {
1902 front = 0b00_0000_0001, ///
1903 back = 0b00_0000_0010, /// Ditto
1904 popFront = 0b00_0000_0100, /// Ditto
1905 popBack = 0b00_0000_1000, /// Ditto
1906 empty = 0b00_0001_0000, /// Ditto
1907 save = 0b00_0010_0000, /// Ditto
1908 length = 0b00_0100_0000, /// Ditto
1909 opDollar = 0b00_1000_0000, /// Ditto
1910 opIndex = 0b01_0000_0000, /// Ditto
1911 opSlice = 0b10_0000_0000, /// Ditto
1912 access = front | back | opIndex, /// Ditto
1913 pop = popFront | popBack, /// Ditto
1914 }
1915
1916 ///
1917 pure @safe unittest
1918 {
1919 import std.algorithm.comparison : equal;
1920 import std.algorithm.iteration : map, splitter;
1921 import std.conv : to, ConvException;
1922
1923 auto s = "12,1337z32,54,2,7,9,1z,6,8";
1924
1925 // The next line composition will throw when iterated
1926 // as some elements of the input do not convert to integer
1927 auto r = s.splitter(',').map!(a => to!int(a));
1928
1929 // Substitute 0 for cases of ConvException
1930 auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0);
1931 assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8]));
1932 }
1933
1934 ///
1935 pure @safe unittest
1936 {
1937 import std.algorithm.comparison : equal;
1938 import std.range : retro;
1939 import std.utf : UTFException;
1940
1941 auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit
1942
1943 auto handled = str.handle!(UTFException, RangePrimitive.access,
1944 (e, r) => ' '); // Replace invalid code points with spaces
1945
1946 assert(handled.equal("hello world")); // `front` is handled,
1947 assert(handled.retro.equal("dlrow olleh")); // as well as `back`
1948 }
1949
1950 /** Handle exceptions thrown from range primitives.
1951
1952 Use the $(LREF RangePrimitive) enum to specify which primitives to _handle.
1953 Multiple range primitives can be handled at once by using the `OR` operator
1954 or the pseudo-primitives `RangePrimitive.access` and `RangePrimitive.pop`.
1955 All handled primitives must have return types or values compatible with the
1956 user-supplied handler.
1957
1958 Params:
1959 E = The type of `Throwable` to _handle.
1960 primitivesToHandle = Set of range primitives to _handle.
1961 handler = The callable that is called when a handled primitive throws a
1962 `Throwable` of type `E`. The handler must accept arguments of
1963 the form $(D E, ref IRange) and its return value is used as the primitive's
1964 return value whenever `E` is thrown. For `opIndex`, the handler can
1965 optionally recieve a third argument; the index that caused the exception.
1966 input = The range to _handle.
1967
1968 Returns: A wrapper `struct` that preserves the range interface of `input`.
1969
1970 Note:
1971 Infinite ranges with slicing support must return an instance of
1972 $(REF Take, std,range) when sliced with a specific lower and upper
1973 bound (see $(REF hasSlicing, std,range,primitives)); `handle` deals with
1974 this by `take`ing 0 from the return value of the handler function and
1975 returning that when an exception is caught.
1976 */
1977 auto handle(E : Throwable, RangePrimitive primitivesToHandle, alias handler, Range)(Range input)
1978 if (isInputRange!Range)
1979 {
1980 static struct Handler
1981 {
1982 private Range range;
1983
1984 static if (isForwardRange!Range)
1985 {
1986 @property typeof(this) save()
1987 {
1988 static if (primitivesToHandle & RangePrimitive.save)
1989 {
1990 try
1991 {
1992 return typeof(this)(range.save);
1993 }
1994 catch (E exception)
1995 {
1996 return typeof(this)(handler(exception, this.range));
1997 }
1998 }
1999 else
2000 return typeof(this)(range.save);
2001 }
2002 }
2003
2004 static if (isInfinite!Range)
2005 {
2006 enum bool empty = false;
2007 }
2008 else
2009 {
2010 @property bool empty()
2011 {
2012 static if (primitivesToHandle & RangePrimitive.empty)
2013 {
2014 try
2015 {
2016 return this.range.empty;
2017 }
2018 catch (E exception)
2019 {
2020 return handler(exception, this.range);
2021 }
2022 }
2023 else
2024 return this.range.empty;
2025 }
2026 }
2027
2028 @property auto ref front()
2029 {
2030 static if (primitivesToHandle & RangePrimitive.front)
2031 {
2032 try
2033 {
2034 return this.range.front;
2035 }
2036 catch (E exception)
2037 {
2038 return handler(exception, this.range);
2039 }
2040 }
2041 else
2042 return this.range.front;
2043 }
2044
2045 void popFront()
2046 {
2047 static if (primitivesToHandle & RangePrimitive.popFront)
2048 {
2049 try
2050 {
2051 this.range.popFront();
2052 }
2053 catch (E exception)
2054 {
2055 handler(exception, this.range);
2056 }
2057 }
2058 else
2059 this.range.popFront();
2060 }
2061
2062 static if (isBidirectionalRange!Range)
2063 {
2064 @property auto ref back()
2065 {
2066 static if (primitivesToHandle & RangePrimitive.back)
2067 {
2068 try
2069 {
2070 return this.range.back;
2071 }
2072 catch (E exception)
2073 {
2074 return handler(exception, this.range);
2075 }
2076 }
2077 else
2078 return this.range.back;
2079 }
2080
2081 void popBack()
2082 {
2083 static if (primitivesToHandle & RangePrimitive.popBack)
2084 {
2085 try
2086 {
2087 this.range.popBack();
2088 }
2089 catch (E exception)
2090 {
2091 handler(exception, this.range);
2092 }
2093 }
2094 else
2095 this.range.popBack();
2096 }
2097 }
2098
2099 static if (isRandomAccessRange!Range)
2100 {
2101 auto ref opIndex(size_t index)
2102 {
2103 static if (primitivesToHandle & RangePrimitive.opIndex)
2104 {
2105 try
2106 {
2107 return this.range[index];
2108 }
2109 catch (E exception)
2110 {
2111 static if (__traits(compiles, handler(exception, this.range, index)))
2112 return handler(exception, this.range, index);
2113 else
2114 return handler(exception, this.range);
2115 }
2116 }
2117 else
2118 return this.range[index];
2119 }
2120 }
2121
2122 static if (hasLength!Range)
2123 {
2124 @property auto length()
2125 {
2126 static if (primitivesToHandle & RangePrimitive.length)
2127 {
2128 try
2129 {
2130 return this.range.length;
2131 }
2132 catch (E exception)
2133 {
2134 return handler(exception, this.range);
2135 }
2136 }
2137 else
2138 return this.range.length;
2139 }
2140 }
2141
2142 static if (hasSlicing!Range)
2143 {
2144 static if (hasLength!Range)
2145 {
2146 typeof(this) opSlice(size_t lower, size_t upper)
2147 {
2148 static if (primitivesToHandle & RangePrimitive.opSlice)
2149 {
2150 try
2151 {
2152 return typeof(this)(this.range[lower .. upper]);
2153 }
2154 catch (E exception)
2155 {
2156 return typeof(this)(handler(exception, this.range));
2157 }
2158 }
2159 else
2160 return typeof(this)(this.range[lower .. upper]);
2161 }
2162 }
2163 else static if (is(typeof(Range.init[size_t.init .. $])))
2164 {
2165 import std.range : Take, takeExactly;
2166 static struct DollarToken {}
2167 enum opDollar = DollarToken.init;
2168
2169 typeof(this) opSlice(size_t lower, DollarToken)
2170 {
2171 static if (primitivesToHandle & RangePrimitive.opSlice)
2172 {
2173 try
2174 {
2175 return typeof(this)(this.range[lower .. $]);
2176 }
2177 catch (E exception)
2178 {
2179 return typeof(this)(handler(exception, this.range));
2180 }
2181 }
2182 else
2183 return typeof(this)(this.range[lower .. $]);
2184 }
2185
2186 Take!Handler opSlice(size_t lower, size_t upper)
2187 {
2188 static if (primitivesToHandle & RangePrimitive.opSlice)
2189 {
2190 try
2191 {
2192 return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1);
2193 }
2194 catch (E exception)
2195 {
2196 return takeExactly(typeof(this)(handler(exception, this.range)), 0);
2197 }
2198 }
2199 else
2200 return takeExactly(typeof(this)(this.range[lower .. $]), upper - 1);
2201 }
2202 }
2203 }
2204 }
2205
2206 return Handler(input);
2207 }
2208
2209 ///
2210 pure @safe unittest
2211 {
2212 import std.algorithm.comparison : equal;
2213 import std.algorithm.iteration : map, splitter;
2214 import std.conv : to, ConvException;
2215
2216 auto s = "12,1337z32,54,2,7,9,1z,6,8";
2217
2218 // The next line composition will throw when iterated
2219 // as some elements of the input do not convert to integer
2220 auto r = s.splitter(',').map!(a => to!int(a));
2221
2222 // Substitute 0 for cases of ConvException
2223 auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0);
2224 assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8]));
2225 }
2226
2227 ///
2228 pure @safe unittest
2229 {
2230 import std.algorithm.comparison : equal;
2231 import std.range : retro;
2232 import std.utf : UTFException;
2233
2234 auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit
2235
2236 auto handled = str.handle!(UTFException, RangePrimitive.access,
2237 (e, r) => ' '); // Replace invalid code points with spaces
2238
2239 assert(handled.equal("hello world")); // `front` is handled,
2240 assert(handled.retro.equal("dlrow olleh")); // as well as `back`
2241 }
2242
2243 pure nothrow @safe unittest
2244 {
2245 static struct ThrowingRange
2246 {
2247 pure @safe:
2248 @property bool empty()
2249 {
2250 throw new Exception("empty has thrown");
2251 }
2252
2253 @property int front()
2254 {
2255 throw new Exception("front has thrown");
2256 }
2257
2258 @property int back()
2259 {
2260 throw new Exception("back has thrown");
2261 }
2262
2263 void popFront()
2264 {
2265 throw new Exception("popFront has thrown");
2266 }
2267
2268 void popBack()
2269 {
2270 throw new Exception("popBack has thrown");
2271 }
2272
2273 int opIndex(size_t)
2274 {
2275 throw new Exception("opIndex has thrown");
2276 }
2277
2278 ThrowingRange opSlice(size_t, size_t)
2279 {
2280 throw new Exception("opSlice has thrown");
2281 }
2282
2283 @property size_t length()
2284 {
2285 throw new Exception("length has thrown");
2286 }
2287
2288 alias opDollar = length;
2289
2290 @property ThrowingRange save()
2291 {
2292 throw new Exception("save has thrown");
2293 }
2294 }
2295
2296 static assert(isInputRange!ThrowingRange);
2297 static assert(isForwardRange!ThrowingRange);
2298 static assert(isBidirectionalRange!ThrowingRange);
2299 static assert(hasSlicing!ThrowingRange);
2300 static assert(hasLength!ThrowingRange);
2301
2302 auto f = ThrowingRange();
2303 auto fb = f.handle!(Exception, RangePrimitive.front | RangePrimitive.back,
2304 (e, r) => -1)();
2305 assert(fb.front == -1);
2306 assert(fb.back == -1);
2307 assertThrown(fb.popFront());
2308 assertThrown(fb.popBack());
2309 assertThrown(fb.empty);
2310 assertThrown(fb.save);
2311 assertThrown(fb[0]);
2312
2313 auto accessRange = f.handle!(Exception, RangePrimitive.access,
2314 (e, r) => -1);
2315 assert(accessRange.front == -1);
2316 assert(accessRange.back == -1);
2317 assert(accessRange[0] == -1);
2318 assertThrown(accessRange.popFront());
2319 assertThrown(accessRange.popBack());
2320
2321 auto pfb = f.handle!(Exception, RangePrimitive.pop, (e, r) => -1)();
2322
2323 pfb.popFront(); // this would throw otherwise
2324 pfb.popBack(); // this would throw otherwise
2325
2326 auto em = f.handle!(Exception,
2327 RangePrimitive.empty, (e, r) => false)();
2328
2329 assert(!em.empty);
2330
2331 auto arr = f.handle!(Exception,
2332 RangePrimitive.opIndex, (e, r) => 1337)();
2333
2334 assert(arr[0] == 1337);
2335
2336 auto arr2 = f.handle!(Exception,
2337 RangePrimitive.opIndex, (e, r, i) => i)();
2338
2339 assert(arr2[0] == 0);
2340 assert(arr2[1337] == 1337);
2341
2342 auto save = f.handle!(Exception,
2343 RangePrimitive.save,
2344 function(Exception e, ref ThrowingRange r) {
2345 return ThrowingRange();
2346 })();
2347
2348 save.save;
2349
2350 auto slice = f.handle!(Exception,
2351 RangePrimitive.opSlice, (e, r) => ThrowingRange())();
2352
2353 auto sliced = slice[0 .. 1337]; // this would throw otherwise
2354
2355 static struct Infinite
2356 {
2357 import std.range : Take;
2358 pure @safe:
2359 enum bool empty = false;
2360 int front() { assert(false); }
2361 void popFront() { assert(false); }
2362 Infinite save() @property { assert(false); }
2363 static struct DollarToken {}
2364 enum opDollar = DollarToken.init;
2365 Take!Infinite opSlice(size_t, size_t) { assert(false); }
2366 Infinite opSlice(size_t, DollarToken)
2367 {
2368 throw new Exception("opSlice has thrown");
2369 }
2370 }
2371
2372 static assert(isInputRange!Infinite);
2373 static assert(isInfinite!Infinite);
2374 static assert(hasSlicing!Infinite);
2375
2376 assertThrown(Infinite()[0 .. $]);
2377
2378 auto infinite = Infinite.init.handle!(Exception,
2379 RangePrimitive.opSlice, (e, r) => Infinite())();
2380
2381 auto infSlice = infinite[0 .. $]; // this would throw otherwise
2382 }
2383
2384
2385 /++
2386 Convenience mixin for trivially sub-classing exceptions
2387
2388 Even trivially sub-classing an exception involves writing boilerplate code
2389 for the constructor to: 1$(RPAREN) correctly pass in the source file and line number
2390 the exception was thrown from; 2$(RPAREN) be usable with $(LREF enforce) which
2391 expects exception constructors to take arguments in a fixed order. This
2392 mixin provides that boilerplate code.
2393
2394 Note however that you need to mark the $(B mixin) line with at least a
2395 minimal (i.e. just $(B ///)) DDoc comment if you want the mixed-in
2396 constructors to be documented in the newly created Exception subclass.
2397
2398 $(RED Current limitation): Due to
2399 $(LINK2 https://issues.dlang.org/show_bug.cgi?id=11500, bug #11500),
2400 currently the constructors specified in this mixin cannot be overloaded with
2401 any other custom constructors. Thus this mixin can currently only be used
2402 when no such custom constructors need to be explicitly specified.
2403 +/
2404 mixin template basicExceptionCtors()
2405 {
2406 /++
2407 Params:
2408 msg = The message for the exception.
2409 file = The file where the exception occurred.
2410 line = The line number where the exception occurred.
2411 next = The previous exception in the chain of exceptions, if any.
2412 +/
2413 this(string msg, string file = __FILE__, size_t line = __LINE__,
2414 Throwable next = null) @nogc @safe pure nothrow
2415 {
2416 super(msg, file, line, next);
2417 }
2418
2419 /++
2420 Params:
2421 msg = The message for the exception.
2422 next = The previous exception in the chain of exceptions.
2423 file = The file where the exception occurred.
2424 line = The line number where the exception occurred.
2425 +/
2426 this(string msg, Throwable next, string file = __FILE__,
2427 size_t line = __LINE__) @nogc @safe pure nothrow
2428 {
2429 super(msg, file, line, next);
2430 }
2431 }
2432
2433 ///
2434 @safe unittest
2435 {
2436 class MeaCulpa: Exception
2437 {
2438 ///
2439 mixin basicExceptionCtors;
2440 }
2441
2442 try
2443 throw new MeaCulpa("test");
2444 catch (MeaCulpa e)
2445 {
2446 assert(e.msg == "test");
2447 assert(e.file == __FILE__);
2448 assert(e.line == __LINE__ - 5);
2449 }
2450 }
2451
2452 @safe pure nothrow unittest
2453 {
2454 class TestException : Exception { mixin basicExceptionCtors; }
2455 auto e = new Exception("msg");
2456 auto te1 = new TestException("foo");
2457 auto te2 = new TestException("foo", e);
2458 }
2459
2460 @safe unittest
2461 {
2462 class TestException : Exception { mixin basicExceptionCtors; }
2463 auto e = new Exception("!!!");
2464
2465 auto te1 = new TestException("message", "file", 42, e);
2466 assert(te1.msg == "message");
2467 assert(te1.file == "file");
2468 assert(te1.line == 42);
2469 assert(te1.next is e);
2470
2471 auto te2 = new TestException("message", e, "file", 42);
2472 assert(te2.msg == "message");
2473 assert(te2.file == "file");
2474 assert(te2.line == 42);
2475 assert(te2.next is e);
2476
2477 auto te3 = new TestException("foo");
2478 assert(te3.msg == "foo");
2479 assert(te3.file == __FILE__);
2480 assert(te3.line == __LINE__ - 3);
2481 assert(te3.next is null);
2482
2483 auto te4 = new TestException("foo", e);
2484 assert(te4.msg == "foo");
2485 assert(te4.file == __FILE__);
2486 assert(te4.line == __LINE__ - 3);
2487 assert(te4.next is e);
2488 }