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