1 // Written in the D programming language.
2 
3 /**
4 A one-stop shop for converting values from one type to another.
5 
6 $(SCRIPT inhibitQuickIndex = 1;)
7 $(DIVC quickindex,
8 $(BOOKTABLE,
9 $(TR $(TH Category) $(TH Functions))
10 $(TR $(TD Generic) $(TD
11         $(LREF asOriginalType)
12         $(LREF castFrom)
13         $(LREF parse)
14         $(LREF to)
15         $(LREF toChars)
16         $(LREF bitCast)
17 ))
18 $(TR $(TD Strings) $(TD
19         $(LREF text)
20         $(LREF wtext)
21         $(LREF dtext)
22         $(LREF writeText)
23         $(LREF writeWText)
24         $(LREF writeDText)
25         $(LREF hexString)
26 ))
27 $(TR $(TD Numeric) $(TD
28         $(LREF octal)
29         $(LREF roundTo)
30         $(LREF signed)
31         $(LREF unsigned)
32 ))
33 $(TR $(TD Exceptions) $(TD
34         $(LREF ConvException)
35         $(LREF ConvOverflowException)
36 ))
37 ))
38 
39 Copyright: Copyright The D Language Foundation 2007-.
40 
41 License:   $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0).
42 
43 Authors:   $(HTTP digitalmars.com, Walter Bright),
44            $(HTTP erdani.org, Andrei Alexandrescu),
45            Shin Fujishiro,
46            Adam D. Ruppe,
47            Kenji Hara
48 
49 Source:    $(PHOBOSSRC std/conv.d)
50 
51 */
52 module std.conv;
53 
54 public import std.ascii : LetterCase;
55 
56 import std.meta;
57 import std.range;
58 import std.traits;
59 import std.typecons : Flag, Yes, No, tuple, isTuple;
60 
61 // Same as std.string.format, but "self-importing".
62 // Helps reduce code and imports, particularly in static asserts.
63 // Also helps with missing imports errors.
64 package template convFormat()
65 {
66     import std.format : format;
67     alias convFormat = format;
68 }
69 
70 /* ************* Exceptions *************** */
71 
72 /**
73  * Thrown on conversion errors.
74  */
75 class ConvException : Exception
76 {
77     import std.exception : basicExceptionCtors;
78     ///
79     mixin basicExceptionCtors;
80 }
81 
82 ///
83 @safe unittest
84 {
85     import std.exception : assertThrown;
86     assertThrown!ConvException(to!int("abc"));
87 }
88 
89 private auto convError(S, T)(S source, string fn = __FILE__, size_t ln = __LINE__)
90 {
91     string msg;
92 
93     if (source.empty)
94         msg = "Unexpected end of input when converting from type " ~ S.stringof ~ " to type " ~ T.stringof;
95     else
96     {
97         ElementType!S el = source.front;
98 
99         if (el == '\n')
100             msg = text("Unexpected '\\n' when converting from type " ~ S.stringof ~ " to type " ~ T.stringof);
101         else
102             msg =  text("Unexpected '", el,
103                  "' when converting from type " ~ S.stringof ~ " to type " ~ T.stringof);
104     }
105 
106     return new ConvException(msg, fn, ln);
107 }
108 
109 @safe pure/* nothrow*/  // lazy parameter bug
110 private auto parseError(lazy string msg, string fn = __FILE__, size_t ln = __LINE__)
111 {
112     return new ConvException(text("Can't parse string: ", msg), fn, ln);
113 }
114 
115 private void parseCheck(alias source)(dchar c, string fn = __FILE__, size_t ln = __LINE__)
116 {
117     if (source.empty)
118         throw parseError(text("unexpected end of input when expecting \"", c, "\""));
119     if (source.front != c)
120         throw parseError(text("\"", c, "\" is missing"), fn, ln);
121     source.popFront();
122 }
123 
124 private
125 {
126     T toStr(T, S)(S src)
127     if (isSomeString!T)
128     {
129         // workaround for https://issues.dlang.org/show_bug.cgi?id=14198
130         static if (is(S == bool) && is(typeof({ T s = "string"; })))
131         {
132             return src ? "true" : "false";
133         }
134         else
135         {
136             import std.array : appender;
137             import std.format.spec : FormatSpec;
138             import std.format.write : formatValue;
139 
140             auto w = appender!T();
141             FormatSpec!(ElementEncodingType!T) f;
142             formatValue(w, src, f);
143             return w.data;
144         }
145     }
146 
147     template isExactSomeString(T)
148     {
149         enum isExactSomeString = isSomeString!T && !is(T == enum);
150     }
151 
152     template isEnumStrToStr(S, T)
153     {
154         enum isEnumStrToStr = is(S : T) &&
155                               is(S == enum) && isExactSomeString!T;
156     }
157     template isNullToStr(S, T)
158     {
159         enum isNullToStr = is(S : T) &&
160                            (is(immutable S == immutable typeof(null))) && isExactSomeString!T;
161     }
162 }
163 
164 /**
165  * Thrown on conversion overflow errors.
166  */
167 class ConvOverflowException : ConvException
168 {
169     @safe pure nothrow
170     this(string s, string fn = __FILE__, size_t ln = __LINE__)
171     {
172         super(s, fn, ln);
173     }
174 }
175 
176 ///
177 @safe unittest
178 {
179     import std.exception : assertThrown;
180     assertThrown!ConvOverflowException(to!ubyte(1_000_000));
181 }
182 
183 /**
184 The `to` template converts a value from one type _to another.
185 The source type is deduced and the target type must be specified, for example the
186 expression `to!int(42.0)` converts the number 42 from
187 `double` _to `int`. The conversion is "safe", i.e.,
188 it checks for overflow; `to!int(4.2e10)` would throw the
189 `ConvOverflowException` exception. Overflow checks are only
190 inserted when necessary, e.g., `to!double(42)` does not do
191 any checking because any `int` fits in a `double`.
192 
193 Conversions from string _to numeric types differ from the C equivalents
194 `atoi()` and `atol()` by checking for overflow and not allowing whitespace.
195 
196 For conversion of strings _to signed types, the grammar recognized is:
197 $(PRE $(I Integer):
198     $(I Sign UnsignedInteger)
199     $(I UnsignedInteger)
200 $(I Sign):
201     $(B +)
202     $(B -))
203 
204 For conversion _to unsigned types, the grammar recognized is:
205 $(PRE $(I UnsignedInteger):
206     $(I DecimalDigit)
207     $(I DecimalDigit) $(I UnsignedInteger))
208  */
209 template to(T)
210 {
211     T to(A...)(A args)
212     if (A.length > 0)
213     {
214         return toImpl!T(args);
215     }
216 
217     // Fix https://issues.dlang.org/show_bug.cgi?id=6175
218     T to(S)(ref S arg)
219     if (isStaticArray!S)
220     {
221         return toImpl!T(arg);
222     }
223 
224     // Fix https://issues.dlang.org/show_bug.cgi?id=16108
225     T to(S)(ref S arg)
226     if (isAggregateType!S && !isCopyable!S)
227     {
228         return toImpl!T(arg);
229     }
230 }
231 
232 /**
233  * Converting a value _to its own type (useful mostly for generic code)
234  * simply returns its argument.
235  */
236 @safe pure unittest
237 {
238     int a = 42;
239     int b = to!int(a);
240     double c = to!double(3.14); // c is double with value 3.14
241 }
242 
243 /**
244  * Converting among numeric types is a safe way _to cast them around.
245  *
246  * Conversions from floating-point types _to integral types allow loss of
247  * precision (the fractional part of a floating-point number). The
248  * conversion is truncating towards zero, the same way a cast would
249  * truncate. (_To round a floating point value when casting _to an
250  * integral, use `roundTo`.)
251  */
252 @safe pure unittest
253 {
254     import std.exception : assertThrown;
255 
256     int a = 420;
257     assert(to!long(a) == a);
258     assertThrown!ConvOverflowException(to!byte(a));
259 
260     assert(to!int(4.2e6) == 4200000);
261     assertThrown!ConvOverflowException(to!uint(-3.14));
262     assert(to!uint(3.14) == 3);
263     assert(to!uint(3.99) == 3);
264     assert(to!int(-3.99) == -3);
265 }
266 
267 /**
268  * When converting strings _to numeric types, note that D hexadecimal and binary
269  * literals are not handled. Neither the prefixes that indicate the base, nor the
270  * horizontal bar used _to separate groups of digits are recognized. This also
271  * applies to the suffixes that indicate the type.
272  *
273  * _To work around this, you can specify a radix for conversions involving numbers.
274  */
275 @safe pure unittest
276 {
277     auto str = to!string(42, 16);
278     assert(str == "2A");
279     auto i = to!int(str, 16);
280     assert(i == 42);
281 }
282 
283 /**
284  * Conversions from integral types _to floating-point types always
285  * succeed, but might lose accuracy. The largest integers with a
286  * predecessor representable in floating-point format are `2^24-1` for
287  * `float`, `2^53-1` for `double`, and `2^64-1` for `real` (when
288  * `real` is 80-bit, e.g. on Intel machines).
289  */
290 @safe pure unittest
291 {
292     // 2^24 - 1, largest proper integer representable as float
293     int a = 16_777_215;
294     assert(to!int(to!float(a)) == a);
295     assert(to!int(to!float(-a)) == -a);
296 }
297 
298 /**
299    Conversion from string types to char types enforces the input
300    to consist of a single code point, and said code point must
301    fit in the target type. Otherwise, $(LREF ConvException) is thrown.
302  */
303 @safe pure unittest
304 {
305     import std.exception : assertThrown;
306 
307     assert(to!char("a") == 'a');
308     assertThrown(to!char("ñ")); // 'ñ' does not fit into a char
309     assert(to!wchar("ñ") == 'ñ');
310     assertThrown(to!wchar("😃")); // '😃' does not fit into a wchar
311     assert(to!dchar("😃") == '😃');
312 
313     // Using wstring or dstring as source type does not affect the result
314     assert(to!char("a"w) == 'a');
315     assert(to!char("a"d) == 'a');
316 
317     // Two code points cannot be converted to a single one
318     assertThrown(to!char("ab"));
319 }
320 
321 /**
322  * Converting an array _to another array type works by converting each
323  * element in turn. Associative arrays can be converted _to associative
324  * arrays as long as keys and values can in turn be converted.
325  */
326 @safe pure unittest
327 {
328     import std.string : split;
329 
330     int[] a = [1, 2, 3];
331     auto b = to!(float[])(a);
332     assert(b == [1.0f, 2, 3]);
333     string str = "1 2 3 4 5 6";
334     auto numbers = to!(double[])(split(str));
335     assert(numbers == [1.0, 2, 3, 4, 5, 6]);
336     int[string] c;
337     c["a"] = 1;
338     c["b"] = 2;
339     auto d = to!(double[wstring])(c);
340     assert(d["a"w] == 1 && d["b"w] == 2);
341 }
342 
343 /**
344  * Conversions operate transitively, meaning that they work on arrays and
345  * associative arrays of any complexity.
346  *
347  * This conversion works because `to!short` applies _to an `int`, `to!wstring`
348  * applies _to a `string`, `to!string` applies _to a `double`, and
349  * `to!(double[])` applies _to an `int[]`. The conversion might throw an
350  * exception because `to!short` might fail the range check.
351  */
352 @safe unittest
353 {
354     int[string][double[int[]]] a;
355     auto b = to!(short[wstring][string[double[]]])(a);
356 }
357 
358 /**
359  * Object-to-object conversions by dynamic casting throw exception when
360  * the source is non-null and the target is null.
361  */
362 @safe pure unittest
363 {
364     import std.exception : assertThrown;
365     // Testing object conversions
366     class A {}
367     class B : A {}
368     class C : A {}
369     A a1 = new A, a2 = new B, a3 = new C;
370     assert(to!B(a2) is a2);
371     assert(to!C(a3) is a3);
372     assertThrown!ConvException(to!B(a3));
373 }
374 
375 /**
376  * Stringize conversion from all types is supported.
377  * $(UL
378  *   $(LI String _to string conversion works for any two string types having
379  *        (`char`, `wchar`, `dchar`) character widths and any
380  *        combination of qualifiers (mutable, `const`, or `immutable`).)
381  *   $(LI Converts array (other than strings) _to string.
382  *        Each element is converted by calling `to!T`.)
383  *   $(LI Associative array _to string conversion.
384  *        Each element is converted by calling `to!T`.)
385  *   $(LI Object _to string conversion calls `toString` against the object or
386  *        returns `"null"` if the object is null.)
387  *   $(LI Struct _to string conversion calls `toString` against the struct if
388  *        it is defined.)
389  *   $(LI For structs that do not define `toString`, the conversion _to string
390  *        produces the list of fields.)
391  *   $(LI Enumerated types are converted _to strings as their symbolic names.)
392  *   $(LI Boolean values are converted to `"true"` or `"false"`.)
393  *   $(LI `char`, `wchar`, `dchar` _to a string type.)
394  *   $(LI Unsigned or signed integers _to strings.
395  *        $(DL $(DT [special case])
396  *             $(DD Convert integral value _to string in $(D_PARAM radix) radix.
397  *             radix must be a value from 2 to 36.
398  *             value is treated as a signed value only if radix is 10.
399  *             The characters A through Z are used to represent values 10 through 36
400  *             and their case is determined by the $(D_PARAM letterCase) parameter.)))
401  *   $(LI All floating point types _to all string types.)
402  *   $(LI Pointer to string conversions convert the pointer to a `size_t` value.
403  *        If pointer is `char*`, treat it as C-style strings.
404  *        In that case, this function is `@system`.))
405  * See $(REF formatValue, std,format) on how `toString` should be defined.
406  */
407 @system pure unittest // @system due to cast and ptr
408 {
409     // Conversion representing dynamic/static array with string
410     long[] a = [ 1, 3, 5 ];
411     assert(to!string(a) == "[1, 3, 5]");
412 
413     // Conversion representing associative array with string
414     int[string] associativeArray = ["0":1, "1":2];
415     assert(to!string(associativeArray) == `["0":1, "1":2]` ||
416            to!string(associativeArray) == `["1":2, "0":1]`);
417 
418     // char* to string conversion
419     assert(to!string(cast(char*) null) == "");
420     assert(to!string("foo\0".ptr) == "foo");
421 
422     // Conversion reinterpreting void array to string
423     auto w = "abcx"w;
424     const(void)[] b = w;
425     assert(b.length == 8);
426 
427     auto c = to!(wchar[])(b);
428     assert(c == "abcx");
429 }
430 
431 /**
432  * Strings can be converted to enum types. The enum member with the same name as the
433  * input string is returned. The comparison is case-sensitive.
434  *
435  * A $(LREF ConvException) is thrown if the enum does not have the specified member.
436  */
437 @safe pure unittest
438 {
439     import std.exception : assertThrown;
440 
441     enum E { a, b, c }
442     assert(to!E("a") == E.a);
443     assert(to!E("b") == E.b);
444     assertThrown!ConvException(to!E("A"));
445 }
446 
447 // Tests for https://issues.dlang.org/show_bug.cgi?id=6175
448 @safe pure nothrow unittest
449 {
450     char[9] sarr = "blablabla";
451     auto darr = to!(char[])(sarr);
452     assert(sarr.ptr == darr.ptr);
453     assert(sarr.length == darr.length);
454 }
455 
456 // Tests for https://issues.dlang.org/show_bug.cgi?id=7348
457 @safe pure /+nothrow+/ unittest
458 {
459     assert(to!string(null) == "null");
460     assert(text(null) == "null");
461 }
462 
463 // Test `scope` inference of parameters of `text`
464 @safe unittest
465 {
466     static struct S
467     {
468         int* x; // make S a type with pointers
469         string toString() const scope
470         {
471             return "S";
472         }
473     }
474     scope S s;
475     assert(text("a", s) == "aS");
476 }
477 
478 // Tests for https://issues.dlang.org/show_bug.cgi?id=11390
479 @safe pure /+nothrow+/ unittest
480 {
481     const(typeof(null)) ctn;
482     immutable(typeof(null)) itn;
483     assert(to!string(ctn) == "null");
484     assert(to!string(itn) == "null");
485 }
486 
487 // Tests for https://issues.dlang.org/show_bug.cgi?id=8729: do NOT skip leading WS
488 @safe pure unittest
489 {
490     import std.exception;
491     static foreach (T; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
492     {
493         assertThrown!ConvException(to!T(" 0"));
494         assertThrown!ConvException(to!T(" 0", 8));
495     }
496     static foreach (T; AliasSeq!(float, double, real))
497     {
498         assertThrown!ConvException(to!T(" 0"));
499     }
500 
501     assertThrown!ConvException(to!bool(" true"));
502 
503     alias NullType = typeof(null);
504     assertThrown!ConvException(to!NullType(" null"));
505 
506     alias ARR = int[];
507     assertThrown!ConvException(to!ARR(" [1]"));
508 
509     alias AA = int[int];
510     assertThrown!ConvException(to!AA(" [1:1]"));
511 }
512 
513 // https://issues.dlang.org/show_bug.cgi?id=20623
514 @safe pure nothrow unittest
515 {
516     // static class C
517     // {
518     //     override string toString() const
519     //     {
520     //         return "C()";
521     //     }
522     // }
523 
524     static struct S
525     {
526         bool b;
527         int i;
528         float f;
529         int[] a;
530         int[int] aa;
531         S* p;
532         // C c; // TODO: Fails because of hasToString
533 
534         void fun() inout
535         {
536             static foreach (const idx; 0 .. this.tupleof.length)
537             {
538                 {
539                     const _ = this.tupleof[idx].to!string();
540                 }
541             }
542         }
543     }
544 }
545 
546 private T toImpl(T, S)(S)
547 if (isInputRange!S && isInfinite!S && isExactSomeString!T)
548 {
549     static assert(0, "Cannot convert infinite range to string. " ~
550                 "Use `std.range.take` or `std.range.takeExactly` to make it finite.");
551 }
552 
553 // Test for issue : https://github.com/dlang/phobos/issues/10559
554 @safe pure nothrow unittest
555 {
556     import std.range : repeat;
557     import std.conv : to;
558 
559     // Test that converting an infinite range doesn't compile
560     static assert(!__traits(compiles, repeat(1).to!string));
561 }
562 
563 /**
564 If the source type is implicitly convertible to the target type, $(D
565 to) simply performs the implicit conversion.
566  */
567 private T toImpl(T, S)(S value)
568 if (is(S : T) &&
569     !isEnumStrToStr!(S, T) && !isNullToStr!(S, T))
570 {
571     template isSignedInt(T)
572     {
573         enum isSignedInt = isIntegral!T && isSigned!T;
574     }
575     alias isUnsignedInt = isUnsigned;
576 
577     // Conversion from integer to integer, and changing its sign
578     static if (isUnsignedInt!S && isSignedInt!T && S.sizeof == T.sizeof)
579     {   // unsigned to signed & same size
580         import std.exception : enforce;
581         enforce(value <= cast(S) T.max,
582                 new ConvOverflowException("Conversion positive overflow"));
583     }
584     else static if (isSignedInt!S && isUnsignedInt!T)
585     {   // signed to unsigned
586         import std.exception : enforce;
587         enforce(0 <= value,
588                 new ConvOverflowException("Conversion negative overflow"));
589     }
590 
591     return value;
592 }
593 
594 // https://issues.dlang.org/show_bug.cgi?id=9523: Allow identity enum conversion
595 @safe pure nothrow unittest
596 {
597     enum E { a }
598     auto e = to!E(E.a);
599     assert(e == E.a);
600 }
601 
602 @safe pure nothrow unittest
603 {
604     int a = 42;
605     auto b = to!long(a);
606     assert(a == b);
607 }
608 
609 // https://issues.dlang.org/show_bug.cgi?id=6377
610 @safe pure unittest
611 {
612     import std.exception;
613     // Conversion between same size
614     static foreach (S; AliasSeq!(byte, short, int, long))
615     {{
616         alias U = Unsigned!S;
617 
618         static foreach (Sint; AliasSeq!(S, const S, immutable S))
619         static foreach (Uint; AliasSeq!(U, const U, immutable U))
620         {{
621             // positive overflow
622             Uint un = Uint.max;
623             assertThrown!ConvOverflowException(to!Sint(un),
624                 text(Sint.stringof, ' ', Uint.stringof, ' ', un));
625 
626             // negative overflow
627             Sint sn = -1;
628             assertThrown!ConvOverflowException(to!Uint(sn),
629                 text(Sint.stringof, ' ', Uint.stringof, ' ', un));
630         }}
631     }}
632 
633     // Conversion between different size
634     static foreach (i, S1; AliasSeq!(byte, short, int, long))
635     static foreach (   S2; AliasSeq!(byte, short, int, long)[i+1..$])
636     {{
637         alias U1 = Unsigned!S1;
638         alias U2 = Unsigned!S2;
639 
640         static assert(U1.sizeof < S2.sizeof);
641 
642         // small unsigned to big signed
643         static foreach (Uint; AliasSeq!(U1, const U1, immutable U1))
644         static foreach (Sint; AliasSeq!(S2, const S2, immutable S2))
645         {{
646             Uint un = Uint.max;
647             assertNotThrown(to!Sint(un));
648             assert(to!Sint(un) == un);
649         }}
650 
651         // big unsigned to small signed
652         static foreach (Uint; AliasSeq!(U2, const U2, immutable U2))
653         static foreach (Sint; AliasSeq!(S1, const S1, immutable S1))
654         {{
655             Uint un = Uint.max;
656             assertThrown(to!Sint(un));
657         }}
658 
659         static assert(S1.sizeof < U2.sizeof);
660 
661         // small signed to big unsigned
662         static foreach (Sint; AliasSeq!(S1, const S1, immutable S1))
663         static foreach (Uint; AliasSeq!(U2, const U2, immutable U2))
664         {{
665             Sint sn = -1;
666             assertThrown!ConvOverflowException(to!Uint(sn));
667         }}
668 
669         // big signed to small unsigned
670         static foreach (Sint; AliasSeq!(S2, const S2, immutable S2))
671         static foreach (Uint; AliasSeq!(U1, const U1, immutable U1))
672         {{
673             Sint sn = -1;
674             assertThrown!ConvOverflowException(to!Uint(sn));
675         }}
676     }}
677 }
678 
679 // https://issues.dlang.org/show_bug.cgi?id=13551
680 private T toImpl(T, S)(S value)
681 if (isTuple!T)
682 {
683     T t;
684     static foreach (i; 0 .. T.length)
685     {
686         t[i] = value[i].to!(typeof(T[i]));
687     }
688     return t;
689 }
690 
691 @safe unittest
692 {
693     import std.typecons : Tuple;
694 
695     auto test = ["10", "20", "30"];
696     assert(test.to!(Tuple!(int, int, int)) == Tuple!(int, int, int)(10, 20, 30));
697 
698     auto test1 = [1, 2];
699     assert(test1.to!(Tuple!(int, int)) == Tuple!(int, int)(1, 2));
700 
701     auto test2 = [1.0, 2.0, 3.0];
702     assert(test2.to!(Tuple!(int, int, int)) == Tuple!(int, int, int)(1, 2, 3));
703 }
704 
705 /*
706   Converting static arrays forwards to their dynamic counterparts.
707  */
708 private T toImpl(T, S)(ref S s)
709 if (isStaticArray!S)
710 {
711     return toImpl!(T, typeof(s[0])[])(s);
712 }
713 
714 @safe pure nothrow unittest
715 {
716     char[4] test = ['a', 'b', 'c', 'd'];
717     static assert(!isInputRange!(Unqual!(char[4])));
718     assert(to!string(test) == test);
719 }
720 
721 /**
722 When source type supports member template function opCast, it is used.
723 */
724 private T toImpl(T, S)(S value)
725 if (!is(S : T) &&
726     is(typeof(S.init.opCast!T()) : T) &&
727     !isExactSomeString!T &&
728     !is(typeof(T(value))))
729 {
730     return value.opCast!T();
731 }
732 
733 @safe pure unittest
734 {
735     static struct Test
736     {
737         struct T
738         {
739             this(S s) @safe pure { }
740         }
741         struct S
742         {
743             T opCast(U)() @safe pure { assert(false); }
744         }
745     }
746     cast(void) to!(Test.T)(Test.S());
747 
748     // make sure std.conv.to is doing the same thing as initialization
749     Test.S s;
750     Test.T t = s;
751 }
752 
753 @safe pure unittest
754 {
755     class B
756     {
757         T opCast(T)() { return 43; }
758     }
759     auto b = new B;
760     assert(to!int(b) == 43);
761 
762     struct S
763     {
764         T opCast(T)() { return 43; }
765     }
766     auto s = S();
767     assert(to!int(s) == 43);
768 }
769 
770 /**
771 When target type supports 'converting construction', it is used.
772 $(UL $(LI If target type is struct, `T(value)` is used.)
773      $(LI If target type is class, $(D new T(value)) is used.))
774 */
775 private T toImpl(T, S)(S value)
776 if (!is(S : T) &&
777     is(T == struct) && is(typeof(T(value))))
778 {
779     return T(value);
780 }
781 
782 // https://issues.dlang.org/show_bug.cgi?id=3961
783 @safe pure unittest
784 {
785     struct Int
786     {
787         int x;
788     }
789     Int i = to!Int(1);
790 
791     static struct Int2
792     {
793         int x;
794         this(int x) @safe pure { this.x = x; }
795     }
796     Int2 i2 = to!Int2(1);
797 
798     static struct Int3
799     {
800         int x;
801         static Int3 opCall(int x) @safe pure
802         {
803             Int3 i;
804             i.x = x;
805             return i;
806         }
807     }
808     Int3 i3 = to!Int3(1);
809 }
810 
811 // https://issues.dlang.org/show_bug.cgi?id=6808
812 @safe pure unittest
813 {
814     static struct FakeBigInt
815     {
816         this(string s) @safe pure {}
817     }
818 
819     string s = "101";
820     auto i3 = to!FakeBigInt(s);
821 }
822 
823 /// ditto
824 private T toImpl(T, S)(S value)
825 if (!is(S : T) &&
826     is(T == class) && is(typeof(new T(value))))
827 {
828     return new T(value);
829 }
830 
831 @safe pure unittest
832 {
833     static struct S
834     {
835         int x;
836     }
837     static class C
838     {
839         int x;
840         this(int x) @safe pure { this.x = x; }
841     }
842 
843     static class B
844     {
845         int value;
846         this(S src) @safe pure { value = src.x; }
847         this(C src) @safe pure { value = src.x; }
848     }
849 
850     S s = S(1);
851     auto b1 = to!B(s);  // == new B(s)
852     assert(b1.value == 1);
853 
854     C c = new C(2);
855     auto b2 = to!B(c);  // == new B(c)
856     assert(b2.value == 2);
857 
858     auto c2 = to!C(3);   // == new C(3)
859     assert(c2.x == 3);
860 }
861 
862 @safe pure unittest
863 {
864     struct S
865     {
866         class A
867         {
868             this(B b) @safe pure {}
869         }
870         class B : A
871         {
872             this() @safe pure { super(this); }
873         }
874     }
875 
876     S.B b = new S.B();
877     S.A a = to!(S.A)(b);      // == cast(S.A) b
878                               // (do not run construction conversion like new S.A(b))
879     assert(b is a);
880 
881     static class C : Object
882     {
883         this() @safe pure {}
884         this(Object o) @safe pure {}
885     }
886 
887     Object oc = new C();
888     C a2 = to!C(oc);    // == new C(a)
889                         // Construction conversion overrides down-casting conversion
890     assert(a2 !is a);   //
891 }
892 
893 /**
894 Object-to-object conversions by dynamic casting throw exception when the source is
895 non-null and the target is null.
896  */
897 private T toImpl(T, S)(S value)
898 if (!is(S : T) &&
899     (is(S == class) || is(S == interface)) && !is(typeof(value.opCast!T()) : T) &&
900     (is(T == class) || is(T == interface)) && !is(typeof(new T(value))))
901 {
902     static if (is(T == immutable))
903     {
904             // immutable <- immutable
905             enum isModConvertible = is(S == immutable);
906     }
907     else static if (is(T == const))
908     {
909         static if (is(T == shared))
910         {
911             // shared const <- shared
912             // shared const <- shared const
913             // shared const <- immutable
914             enum isModConvertible = is(S == shared) || is(S == immutable);
915         }
916         else
917         {
918             // const <- mutable
919             // const <- immutable
920             enum isModConvertible = !is(S == shared);
921         }
922     }
923     else
924     {
925         static if (is(T == shared))
926         {
927             // shared <- shared mutable
928             enum isModConvertible = is(S == shared) && !is(S == const);
929         }
930         else
931         {
932             // (mutable) <- (mutable)
933             enum isModConvertible = is(Unqual!S == S);
934         }
935     }
936     static assert(isModConvertible, "Bad modifier conversion: "~S.stringof~" to "~T.stringof);
937 
938     auto result = ()@trusted{ return cast(T) value; }();
939     if (!result && value)
940     {
941         string name(TypeInfo ti) @trusted
942         {
943             while (auto tc = (cast(TypeInfo_Const) ti))
944             {
945                 ti = tc.base;
946             }
947             if (auto tinf = cast(TypeInfo_Interface) ti)
948             {
949                 ti = tinf.info;
950             }
951             TypeInfo_Class tc = cast(TypeInfo_Class) ti;
952             assert(tc);
953             return tc.name;
954         }
955         throw new ConvException("Cannot convert object of static type " ~
956                 name(typeid(S)) ~ " and dynamic type " ~ name(typeid(value)) ~ " to type " ~ name(typeid(T)));
957     }
958     return result;
959 }
960 
961 // Unittest for 6288
962 @safe pure unittest
963 {
964     import std.exception;
965 
966     alias Identity(T)      =              T;
967     alias toConst(T)       =        const T;
968     alias toShared(T)      =       shared T;
969     alias toSharedConst(T) = shared const T;
970     alias toImmutable(T)   =    immutable T;
971     template AddModifier(int n)
972     if (0 <= n && n < 5)
973     {
974              static if (n == 0) alias AddModifier = Identity;
975         else static if (n == 1) alias AddModifier = toConst;
976         else static if (n == 2) alias AddModifier = toShared;
977         else static if (n == 3) alias AddModifier = toSharedConst;
978         else static if (n == 4) alias AddModifier = toImmutable;
979     }
980 
981     interface I {}
982     interface J {}
983 
984     class A {}
985     class B : A {}
986     class C : B, I, J {}
987     class D : I {}
988 
989     static foreach (m1; 0 .. 5) // enumerate modifiers
990     static foreach (m2; 0 .. 5) // ditto
991     {{
992         alias srcmod = AddModifier!m1;
993         alias tgtmod = AddModifier!m2;
994 
995         // Compile time convertible equals to modifier convertible.
996         static if (is(srcmod!Object : tgtmod!Object))
997         {
998             // Test runtime conversions: class to class, class to interface,
999             // interface to class, and interface to interface
1000 
1001             // Check that the runtime conversion to succeed
1002             srcmod!A ac = new srcmod!C();
1003             srcmod!I ic = new srcmod!C();
1004             assert(to!(tgtmod!C)(ac) !is null); // A(c) to C
1005             assert(to!(tgtmod!I)(ac) !is null); // A(c) to I
1006             assert(to!(tgtmod!C)(ic) !is null); // I(c) to C
1007             assert(to!(tgtmod!J)(ic) !is null); // I(c) to J
1008 
1009             // Check that the runtime conversion fails
1010             srcmod!A ab = new srcmod!B();
1011             srcmod!I id = new srcmod!D();
1012             assertThrown(to!(tgtmod!C)(ab));    // A(b) to C
1013             assertThrown(to!(tgtmod!I)(ab));    // A(b) to I
1014             assertThrown(to!(tgtmod!C)(id));    // I(d) to C
1015             assertThrown(to!(tgtmod!J)(id));    // I(d) to J
1016         }
1017         else
1018         {
1019             // Check that the conversion is rejected statically
1020             static assert(!is(typeof(to!(tgtmod!C)(srcmod!A.init))));   // A to C
1021             static assert(!is(typeof(to!(tgtmod!I)(srcmod!A.init))));   // A to I
1022             static assert(!is(typeof(to!(tgtmod!C)(srcmod!I.init))));   // I to C
1023             static assert(!is(typeof(to!(tgtmod!J)(srcmod!I.init))));   // I to J
1024         }
1025     }}
1026 }
1027 
1028 /**
1029 Handles type _to string conversions
1030 */
1031 private T toImpl(T, S)(S value)
1032 if (!(is(S : T) &&
1033     !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) &&
1034     !isInfinite!S && isExactSomeString!T)
1035 {
1036     static if (isExactSomeString!S && value[0].sizeof == ElementEncodingType!T.sizeof)
1037     {
1038         // string-to-string with incompatible qualifier conversion
1039         static if (is(ElementEncodingType!T == immutable))
1040         {
1041             // conversion (mutable|const) -> immutable
1042             return value.idup;
1043         }
1044         else
1045         {
1046             // conversion (immutable|const) -> mutable
1047             return value.dup;
1048         }
1049     }
1050     else static if (isExactSomeString!S)
1051     {
1052         import std.array : appender;
1053         // other string-to-string
1054         //Use Appender directly instead of toStr, which also uses a formatedWrite
1055         auto w = appender!T();
1056         w.put(value);
1057         return w.data;
1058     }
1059     else static if (isIntegral!S && !is(S == enum))
1060     {
1061         // other integral-to-string conversions with default radix
1062 
1063         import core.internal.string : signedToTempString, unsignedToTempString;
1064 
1065         alias EEType = Unqual!(ElementEncodingType!T);
1066         EEType[long.sizeof * 3 + 1] buf = void;
1067         EEType[] t = isSigned!S
1068             ?   signedToTempString!(10, false, EEType)(value, buf)
1069             : unsignedToTempString!(10, false, EEType)(value, buf);
1070         return t.dup;
1071     }
1072     else static if (is(S == void[]) || is(S == const(void)[]) || is(S == immutable(void)[]))
1073     {
1074         import core.stdc.string : memcpy;
1075         import std.exception : enforce;
1076         // Converting void array to string
1077         alias Char = Unqual!(ElementEncodingType!T);
1078         auto raw = cast(const(ubyte)[]) value;
1079         enforce(raw.length % Char.sizeof == 0,
1080                 new ConvException("Alignment mismatch in converting a "
1081                         ~ S.stringof ~ " to a "
1082                         ~ T.stringof));
1083         auto result = new Char[raw.length / Char.sizeof];
1084         ()@trusted{ memcpy(result.ptr, value.ptr, value.length); }();
1085         return cast(T) result;
1086     }
1087     else static if (isPointer!S && isSomeChar!(PointerTarget!S))
1088     {
1089         // This is unsafe because we cannot guarantee that the pointer is null terminated.
1090         return () @system {
1091             static if (is(S : const(char)*))
1092                 import core.stdc.string : strlen;
1093             else
1094                 size_t strlen(S s) nothrow
1095                 {
1096                     S p = s;
1097                     while (*p++) {}
1098                     return p-s-1;
1099                 }
1100             return toImpl!T(value ? value[0 .. strlen(value)].dup : null);
1101         }();
1102     }
1103     else static if (isSomeString!T && is(S == enum))
1104     {
1105         static if (isSwitchable!(OriginalType!S) && EnumMembers!S.length <= 50)
1106         {
1107             switch (value)
1108             {
1109                 foreach (member; NoDuplicates!(EnumMembers!S))
1110                 {
1111                     case member:
1112                         return to!T(enumRep!(immutable(T), S, member));
1113                 }
1114                 default:
1115             }
1116         }
1117         else
1118         {
1119             foreach (member; EnumMembers!S)
1120             {
1121                 if (value == member)
1122                     return to!T(enumRep!(immutable(T), S, member));
1123             }
1124         }
1125 
1126         import std.array : appender;
1127         import std.format.spec : FormatSpec;
1128         import std.format.write : formatValue;
1129 
1130         //Default case, delegate to format
1131         //Note: we don't call toStr directly, to avoid duplicate work.
1132         auto app = appender!T();
1133         app.put("cast(" ~ S.stringof ~ ")");
1134         FormatSpec!char f;
1135         formatValue(app, cast(OriginalType!S) value, f);
1136         return app.data;
1137     }
1138     else
1139     {
1140         // other non-string values runs formatting
1141         return toStr!T(value);
1142     }
1143 }
1144 
1145 // https://issues.dlang.org/show_bug.cgi?id=14042
1146 @system unittest
1147 {
1148     immutable(char)* ptr = "hello".ptr;
1149     auto result = ptr.to!(char[]);
1150 }
1151 // https://issues.dlang.org/show_bug.cgi?id=8384
1152 @system unittest
1153 {
1154     void test1(T)(T lp, string cmp)
1155     {
1156         static foreach (e; AliasSeq!(char, wchar, dchar))
1157         {
1158             test2!(e[])(lp, cmp);
1159             test2!(const(e)[])(lp, cmp);
1160             test2!(immutable(e)[])(lp, cmp);
1161         }
1162     }
1163 
1164     void test2(D, S)(S lp, string cmp)
1165     {
1166         assert(to!string(to!D(lp)) == cmp);
1167     }
1168 
1169     static foreach (e; AliasSeq!("Hello, world!", "Hello, world!"w, "Hello, world!"d))
1170     {
1171         test1(e, "Hello, world!");
1172         test1(e.ptr, "Hello, world!");
1173     }
1174     static foreach (e; AliasSeq!("", ""w, ""d))
1175     {
1176         test1(e, "");
1177         test1(e.ptr, "");
1178     }
1179 }
1180 
1181 /*
1182     To string conversion for non copy-able structs
1183  */
1184 private T toImpl(T, S)(ref S value)
1185 if (!(is(S : T) &&
1186     !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) &&
1187     !isInfinite!S && isExactSomeString!T && !isCopyable!S && !isStaticArray!S)
1188 {
1189     import std.array : appender;
1190     import std.format.spec : FormatSpec;
1191     import std.format.write : formatValue;
1192 
1193     auto w = appender!T();
1194     FormatSpec!(ElementEncodingType!T) f;
1195     formatValue(w, value, f);
1196     return w.data;
1197 }
1198 
1199 // https://issues.dlang.org/show_bug.cgi?id=16108
1200 @safe unittest
1201 {
1202     static struct A
1203     {
1204         int val;
1205         bool flag;
1206 
1207         string toString() { return text(val, ":", flag); }
1208 
1209         @disable this(this);
1210     }
1211 
1212     auto a = A();
1213     assert(to!string(a) == "0:false");
1214 
1215     static struct B
1216     {
1217         int val;
1218         bool flag;
1219 
1220         @disable this(this);
1221     }
1222 
1223     auto b = B();
1224     assert(to!string(b) == "B(0, false)");
1225 }
1226 
1227 // https://issues.dlang.org/show_bug.cgi?id=20070
1228 @safe unittest
1229 {
1230     void writeThem(T)(ref inout(T) them)
1231     {
1232         assert(them.to!string == "[1, 2, 3, 4]");
1233     }
1234 
1235     const(uint)[4] vals = [ 1, 2, 3, 4 ];
1236     writeThem(vals);
1237 }
1238 
1239 /*
1240     Check whether type `T` can be used in a switch statement.
1241     This is useful for compile-time generation of switch case statements.
1242 */
1243 private template isSwitchable(E)
1244 {
1245     enum bool isSwitchable = is(typeof({
1246         switch (E.init) { default: }
1247     }));
1248 }
1249 
1250 //
1251 @safe unittest
1252 {
1253     static assert(isSwitchable!int);
1254     static assert(!isSwitchable!double);
1255     static assert(!isSwitchable!real);
1256 }
1257 
1258 //Static representation of the index I of the enum S,
1259 //In representation T.
1260 //T must be an immutable string (avoids un-necessary initializations).
1261 private template enumRep(T, S, S value)
1262 if (is (T == immutable) && isExactSomeString!T && is(S == enum))
1263 {
1264     static T enumRep = toStr!T(value);
1265 }
1266 
1267 @safe pure unittest
1268 {
1269     import std.exception;
1270     void dg()
1271     {
1272         // string to string conversion
1273         alias Chars = AliasSeq!(char, wchar, dchar);
1274         foreach (LhsC; Chars)
1275         {
1276             alias LhStrings = AliasSeq!(LhsC[], const(LhsC)[], immutable(LhsC)[]);
1277             foreach (Lhs; LhStrings)
1278             {
1279                 foreach (RhsC; Chars)
1280                 {
1281                     alias RhStrings = AliasSeq!(RhsC[], const(RhsC)[], immutable(RhsC)[]);
1282                     foreach (Rhs; RhStrings)
1283                     {
1284                         Lhs s1 = to!Lhs("wyda");
1285                         Rhs s2 = to!Rhs(s1);
1286                         //writeln(Lhs.stringof, " -> ", Rhs.stringof);
1287                         assert(s1 == to!Lhs(s2));
1288                     }
1289                 }
1290             }
1291         }
1292 
1293         foreach (T; Chars)
1294         {
1295             foreach (U; Chars)
1296             {
1297                 T[] s1 = to!(T[])("Hello, world!");
1298                 auto s2 = to!(U[])(s1);
1299                 assert(s1 == to!(T[])(s2));
1300                 auto s3 = to!(const(U)[])(s1);
1301                 assert(s1 == to!(T[])(s3));
1302                 auto s4 = to!(immutable(U)[])(s1);
1303                 assert(s1 == to!(T[])(s4));
1304             }
1305         }
1306     }
1307     dg();
1308     assertCTFEable!dg;
1309 }
1310 
1311 @safe pure unittest
1312 {
1313     // Conversion representing bool value with string
1314     bool b;
1315     assert(to!string(b) == "false");
1316     b = true;
1317     assert(to!string(b) == "true");
1318 }
1319 
1320 @safe pure unittest
1321 {
1322     // Conversion representing character value with string
1323     alias AllChars =
1324         AliasSeq!( char, const( char), immutable( char),
1325                   wchar, const(wchar), immutable(wchar),
1326                   dchar, const(dchar), immutable(dchar));
1327     foreach (Char1; AllChars)
1328     {
1329         foreach (Char2; AllChars)
1330         {
1331             Char1 c = 'a';
1332             assert(to!(Char2[])(c)[0] == c);
1333         }
1334         uint x = 4;
1335         assert(to!(Char1[])(x) == "4");
1336     }
1337 
1338     string s = "foo";
1339     string s2;
1340     foreach (char c; s)
1341     {
1342         s2 ~= to!string(c);
1343     }
1344     assert(s2 == "foo");
1345 }
1346 
1347 @safe pure nothrow unittest
1348 {
1349     import std.exception;
1350     // Conversion representing integer values with string
1351 
1352     static foreach (Int; AliasSeq!(ubyte, ushort, uint, ulong))
1353     {
1354         assert(to!string(Int(0)) == "0");
1355         assert(to!string(Int(9)) == "9");
1356         assert(to!string(Int(123)) == "123");
1357     }
1358 
1359     static foreach (Int; AliasSeq!(byte, short, int, long))
1360     {
1361         assert(to!string(Int(0)) == "0");
1362         assert(to!string(Int(9)) == "9");
1363         assert(to!string(Int(123)) == "123");
1364         assert(to!string(Int(-0)) == "0");
1365         assert(to!string(Int(-9)) == "-9");
1366         assert(to!string(Int(-123)) == "-123");
1367         assert(to!string(const(Int)(6)) == "6");
1368     }
1369 
1370     assert(wtext(int.max) == "2147483647"w);
1371     assert(wtext(int.min) == "-2147483648"w);
1372     assert(to!string(0L) == "0");
1373 
1374     assertCTFEable!(
1375     {
1376         assert(to!string(1uL << 62) == "4611686018427387904");
1377         assert(to!string(0x100000000) == "4294967296");
1378         assert(to!string(-138L) == "-138");
1379     });
1380 }
1381 
1382 @safe unittest // sprintf issue
1383 {
1384     double[2] a = [ 1.5, 2.5 ];
1385     assert(to!string(a) == "[1.5, 2.5]");
1386 }
1387 
1388 @safe unittest
1389 {
1390     // Conversion representing class object with string
1391     class A
1392     {
1393         override string toString() @safe const { return "an A"; }
1394     }
1395     A a;
1396     assert(to!string(a) == "null");
1397     a = new A;
1398     assert(to!string(a) == "an A");
1399 
1400     // https://issues.dlang.org/show_bug.cgi?id=7660
1401     class C { override string toString() @safe const { return "C"; } }
1402     struct S { C c; alias c this; }
1403     S s; s.c = new C();
1404     assert(to!string(s) == "C");
1405 }
1406 
1407 @safe unittest
1408 {
1409     // Conversion representing struct object with string
1410     struct S1
1411     {
1412         string toString() { return "wyda"; }
1413     }
1414     assert(to!string(S1()) == "wyda");
1415 
1416     struct S2
1417     {
1418         int a = 42;
1419         float b = 43.5;
1420     }
1421     S2 s2;
1422     assert(to!string(s2) == "S2(42, 43.5)");
1423 
1424     // Test for https://issues.dlang.org/show_bug.cgi?id=8080
1425     struct S8080
1426     {
1427         short[4] data;
1428         alias data this;
1429         string toString() { return "<S>"; }
1430     }
1431     S8080 s8080;
1432     assert(to!string(s8080) == "<S>");
1433 }
1434 
1435 @safe unittest
1436 {
1437     // Conversion representing enum value with string
1438     enum EB : bool { a = true }
1439     enum EU : uint { a = 0, b = 1, c = 2 }  // base type is unsigned
1440     // base type is signed (https://issues.dlang.org/show_bug.cgi?id=7909)
1441     enum EI : int { a = -1, b = 0, c = 1 }
1442     enum EF : real { a = 1.414, b = 1.732, c = 2.236 }
1443     enum EC : char { a = 'x', b = 'y' }
1444     enum ES : string { a = "aaa", b = "bbb" }
1445 
1446     static foreach (E; AliasSeq!(EB, EU, EI, EF, EC, ES))
1447     {
1448         assert(to! string(E.a) == "a"c);
1449         assert(to!wstring(E.a) == "a"w);
1450         assert(to!dstring(E.a) == "a"d);
1451     }
1452 
1453     // Test an value not corresponding to an enum member.
1454     auto o = cast(EU) 5;
1455     assert(to! string(o) == "cast(EU)5"c);
1456     assert(to!wstring(o) == "cast(EU)5"w);
1457     assert(to!dstring(o) == "cast(EU)5"d);
1458 }
1459 
1460 @safe unittest
1461 {
1462     enum E
1463     {
1464         foo,
1465         doo = foo, // check duplicate switch statements
1466         bar,
1467     }
1468 
1469     //Test regression 12494
1470     assert(to!string(E.foo) == "foo");
1471     assert(to!string(E.doo) == "foo");
1472     assert(to!string(E.bar) == "bar");
1473 
1474     static foreach (S; AliasSeq!(string, wstring, dstring, const(char[]), const(wchar[]), const(dchar[])))
1475     {{
1476         auto s1 = to!S(E.foo);
1477         auto s2 = to!S(E.foo);
1478         assert(s1 == s2);
1479         // ensure we don't allocate when it's unnecessary
1480         assert(s1 is s2);
1481     }}
1482 
1483     static foreach (S; AliasSeq!(char[], wchar[], dchar[]))
1484     {{
1485         auto s1 = to!S(E.foo);
1486         auto s2 = to!S(E.foo);
1487         assert(s1 == s2);
1488         // ensure each mutable array is unique
1489         assert(s1 !is s2);
1490     }}
1491 }
1492 
1493 // ditto
1494 @trusted pure private T toImpl(T, S)(S value, uint radix, LetterCase letterCase = LetterCase.upper)
1495 if (isIntegral!S &&
1496     isExactSomeString!T)
1497 in
1498 {
1499     assert(radix >= 2 && radix <= 36, "radix must be in range [2,36]");
1500 }
1501 do
1502 {
1503     alias EEType = Unqual!(ElementEncodingType!T);
1504 
1505     T toStringRadixConvert(size_t bufLen)(uint runtimeRadix = 0)
1506     {
1507         Unsigned!(Unqual!S) div = void, mValue = unsigned(value);
1508 
1509         size_t index = bufLen;
1510         EEType[bufLen] buffer = void;
1511         char baseChar = letterCase == LetterCase.lower ? 'a' : 'A';
1512         char mod = void;
1513 
1514         do
1515         {
1516             div = cast(S)(mValue / runtimeRadix );
1517             mod = cast(ubyte)(mValue % runtimeRadix);
1518             mod += mod < 10 ? '0' : baseChar - 10;
1519             buffer[--index] = cast(char) mod;
1520             mValue = div;
1521         } while (mValue);
1522 
1523         return cast(T) buffer[index .. $].dup;
1524     }
1525 
1526     import std.array : array;
1527     switch (radix)
1528     {
1529         case 10:
1530             // The (value+0) is so integral promotions happen to the type
1531             return toChars!(10, EEType)(value + 0).array;
1532         case 16:
1533             // The unsigned(unsigned(value)+0) is so unsigned integral promotions happen to the type
1534             if (letterCase == letterCase.upper)
1535                 return toChars!(16, EEType, LetterCase.upper)(unsigned(unsigned(value) + 0)).array;
1536             else
1537                 return toChars!(16, EEType, LetterCase.lower)(unsigned(unsigned(value) + 0)).array;
1538         case 2:
1539             return toChars!(2, EEType)(unsigned(unsigned(value) + 0)).array;
1540         case 8:
1541             return toChars!(8, EEType)(unsigned(unsigned(value) + 0)).array;
1542 
1543         default:
1544             return toStringRadixConvert!(S.sizeof * 6)(radix);
1545     }
1546 }
1547 
1548 @safe pure nothrow unittest
1549 {
1550     static foreach (Int; AliasSeq!(uint, ulong))
1551     {
1552         assert(to!string(Int(16), 16) == "10");
1553         assert(to!string(Int(15), 2u) == "1111");
1554         assert(to!string(Int(1), 2u) == "1");
1555         assert(to!string(Int(0x1234AF), 16u) == "1234AF");
1556         assert(to!string(Int(0x1234BCD), 16u, LetterCase.upper) == "1234BCD");
1557         assert(to!string(Int(0x1234AF), 16u, LetterCase.lower) == "1234af");
1558     }
1559 
1560     static foreach (Int; AliasSeq!(int, long))
1561     {
1562         assert(to!string(Int(-10), 10u) == "-10");
1563     }
1564 
1565     assert(to!string(byte(-10), 16) == "F6");
1566     assert(to!string(long.min) == "-9223372036854775808");
1567     assert(to!string(long.max) == "9223372036854775807");
1568 }
1569 
1570 /**
1571 Narrowing numeric-numeric conversions throw when the value does not
1572 fit in the narrower type.
1573  */
1574 private T toImpl(T, S)(S value)
1575 if (!is(S : T) &&
1576     (isNumeric!S || isSomeChar!S || isBoolean!S) &&
1577     (isNumeric!T || isSomeChar!T || isBoolean!T) && !is(T == enum))
1578 {
1579     static if (isFloatingPoint!S && isIntegral!T)
1580     {
1581         import std.math.traits : isNaN;
1582         if (value.isNaN) throw new ConvException("Input was NaN");
1583     }
1584 
1585     enum sSmallest = mostNegative!S;
1586     enum tSmallest = mostNegative!T;
1587     static if (sSmallest < 0)
1588     {
1589         // possible underflow converting from a signed
1590         static if (tSmallest == 0)
1591         {
1592             immutable good = value >= 0;
1593         }
1594         else
1595         {
1596             static assert(tSmallest < 0,
1597                 "minimum value of T must be smaller than 0");
1598             immutable good = value >= tSmallest;
1599         }
1600         if (!good)
1601             throw new ConvOverflowException("Conversion negative overflow");
1602     }
1603     static if (S.max > T.max)
1604     {
1605         // possible overflow
1606         if (value > T.max)
1607             throw new ConvOverflowException("Conversion positive overflow");
1608     }
1609     return (ref value)@trusted{ return cast(T) value; }(value);
1610 }
1611 
1612 @safe pure unittest
1613 {
1614     import std.exception;
1615 
1616     dchar a = ' ';
1617     assert(to!char(a) == ' ');
1618     a = 300;
1619     assert(collectException(to!char(a)));
1620 
1621     dchar from0 = 'A';
1622     char to0 = to!char(from0);
1623 
1624     wchar from1 = 'A';
1625     char to1 = to!char(from1);
1626 
1627     char from2 = 'A';
1628     char to2 = to!char(from2);
1629 
1630     char from3 = 'A';
1631     wchar to3 = to!wchar(from3);
1632 
1633     char from4 = 'A';
1634     dchar to4 = to!dchar(from4);
1635 }
1636 
1637 @safe unittest
1638 {
1639     import std.exception;
1640 
1641     // Narrowing conversions from enum -> integral should be allowed, but they
1642     // should throw at runtime if the enum value doesn't fit in the target
1643     // type.
1644     enum E1 : ulong { A = 1, B = 1UL << 48, C = 0 }
1645     assert(to!int(E1.A) == 1);
1646     assert(to!bool(E1.A) == true);
1647     assertThrown!ConvOverflowException(to!int(E1.B)); // E1.B overflows int
1648     assertThrown!ConvOverflowException(to!bool(E1.B)); // E1.B overflows bool
1649     assert(to!bool(E1.C) == false);
1650 
1651     enum E2 : long { A = -1L << 48, B = -1 << 31, C = 1 << 31 }
1652     assertThrown!ConvOverflowException(to!int(E2.A)); // E2.A overflows int
1653     assertThrown!ConvOverflowException(to!uint(E2.B)); // E2.B overflows uint
1654     assert(to!int(E2.B) == -1 << 31); // but does not overflow int
1655     assert(to!int(E2.C) == 1 << 31);  // E2.C does not overflow int
1656 
1657     enum E3 : int { A = -1, B = 1, C = 255, D = 0 }
1658     assertThrown!ConvOverflowException(to!ubyte(E3.A));
1659     assertThrown!ConvOverflowException(to!bool(E3.A));
1660     assert(to!byte(E3.A) == -1);
1661     assert(to!byte(E3.B) == 1);
1662     assert(to!ubyte(E3.C) == 255);
1663     assert(to!bool(E3.B) == true);
1664     assertThrown!ConvOverflowException(to!byte(E3.C));
1665     assertThrown!ConvOverflowException(to!bool(E3.C));
1666     assert(to!bool(E3.D) == false);
1667 
1668 }
1669 
1670 @safe unittest
1671 {
1672     import std.exception;
1673     import std.math.traits : isNaN;
1674 
1675     double d = double.nan;
1676     float f = to!float(d);
1677     assert(f.isNaN);
1678     assert(to!double(f).isNaN);
1679     assertThrown!ConvException(to!int(d));
1680     assertThrown!ConvException(to!int(f));
1681     auto ex = collectException(d.to!int);
1682     assert(ex.msg == "Input was NaN");
1683 }
1684 
1685 /**
1686 Array-to-array conversion (except when target is a string type)
1687 converts each element in turn by using `to`.
1688  */
1689 private T toImpl(T, S)(scope S value)
1690 if (!is(S : T) &&
1691     !isSomeString!S && isDynamicArray!S &&
1692     !isExactSomeString!T && isArray!T)
1693 {
1694     alias E = typeof(T.init[0]);
1695 
1696     static if (isStaticArray!T)
1697     {
1698         import std.exception : enforce;
1699         auto res = to!(E[])(value);
1700         enforce!ConvException(T.length == res.length,
1701             convFormat("Length mismatch when converting to static array: %s vs %s", T.length, res.length));
1702         return res[0 .. T.length];
1703     }
1704     else
1705     {
1706         import std.array : appender;
1707         auto w = appender!(E[])();
1708         w.reserve(value.length);
1709         foreach (ref e; value)
1710         {
1711             w.put(to!E(e));
1712         }
1713         return w.data;
1714     }
1715 }
1716 
1717 @safe pure unittest
1718 {
1719     import std.exception;
1720 
1721     // array to array conversions
1722     uint[] a = [ 1u, 2, 3 ];
1723     auto b = to!(float[])(a);
1724     assert(b == [ 1.0f, 2, 3 ]);
1725 
1726     immutable(int)[3] d = [ 1, 2, 3 ];
1727     b = to!(float[])(d);
1728     assert(b == [ 1.0f, 2, 3 ]);
1729 
1730     uint[][] e = [ a, a ];
1731     auto f = to!(float[][])(e);
1732     assert(f[0] == b && f[1] == b);
1733 
1734     // Test for https://issues.dlang.org/show_bug.cgi?id=8264
1735     struct Wrap
1736     {
1737         string wrap;
1738         alias wrap this;
1739     }
1740     Wrap[] warr = to!(Wrap[])(["foo", "bar"]);  // should work
1741 
1742     // https://issues.dlang.org/show_bug.cgi?id=12633
1743     import std.conv : to;
1744     const s2 = ["10", "20"];
1745 
1746     immutable int[2] a3 = s2.to!(int[2]);
1747     assert(a3 == [10, 20]);
1748 
1749     // verify length mismatches are caught
1750     immutable s4 = [1, 2, 3, 4];
1751     foreach (i; [1, 4])
1752     {
1753         auto ex = collectException(s4[0 .. i].to!(int[2]));
1754             assert(ex && ex.msg == "Length mismatch when converting to static array: 2 vs " ~ [cast(char)(i + '0')],
1755                 ex ? ex.msg : "Exception was not thrown!");
1756     }
1757 }
1758 
1759 @safe unittest
1760 {
1761     auto b = [ 1.0f, 2, 3 ];
1762 
1763     auto c = to!(string[])(b);
1764     assert(c[0] == "1" && c[1] == "2" && c[2] == "3");
1765 }
1766 
1767 /**
1768 Associative array to associative array conversion converts each key
1769 and each value in turn.
1770  */
1771 private T toImpl(T, S)(S value)
1772 if (!is(S : T) && isAssociativeArray!S &&
1773     isAssociativeArray!T && !is(T == enum))
1774 {
1775     /* This code is potentially unsafe.
1776      */
1777     alias K2 = KeyType!T;
1778     alias V2 = ValueType!T;
1779 
1780     // While we are "building" the AA, we need to unqualify its values, and only re-qualify at the end
1781     Unqual!V2[K2] result;
1782 
1783     foreach (k1, v1; value)
1784     {
1785         // Cast values temporarily to Unqual!V2 to store them to result variable
1786         result[to!K2(k1)] = to!(Unqual!V2)(v1);
1787     }
1788     // Cast back to original type
1789     return () @trusted { return cast(T) result; }();
1790 }
1791 
1792 @safe unittest
1793 {
1794     // hash to hash conversions
1795     int[string] a;
1796     a["0"] = 1;
1797     a["1"] = 2;
1798     auto b = to!(double[dstring])(a);
1799     assert(b["0"d] == 1 && b["1"d] == 2);
1800 }
1801 
1802 // https://issues.dlang.org/show_bug.cgi?id=8705, from doc
1803 @safe unittest
1804 {
1805     import std.exception;
1806     int[string][double[int[]]] a;
1807     auto b = to!(short[wstring][string[double[]]])(a);
1808     a = [null:["hello":int.max]];
1809     assertThrown!ConvOverflowException(to!(short[wstring][string[double[]]])(a));
1810 }
1811 @system unittest // Extra cases for AA with qualifiers conversion
1812 {
1813     int[][int[]] a;// = [[], []];
1814     auto b = to!(immutable(short[])[immutable short[]])(a);
1815 
1816     double[dstring][int[long[]]] c;
1817     auto d = to!(immutable(short[immutable wstring])[immutable string[double[]]])(c);
1818 }
1819 
1820 @safe unittest
1821 {
1822     import std.algorithm.comparison : equal;
1823     import std.array : byPair;
1824 
1825     int[int] a;
1826     assert(a.to!(int[int]) == a);
1827     assert(a.to!(const(int)[int]).byPair.equal(a.byPair));
1828 }
1829 
1830 @safe pure unittest
1831 {
1832     static void testIntegralToFloating(Integral, Floating)()
1833     {
1834         Integral a = 42;
1835         auto b = to!Floating(a);
1836         assert(a == b);
1837         assert(a == to!Integral(b));
1838     }
1839     static void testFloatingToIntegral(Floating, Integral)()
1840     {
1841         import std.math.traits : floatTraits, RealFormat;
1842 
1843         bool convFails(Source, Target, E)(Source src)
1844         {
1845             try
1846                 cast(void) to!Target(src);
1847             catch (E)
1848                 return true;
1849             return false;
1850         }
1851 
1852         // convert some value
1853         Floating a = 4.2e1;
1854         auto b = to!Integral(a);
1855         assert(is(typeof(b) == Integral) && b == 42);
1856         // convert some negative value (if applicable)
1857         a = -4.2e1;
1858         static if (Integral.min < 0)
1859         {
1860             b = to!Integral(a);
1861             assert(is(typeof(b) == Integral) && b == -42);
1862         }
1863         else
1864         {
1865             // no go for unsigned types
1866             assert(convFails!(Floating, Integral, ConvOverflowException)(a));
1867         }
1868         // convert to the smallest integral value
1869         a = 0.0 + Integral.min;
1870         static if (Integral.min < 0)
1871         {
1872             a = -a; // -Integral.min not representable as an Integral
1873             assert(convFails!(Floating, Integral, ConvOverflowException)(a)
1874                     || Floating.sizeof <= Integral.sizeof
1875                     || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
1876         }
1877         a = 0.0 + Integral.min;
1878         assert(to!Integral(a) == Integral.min);
1879         --a; // no more representable as an Integral
1880         assert(convFails!(Floating, Integral, ConvOverflowException)(a)
1881                 || Floating.sizeof <= Integral.sizeof
1882                 || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
1883         a = 0.0 + Integral.max;
1884         assert(to!Integral(a) == Integral.max
1885                 || Floating.sizeof <= Integral.sizeof
1886                 || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
1887         ++a; // no more representable as an Integral
1888         assert(convFails!(Floating, Integral, ConvOverflowException)(a)
1889                 || Floating.sizeof <= Integral.sizeof
1890                 || floatTraits!Floating.realFormat == RealFormat.ieeeExtended53);
1891         // convert a value with a fractional part
1892         a = 3.14;
1893         assert(to!Integral(a) == 3);
1894         a = 3.99;
1895         assert(to!Integral(a) == 3);
1896         static if (Integral.min < 0)
1897         {
1898             a = -3.14;
1899             assert(to!Integral(a) == -3);
1900             a = -3.99;
1901             assert(to!Integral(a) == -3);
1902         }
1903     }
1904 
1905     alias AllInts = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong);
1906     alias AllFloats = AliasSeq!(float, double, real);
1907     alias AllNumerics = AliasSeq!(AllInts, AllFloats);
1908     // test with same type
1909     {
1910         foreach (T; AllNumerics)
1911         {
1912             T a = 42;
1913             auto b = to!T(a);
1914             assert(is(typeof(a) == typeof(b)) && a == b);
1915         }
1916     }
1917     // test that floating-point numbers convert properly to largest ints
1918     // see http://oregonstate.edu/~peterseb/mth351/docs/351s2001_fp80x87.html
1919     // look for "largest fp integer with a predecessor"
1920     {
1921         // float
1922         int a = 16_777_215; // 2^24 - 1
1923         assert(to!int(to!float(a)) == a);
1924         assert(to!int(to!float(-a)) == -a);
1925         // double
1926         long b = 9_007_199_254_740_991; // 2^53 - 1
1927         assert(to!long(to!double(b)) == b);
1928         assert(to!long(to!double(-b)) == -b);
1929         // real
1930         static if (real.mant_dig >= 64)
1931         {
1932             ulong c = 18_446_744_073_709_551_615UL; // 2^64 - 1
1933             assert(to!ulong(to!real(c)) == c);
1934         }
1935     }
1936     // test conversions floating => integral
1937     {
1938         foreach (Integral; AllInts)
1939         {
1940             foreach (Floating; AllFloats)
1941             {
1942                 testFloatingToIntegral!(Floating, Integral)();
1943             }
1944         }
1945     }
1946     // test conversion integral => floating
1947     {
1948         foreach (Integral; AllInts)
1949         {
1950             foreach (Floating; AllFloats)
1951             {
1952                 testIntegralToFloating!(Integral, Floating)();
1953             }
1954         }
1955     }
1956     // test parsing
1957     {
1958         foreach (T; AllNumerics)
1959         {
1960             // from type immutable(char)[2]
1961             auto a = to!T("42");
1962             assert(a == 42);
1963             // from type char[]
1964             char[] s1 = "42".dup;
1965             a = to!T(s1);
1966             assert(a == 42);
1967             // from type char[2]
1968             char[2] s2;
1969             s2[] = "42";
1970             a = to!T(s2);
1971             assert(a == 42);
1972             // from type immutable(wchar)[2]
1973             a = to!T("42"w);
1974             assert(a == 42);
1975         }
1976     }
1977 }
1978 
1979 @safe unittest
1980 {
1981     alias AllInts = AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong);
1982     alias AllFloats = AliasSeq!(float, double, real);
1983     alias AllNumerics = AliasSeq!(AllInts, AllFloats);
1984     // test conversions to string
1985     {
1986         foreach (T; AllNumerics)
1987         {
1988             T a = 42;
1989             string s = to!string(a);
1990             assert(s == "42", s);
1991             wstring ws = to!wstring(a);
1992             assert(ws == "42"w, to!string(ws));
1993             dstring ds = to!dstring(a);
1994             assert(ds == "42"d, to!string(ds));
1995             // array test
1996             T[] b = new T[2];
1997             b[0] = 42;
1998             b[1] = 33;
1999             assert(to!string(b) == "[42, 33]");
2000         }
2001     }
2002     // test array to string conversion
2003     foreach (T ; AllNumerics)
2004     {
2005         auto a = [to!T(1), 2, 3];
2006         assert(to!string(a) == "[1, 2, 3]");
2007     }
2008     // test enum to int conversion
2009     enum Testing { Test1, Test2 }
2010     Testing t;
2011     auto a = to!string(t);
2012     assert(a == "Test1");
2013 }
2014 
2015 
2016 /**
2017 String, or string-like input range, to non-string conversion runs parsing.
2018 $(UL
2019   $(LI When the source is a wide string, it is first converted to a narrow
2020        string and then parsed.)
2021   $(LI When the source is a narrow string, normal text parsing occurs.))
2022 */
2023 private T toImpl(T, S)(S value)
2024 if (isInputRange!S && isSomeChar!(ElementEncodingType!S) &&
2025     !isExactSomeString!T && is(typeof(parse!T(value))) &&
2026     // https://issues.dlang.org/show_bug.cgi?id=20539
2027     !(is(T == enum) && is(typeof(value == OriginalType!T.init)) && !isSomeString!(OriginalType!T)))
2028 {
2029     scope(success)
2030     {
2031         if (!value.empty)
2032         {
2033             throw convError!(S, T)(value);
2034         }
2035     }
2036     return parse!T(value);
2037 }
2038 
2039 /// ditto
2040 private T toImpl(T, S)(S value, uint radix)
2041 if (isSomeFiniteCharInputRange!S &&
2042     isIntegral!T && is(typeof(parse!T(value, radix))))
2043 {
2044     scope(success)
2045     {
2046         if (!value.empty)
2047         {
2048             throw convError!(S, T)(value);
2049         }
2050     }
2051     return parse!T(value, radix);
2052 }
2053 
2054 @safe pure unittest
2055 {
2056     // https://issues.dlang.org/show_bug.cgi?id=6668
2057     // ensure no collaterals thrown
2058     try { to!uint("-1"); }
2059     catch (ConvException e) { assert(e.next is null); }
2060 }
2061 
2062 @safe pure unittest
2063 {
2064     static foreach (Str; AliasSeq!(string, wstring, dstring))
2065     {{
2066         Str a = "123";
2067         assert(to!int(a) == 123);
2068         assert(to!double(a) == 123);
2069     }}
2070 
2071     // https://issues.dlang.org/show_bug.cgi?id=6255
2072     auto n = to!int("FF", 16);
2073     assert(n == 255);
2074 }
2075 
2076 // https://issues.dlang.org/show_bug.cgi?id=15800
2077 @safe unittest
2078 {
2079     import std.utf : byCodeUnit, byChar, byWchar, byDchar;
2080 
2081     assert(to!int(byCodeUnit("10")) == 10);
2082     assert(to!int(byCodeUnit("10"), 10) == 10);
2083     assert(to!int(byCodeUnit("10"w)) == 10);
2084     assert(to!int(byCodeUnit("10"w), 10) == 10);
2085 
2086     assert(to!int(byChar("10")) == 10);
2087     assert(to!int(byChar("10"), 10) == 10);
2088     assert(to!int(byWchar("10")) == 10);
2089     assert(to!int(byWchar("10"), 10) == 10);
2090     assert(to!int(byDchar("10")) == 10);
2091     assert(to!int(byDchar("10"), 10) == 10);
2092 }
2093 
2094 /**
2095 String, or string-like input range, to char type not directly
2096 supported by parse parses the first dchar of the source.
2097 
2098 Returns: the first code point of the input range, converted
2099          to type T.
2100 
2101 Throws: ConvException if the input range contains more than
2102         a single code point, or if the code point does not
2103         fit into a code unit of type T.
2104 */
2105 private T toImpl(T, S)(S value)
2106 if (isSomeChar!T && !is(typeof(parse!T(value))) &&
2107     is(typeof(parse!dchar(value))))
2108 {
2109     import std.utf : encode;
2110 
2111     immutable dchar codepoint = parse!dchar(value);
2112     if (!value.empty)
2113         throw new ConvException(convFormat("Cannot convert \"%s\" to %s because it " ~
2114                                            "contains more than a single code point.",
2115                                            value, T.stringof));
2116     T[dchar.sizeof / T.sizeof] decodedCodepoint;
2117     if (encode(decodedCodepoint, codepoint) != 1)
2118         throw new ConvException(convFormat("First code point '%s' of \"%s\" does not fit into a " ~
2119                                            "single %s code unit", codepoint, value, T.stringof));
2120     return decodedCodepoint[0];
2121 }
2122 
2123 @safe pure unittest
2124 {
2125     import std.exception : assertThrown;
2126 
2127     assert(toImpl!wchar("a") == 'a');
2128 
2129     assert(toImpl!char("a"d) == 'a');
2130     assert(toImpl!char("a"w) == 'a');
2131     assert(toImpl!wchar("a"d) == 'a');
2132 
2133     assertThrown!ConvException(toImpl!wchar("ab"));
2134     assertThrown!ConvException(toImpl!char("😃"d));
2135 }
2136 
2137 /**
2138 Convert a value that is implicitly convertible to the enum base type
2139 into an Enum value. If the value does not match any enum member values
2140 a ConvException is thrown.
2141 Enums with floating-point or string base types are not supported.
2142 */
2143 private T toImpl(T, S)(S value)
2144 if (is(T == enum) && !is(S == enum)
2145     && is(typeof(value == OriginalType!T.init))
2146     && !isFloatingPoint!(OriginalType!T) && !isSomeString!(OriginalType!T))
2147 {
2148     foreach (Member; EnumMembers!T)
2149     {
2150         if (Member == value)
2151             return Member;
2152     }
2153     throw new ConvException(convFormat("Value (%s) does not match any member value of enum '%s'", value, T.stringof));
2154 }
2155 
2156 @safe pure unittest
2157 {
2158     import std.exception;
2159     enum En8143 : int { A = 10, B = 20, C = 30, D = 20 }
2160     enum En8143[][] m3 = to!(En8143[][])([[10, 30], [30, 10]]);
2161     static assert(m3 == [[En8143.A, En8143.C], [En8143.C, En8143.A]]);
2162 
2163     En8143 en1 = to!En8143(10);
2164     assert(en1 == En8143.A);
2165     assertThrown!ConvException(to!En8143(5));   // matches none
2166     En8143[][] m1 = to!(En8143[][])([[10, 30], [30, 10]]);
2167     assert(m1 == [[En8143.A, En8143.C], [En8143.C, En8143.A]]);
2168 }
2169 
2170 // https://issues.dlang.org/show_bug.cgi?id=20539
2171 @safe pure unittest
2172 {
2173     import std.exception : assertNotThrown;
2174 
2175     // To test that the bug is fixed it is required that the struct is static,
2176     // otherwise, the frame pointer makes the test pass even if the bug is not
2177     // fixed.
2178 
2179     static struct A
2180     {
2181         auto opEquals(U)(U)
2182         {
2183             return true;
2184         }
2185     }
2186 
2187     enum ColorA
2188     {
2189         red = A()
2190     }
2191 
2192     assertNotThrown("xxx".to!ColorA);
2193 
2194     // This is a guard for the future.
2195 
2196     struct B
2197     {
2198         auto opEquals(U)(U)
2199         {
2200             return true;
2201         }
2202     }
2203 
2204     enum ColorB
2205     {
2206         red = B()
2207     }
2208 
2209     assertNotThrown("xxx".to!ColorB);
2210 }
2211 
2212 /***************************************************************
2213  Rounded conversion from floating point to integral.
2214 
2215 Rounded conversions do not work with non-integral target types.
2216  */
2217 
2218 template roundTo(Target)
2219 {
2220     Target roundTo(Source)(Source value)
2221     {
2222         import core.math : abs = fabs;
2223         import std.math.exponential : log2;
2224         import std.math.rounding : trunc;
2225 
2226         static assert(isFloatingPoint!Source);
2227         static assert(isIntegral!Target);
2228 
2229         // If value >= 2 ^^ (real.mant_dig - 1), the number is an integer
2230         // and adding 0.5 won't work, but we allready know, that we do
2231         // not have to round anything.
2232         if (log2(abs(value)) >= real.mant_dig - 1)
2233             return to!Target(value);
2234 
2235         return to!Target(trunc(value + (value < 0 ? -0.5L : 0.5L)));
2236     }
2237 }
2238 
2239 ///
2240 @safe unittest
2241 {
2242     assert(roundTo!int(3.14) == 3);
2243     assert(roundTo!int(3.49) == 3);
2244     assert(roundTo!int(3.5) == 4);
2245     assert(roundTo!int(3.999) == 4);
2246     assert(roundTo!int(-3.14) == -3);
2247     assert(roundTo!int(-3.49) == -3);
2248     assert(roundTo!int(-3.5) == -4);
2249     assert(roundTo!int(-3.999) == -4);
2250     assert(roundTo!(const int)(to!(const double)(-3.999)) == -4);
2251 }
2252 
2253 @safe unittest
2254 {
2255     import std.exception;
2256     // boundary values
2257     static foreach (Int; AliasSeq!(byte, ubyte, short, ushort, int, uint))
2258     {
2259         assert(roundTo!Int(Int.min - 0.4L) == Int.min);
2260         assert(roundTo!Int(Int.max + 0.4L) == Int.max);
2261         assertThrown!ConvOverflowException(roundTo!Int(Int.min - 0.5L));
2262         assertThrown!ConvOverflowException(roundTo!Int(Int.max + 0.5L));
2263     }
2264 }
2265 
2266 @safe unittest
2267 {
2268     import std.exception;
2269     assertThrown!ConvException(roundTo!int(float.init));
2270     auto ex = collectException(roundTo!int(float.init));
2271     assert(ex.msg == "Input was NaN");
2272 }
2273 
2274 // https://issues.dlang.org/show_bug.cgi?id=5232
2275 @safe pure unittest
2276 {
2277     static if (real.mant_dig >= 64)
2278         ulong maxOdd = ulong.max;
2279     else
2280         ulong maxOdd = (1UL << real.mant_dig) - 1;
2281 
2282     real r1 = maxOdd;
2283     assert(roundTo!ulong(r1) == maxOdd);
2284 
2285     real r2 = maxOdd - 1;
2286     assert(roundTo!ulong(r2) == maxOdd - 1);
2287 
2288     real r3 = maxOdd / 2;
2289     assert(roundTo!ulong(r3) == maxOdd / 2);
2290 
2291     real r4 = maxOdd / 2 + 1;
2292     assert(roundTo!ulong(r4) == maxOdd / 2 + 1);
2293 
2294     // this is only an issue on computers where real == double
2295     long l = -((1L << double.mant_dig) - 1);
2296     double r5 = l;
2297     assert(roundTo!long(r5) == l);
2298 }
2299 
2300 /**
2301 $(PANEL
2302 The `parse` family of functions works quite like the $(LREF to)
2303 family, except that:
2304 $(OL
2305     $(LI It only works with character ranges as input.)
2306     $(LI It takes the input by reference. This means that rvalues (such
2307     as string literals) are not accepted: use `to` instead.)
2308     $(LI It advances the input to the position following the conversion.)
2309     $(LI It does not throw if it could not convert the entire input.))
2310 )
2311 
2312 This overload parses a `bool` from a character input range.
2313 
2314 Params:
2315     Target = the boolean type to convert to
2316     source = the lvalue of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
2317     doCount = the flag for deciding to report the number of consumed characters
2318 
2319 Returns:
2320 $(UL
2321     $(LI A `bool` if `doCount` is set to `No.doCount`)
2322     $(LI A `tuple` containing a `bool` and a `size_t` if `doCount` is set to `Yes.doCount`))
2323 
2324 Throws:
2325     A $(LREF ConvException) if the range does not represent a `bool`.
2326 
2327 Note:
2328     All character input range conversions using $(LREF to) are forwarded
2329     to `parse` and do not require lvalues.
2330 */
2331 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source)
2332 if (is(immutable Target == immutable bool) &&
2333     isInputRange!Source &&
2334     isSomeChar!(ElementType!Source))
2335 {
2336     import std.ascii : toLower;
2337 
2338     static if (isNarrowString!Source)
2339     {
2340         import std.string : representation;
2341         auto s = source.representation;
2342     }
2343     else
2344     {
2345         alias s = source;
2346     }
2347 
2348     if (!s.empty)
2349     {
2350         auto c1 = toLower(s.front);
2351         bool result = c1 == 't';
2352         if (result || c1 == 'f')
2353         {
2354             s.popFront();
2355             foreach (c; result ? "rue" : "alse")
2356             {
2357                 if (s.empty || toLower(s.front) != c)
2358                     goto Lerr;
2359                 s.popFront();
2360             }
2361 
2362             static if (isNarrowString!Source)
2363                 source = cast(Source) s;
2364 
2365             static if (doCount)
2366             {
2367                 if (result)
2368                     return tuple!("data", "count")(result, 4);
2369                 return tuple!("data", "count")(result, 5);
2370             }
2371             else
2372             {
2373                 return result;
2374             }
2375         }
2376     }
2377 Lerr:
2378     throw parseError("bool should be case-insensitive 'true' or 'false'");
2379 }
2380 
2381 ///
2382 @safe unittest
2383 {
2384     import std.typecons : Flag, Yes, No;
2385     auto s = "true";
2386     bool b = parse!bool(s);
2387     assert(b);
2388     auto s2 = "true";
2389     bool b2 = parse!(bool, string, No.doCount)(s2);
2390     assert(b2);
2391     auto s3 = "true";
2392     auto b3 = parse!(bool, string, Yes.doCount)(s3);
2393     assert(b3.data && b3.count == 4);
2394     auto s4 = "falSE";
2395     auto b4 = parse!(bool, string, Yes.doCount)(s4);
2396     assert(!b4.data && b4.count == 5);
2397 }
2398 
2399 @safe unittest
2400 {
2401     import std.algorithm.comparison : equal;
2402     import std.exception;
2403     struct InputString
2404     {
2405         string _s;
2406         @property auto front() { return _s.front; }
2407         @property bool empty() { return _s.empty; }
2408         void popFront() { _s.popFront(); }
2409     }
2410 
2411     auto s = InputString("trueFALSETrueFalsetRUEfALSE");
2412     assert(parse!bool(s) == true);
2413     assert(s.equal("FALSETrueFalsetRUEfALSE"));
2414     assert(parse!bool(s) == false);
2415     assert(s.equal("TrueFalsetRUEfALSE"));
2416     assert(parse!bool(s) == true);
2417     assert(s.equal("FalsetRUEfALSE"));
2418     assert(parse!bool(s) == false);
2419     assert(s.equal("tRUEfALSE"));
2420     assert(parse!bool(s) == true);
2421     assert(s.equal("fALSE"));
2422     assert(parse!bool(s) == false);
2423     assert(s.empty);
2424 
2425     foreach (ss; ["tfalse", "ftrue", "t", "f", "tru", "fals", ""])
2426     {
2427         s = InputString(ss);
2428         assertThrown!ConvException(parse!bool(s));
2429     }
2430 }
2431 
2432 /**
2433 Parses an integer from a character $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
2434 
2435 Params:
2436     Target = the integral type to convert to
2437     s = the lvalue of an input range
2438     doCount = the flag for deciding to report the number of consumed characters
2439 
2440 Returns:
2441 $(UL
2442     $(LI A number of type `Target` if `doCount` is set to `No.doCount`)
2443     $(LI A `tuple` containing a number of type `Target` and a `size_t` if `doCount` is set to `Yes.doCount`))
2444 
2445 Throws:
2446     A $(LREF ConvException) If an overflow occurred during conversion or
2447     if no character of the input was meaningfully converted.
2448 */
2449 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref scope Source s)
2450 if (isIntegral!Target && !is(Target == enum) &&
2451     isSomeChar!(ElementType!Source))
2452 {
2453     static if (Target.sizeof < int.sizeof)
2454     {
2455         // smaller types are handled like integers
2456         auto v = .parse!(Select!(Target.min < 0, int, uint), Source, Yes.doCount)(s);
2457         auto result = (() @trusted => cast (Target) v.data)();
2458         if (result == v.data)
2459         {
2460             static if (doCount)
2461             {
2462                 return tuple!("data", "count")(result, v.count);
2463             }
2464             else
2465             {
2466                 return result;
2467             }
2468         }
2469         throw new ConvOverflowException("Overflow in integral conversion");
2470     }
2471     else
2472     {
2473         // int or larger types
2474 
2475         static if (Target.min < 0)
2476             bool sign = false;
2477         else
2478             enum bool sign = false;
2479 
2480         enum char maxLastDigit = Target.min < 0 ? 7 : 5;
2481         uint c;
2482 
2483         static if (isNarrowString!Source)
2484         {
2485             import std.string : representation;
2486             auto source = s.representation;
2487         }
2488         else
2489         {
2490             alias source = s;
2491         }
2492 
2493         static if (doCount)
2494             size_t count = 0;
2495 
2496         if (source.empty)
2497             goto Lerr;
2498 
2499         c = source.front;
2500 
2501         static if (Target.min < 0)
2502         {
2503             switch (c)
2504             {
2505                 case '-':
2506                     sign = true;
2507                     goto case '+';
2508                 case '+':
2509                     static if (doCount)
2510                         ++count;
2511                     source.popFront();
2512 
2513                     if (source.empty)
2514                         goto Lerr;
2515 
2516                     c = source.front;
2517 
2518                     break;
2519 
2520                 default:
2521                     break;
2522             }
2523         }
2524         c -= '0';
2525         if (c <= 9)
2526         {
2527             Target v = cast(Target) c;
2528 
2529             static if (doCount)
2530                 ++count;
2531             source.popFront();
2532 
2533             while (!source.empty)
2534             {
2535                 c = cast(typeof(c)) (source.front - '0');
2536 
2537                 if (c > 9)
2538                     break;
2539 
2540                 if (v >= 0 && (v < Target.max/10 ||
2541                     (v == Target.max/10 && c <= maxLastDigit + sign)))
2542                 {
2543                     // Note: `v` can become negative here in case of parsing
2544                     // the most negative value:
2545                     v = cast(Target) (v * 10 + c);
2546                     static if (doCount)
2547                         ++count;
2548                     source.popFront();
2549                 }
2550                 else
2551                     throw new ConvOverflowException("Overflow in integral conversion");
2552             }
2553 
2554             if (sign)
2555                 v = -v;
2556 
2557             static if (isNarrowString!Source)
2558                 s = s[$-source.length..$];
2559 
2560             static if (doCount)
2561             {
2562                 return tuple!("data", "count")(v, count);
2563             }
2564             else
2565             {
2566                 return v;
2567             }
2568         }
2569 Lerr:
2570         static if (isNarrowString!Source)
2571             throw convError!(Source, Target)(cast(Source) source);
2572         else
2573             throw convError!(Source, Target)(source);
2574     }
2575 }
2576 
2577 ///
2578 @safe pure unittest
2579 {
2580     import std.typecons : Flag, Yes, No;
2581     string s = "123";
2582     auto a = parse!int(s);
2583     assert(a == 123);
2584 
2585     string s1 = "123";
2586     auto a1 = parse!(int, string, Yes.doCount)(s1);
2587     assert(a1.data == 123 && a1.count == 3);
2588 }
2589 
2590 ///
2591 @safe pure unittest
2592 {
2593     import std.string : tr;
2594     import std.typecons : Flag, Yes, No;
2595     string test = "123 \t  76.14";
2596     auto a = parse!uint(test);
2597     assert(a == 123);
2598     assert(test == " \t  76.14"); // parse bumps string
2599     test = tr(test, " \t\n\r", "", "d"); // skip ws
2600     assert(test == "76.14");
2601     auto b = parse!double(test);
2602     assert(b == 76.14);
2603     assert(test == "");
2604 
2605     string test2 = "123 \t  76.14";
2606     auto a2 = parse!(uint, string, Yes.doCount)(test2);
2607     assert(a2.data == 123 && a2.count == 3);
2608     assert(test2 == " \t  76.14");// parse bumps string
2609     test2 = tr(test2, " \t\n\r", "", "d"); // skip ws
2610     assert(test2 == "76.14");
2611     auto b2 = parse!(double, string, Yes.doCount)(test2);
2612     assert(b2.data == 76.14 && b2.count == 5);
2613     assert(test2 == "");
2614 
2615 }
2616 
2617 @safe pure unittest
2618 {
2619     static foreach (Int; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
2620     {
2621         {
2622             assert(to!Int("0") == 0);
2623 
2624             static if (isSigned!Int)
2625             {
2626                 assert(to!Int("+0") == 0);
2627                 assert(to!Int("-0") == 0);
2628             }
2629         }
2630 
2631         static if (Int.sizeof >= byte.sizeof)
2632         {
2633                 assert(to!Int("6") == 6);
2634                 assert(to!Int("23") == 23);
2635                 assert(to!Int("68") == 68);
2636                 assert(to!Int("127") == 0x7F);
2637 
2638             static if (isUnsigned!Int)
2639             {
2640                 assert(to!Int("255") == 0xFF);
2641             }
2642             static if (isSigned!Int)
2643             {
2644                 assert(to!Int("+6") == 6);
2645                 assert(to!Int("+23") == 23);
2646                 assert(to!Int("+68") == 68);
2647                 assert(to!Int("+127") == 0x7F);
2648 
2649                 assert(to!Int("-6") == -6);
2650                 assert(to!Int("-23") == -23);
2651                 assert(to!Int("-68") == -68);
2652                 assert(to!Int("-128") == -128);
2653             }
2654         }
2655 
2656         static if (Int.sizeof >= short.sizeof)
2657         {
2658                 assert(to!Int("468") == 468);
2659                 assert(to!Int("32767") == 0x7FFF);
2660 
2661             static if (isUnsigned!Int)
2662             {
2663                 assert(to!Int("65535") == 0xFFFF);
2664             }
2665             static if (isSigned!Int)
2666             {
2667                 assert(to!Int("+468") == 468);
2668                 assert(to!Int("+32767") == 0x7FFF);
2669 
2670                 assert(to!Int("-468") == -468);
2671                 assert(to!Int("-32768") == -32768);
2672             }
2673         }
2674 
2675         static if (Int.sizeof >= int.sizeof)
2676         {
2677                 assert(to!Int("2147483647") == 0x7FFFFFFF);
2678 
2679             static if (isUnsigned!Int)
2680             {
2681                 assert(to!Int("4294967295") == 0xFFFFFFFF);
2682             }
2683 
2684             static if (isSigned!Int)
2685             {
2686                 assert(to!Int("+2147483647") == 0x7FFFFFFF);
2687 
2688                 assert(to!Int("-2147483648") == -2147483648);
2689             }
2690         }
2691 
2692         static if (Int.sizeof >= long.sizeof)
2693         {
2694                 assert(to!Int("9223372036854775807") == 0x7FFFFFFFFFFFFFFF);
2695 
2696             static if (isUnsigned!Int)
2697             {
2698                 assert(to!Int("18446744073709551615") == 0xFFFFFFFFFFFFFFFF);
2699             }
2700 
2701             static if (isSigned!Int)
2702             {
2703                 assert(to!Int("+9223372036854775807") == 0x7FFFFFFFFFFFFFFF);
2704 
2705                 assert(to!Int("-9223372036854775808") == 0x8000000000000000);
2706             }
2707         }
2708     }
2709 }
2710 
2711 @safe pure unittest
2712 {
2713     import std.exception;
2714 
2715     immutable string[] errors =
2716     [
2717         "",
2718         "-",
2719         "+",
2720         "-+",
2721         " ",
2722         " 0",
2723         "0 ",
2724         "- 0",
2725         "1-",
2726         "xx",
2727         "123h",
2728         "-+1",
2729         "--1",
2730         "+-1",
2731         "++1",
2732     ];
2733 
2734     immutable string[] unsignedErrors =
2735     [
2736         "+5",
2737         "-78",
2738     ];
2739 
2740     // parsing error check
2741     static foreach (Int; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
2742     {
2743         foreach (j, s; errors)
2744             assertThrown!ConvException(to!Int(s));
2745 
2746         // parse!SomeUnsigned cannot parse head sign.
2747         static if (isUnsigned!Int)
2748         {
2749             foreach (j, s; unsignedErrors)
2750                 assertThrown!ConvException(to!Int(s));
2751         }
2752     }
2753 
2754     immutable string[] positiveOverflowErrors =
2755     [
2756         "128",                  // > byte.max
2757         "256",                  // > ubyte.max
2758         "32768",                // > short.max
2759         "65536",                // > ushort.max
2760         "2147483648",           // > int.max
2761         "4294967296",           // > uint.max
2762         "9223372036854775808",  // > long.max
2763         "18446744073709551616", // > ulong.max
2764     ];
2765     // positive overflow check
2766     static foreach (i, Int; AliasSeq!(byte, ubyte, short, ushort, int, uint, long, ulong))
2767     {
2768         foreach (j, s; positiveOverflowErrors[i..$])
2769             assertThrown!ConvOverflowException(to!Int(s));
2770     }
2771 
2772     immutable string[] negativeOverflowErrors =
2773     [
2774         "-129",                 // < byte.min
2775         "-32769",               // < short.min
2776         "-2147483649",          // < int.min
2777         "-9223372036854775809", // < long.min
2778     ];
2779     // negative overflow check
2780     static foreach (i, Int; AliasSeq!(byte, short, int, long))
2781     {
2782         foreach (j, s; negativeOverflowErrors[i..$])
2783             assertThrown!ConvOverflowException(to!Int(s));
2784     }
2785 }
2786 
2787 @safe pure unittest
2788 {
2789     void checkErrMsg(string input, dchar charInMsg, dchar charNotInMsg)
2790     {
2791         try
2792         {
2793             int x = input.to!int();
2794             assert(false, "Invalid conversion did not throw");
2795         }
2796         catch (ConvException e)
2797         {
2798             // Ensure error message contains failing character, not the character
2799             // beyond.
2800             import std.algorithm.searching : canFind;
2801             assert( e.msg.canFind(charInMsg) &&
2802                    !e.msg.canFind(charNotInMsg));
2803         }
2804         catch (Exception e)
2805         {
2806             assert(false, "Did not throw ConvException");
2807         }
2808     }
2809     checkErrMsg("@$", '@', '$');
2810     checkErrMsg("@$123", '@', '$');
2811     checkErrMsg("1@$23", '@', '$');
2812     checkErrMsg("1@$", '@', '$');
2813     checkErrMsg("1@$2", '@', '$');
2814     checkErrMsg("12@$", '@', '$');
2815 }
2816 
2817 @safe pure unittest
2818 {
2819     import std.exception;
2820     assertCTFEable!({ string s =  "1234abc"; assert(parse! int(s) ==  1234 && s == "abc"); });
2821     assertCTFEable!({ string s = "-1234abc"; assert(parse! int(s) == -1234 && s == "abc"); });
2822     assertCTFEable!({ string s =  "1234abc"; assert(parse!uint(s) ==  1234 && s == "abc"); });
2823 
2824     assertCTFEable!({ string s =  "1234abc"; assert(parse!( int, string, Yes.doCount)(s) ==
2825         tuple( 1234, 4) && s == "abc"); });
2826     assertCTFEable!({ string s = "-1234abc"; assert(parse!( int, string, Yes.doCount)(s) ==
2827         tuple(-1234, 5) && s == "abc"); });
2828     assertCTFEable!({ string s =  "1234abc"; assert(parse!(uint, string, Yes.doCount)(s) ==
2829         tuple( 1234 ,4) && s == "abc"); });
2830 }
2831 
2832 // https://issues.dlang.org/show_bug.cgi?id=13931
2833 @safe pure unittest
2834 {
2835     import std.exception;
2836 
2837     assertThrown!ConvOverflowException("-21474836480".to!int());
2838     assertThrown!ConvOverflowException("-92233720368547758080".to!long());
2839 }
2840 
2841 // https://issues.dlang.org/show_bug.cgi?id=14396
2842 @safe pure unittest
2843 {
2844     struct StrInputRange
2845     {
2846         this (string s) { str = s; }
2847         char front() const @property { return str[front_index]; }
2848         char popFront() { return str[front_index++]; }
2849         bool empty() const @property { return str.length <= front_index; }
2850         string str;
2851         size_t front_index = 0;
2852     }
2853     auto input = StrInputRange("777");
2854     assert(parse!int(input) == 777);
2855 
2856     auto input2 = StrInputRange("777");
2857     assert(parse!(int, StrInputRange, Yes.doCount)(input2) == tuple(777, 3));
2858 }
2859 
2860 // https://issues.dlang.org/show_bug.cgi?id=9621
2861 @safe pure unittest
2862 {
2863     string s1 = "[ \"\\141\", \"\\0\", \"\\41\", \"\\418\" ]";
2864     assert(parse!(string[])(s1) == ["a", "\0", "!", "!8"]);
2865 
2866     s1 = "[ \"\\141\", \"\\0\", \"\\41\", \"\\418\" ]";
2867     auto len = s1.length;
2868     assert(parse!(string[], string, Yes.doCount)(s1) == tuple(["a", "\0", "!", "!8"], len));
2869 }
2870 
2871 /// ditto
2872 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source, uint radix)
2873 if (isIntegral!Target && !is(Target == enum) &&
2874     isSomeChar!(ElementType!Source))
2875 in
2876 {
2877     assert(radix >= 2 && radix <= 36, "radix must be in range [2,36]");
2878 }
2879 do
2880 {
2881     import core.checkedint : mulu, addu;
2882     import std.exception : enforce;
2883 
2884     if (radix == 10)
2885     {
2886         return parse!(Target, Source, doCount)(source);
2887     }
2888 
2889     enforce!ConvException(!source.empty, "s must not be empty in integral parse");
2890 
2891     immutable uint beyond = (radix < 10 ? '0' : 'a'-10) + radix;
2892     Target v = 0;
2893 
2894     static if (isNarrowString!Source)
2895     {
2896         import std.string : representation;
2897         scope s = source.representation;
2898     }
2899     else
2900     {
2901         alias s = source;
2902     }
2903 
2904     static if (doCount)
2905         size_t count = 0;
2906     auto found = false;
2907     do
2908     {
2909         uint c = s.front;
2910         if (c < '0')
2911             break;
2912         if (radix < 10)
2913         {
2914             if (c >= beyond)
2915                 break;
2916         }
2917         else
2918         {
2919             if (c > '9')
2920             {
2921                 c |= 0x20;//poorman's tolower
2922                 if (c < 'a' || c >= beyond)
2923                     break;
2924                 c -= 'a'-10-'0';
2925             }
2926         }
2927 
2928         bool overflow = false;
2929         auto nextv = v.mulu(radix, overflow).addu(c - '0', overflow);
2930         enforce!ConvOverflowException(!overflow && nextv <= Target.max, "Overflow in integral conversion");
2931         v = cast(Target) nextv;
2932         static if (doCount)
2933             ++count;
2934         s.popFront();
2935         found = true;
2936     } while (!s.empty);
2937 
2938     if (!found)
2939     {
2940         static if (isNarrowString!Source)
2941             throw convError!(Source, Target)(cast(Source) source);
2942         else
2943             throw convError!(Source, Target)(source);
2944     }
2945 
2946     static if (isNarrowString!Source)
2947         source = source[$ - s.length .. $];
2948 
2949     static if (doCount)
2950     {
2951         return tuple!("data", "count")(v, count);
2952     }
2953     else
2954     {
2955         return v;
2956     }
2957 }
2958 
2959 @safe pure unittest
2960 {
2961     string s; // parse doesn't accept rvalues
2962     foreach (i; 2 .. 37)
2963     {
2964         assert(parse!int(s = "0", i) == 0);
2965         assert(parse!int(s = "1", i) == 1);
2966         assert(parse!byte(s = "10", i) == i);
2967         assert(parse!(int, string, Yes.doCount)(s = "0", i) == tuple(0, 1));
2968         assert(parse!(int, string, Yes.doCount)(s = "1", i) == tuple(1, 1));
2969         assert(parse!(byte, string, Yes.doCount)(s = "10", i) == tuple(i, 2));
2970     }
2971 
2972     assert(parse!int(s = "0011001101101", 2) == 0b0011001101101);
2973     assert(parse!int(s = "765", 8) == octal!765);
2974     assert(parse!int(s = "000135", 8) == octal!"135");
2975     assert(parse!int(s = "fCDe", 16) == 0xfcde);
2976 
2977     // https://issues.dlang.org/show_bug.cgi?id=6609
2978     assert(parse!int(s = "-42", 10) == -42);
2979 
2980     assert(parse!ubyte(s = "ff", 16) == 0xFF);
2981 }
2982 
2983 // https://issues.dlang.org/show_bug.cgi?id=7302
2984 @safe pure unittest
2985 {
2986     import std.range : cycle;
2987     auto r = cycle("2A!");
2988     auto u = parse!uint(r, 16);
2989     assert(u == 42);
2990     assert(r.front == '!');
2991 
2992     auto r2 = cycle("2A!");
2993     auto u2 = parse!(uint, typeof(r2), Yes.doCount)(r2, 16);
2994     assert(u2.data == 42 && u2.count == 2);
2995     assert(r2.front == '!');
2996 }
2997 
2998 // https://issues.dlang.org/show_bug.cgi?id=13163
2999 @safe pure unittest
3000 {
3001     import std.exception;
3002     foreach (s; ["fff", "123"])
3003         assertThrown!ConvOverflowException(s.parse!ubyte(16));
3004 }
3005 
3006 // https://issues.dlang.org/show_bug.cgi?id=17282
3007 @safe pure unittest
3008 {
3009     auto str = "0=\x00\x02\x55\x40&\xff\xf0\n\x00\x04\x55\x40\xff\xf0~4+10\n";
3010     assert(parse!uint(str) == 0);
3011 
3012     str = "0=\x00\x02\x55\x40&\xff\xf0\n\x00\x04\x55\x40\xff\xf0~4+10\n";
3013     assert(parse!(uint, string, Yes.doCount)(str) == tuple(0, 1));
3014 }
3015 
3016 // https://issues.dlang.org/show_bug.cgi?id=18248
3017 @safe pure unittest
3018 {
3019     import std.exception : assertThrown;
3020 
3021     auto str = ";";
3022     assertThrown(str.parse!uint(16));
3023     assertThrown(str.parse!(uint, string, Yes.doCount)(16));
3024 }
3025 
3026 /**
3027  * Parses an `enum` type from a string representing an enum member name.
3028  *
3029  * Params:
3030  *     Target = the `enum` type to convert to
3031  *     s = the lvalue of the range to _parse
3032  *     doCount = the flag for deciding to report the number of consumed characters
3033  *
3034  * Returns:
3035  $(UL
3036  *     $(LI An `enum` of type `Target` if `doCount` is set to `No.doCount`)
3037  *     $(LI A `tuple` containing an `enum` of type `Target` and a `size_t` if `doCount` is set to `Yes.doCount`))
3038  *
3039  * Throws:
3040  *     A $(LREF ConvException) if type `Target` does not have a member
3041  *     represented by `s`.
3042  */
3043 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
3044 if (is(Target == enum) && isSomeString!Source && !is(Source == enum))
3045 {
3046     import std.algorithm.searching : startsWith;
3047     import std.traits : Unqual, EnumMembers;
3048 
3049     Unqual!Target result;
3050     size_t longest_match = 0;
3051 
3052     foreach (i, e; EnumMembers!Target)
3053     {
3054         auto ident = __traits(allMembers, Target)[i];
3055         if (longest_match < ident.length && s.startsWith(ident))
3056         {
3057             result = e;
3058             longest_match = ident.length ;
3059         }
3060     }
3061 
3062     if (longest_match > 0)
3063     {
3064         s = s[longest_match .. $];
3065         static if (doCount)
3066         {
3067             return tuple!("data", "count")(result, longest_match);
3068         }
3069         else
3070         {
3071             return result;
3072         }
3073     }
3074 
3075     throw new ConvException(
3076         Target.stringof ~ " does not have a member named '"
3077         ~ to!string(s) ~ "'");
3078 }
3079 
3080 ///
3081 @safe unittest
3082 {
3083     import std.typecons : Flag, Yes, No, tuple;
3084     enum EnumType : bool { a = true, b = false, c = a }
3085 
3086     auto str = "a";
3087     assert(parse!EnumType(str) == EnumType.a);
3088     auto str2 = "a";
3089     assert(parse!(EnumType, string, No.doCount)(str2) == EnumType.a);
3090     auto str3 = "a";
3091     assert(parse!(EnumType, string, Yes.doCount)(str3) == tuple(EnumType.a, 1));
3092 
3093 }
3094 
3095 @safe unittest
3096 {
3097     import std.exception;
3098 
3099     enum EB : bool { a = true, b = false, c = a }
3100     enum EU { a, b, c }
3101     enum EI { a = -1, b = 0, c = 1 }
3102     enum EF : real { a = 1.414, b = 1.732, c = 2.236 }
3103     enum EC : char { a = 'a', b = 'b', c = 'c' }
3104     enum ES : string { a = "aaa", b = "bbb", c = "ccc" }
3105 
3106     static foreach (E; AliasSeq!(EB, EU, EI, EF, EC, ES))
3107     {
3108         assert(to!E("a"c) == E.a);
3109         assert(to!E("b"w) == E.b);
3110         assert(to!E("c"d) == E.c);
3111 
3112         assert(to!(const E)("a") == E.a);
3113         assert(to!(immutable E)("a") == E.a);
3114         assert(to!(shared E)("a") == E.a);
3115 
3116         assertThrown!ConvException(to!E("d"));
3117     }
3118 }
3119 
3120 // https://issues.dlang.org/show_bug.cgi?id=4744
3121 @safe pure unittest
3122 {
3123     enum A { member1, member11, member111 }
3124     assert(to!A("member1"  ) == A.member1  );
3125     assert(to!A("member11" ) == A.member11 );
3126     assert(to!A("member111") == A.member111);
3127     auto s = "member1111";
3128     assert(parse!A(s) == A.member111 && s == "1");
3129     auto s2 = "member1111";
3130     assert(parse!(A, string, No.doCount)(s2) == A.member111 && s2 == "1");
3131     auto s3 = "member1111";
3132     assert(parse!(A, string, Yes.doCount)(s3) == tuple(A.member111, 9) && s3 == "1");
3133 }
3134 
3135 /**
3136  * Parses a floating point number from a character range.
3137  *
3138  * Params:
3139  *     Target = a floating point type
3140  *     source = the lvalue of the range to _parse
3141  *     doCount = the flag for deciding to report the number of consumed characters
3142  *
3143  * Returns:
3144  $(UL
3145  *     $(LI A floating point number of type `Target` if `doCount` is set to `No.doCount`)
3146  *     $(LI A `tuple` containing a floating point number of·type `Target` and a `size_t`
3147  *     if `doCount` is set to `Yes.doCount`))
3148  *
3149  * Throws:
3150  *     A $(LREF ConvException) if `source` is empty, if no number could be
3151  *     parsed, or if an overflow occurred.
3152  */
3153 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source)
3154 if (isFloatingPoint!Target && !is(Target == enum) &&
3155     isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum))
3156 {
3157     import std.ascii : isDigit, isAlpha, toLower, toUpper, isHexDigit;
3158     import std.exception : enforce;
3159 
3160     static if (isNarrowString!Source)
3161     {
3162         import std.string : representation;
3163         scope p = source.representation;
3164     }
3165     else
3166     {
3167         alias p = source;
3168     }
3169 
3170     void advanceSource()
3171     {
3172         static if (isNarrowString!Source)
3173             source = source[$ - p.length .. $];
3174     }
3175 
3176     static immutable real[14] negtab =
3177         [ 1e-4096L,1e-2048L,1e-1024L,1e-512L,1e-256L,1e-128L,1e-64L,1e-32L,
3178                 1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L ];
3179     static immutable real[13] postab =
3180         [ 1e+4096L,1e+2048L,1e+1024L,1e+512L,1e+256L,1e+128L,1e+64L,1e+32L,
3181                 1e+16L,1e+8L,1e+4L,1e+2L,1e+1L ];
3182 
3183     ConvException bailOut()(string msg = null, string fn = __FILE__, size_t ln = __LINE__)
3184     {
3185         if (msg == null)
3186             msg = "Floating point conversion error";
3187         return new ConvException(text(msg, " for input \"", source, "\"."), fn, ln);
3188     }
3189 
3190     enforce(!p.empty, bailOut());
3191 
3192     size_t count = 0;
3193     bool sign = false;
3194     switch (p.front)
3195     {
3196     case '-':
3197         sign = true;
3198         static if (doCount) ++count;
3199         p.popFront();
3200         enforce(!p.empty, bailOut());
3201         if (toLower(p.front) == 'i')
3202             goto case 'i';
3203         break;
3204     case '+':
3205         static if (doCount) ++count;
3206         p.popFront();
3207         enforce(!p.empty, bailOut());
3208         break;
3209     case 'i': case 'I':
3210         // inf
3211         static if (doCount) ++count;
3212         p.popFront();
3213         enforce(!p.empty && toUpper(p.front) == 'N',
3214                bailOut("error converting input to floating point"));
3215         static if (doCount) ++count;
3216         p.popFront();
3217         enforce(!p.empty && toUpper(p.front) == 'F',
3218                bailOut("error converting input to floating point"));
3219         // skip past the last 'f'
3220         static if (doCount) ++count;
3221         p.popFront();
3222         advanceSource();
3223         static if (doCount)
3224         {
3225             return tuple!("data", "count")(sign ? -Target.infinity : Target.infinity, count);
3226         }
3227         else
3228         {
3229             return sign ? -Target.infinity : Target.infinity;
3230         }
3231     default: {}
3232     }
3233 
3234     bool isHex = false;
3235     bool startsWithZero = p.front == '0';
3236     if (startsWithZero)
3237     {
3238         static if (doCount) ++count;
3239         p.popFront();
3240         if (p.empty)
3241         {
3242             advanceSource();
3243             static if (doCount)
3244             {
3245                 return tuple!("data", "count")(cast (Target) (sign ? -0.0 : 0.0), count);
3246             }
3247             else
3248             {
3249                 return sign ? -0.0 : 0.0;
3250             }
3251         }
3252 
3253         isHex = p.front == 'x' || p.front == 'X';
3254         if (isHex)
3255         {
3256             static if (doCount) ++count;
3257             p.popFront();
3258         }
3259     }
3260     else if (toLower(p.front) == 'n')
3261     {
3262         // nan
3263         static if (doCount) ++count;
3264         p.popFront();
3265         enforce(!p.empty && toUpper(p.front) == 'A',
3266                bailOut("error converting input to floating point"));
3267         static if (doCount) ++count;
3268         p.popFront();
3269         enforce(!p.empty && toUpper(p.front) == 'N',
3270                bailOut("error converting input to floating point"));
3271         // skip past the last 'n'
3272         static if (doCount) ++count;
3273         p.popFront();
3274         advanceSource();
3275         static if (doCount)
3276         {
3277             return tuple!("data", "count")(Target.nan, count);
3278         }
3279         else
3280         {
3281             return typeof(return).nan;
3282         }
3283     }
3284 
3285     /*
3286      * The following algorithm consists of 2 steps:
3287      * 1) parseDigits processes the textual input into msdec and possibly
3288      *    lsdec/msscale variables, followed by the exponent parser which sets
3289      *    exp below.
3290      *    Hex: input is 0xaaaaa...p+000... where aaaa is the mantissa in hex
3291      *    and 000 is the exponent in decimal format with base 2.
3292      *    Decimal: input is 0.00333...p+000... where 0.0033 is the mantissa
3293      *    in decimal and 000 is the exponent in decimal format with base 10.
3294      * 2) Convert msdec/lsdec and exp into native real format
3295      */
3296 
3297     real ldval = 0.0;
3298     char dot = 0;                        /* if decimal point has been seen */
3299     int exp = 0;
3300     ulong msdec = 0, lsdec = 0;
3301     ulong msscale = 1;
3302     bool sawDigits;
3303 
3304     enum { hex, decimal }
3305 
3306     // sets msdec, lsdec/msscale, and sawDigits by parsing the mantissa digits
3307     void parseDigits(alias FloatFormat)()
3308     {
3309         static if (FloatFormat == hex)
3310         {
3311             enum uint base = 16;
3312             enum ulong msscaleMax = 0x1000_0000_0000_0000UL; // largest power of 16 a ulong holds
3313             enum ubyte expIter = 4; // iterate the base-2 exponent by 4 for every hex digit
3314             alias checkDigit = isHexDigit;
3315             /*
3316              * convert letter to binary representation: First clear bit
3317              * to convert lower space chars to upperspace, then -('A'-10)
3318              * converts letter A to 10, letter B to 11, ...
3319              */
3320             alias convertDigit = (int x) => isAlpha(x) ? ((x & ~0x20) - ('A' - 10)) : x - '0';
3321             sawDigits = false;
3322         }
3323         else static if (FloatFormat == decimal)
3324         {
3325             enum uint base = 10;
3326             enum ulong msscaleMax = 10_000_000_000_000_000_000UL; // largest power of 10 a ulong holds
3327             enum ubyte expIter = 1; // iterate the base-10 exponent once for every decimal digit
3328             alias checkDigit = isDigit;
3329             alias convertDigit = (int x) => x - '0';
3330             // Used to enforce that any mantissa digits are present
3331             sawDigits = startsWithZero;
3332         }
3333         else
3334             static assert(false, "Unrecognized floating-point format used.");
3335 
3336         while (!p.empty)
3337         {
3338             int i = p.front;
3339             while (checkDigit(i))
3340             {
3341                 sawDigits = true;        /* must have at least 1 digit   */
3342 
3343                 i = convertDigit(i);
3344 
3345                 if (msdec < (ulong.max - base)/base)
3346                 {
3347                     // For base 16: Y = ... + y3*16^3 + y2*16^2 + y1*16^1 + y0*16^0
3348                     msdec = msdec * base + i;
3349                 }
3350                 else if (msscale < msscaleMax)
3351                 {
3352                     lsdec = lsdec * base + i;
3353                     msscale *= base;
3354                 }
3355                 else
3356                 {
3357                     exp += expIter;
3358                 }
3359                 exp -= dot;
3360                 static if (doCount) ++count;
3361                 p.popFront();
3362                 if (p.empty)
3363                     break;
3364                 i = p.front;
3365                 if (i == '_')
3366                 {
3367                     static if (doCount) ++count;
3368                     p.popFront();
3369                     if (p.empty)
3370                         break;
3371                     i = p.front;
3372                 }
3373             }
3374             if (i == '.' && !dot)
3375             {
3376                 static if (doCount) ++count;
3377                 p.popFront();
3378                 dot += expIter;
3379             }
3380             else
3381                 break;
3382         }
3383 
3384         // Have we seen any mantissa digits so far?
3385         enforce(sawDigits, bailOut("no digits seen"));
3386         static if (FloatFormat == hex)
3387             enforce(!p.empty && (p.front == 'p' || p.front == 'P'),
3388                     bailOut("Floating point parsing: exponent is required"));
3389     }
3390 
3391     if (isHex)
3392         parseDigits!hex;
3393     else
3394         parseDigits!decimal;
3395 
3396     if (isHex || (!p.empty && (p.front == 'e' || p.front == 'E')))
3397     {
3398         char sexp = 0;
3399         int e = 0;
3400 
3401         static if (doCount) ++count;
3402         p.popFront();
3403         enforce(!p.empty, new ConvException("Unexpected end of input"));
3404         switch (p.front)
3405         {
3406             case '-':    sexp++;
3407                          goto case;
3408             case '+':    static if (doCount) ++count;
3409                          p.popFront();
3410                          break;
3411             default: {}
3412         }
3413         sawDigits = false;
3414         while (!p.empty && isDigit(p.front))
3415         {
3416             if (e < 0x7FFFFFFF / 10 - 10)   // prevent integer overflow
3417             {
3418                 e = e * 10 + p.front - '0';
3419             }
3420             static if (doCount) ++count;
3421             p.popFront();
3422             sawDigits = true;
3423         }
3424         exp += (sexp) ? -e : e;
3425         enforce(sawDigits, new ConvException("No digits seen."));
3426     }
3427 
3428     ldval = msdec;
3429     if (msscale != 1)               /* if stuff was accumulated in lsdec */
3430         ldval = ldval * msscale + lsdec;
3431     if (isHex)
3432     {
3433         import core.math : ldexp;
3434 
3435         // Exponent is power of 2, not power of 10
3436         ldval = ldexp(ldval,exp);
3437     }
3438     else if (ldval)
3439     {
3440         uint u = 0;
3441         int pow = 4096;
3442 
3443         while (exp > 0)
3444         {
3445             while (exp >= pow)
3446             {
3447                 ldval *= postab[u];
3448                 exp -= pow;
3449             }
3450             pow >>= 1;
3451             u++;
3452         }
3453         while (exp < 0)
3454         {
3455             while (exp <= -pow)
3456             {
3457                 ldval *= negtab[u];
3458                 enforce(ldval != 0, new ConvException("Range error"));
3459                 exp += pow;
3460             }
3461             pow >>= 1;
3462             u++;
3463         }
3464     }
3465 
3466     Target result = cast(Target) (sign ? -ldval : ldval);
3467 
3468     // if overflow occurred
3469     import std.math.traits : isFinite;
3470     enforce(isFinite(result), new ConvException("Range error"));
3471 
3472     advanceSource();
3473     static if (doCount)
3474     {
3475         return tuple!("data", "count")(result, count);
3476     }
3477     else
3478     {
3479         return result;
3480     }
3481 }
3482 
3483 
3484 ///
3485 @safe unittest
3486 {
3487     import std.math.operations : isClose;
3488     import std.math.traits : isNaN, isInfinity;
3489     import std.typecons : Flag, Yes, No;
3490     auto str = "123.456";
3491     assert(parse!double(str).isClose(123.456));
3492     auto str2 = "123.456";
3493     assert(parse!(double, string, No.doCount)(str2).isClose(123.456));
3494     auto str3 = "123.456";
3495     auto r = parse!(double, string, Yes.doCount)(str3);
3496     assert(r.data.isClose(123.456));
3497     assert(r.count == 7);
3498     auto str4 = "-123.456";
3499     r = parse!(double, string, Yes.doCount)(str4);
3500     assert(r.data.isClose(-123.456));
3501     assert(r.count == 8);
3502     auto str5 = "+123.456";
3503     r = parse!(double, string, Yes.doCount)(str5);
3504     assert(r.data.isClose(123.456));
3505     assert(r.count == 8);
3506     auto str6 = "inf0";
3507     r = parse!(double, string, Yes.doCount)(str6);
3508     assert(isInfinity(r.data) && r.count == 3 && str6 == "0");
3509     auto str7 = "-0";
3510     auto r2 = parse!(float, string, Yes.doCount)(str7);
3511     assert(r2.data.isClose(0.0) && r2.count == 2);
3512     auto str8 = "nan";
3513     auto r3 = parse!(real, string, Yes.doCount)(str8);
3514     assert(isNaN(r3.data) && r3.count == 3);
3515 }
3516 
3517 @safe unittest
3518 {
3519     import std.exception;
3520     import std.math.traits : isNaN, isInfinity;
3521     import std.math.algebraic : fabs;
3522 
3523     // Compare reals with given precision
3524     bool feq(in real rx, in real ry, in real precision = 0.000001L)
3525     {
3526         if (rx == ry)
3527             return 1;
3528 
3529         if (isNaN(rx))
3530             return cast(bool) isNaN(ry);
3531 
3532         if (isNaN(ry))
3533             return 0;
3534 
3535         return cast(bool)(fabs(rx - ry) <= precision);
3536     }
3537 
3538     // Make given typed literal
3539     F Literal(F)(F f)
3540     {
3541         return f;
3542     }
3543 
3544     static foreach (Float; AliasSeq!(float, double, real))
3545     {
3546         assert(to!Float("123") == Literal!Float(123));
3547         assert(to!Float("+123") == Literal!Float(+123));
3548         assert(to!Float("-123") == Literal!Float(-123));
3549         assert(to!Float("123e2") == Literal!Float(123e2));
3550         assert(to!Float("123e+2") == Literal!Float(123e+2));
3551         assert(to!Float("123e-2") == Literal!Float(123e-2L));
3552         assert(to!Float("123.") == Literal!Float(123.0));
3553         assert(to!Float(".375") == Literal!Float(.375));
3554 
3555         assert(to!Float("1.23375E+2") == Literal!Float(1.23375E+2));
3556 
3557         assert(to!Float("0") is 0.0);
3558         assert(to!Float("-0") is -0.0);
3559 
3560         assert(isNaN(to!Float("nan")));
3561 
3562         assertThrown!ConvException(to!Float("\x00"));
3563     }
3564 
3565     // min and max
3566     float f = to!float("1.17549e-38");
3567     assert(feq(cast(real) f, cast(real) 1.17549e-38));
3568     assert(feq(cast(real) f, cast(real) float.min_normal));
3569     f = to!float("3.40282e+38");
3570     assert(to!string(f) == to!string(3.40282e+38));
3571 
3572     // min and max
3573     double d = to!double("2.22508e-308");
3574     assert(feq(cast(real) d, cast(real) 2.22508e-308));
3575     assert(feq(cast(real) d, cast(real) double.min_normal));
3576     d = to!double("1.79769e+308");
3577     assert(to!string(d) == to!string(1.79769e+308));
3578     assert(to!string(d) == to!string(double.max));
3579 
3580     auto z = real.max / 2L;
3581     static assert(is(typeof(z) == real));
3582     assert(!isNaN(z));
3583     assert(!isInfinity(z));
3584     string a = to!string(z);
3585     real b = to!real(a);
3586     string c = to!string(b);
3587 
3588     assert(c == a, "\n" ~ c ~ "\n" ~ a);
3589 
3590     assert(to!string(to!real(to!string(real.max / 2L))) == to!string(real.max / 2L));
3591 
3592     // min and max
3593     real r = to!real(to!string(real.min_normal));
3594     version (NetBSD)
3595     {
3596         // NetBSD notice
3597         // to!string returns 3.3621e-4932L. It is less than real.min_normal and it is subnormal value
3598         // Simple C code
3599         //     long double rd = 3.3621e-4932L;
3600         //     printf("%Le\n", rd);
3601         // has unexpected result: 1.681050e-4932
3602         //
3603         // Bug report: http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=50937
3604     }
3605     else
3606     {
3607         assert(to!string(r) == to!string(real.min_normal));
3608     }
3609     r = to!real(to!string(real.max));
3610     assert(to!string(r) == to!string(real.max));
3611 
3612     real pi = 3.1415926535897932384626433832795028841971693993751L;
3613     string fullPrecision = "3.1415926535897932384626433832795028841971693993751";
3614     assert(feq(parse!real(fullPrecision), pi, 2*real.epsilon));
3615     string fullPrecision2 = "3.1415926535897932384626433832795028841971693993751";
3616     assert(feq(parse!(real, string, No.doCount)(fullPrecision2), pi, 2*real.epsilon));
3617     string fullPrecision3= "3.1415926535897932384626433832795028841971693993751";
3618     auto len = fullPrecision3.length;
3619     auto res = parse!(real, string, Yes.doCount)(fullPrecision3);
3620     assert(feq(res.data, pi, 2*real.epsilon));
3621     assert(res.count == len);
3622 
3623     real x = 0x1.FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAAFAAFAFAFAFAFAFAFAP-252L;
3624     string full = "0x1.FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAAFAAFAFAFAFAFAFAFAP-252";
3625     assert(parse!real(full) == x);
3626     string full2 = "0x1.FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAAFAAFAFAFAFAFAFAFAP-252";
3627     assert(parse!(real, string, No.doCount)(full2) == x);
3628     string full3 = "0x1.FAFAFAFAFAFAFAFAFAFAFAFAFAFAFAFAAFAAFAFAFAFAFAFAFAP-252";
3629     auto len2 = full3.length;
3630     assert(parse!(real, string, Yes.doCount)(full3) == tuple(x, len2));
3631 }
3632 
3633 // Tests for the double implementation
3634 @system unittest
3635 {
3636     // @system because strtod is not @safe.
3637     import std.math.traits : floatTraits, RealFormat;
3638 
3639     static if (floatTraits!real.realFormat == RealFormat.ieeeDouble)
3640     {
3641         import core.stdc.stdlib, std.exception, std.math;
3642 
3643         //Should be parsed exactly: 53 bit mantissa
3644         string s = "0x1A_BCDE_F012_3456p10";
3645         auto x = parse!real(s);
3646         assert(x == 0x1A_BCDE_F012_3456p10L);
3647         //1 bit is implicit
3648         assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0xA_BCDE_F012_3456);
3649         assert(strtod("0x1ABCDEF0123456p10", null) == x);
3650 
3651         s = "0x1A_BCDE_F012_3456p10";
3652         auto len = s.length;
3653         assert(parse!(real, string, Yes.doCount)(s) == tuple(x, len));
3654 
3655         //Should be parsed exactly: 10 bit mantissa
3656         s = "0x3FFp10";
3657         x = parse!real(s);
3658         assert(x == 0x03FFp10);
3659         //1 bit is implicit
3660         assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_F800_0000_0000);
3661         assert(strtod("0x3FFp10", null) == x);
3662 
3663         //60 bit mantissa, round up
3664         s = "0xFFF_FFFF_FFFF_FFFFp10";
3665         x = parse!real(s);
3666         assert(isClose(x, 0xFFF_FFFF_FFFF_FFFFp10));
3667         //1 bit is implicit
3668         assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x0000_0000_0000_0000);
3669         assert(strtod("0xFFFFFFFFFFFFFFFp10", null) == x);
3670 
3671         //60 bit mantissa, round down
3672         s = "0xFFF_FFFF_FFFF_FF90p10";
3673         x = parse!real(s);
3674         assert(isClose(x, 0xFFF_FFFF_FFFF_FF90p10));
3675         //1 bit is implicit
3676         assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_FFFF_FFFF_FFFF);
3677         assert(strtod("0xFFFFFFFFFFFFF90p10", null) == x);
3678 
3679         //61 bit mantissa, round up 2
3680         s = "0x1F0F_FFFF_FFFF_FFFFp10";
3681         x = parse!real(s);
3682         assert(isClose(x, 0x1F0F_FFFF_FFFF_FFFFp10));
3683         //1 bit is implicit
3684         assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_1000_0000_0000);
3685         assert(strtod("0x1F0FFFFFFFFFFFFFp10", null) == x);
3686 
3687         //61 bit mantissa, round down 2
3688         s = "0x1F0F_FFFF_FFFF_FF10p10";
3689         x = parse!real(s);
3690         assert(isClose(x, 0x1F0F_FFFF_FFFF_FF10p10));
3691         //1 bit is implicit
3692         assert(((*cast(ulong*)&x) & 0x000F_FFFF_FFFF_FFFF) == 0x000F_0FFF_FFFF_FFFF);
3693         assert(strtod("0x1F0FFFFFFFFFFF10p10", null) == x);
3694 
3695         //Huge exponent
3696         s = "0x1F_FFFF_FFFF_FFFFp900";
3697         x = parse!real(s);
3698         assert(strtod("0x1FFFFFFFFFFFFFp900", null) == x);
3699 
3700         //exponent too big -> converror
3701         s = "";
3702         assertThrown!ConvException(x = parse!real(s));
3703         assert(strtod("0x1FFFFFFFFFFFFFp1024", null) == real.infinity);
3704 
3705         //-exponent too big -> 0
3706         s = "0x1FFFFFFFFFFFFFp-2000";
3707         x = parse!real(s);
3708         assert(x == 0);
3709         assert(strtod("0x1FFFFFFFFFFFFFp-2000", null) == x);
3710 
3711         s = "0x1FFFFFFFFFFFFFp-2000";
3712         len = s.length;
3713         assert(parse!(real, string, Yes.doCount)(s) == tuple(x, len));
3714     }
3715 }
3716 
3717 @system unittest
3718 {
3719     import core.stdc.errno;
3720     import core.stdc.stdlib;
3721     import std.math.traits : floatTraits, RealFormat;
3722 
3723     errno = 0;  // In case it was set by another unittest in a different module.
3724     struct longdouble
3725     {
3726         static if (floatTraits!real.realFormat == RealFormat.ieeeQuadruple)
3727         {
3728             ushort[8] value;
3729         }
3730         else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended ||
3731                         floatTraits!real.realFormat == RealFormat.ieeeExtended53)
3732         {
3733             ushort[5] value;
3734         }
3735         else static if (floatTraits!real.realFormat == RealFormat.ieeeDouble)
3736         {
3737             ushort[4] value;
3738         }
3739         else
3740             static assert(false, "Not implemented");
3741     }
3742 
3743     real ld;
3744     longdouble x;
3745     real ld1;
3746     longdouble x1;
3747     int i;
3748 
3749     static if (floatTraits!real.realFormat == RealFormat.ieeeQuadruple)
3750         enum s = "0x1.FFFFFFFFFFFFFFFFFFFFFFFFFFFFp-16382";
3751     else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended)
3752         enum s = "0x1.FFFFFFFFFFFFFFFEp-16382";
3753     else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended53)
3754         enum s = "0x1.FFFFFFFFFFFFFFFEp-16382";
3755     else static if (floatTraits!real.realFormat == RealFormat.ieeeDouble)
3756         enum s = "0x1.FFFFFFFFFFFFFFFEp-1000";
3757     else
3758         static assert(false, "Floating point format for real not supported");
3759 
3760     auto s2 = s.idup;
3761     ld = parse!real(s2);
3762     assert(s2.empty);
3763     x = *cast(longdouble *)&ld;
3764 
3765     static if (floatTraits!real.realFormat == RealFormat.ieeeExtended)
3766     {
3767         version (CRuntime_Microsoft)
3768             ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold currently mapped to strtod
3769         else
3770             ld1 = strtold(s.ptr, null);
3771     }
3772     else static if (floatTraits!real.realFormat == RealFormat.ieeeExtended53)
3773         ld1 = 0x1.FFFFFFFFFFFFFFFEp-16382L; // strtold rounds to 53 bits.
3774     else
3775         ld1 = strtold(s.ptr, null);
3776 
3777     x1 = *cast(longdouble *)&ld1;
3778     assert(x1 == x && ld1 == ld);
3779 
3780     assert(!errno);
3781 
3782     s2 = "1.0e5";
3783     ld = parse!real(s2);
3784     assert(s2.empty);
3785     x = *cast(longdouble *)&ld;
3786     ld1 = strtold("1.0e5", null);
3787     x1 = *cast(longdouble *)&ld1;
3788 }
3789 
3790 @safe pure unittest
3791 {
3792     import std.exception;
3793 
3794     // https://issues.dlang.org/show_bug.cgi?id=4959
3795     {
3796         auto s = "0 ";
3797         auto x = parse!double(s);
3798         assert(s == " ");
3799         assert(x == 0.0);
3800     }
3801     {
3802         auto s = "0 ";
3803         auto x = parse!(double, string, Yes.doCount)(s);
3804         assert(s == " ");
3805         assert(x == tuple(0.0, 1));
3806     }
3807 
3808     // https://issues.dlang.org/show_bug.cgi?id=3369
3809     assert(to!float("inf") == float.infinity);
3810     assert(to!float("-inf") == -float.infinity);
3811 
3812     // https://issues.dlang.org/show_bug.cgi?id=6160
3813     assert(6_5.536e3L == to!real("6_5.536e3"));                     // 2^16
3814     assert(0x1000_000_000_p10 == to!real("0x1000_000_000_p10"));    // 7.03687e+13
3815 
3816     // https://issues.dlang.org/show_bug.cgi?id=6258
3817     assertThrown!ConvException(to!real("-"));
3818     assertThrown!ConvException(to!real("in"));
3819 
3820     // https://issues.dlang.org/show_bug.cgi?id=7055
3821     assertThrown!ConvException(to!float("INF2"));
3822 
3823     //extra stress testing
3824     auto ssOK    = ["1.", "1.1.1", "1.e5", "2e1e", "2a", "2e1_1", "3.4_",
3825                     "inf", "-inf", "infa", "-infa", "inf2e2", "-inf2e2",
3826                     "nan", "-NAN", "+NaN", "-nAna", "NAn2e2", "-naN2e2"];
3827     auto ssKO    = ["", " ", "2e", "2e+", "2e-", "2ee", "2e++1", "2e--1", "2e_1",
3828                     "+inf", "-in", "I", "+N", "-NaD", "0x3.F"];
3829     foreach (s; ssOK)
3830         parse!double(s);
3831     foreach (s; ssKO)
3832         assertThrown!ConvException(parse!double(s));
3833 }
3834 
3835 @safe unittest // https://issues.dlang.org/show_bug.cgi?id=22637
3836 {
3837     import std.exception : assertThrown, assertNotThrown;
3838     auto src = "9991232549867999698999493543521458974414359998784641646846435132132543645435456345634541999999999999999"
3839     ~ "9999999943321231321311999231345312413646846354354354399999934153465464654646464654134135354199999999996515734999"
3840     ~ "9999999320135273486741354354731567431324134999999999999999999999999999999999999999999999135411.9";
3841     assertThrown!ConvException(parse!double(src));
3842     static if (real.max_10_exp > 310) assertNotThrown!ConvException(parse!real(src));
3843 }
3844 
3845 /**
3846 Parses one character from a character range.
3847 
3848 Params:
3849     Target = the type to convert to
3850     s = the lvalue of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3851     doCount = the flag for deciding to report the number of consumed characters
3852 
3853 Returns:
3854 $(UL
3855     $(LI A character of type `Target` if `doCount` is set to `No.doCount`)
3856     $(LI A `tuple` containing a character of type `Target` and a `size_t` if `doCount` is set to `Yes.doCount`))
3857 
3858 Throws:
3859     A $(LREF ConvException) if the range is empty.
3860  */
3861 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
3862 if (staticIndexOf!(immutable Target, immutable dchar, immutable ElementEncodingType!Source) >= 0 &&
3863     isSomeString!Source && !is(Source == enum))
3864 {
3865     if (s.empty)
3866         throw convError!(Source, Target)(s);
3867     static if (is(immutable Target == immutable dchar))
3868     {
3869         Target result = s.front;
3870         s.popFront();
3871         static if (doCount)
3872         {
3873             return tuple!("data", "count")(result, 1);
3874         }
3875         else
3876         {
3877             return result;
3878         }
3879 
3880     }
3881     else
3882     {
3883         // Special case: okay so parse a Char off a Char[]
3884         Target result = s[0];
3885         s = s[1 .. $];
3886         static if (doCount)
3887         {
3888             return tuple!("data", "count")(result, 1);
3889         }
3890         else
3891         {
3892             return result;
3893         }
3894     }
3895 }
3896 
3897 @safe pure unittest
3898 {
3899     static foreach (Str; AliasSeq!(string, wstring, dstring))
3900     {
3901         static foreach (Char; AliasSeq!(char, wchar, dchar))
3902         {{
3903             static if (is(immutable Char == immutable dchar) ||
3904                        Char.sizeof == ElementEncodingType!Str.sizeof)
3905             {
3906                 Str s = "aaa";
3907                 assert(parse!Char(s) == 'a');
3908                 assert(s == "aa");
3909                 assert(parse!(Char, typeof(s), No.doCount)(s) == 'a');
3910                 assert(s == "a");
3911                 assert(parse!(Char, typeof(s), Yes.doCount)(s) == tuple('a', 1) && s == "");
3912             }
3913         }}
3914     }
3915 }
3916 
3917 /// ditto
3918 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
3919 if (isSomeChar!Target && Target.sizeof >= ElementType!Source.sizeof && !is(Target == enum) &&
3920     !isSomeString!Source && isInputRange!Source && isSomeChar!(ElementType!Source))
3921 {
3922     if (s.empty)
3923         throw convError!(Source, Target)(s);
3924     Target result = s.front;
3925     s.popFront();
3926     static if (doCount)
3927     {
3928         return tuple!("data", "count")(result, 1);
3929     }
3930     else
3931     {
3932         return result;
3933     }
3934 }
3935 
3936 ///
3937 @safe pure unittest
3938 {
3939     import std.typecons : Flag, Yes, No;
3940     auto s = "Hello, World!";
3941     char first = parse!char(s);
3942     assert(first == 'H');
3943     assert(s == "ello, World!");
3944     char second = parse!(char, string, No.doCount)(s);
3945     assert(second == 'e');
3946     assert(s == "llo, World!");
3947     auto third = parse!(char, string, Yes.doCount)(s);
3948     assert(third.data == 'l' && third.count == 1);
3949     assert(s == "lo, World!");
3950 }
3951 
3952 
3953 /*
3954     Tests for to!bool and parse!bool
3955 */
3956 @safe pure unittest
3957 {
3958     import std.exception;
3959 
3960     assert(to!bool("TruE") == true);
3961     assert(to!bool("faLse"d) == false);
3962     assertThrown!ConvException(to!bool("maybe"));
3963 
3964     auto t = "TrueType";
3965     assert(parse!bool(t) == true);
3966     assert(t == "Type");
3967 
3968     auto f = "False killer whale"d;
3969     assert(parse!bool(f) == false);
3970     assert(f == " killer whale"d);
3971 
3972     f = "False killer whale"d;
3973     assert(parse!(bool, dstring, Yes.doCount)(f) == tuple(false, 5));
3974     assert(f == " killer whale"d);
3975 
3976     auto m = "maybe";
3977     assertThrown!ConvException(parse!bool(m));
3978     assertThrown!ConvException(parse!(bool, string, Yes.doCount)(m));
3979     assert(m == "maybe");  // m shouldn't change on failure
3980 
3981     auto s = "true";
3982     auto b = parse!(const(bool))(s);
3983     assert(b == true);
3984 }
3985 
3986 /**
3987 Parses `typeof(null)` from a character range if the range
3988 spells `"null"`. This function is case insensitive.
3989 
3990 Params:
3991     Target = the type to convert to
3992     s = the lvalue of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
3993     doCount = the flag for deciding to report the number of consumed characters
3994 
3995 Returns:
3996 $(UL
3997     $(LI `null` if `doCount` is set to `No.doCount`)
3998     $(LI A `tuple` containing `null` and a `size_t` if `doCount` is set to `Yes.doCount`))
3999 
4000 Throws:
4001     A $(LREF ConvException) if the range doesn't represent `null`.
4002  */
4003 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
4004 if (is(immutable Target == immutable typeof(null)) &&
4005     isInputRange!Source &&
4006     isSomeChar!(ElementType!Source))
4007 {
4008     import std.ascii : toLower;
4009     foreach (c; "null")
4010     {
4011         if (s.empty || toLower(s.front) != c)
4012             throw parseError("null should be case-insensitive 'null'");
4013         s.popFront();
4014     }
4015     static if (doCount)
4016     {
4017         return tuple!("data", "count")(null, 4);
4018     }
4019     else
4020     {
4021         return null;
4022     }
4023 }
4024 
4025 ///
4026 @safe pure unittest
4027 {
4028     import std.exception : assertThrown;
4029     import std.typecons : Flag, Yes, No;
4030 
4031     alias NullType = typeof(null);
4032     auto s1 = "null";
4033     assert(parse!NullType(s1) is null);
4034     assert(s1 == "");
4035 
4036     auto s2 = "NUll"d;
4037     assert(parse!NullType(s2) is null);
4038     assert(s2 == "");
4039 
4040     auto s3 = "nuLlNULl";
4041     assert(parse!(NullType, string, No.doCount)(s3) is null);
4042     auto r = parse!(NullType, string, Yes.doCount)(s3);
4043     assert(r.data is null && r.count == 4);
4044 
4045     auto m = "maybe";
4046     assertThrown!ConvException(parse!NullType(m));
4047     assertThrown!ConvException(parse!(NullType, string, Yes.doCount)(m));
4048     assert(m == "maybe");  // m shouldn't change on failure
4049 
4050     auto s = "NULL";
4051     assert(parse!(const NullType)(s) is null);
4052 }
4053 
4054 //Used internally by parse Array/AA, to remove ascii whites
4055 package auto skipWS(R, Flag!"doCount" doCount = No.doCount)(ref R r)
4056 {
4057     import std.ascii : isWhite;
4058     static if (isSomeString!R)
4059     {
4060         //Implementation inspired from stripLeft.
4061         foreach (i, c; r)
4062         {
4063             if (!isWhite(c))
4064             {
4065                 r = r[i .. $];
4066                 static if (doCount)
4067                 {
4068                     return i;
4069                 }
4070                 else
4071                 {
4072                     return;
4073                 }
4074             }
4075         }
4076         auto len = r.length;
4077         r = r[0 .. 0]; //Empty string with correct type.
4078         static if (doCount)
4079         {
4080             return len;
4081         }
4082         else
4083         {
4084             return;
4085         }
4086     }
4087     else
4088     {
4089         size_t i = 0;
4090         for (; !r.empty && isWhite(r.front); r.popFront(), ++i)
4091         { }
4092         static if (doCount)
4093         {
4094             return i;
4095         }
4096     }
4097 }
4098 
4099 /**
4100  * Parses an array from a string given the left bracket (default $(D
4101  * '[')), right bracket (default `']'`), and element separator (by
4102  * default `','`). A trailing separator is allowed.
4103  *
4104  * Params:
4105  *     s = The string to parse
4106  *     lbracket = the character that starts the array
4107  *     rbracket = the character that ends the array
4108  *     comma = the character that separates the elements of the array
4109  *     doCount = the flag for deciding to report the number of consumed characters
4110  *
4111  * Returns:
4112  $(UL
4113  *     $(LI An array of type `Target` if `doCount` is set to `No.doCount`)
4114  *     $(LI A `tuple` containing an array of type `Target` and a `size_t` if `doCount` is set to `Yes.doCount`))
4115  */
4116 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s, dchar lbracket = '[',
4117     dchar rbracket = ']', dchar comma = ',')
4118 if (isDynamicArray!Target && !is(Target == enum) &&
4119     isSomeString!Source && !is(Source == enum))
4120 {
4121     import std.array : appender;
4122 
4123     auto result = appender!Target();
4124 
4125     parseCheck!s(lbracket);
4126     static if (doCount)
4127         size_t count = 1;
4128     static if (doCount)
4129         count += skipWS!(Source, Yes.doCount)(s);
4130     else
4131         skipWS!(Source, No.doCount)(s);
4132     if (s.empty)
4133         throw convError!(Source, Target)(s);
4134     if (s.front == rbracket)
4135     {
4136         s.popFront();
4137         static if (doCount)
4138         {
4139             ++count;
4140             return tuple!("data", "count")(result.data, count);
4141         }
4142         else
4143         {
4144             return result.data;
4145         }
4146     }
4147     for (;;)
4148     {
4149         if (!s.empty && s.front == rbracket)
4150             break;
4151         static if (doCount)
4152         {
4153             auto r = parseElement!(WideElementType!Target, Source, Yes.doCount)(s);
4154             result ~= r.data;
4155             count += r.count;
4156             count += skipWS!(Source, Yes.doCount)(s);
4157         }
4158         else
4159         {
4160             auto r = parseElement!(WideElementType!Target, Source, No.doCount)(s);
4161             result ~= r;
4162             skipWS!(Source, No.doCount)(s);
4163         }
4164         if (s.empty)
4165             throw convError!(Source, Target)(s);
4166         if (s.front != comma)
4167             break;
4168         s.popFront();
4169         static if (doCount)
4170             ++count;
4171         static if (doCount)
4172             count += skipWS!(Source, Yes.doCount)(s);
4173         else
4174             skipWS!(Source, No.doCount)(s);
4175     }
4176     parseCheck!s(rbracket);
4177     static if (doCount)
4178     {
4179         ++count;
4180         return tuple!("data", "count")(result.data, count);
4181     }
4182     else
4183     {
4184         return result.data;
4185     }
4186 }
4187 ///
4188 @safe pure unittest
4189 {
4190     import std.typecons : Flag, Yes, No;
4191     auto s1 = `[['h', 'e', 'l', 'l', 'o'], "world"]`;
4192     auto a1 = parse!(string[])(s1);
4193     assert(a1 == ["hello", "world"]);
4194 
4195     auto s2 = `["aaa", "bbb", "ccc"]`;
4196     auto a2 = parse!(string[])(s2);
4197     assert(a2 == ["aaa", "bbb", "ccc"]);
4198 
4199     auto s3 = `[['h', 'e', 'l', 'l', 'o'], "world"]`;
4200     auto len3 = s3.length;
4201     auto a3 = parse!(string[], string, Yes.doCount)(s3);
4202     assert(a3.data == ["hello", "world"]);
4203     assert(a3.count == len3);
4204 }
4205 
4206 // https://issues.dlang.org/show_bug.cgi?id=9615
4207 @safe unittest
4208 {
4209     import std.typecons : Flag, Yes, No, tuple;
4210     string s0 = "[1,2, ]";
4211     string s1 = "[1,2, \t\v\r\n]";
4212     string s2 = "[1,2]";
4213     assert(s0.parse!(int[]) == [1,2]);
4214     assert(s1.parse!(int[]) == [1,2]);
4215     assert(s2.parse!(int[]) == [1,2]);
4216 
4217     s0 = "[1,2, ]";
4218     auto len0 = s0.length;
4219     s1 = "[1,2, \t\v\r\n]";
4220     auto len1 = s1.length;
4221     s2 = "[1,2]";
4222     auto len2 = s2.length;
4223     assert(s0.parse!(int[], string, Yes.doCount) == tuple([1,2], len0));
4224     assert(s1.parse!(int[], string, Yes.doCount) == tuple([1,2], len1));
4225     assert(s2.parse!(int[], string, Yes.doCount) == tuple([1,2], len2));
4226 
4227     string s3 = `["a","b",]`;
4228     string s4 = `["a","b"]`;
4229     assert(s3.parse!(string[]) == ["a","b"]);
4230     assert(s4.parse!(string[]) == ["a","b"]);
4231 
4232     s3 = `["a","b",]`;
4233     auto len3 = s3.length;
4234     assert(s3.parse!(string[], string, Yes.doCount) == tuple(["a","b"], len3));
4235 
4236     s3 = `[    ]`;
4237     assert(tuple([], s3.length) == s3.parse!(string[], string, Yes.doCount));
4238 
4239     import std.exception : assertThrown;
4240     string s5 = "[,]";
4241     string s6 = "[, \t,]";
4242     assertThrown!ConvException(parse!(string[])(s5));
4243     assertThrown!ConvException(parse!(int[])(s6));
4244 
4245     s5 = "[,]";
4246     s6 = "[,·\t,]";
4247     assertThrown!ConvException(parse!(string[], string, Yes.doCount)(s5));
4248     assertThrown!ConvException(parse!(string[], string, Yes.doCount)(s6));
4249 }
4250 
4251 @safe unittest
4252 {
4253     int[] a = [1, 2, 3, 4, 5];
4254     auto s = to!string(a);
4255     assert(to!(int[])(s) == a);
4256 }
4257 
4258 @safe unittest
4259 {
4260     int[][] a = [ [1, 2] , [3], [4, 5] ];
4261     auto s = to!string(a);
4262     assert(to!(int[][])(s) == a);
4263 }
4264 
4265 @safe unittest
4266 {
4267     int[][][] ia = [ [[1,2],[3,4],[5]] , [[6],[],[7,8,9]] , [[]] ];
4268 
4269     char[] s = to!(char[])(ia);
4270     int[][][] ia2;
4271 
4272     ia2 = to!(typeof(ia2))(s);
4273     assert( ia == ia2);
4274 }
4275 
4276 @safe pure unittest
4277 {
4278     import std.exception;
4279     import std.typecons : Flag, Yes, No;
4280 
4281     //Check proper failure
4282     auto s = "[ 1 , 2 , 3 ]";
4283     auto s2 = s.save;
4284     foreach (i ; 0 .. s.length-1)
4285     {
4286         auto ss = s[0 .. i];
4287         assertThrown!ConvException(parse!(int[])(ss));
4288         assertThrown!ConvException(parse!(int[], string, Yes.doCount)(ss));
4289     }
4290     int[] arr = parse!(int[])(s);
4291     auto arr2 = parse!(int[], string, Yes.doCount)(s2);
4292     arr = arr2.data;
4293 }
4294 
4295 @safe pure unittest
4296 {
4297     //Checks parsing of strings with escaped characters
4298     string s1 = `[
4299         "Contains a\0null!",
4300         "tab\there",
4301         "line\nbreak",
4302         "backslash \\ slash / question \?",
4303         "number \x35 five",
4304         "unicode \u65E5 sun",
4305         "very long \U000065E5 sun"
4306     ]`;
4307 
4308     //Note: escaped characters purposefully replaced and isolated to guarantee
4309     //there are no typos in the escape syntax
4310     string[] s2 = [
4311         "Contains a" ~ '\0' ~ "null!",
4312         "tab" ~ '\t' ~ "here",
4313         "line" ~ '\n' ~ "break",
4314         "backslash " ~ '\\' ~ " slash / question ?",
4315         "number 5 five",
4316         "unicode 日 sun",
4317         "very long 日 sun"
4318     ];
4319     string s3 = s1.save;
4320     assert(s2 == parse!(string[])(s1));
4321     assert(s1.empty);
4322     assert(tuple(s2, s3.length) == parse!(string[], string, Yes.doCount)(s3));
4323 }
4324 
4325 /// ditto
4326 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s, dchar lbracket = '[',
4327     dchar rbracket = ']', dchar comma = ',')
4328 if (isStaticArray!Target && !is(Target == enum) &&
4329     isExactSomeString!Source)
4330 {
4331     static if (hasIndirections!Target)
4332         Target result = Target.init[0].init;
4333     else
4334         Target result = void;
4335 
4336     parseCheck!s(lbracket);
4337     static if (doCount)
4338         size_t count = 1;
4339     static if (doCount)
4340         count += skipWS!(Source, Yes.doCount)(s);
4341     else
4342         skipWS!(Source, No.doCount)(s);
4343     if (s.empty)
4344         throw convError!(Source, Target)(s);
4345     if (s.front == rbracket)
4346     {
4347         static if (result.length != 0)
4348             goto Lmanyerr;
4349         else
4350         {
4351             s.popFront();
4352             static if (doCount)
4353             {
4354                 ++count;
4355                 return tuple!("data", "count")(result, count);
4356             }
4357             else
4358             {
4359                 return result;
4360             }
4361         }
4362     }
4363     for (size_t i = 0; ; )
4364     {
4365         if (i == result.length)
4366             goto Lmanyerr;
4367         static if (doCount)
4368         {
4369             auto r = parseElement!(ElementType!Target, Source, Yes.doCount)(s);
4370             result[i++] = r.data;
4371             count += r.count;
4372             count += skipWS!(Source, Yes.doCount)(s);
4373         }
4374         else
4375         {
4376             auto r = parseElement!(ElementType!Target, Source, No.doCount)(s);
4377             result[i++] = r;
4378             skipWS!(Source, No.doCount)(s);
4379         }
4380         if (s.empty)
4381             throw convError!(Source, Target)(s);
4382         if (s.front != comma)
4383         {
4384             if (i != result.length)
4385                 goto Lfewerr;
4386             break;
4387         }
4388         s.popFront();
4389         static if (doCount)
4390             ++count;
4391         static if (doCount)
4392             count += skipWS!(Source, Yes.doCount)(s);
4393         else
4394             skipWS!(Source, No.doCount)(s);
4395     }
4396     parseCheck!s(rbracket);
4397     static if (doCount)
4398     {
4399         ++count;
4400         return tuple!("data", "count")(result, count);
4401     }
4402     else
4403     {
4404         return result;
4405     }
4406 
4407 Lmanyerr:
4408     throw parseError(text("Too many elements in input, ", result.length, " elements expected."));
4409 Lfewerr:
4410     throw parseError(text("Too few elements in input, ", result.length, " elements expected."));
4411 }
4412 
4413 @safe pure unittest
4414 {
4415     import std.exception;
4416 
4417     auto s1 = "[1,2,3,4]";
4418     auto sa1 = parse!(int[4])(s1);
4419     assert(sa1 == [1,2,3,4]);
4420     s1 = "[1,2,3,4]";
4421     assert(tuple([1,2,3,4], s1.length) == parse!(int[4], string, Yes.doCount)(s1));
4422 
4423     auto s2 = "[[1],[2,3],[4]]";
4424     auto sa2 = parse!(int[][3])(s2);
4425     assert(sa2 == [[1],[2,3],[4]]);
4426     s2 = "[[1],[2,3],[4]]";
4427     assert(tuple([[1],[2,3],[4]], s2.length) == parse!(int[][3], string, Yes.doCount)(s2));
4428 
4429     auto s3 = "[1,2,3]";
4430     assertThrown!ConvException(parse!(int[4])(s3));
4431     assertThrown!ConvException(parse!(int[4], string, Yes.doCount)(s3));
4432 
4433     auto s4 = "[1,2,3,4,5]";
4434     assertThrown!ConvException(parse!(int[4])(s4));
4435     assertThrown!ConvException(parse!(int[4], string, Yes.doCount)(s4));
4436 }
4437 
4438 /**
4439  * Parses an associative array from a string given the left bracket (default $(D
4440  * '[')), right bracket (default `']'`), key-value separator (default $(D
4441  * ':')), and element seprator (by default `','`).
4442  *
4443  * Params:
4444  *     s = the string to parse
4445  *     lbracket = the character that starts the associative array
4446  *     rbracket = the character that ends the associative array
4447  *     keyval = the character that associates the key with the value
4448  *     comma = the character that separates the elements of the associative array
4449  *     doCount = the flag for deciding to report the number of consumed characters
4450  *
4451  * Returns:
4452  $(UL
4453  *     $(LI An associative array of type `Target` if `doCount` is set to `No.doCount`)
4454  *     $(LI A `tuple` containing an associative array of type `Target` and a `size_t`
4455  *     if `doCount` is set to `Yes.doCount`))
4456  */
4457 auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s, dchar lbracket = '[',
4458                              dchar rbracket = ']', dchar keyval = ':', dchar comma = ',')
4459 if (isAssociativeArray!Target && !is(Target == enum) &&
4460     isSomeString!Source && !is(Source == enum))
4461 {
4462     alias KeyType = typeof(Target.init.keys[0]);
4463     alias ValType = typeof(Target.init.values[0]);
4464 
4465     Target result;
4466     static if (doCount) size_t count;
4467 
4468     parseCheck!s(lbracket);
4469     static if (doCount)
4470         count = 1 + skipWS!(Source, Yes.doCount)(s);
4471     else
4472         skipWS!(Source, No.doCount)(s);
4473     if (s.empty)
4474         throw convError!(Source, Target)(s);
4475     if (s.front == rbracket)
4476     {
4477         s.popFront();
4478         static if (doCount)
4479             return tuple!("data", "count")(result, count + 1);
4480         else
4481             return result;
4482     }
4483     for (;;)
4484     {
4485         static if (doCount)
4486         {
4487             auto key = parseElement!(KeyType, Source, Yes.doCount)(s);
4488             count += key.count + skipWS!(Source, Yes.doCount)(s);
4489             parseCheck!s(keyval);
4490             count += 1 + skipWS!(Source, Yes.doCount)(s);
4491             auto val = parseElement!(ValType, Source, Yes.doCount)(s);
4492             count += val.count + skipWS!(Source, Yes.doCount)(s);
4493             result[key.data] = val.data;
4494         }
4495         else
4496         {
4497             auto key = parseElement!(KeyType, Source, No.doCount)(s);
4498             skipWS!(Source, No.doCount)(s);
4499             parseCheck!s(keyval);
4500             skipWS!(Source, No.doCount)(s);
4501             auto val = parseElement!(ValType, Source, No.doCount)(s);
4502             skipWS!(Source, No.doCount)(s);
4503             result[key] = val;
4504         }
4505         if (s.empty)
4506             throw convError!(Source, Target)(s);
4507         if (s.front != comma)
4508             break;
4509         s.popFront();
4510         static if (doCount)
4511             count += 1 + skipWS!(Source, Yes.doCount)(s);
4512         else
4513             skipWS!(Source, No.doCount)(s);
4514     }
4515     parseCheck!s(rbracket);
4516     static if (doCount)
4517         return tuple!("data", "count")(result, count + 1);
4518     else
4519         return result;
4520 }
4521 
4522 ///
4523 @safe pure unittest
4524 {
4525     import std.typecons : Flag, Yes, No, tuple;
4526     import std.range.primitives : save;
4527     import std.array : assocArray;
4528     auto s1 = "[1:10, 2:20, 3:30]";
4529     auto copyS1 = s1.save;
4530     auto aa1 = parse!(int[int])(s1);
4531     assert(aa1 == [1:10, 2:20, 3:30]);
4532     assert(tuple([1:10, 2:20, 3:30], copyS1.length) == parse!(int[int], string, Yes.doCount)(copyS1));
4533 
4534     auto s2 = `["aaa":10, "bbb":20, "ccc":30]`;
4535     auto copyS2 = s2.save;
4536     auto aa2 = parse!(int[string])(s2);
4537     assert(aa2 == ["aaa":10, "bbb":20, "ccc":30]);
4538     assert(tuple(["aaa":10, "bbb":20, "ccc":30], copyS2.length) ==
4539         parse!(int[string], string, Yes.doCount)(copyS2));
4540 
4541     auto s3 = `["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]`;
4542     auto copyS3 = s3.save;
4543     auto aa3 = parse!(int[][string])(s3);
4544     assert(aa3 == ["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]]);
4545     assert(tuple(["aaa":[1], "bbb":[2,3], "ccc":[4,5,6]], copyS3.length) ==
4546         parse!(int[][string], string, Yes.doCount)(copyS3));
4547 
4548     auto s4 = `[]`;
4549     int[int] emptyAA;
4550     assert(tuple(emptyAA, s4.length) == parse!(int[int], string, Yes.doCount)(s4));
4551 }
4552 
4553 @safe pure unittest
4554 {
4555     import std.exception;
4556 
4557     //Check proper failure
4558     auto s = "[1:10, 2:20, 3:30]";
4559     auto s2 = s.save;
4560     foreach (i ; 0 .. s.length-1)
4561     {
4562         auto ss = s[0 .. i];
4563         assertThrown!ConvException(parse!(int[int])(ss));
4564         assertThrown!ConvException(parse!(int[int], string, Yes.doCount)(ss));
4565     }
4566     int[int] aa = parse!(int[int])(s);
4567     auto aa2 = parse!(int[int], string, Yes.doCount)(s2);
4568     aa  = aa2[0];
4569 
4570 }
4571 
4572 private auto parseEscape(Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
4573 if (isInputRange!Source && isSomeChar!(ElementType!Source))
4574 {
4575     parseCheck!s('\\');
4576     size_t count;
4577     static if (doCount)
4578         count = 1;
4579     if (s.empty)
4580         throw parseError("Unterminated escape sequence");
4581 
4582     // consumes 1 element from Source
4583     dchar getHexDigit()(ref Source s_ = s)  // workaround
4584     {
4585         import std.ascii : isAlpha, isHexDigit;
4586         if (s_.empty)
4587             throw parseError("Unterminated escape sequence");
4588         s_.popFront();
4589         if (s_.empty)
4590             throw parseError("Unterminated escape sequence");
4591         dchar c = s_.front;
4592         if (!isHexDigit(c))
4593             throw parseError("Hex digit is missing");
4594         return isAlpha(c) ? ((c & ~0x20) - ('A' - 10)) : c - '0';
4595     }
4596     // We need to do octals separate, because they need a lookahead to find out,
4597     // where the escape sequence ends.
4598     auto first = s.front;
4599     if (first >= '0' && first <= '7')
4600     {
4601         dchar c1 = s.front;
4602         s.popFront();
4603         static if (doCount)
4604             ++count;
4605         if (s.empty)
4606         {
4607             static if (doCount)
4608             {
4609                 return tuple!("data", "count")(cast (dchar) (c1 - '0'), count);
4610             }
4611             else
4612             {
4613                 return cast (dchar) (c1 - '0');
4614             }
4615         }
4616         dchar c2 = s.front;
4617         if (c2 < '0' || c2 > '7')
4618         {
4619             static if (doCount)
4620             {
4621                 return tuple!("data", "count")(cast (dchar)(c1 - '0'), count);
4622             }
4623             else
4624             {
4625                 return cast (dchar)(c1 - '0');
4626             }
4627         }
4628         s.popFront();
4629         static if (doCount)
4630             ++count;
4631         dchar c3 = s.front;
4632         if (c3 < '0' || c3 > '7')
4633         {
4634             static if (doCount)
4635             {
4636                 return tuple!("data", "count")(cast (dchar) (8 * (c1 - '0') + (c2 - '0')), count);
4637             }
4638             else
4639             {
4640                 return cast (dchar) (8 * (c1 - '0') + (c2 - '0'));
4641             }
4642         }
4643         s.popFront();
4644         static if (doCount)
4645             ++count;
4646         if (c1 > '3')
4647             throw parseError("Octal sequence is larger than \\377");
4648         static if (doCount)
4649         {
4650             return tuple!("data", "count")(cast (dchar) (64 * (c1 - '0') + 8 * (c2 - '0') + (c3 - '0')), count);
4651         }
4652         else
4653         {
4654             return cast (dchar) (64 * (c1 - '0') + 8 * (c2 - '0') + (c3 - '0'));
4655         }
4656     }
4657 
4658     dchar result;
4659 
4660     switch (first)
4661     {
4662         case '"':   result = '\"';  break;
4663         case '\'':  result = '\'';  break;
4664         case '?':   result = '\?';  break;
4665         case '\\':  result = '\\';  break;
4666         case 'a':   result = '\a';  break;
4667         case 'b':   result = '\b';  break;
4668         case 'f':   result = '\f';  break;
4669         case 'n':   result = '\n';  break;
4670         case 'r':   result = '\r';  break;
4671         case 't':   result = '\t';  break;
4672         case 'v':   result = '\v';  break;
4673         case 'x':
4674             result  = getHexDigit() << 4;
4675             result |= getHexDigit();
4676             static if (doCount)
4677                 count += 2;
4678             break;
4679         case 'u':
4680             result  = getHexDigit() << 12;
4681             result |= getHexDigit() << 8;
4682             result |= getHexDigit() << 4;
4683             result |= getHexDigit();
4684             static if (doCount)
4685                 count += 4;
4686             break;
4687         case 'U':
4688             result  = getHexDigit() << 28;
4689             result |= getHexDigit() << 24;
4690             result |= getHexDigit() << 20;
4691             result |= getHexDigit() << 16;
4692             result |= getHexDigit() << 12;
4693             result |= getHexDigit() << 8;
4694             result |= getHexDigit() << 4;
4695             result |= getHexDigit();
4696             static if (doCount)
4697                 count += 8;
4698             break;
4699         default:
4700             throw parseError("Unknown escape character " ~ to!string(s.front));
4701     }
4702     if (s.empty)
4703         throw parseError("Unterminated escape sequence");
4704 
4705     s.popFront();
4706 
4707     static if (doCount)
4708     {
4709         return tuple!("data", "count")(cast (dchar) result, ++count);
4710     }
4711     else
4712     {
4713         return cast (dchar) result;
4714     }
4715 }
4716 
4717 @safe pure unittest
4718 {
4719     string[] s1 = [
4720         `\"`, `\'`, `\?`, `\\`, `\a`, `\b`, `\f`, `\n`, `\r`, `\t`, `\v`, //Normal escapes
4721         `\141`,
4722         `\x61`,
4723         `\u65E5`, `\U00012456`,
4724          // https://issues.dlang.org/show_bug.cgi?id=9621 (Named Character Entities)
4725         //`\&amp;`, `\&quot;`,
4726     ];
4727     string[] copyS1 = s1 ~ s1[0 .. 0];
4728 
4729     const(dchar)[] s2 = [
4730         '\"', '\'', '\?', '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v', //Normal escapes
4731         '\141',
4732         '\x61',
4733         '\u65E5', '\U00012456',
4734         // https://issues.dlang.org/show_bug.cgi?id=9621 (Named Character Entities)
4735         //'\&amp;', '\&quot;',
4736     ];
4737     foreach (i ; 0 .. s1.length)
4738     {
4739         assert(s2[i] == parseEscape(s1[i]));
4740         assert(s1[i].empty);
4741 
4742         assert(tuple(s2[i], copyS1[i].length) == parseEscape!(string, Yes.doCount)(copyS1[i]));
4743         assert(copyS1[i].empty);
4744     }
4745 }
4746 
4747 @safe pure unittest
4748 {
4749     import std.exception;
4750 
4751     string[] ss = [
4752         `hello!`,  //Not an escape
4753         `\`,       //Premature termination
4754         `\/`,      //Not an escape
4755         `\gggg`,   //Not an escape
4756         `\xzz`,    //Not an hex
4757         `\x0`,     //Premature hex end
4758         `\XB9`,    //Not legal hex syntax
4759         `\u!!`,    //Not a unicode hex
4760         `\777`,    //Octal is larger than a byte
4761         `\80`,     //Wrong digit at beginning of octal
4762         `\u123`,   //Premature hex end
4763         `\U123123` //Premature hex end
4764     ];
4765     foreach (s ; ss)
4766     {
4767         assertThrown!ConvException(parseEscape(s));
4768         assertThrown!ConvException(parseEscape!(string, Yes.doCount)(s));
4769     }
4770 }
4771 
4772 // Undocumented
4773 auto parseElement(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
4774 if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) &&
4775     isExactSomeString!Target)
4776 {
4777     import std.array : appender;
4778     auto result = appender!Target();
4779 
4780     // parse array of chars
4781     if (s.empty)
4782         throw convError!(Source, Target)(s);
4783     if (s.front == '[')
4784     {
4785         return parse!(Target, Source, doCount)(s);
4786     }
4787 
4788     parseCheck!s('\"');
4789     size_t count;
4790     static if (doCount)
4791         count = 1;
4792     if (s.empty)
4793         throw convError!(Source, Target)(s);
4794     if (s.front == '\"')
4795     {
4796         s.popFront();
4797         static if (doCount)
4798         {
4799             count++;
4800             return tuple!("data", "count")(result.data, count);
4801         }
4802         else
4803         {
4804             return result.data;
4805         }
4806     }
4807     while (true)
4808     {
4809         if (s.empty)
4810             throw parseError("Unterminated quoted string");
4811         switch (s.front)
4812         {
4813             case '\"':
4814                 s.popFront();
4815                 static if (doCount)
4816                 {
4817                     count++;
4818                     return tuple!("data", "count")(result.data, count);
4819                 }
4820                 else
4821                 {
4822                     return result.data;
4823                 }
4824             case '\\':
4825                 static if (doCount)
4826                 {
4827                     auto r = parseEscape!(typeof(s), Yes.doCount)(s);
4828                     result.put(r[0]);
4829                     count += r[1];
4830                 }
4831                 else
4832                 {
4833                     auto r = parseEscape!(typeof(s), No.doCount)(s);
4834                     result.put(r);
4835                 }
4836                 break;
4837             default:
4838                 result.put(s.front);
4839                 static if (doCount)
4840                     count++;
4841                 s.popFront();
4842                 break;
4843         }
4844     }
4845     assert(false, "Unexpected fallthrough");
4846 }
4847 
4848 // ditto
4849 auto parseElement(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
4850 if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) &&
4851     is(CharTypeOf!Target == dchar) && !is(Target == enum))
4852 {
4853     Unqual!Target c;
4854 
4855     parseCheck!s('\'');
4856     size_t count;
4857     static if (doCount)
4858         count = 1;
4859     if (s.empty)
4860         throw convError!(Source, Target)(s);
4861     static if (doCount)
4862         count++;
4863     if (s.front != '\\')
4864     {
4865         c = s.front;
4866         s.popFront();
4867     }
4868     else
4869     {
4870         static if (doCount)
4871             c = parseEscape!(typeof(s), Yes.doCount)(s).data;
4872         else
4873             c = parseEscape!(typeof(s), No.doCount)(s);
4874     }
4875     parseCheck!s('\'');
4876     static if (doCount)
4877     {
4878         count++;
4879         return tuple!("data", "count")(c, count);
4880     }
4881     else
4882     {
4883         return c;
4884     }
4885 }
4886 
4887 // ditto
4888 auto parseElement(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source s)
4889 if (isInputRange!Source && isSomeChar!(ElementType!Source) &&
4890     !isSomeString!Target && !isSomeChar!Target)
4891 {
4892     return parse!(Target, Source, doCount)(s);
4893 }
4894 
4895 // Use this when parsing a type that will ultimately be appended to a
4896 // string.
4897 package template WideElementType(T)
4898 {
4899     alias E = ElementType!T;
4900     static if (isSomeChar!E)
4901         alias WideElementType = dchar;
4902     else
4903         alias WideElementType = E;
4904 }
4905 
4906 
4907 /***************************************************************
4908  * Convenience functions for converting one or more arguments
4909  * of any type into _text (the three character widths).
4910  */
4911 string text(T...)(T args)
4912 if (T.length > 0) { return textImpl!string(args); }
4913 
4914 ///ditto
4915 wstring wtext(T...)(T args)
4916 if (T.length > 0) { return textImpl!wstring(args); }
4917 
4918 ///ditto
4919 dstring dtext(T...)(T args)
4920 if (T.length > 0) { return textImpl!dstring(args); }
4921 
4922 ///
4923 @safe unittest
4924 {
4925     assert( text(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"c);
4926     assert(wtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"w);
4927     assert(dtext(42, ' ', 1.5, ": xyz") == "42 1.5: xyz"d);
4928 }
4929 
4930 @safe unittest
4931 {
4932     char  c = 'h';
4933     wchar w = '你';
4934     dchar d = 'እ';
4935 
4936     assert( text(c, "ello", ' ', w, "好 ", d, "ው ሰላም ነው") == "hello 你好 እው ሰላም ነው"c);
4937     assert(wtext(c, "ello", ' ', w, "好 ", d, "ው ሰላም ነው") == "hello 你好 እው ሰላም ነው"w);
4938     assert(dtext(c, "ello", ' ', w, "好 ", d, "ው ሰላም ነው") == "hello 你好 እው ሰላም ነው"d);
4939 
4940     string  cs = "今日は";
4941     wstring ws = "여보세요";
4942     dstring ds = "Здравствуйте";
4943 
4944     assert( text(cs, ' ', ws, " ", ds) == "今日は 여보세요 Здравствуйте"c);
4945     assert(wtext(cs, ' ', ws, " ", ds) == "今日は 여보세요 Здравствуйте"w);
4946     assert(dtext(cs, ' ', ws, " ", ds) == "今日は 여보세요 Здравствуйте"d);
4947 }
4948 
4949 // Ensure that ranges are being printed as expected.
4950 @safe unittest
4951 {
4952     static struct Range
4953     {
4954         int counter = 0;
4955 
4956     @safe pure nothrow @nogc:
4957         bool empty() const => (counter <= 0);
4958         int front() const => counter;
4959         void popFront() { --counter; }
4960     }
4961 
4962     auto m = Range(2);
4963     assert(text(m) == "[2, 1]");
4964 
4965     const c = Range(3);
4966     assert(text(c) == "const(Range)(3)");
4967 }
4968 
4969 // Ensure that a usage pattern seen in libraries like "unit-threaded" works.
4970 @safe unittest
4971 {
4972     static final class Foo
4973     {
4974         override string toString() const @safe
4975         {
4976             return ":-)";
4977         }
4978     }
4979 
4980     const c = new Foo();
4981     assert(text(c) == ":-)");
4982     assert(text(c, " ") == ":-) ");
4983 }
4984 
4985 // Ensure that classes are printed as expected.
4986 @system unittest
4987 {
4988     import std.string : endsWith, startsWith;
4989 
4990     static final class Bar {}
4991 
4992     // CTFE:                                                         `Bar`
4993     // Runtime:                         `std.conv.__unittest_L4875_C9.Bar`
4994     static assert(text(     new       Bar ()     )  ==               "Bar"   );
4995            assert(text(     new       Bar ()     ).endsWith  (      ".Bar"  ));
4996     static assert(text("=", new       Bar (), ".")  ==              "=Bar."  );
4997            assert(text("=", new       Bar (), ".").endsWith  (      ".Bar." ));
4998     static assert(text(     new const(Bar)()     )  ==         "const(Bar)"  );
4999            assert(text(     new const(Bar)()     ).startsWith( "const("     ));
5000            assert(text(     new const(Bar)()     ).endsWith  (      ".Bar)" ));
5001     static assert(text("=", new const(Bar)(), ".")  ==        "=const(Bar)." );
5002            assert(text("=", new const(Bar)(), ".").startsWith("=const("     ));
5003            assert(text("=", new const(Bar)(), ".").endsWith  (      ".Bar)."));
5004 }
5005 
5006 // Ensure that various types are printed as expected.
5007 @safe unittest
5008 {
5009     import std.string : endsWith;
5010 
5011     int dummy;
5012 
5013     static struct Foo {}
5014     struct Bar { int i() @safe => dummy; }
5015 
5016     static struct Point
5017     {
5018         int x;
5019         int y;
5020     }
5021 
5022     struct Range
5023     {
5024         bool empty()    =>              dummy > 9;
5025         int  front()    =>              dummy;
5026         void popFront() => cast(void) ++dummy;
5027     }
5028 
5029     assert(text(null         ) == "null"     );
5030     assert(text(null, null   ) == "nullnull" );
5031     assert(text(0, null, '\0') == "0null\x00");
5032 
5033     assert(text('\r','\n','\t','\x00') == "\r\n\t\0");
5034     assert(text("\r\n\t\0"           ) == "\r\n\t\0");
5035 
5036     assert(text(       3141,     ) ==    "3141"  );
5037     assert(text(": ",  3141, '\0') ==  ": 3141\0");
5038     assert(text(      -3141,     ) ==   "-3141"  );
5039     assert(text(": ", -3141, '\0') == ": -3141\0");
5040 
5041     () @trusted
5042     {
5043         int* pointer = cast(int*) 3141;
5044         assert(text(       pointer,     ) ==    "C45"  );
5045         assert(text(": ",  pointer, '\0') ==  ": C45\0");
5046     }();
5047 
5048     assert(text(      3.1415923,      ) ==   "3.14159"  );
5049     assert(text(": ", 3.1415923,  '\0') == ": 3.14159\0");
5050     assert(text(      3.1415923f,     ) ==   "3.14159"  );
5051     assert(text(": ", 3.1415923f, '\0') == ": 3.14159\0");
5052 
5053     assert(text(       !3141,     ) ==   "false"  );
5054     assert(text(": ",  !3141, '\0') == ": false\0");
5055     assert(text(      !!3141,     ) ==   "true"   );
5056     assert(text(": ", !!3141, '\0') == ": true\0" );
5057 
5058     assert(text(             Foo(),      ) ==         "Foo()"  );
5059     assert(text(": ",        Foo(),  '\0') ==       ": Foo()\0");
5060     assert(text(      const(Foo)(),     ) ==   "const(Foo)()"  );
5061     assert(text(": ", const(Foo)(), '\0') == ": const(Foo)()\0");
5062 
5063     assert(text(             Bar(),      ) ==         "Bar()"  );
5064     assert(text(": ",        Bar(),  '\0') ==       ": Bar()\0");
5065     assert(text(      const(Bar)(),     ) ==   "const(Bar)()"  );
5066     assert(text(": ", const(Bar)(), '\0') == ": const(Bar)()\0");
5067 
5068     assert(text(                 Point(3, 141),     ) ==              "Point(3, 141)"  );
5069     assert(text(": ",            Point(3, 141), '\0') ==            ": Point(3, 141)\0");
5070     assert(text(          const(Point)(3, 141),     ) ==       "const(Point)(3, 141)"  );
5071     assert(text(": ",     const(Point)(3, 141), '\0') ==     ": const(Point)(3, 141)\0");
5072     assert(text(         shared(Point)(3, 141),     ) ==      "shared(Point)(3, 141)"  );
5073     assert(text(": ",    shared(Point)(3, 141), '\0') ==    ": shared(Point)(3, 141)\0");
5074     assert(text(      immutable(Point)(3, 141),     ) ==   "immutable(Point)(3, 141)"  );
5075     assert(text(": ", immutable(Point)(3, 141), '\0') == ": immutable(Point)(3, 141)\0");
5076 
5077     dummy = 0;
5078     assert(text(            Range(),      ) ==   "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"  );
5079     dummy = 0;
5080     assert(text(": ",       Range(),  '\0') == ": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\0");
5081     assert(text(      const(Range)(),     ) ==   "const(Range)()"                  );
5082     assert(text(": ", const(Range)(), '\0') == ": const(Range)()\0"                );
5083 
5084     void function() @safe fn1;
5085     void delegate() @safe dg1;
5086     assert(text(fn1) == "null");
5087     assert(text(dg1) == "void delegate() @safe");
5088 
5089     bool function(bool, int) @safe    fn2;
5090     bool delegate(bool, int) @safe    dg2;
5091     bool delegate(bool, int) @system  dg3;
5092     bool delegate(bool, int) @trusted dg4;
5093     assert(text(fn2) == "null");
5094     assert(text(dg2) == "bool delegate(bool, int) @safe");
5095     assert(text(dg3) == "bool delegate(bool, int) @system");
5096     assert(text(dg4) == "bool delegate(bool, int) @trusted");
5097 }
5098 
5099 /// Convenience functions for writing arguments to an output range as text.
5100 void writeText(Sink, T...)(ref Sink sink, T args)
5101 if (isOutputRange!(Sink, char) && T.length > 0)
5102 {
5103     sink.writeTextImpl!string(args);
5104 }
5105 
5106 /// ditto
5107 void writeWText(Sink, T...)(ref Sink sink, T args)
5108 if (isOutputRange!(Sink, wchar) && T.length > 0)
5109 {
5110     sink.writeTextImpl!wstring(args);
5111 }
5112 
5113 /// ditto
5114 void writeDText(Sink, T...)(ref Sink sink, T args)
5115 if (isOutputRange!(Sink, dchar) && T.length > 0)
5116 {
5117     sink.writeTextImpl!dstring(args);
5118 }
5119 
5120 ///
5121 @safe unittest
5122 {
5123     import std.array : appender;
5124 
5125     auto output = appender!string();
5126     output.writeText("The answer is ", 42);
5127 
5128     assert(output.data == "The answer is 42");
5129 }
5130 
5131 ///
5132 @safe unittest
5133 {
5134     import std.array : appender;
5135 
5136     const color = "red";
5137     auto output = appender!string();
5138     output.writeText(i"My favorite color is $(color)");
5139 
5140     assert(output.data == "My favorite color is red");
5141 }
5142 
5143 @safe unittest
5144 {
5145     auto capp = appender!string();
5146     auto wapp = appender!wstring();
5147     auto dapp = appender!dstring();
5148 
5149     capp.writeText(42, ' ', 1.5, ": xyz");
5150     wapp.writeWText(42, ' ', 1.5, ": xyz");
5151     dapp.writeDText(42, ' ', 1.5, ": xyz");
5152 
5153     assert(capp.data == "42 1.5: xyz"c);
5154     assert(wapp.data == "42 1.5: xyz"w);
5155     assert(dapp.data == "42 1.5: xyz"d);
5156 }
5157 
5158 // Check range API compliance using OutputRange interface
5159 @system unittest
5160 {
5161     import std.range.interfaces : OutputRange, outputRangeObject;
5162     import std.range : nullSink;
5163 
5164     OutputRange!char testOutput = outputRangeObject!char(nullSink);
5165     testOutput.writeText(42, ' ', 1.5, ": xyz");
5166 }
5167 
5168 private S textImpl(S, U...)(U args)
5169 {
5170     static if (U.length == 0)
5171     {
5172         return null;
5173     }
5174     else static if (U.length == 1)
5175     {
5176         return to!S(args[0]);
5177     }
5178     else
5179     {
5180         import std.array : appender;
5181         import std.traits : isSomeChar, isSomeString;
5182 
5183         auto app = appender!S();
5184 
5185         // assume that on average, parameters will have less
5186         // than 20 elements
5187         app.reserve(U.length * 20);
5188         app.writeTextImpl!S(args);
5189         return app.data;
5190     }
5191 }
5192 
5193 private void writeTextImpl(S, Sink, U...)(ref Sink sink, U args)
5194 if (isSomeString!S && isOutputRange!(Sink, ElementEncodingType!S))
5195 {
5196     // Must be static foreach because of https://issues.dlang.org/show_bug.cgi?id=21209
5197     static foreach (arg; args)
5198     {
5199         static if (
5200             isSomeChar!(typeof(arg))
5201             || isSomeString!(typeof(arg))
5202             || ( isInputRange!(typeof(arg)) && isSomeChar!(ElementType!(typeof(arg))) )
5203         )
5204             put(sink, arg);
5205         else static if (
5206 
5207             is(immutable typeof(arg) == immutable uint) || is(immutable typeof(arg) == immutable ulong) ||
5208             is(immutable typeof(arg) == immutable int) || is(immutable typeof(arg) == immutable long)
5209         )
5210             // https://issues.dlang.org/show_bug.cgi?id=17712#c15
5211             put(sink, textImpl!(S)(arg));
5212         else
5213             put(sink, to!S(arg));
5214     }
5215 }
5216 
5217 
5218 /***************************************************************
5219 The `octal` facility provides a means to declare a number in base 8.
5220 Using `octal!177` or `octal!"177"` for 127 represented in octal
5221 (same as 0177 in C).
5222 
5223 The rules for strings are the usual for literals: If it can fit in an
5224 `int`, it is an `int`. Otherwise, it is a `long`. But, if the
5225 user specifically asks for a `long` with the `L` suffix, always
5226 give the `long`. Give an unsigned iff it is asked for with the $(D
5227 U) or `u` suffix. _Octals created from integers preserve the type
5228 of the passed-in integral.
5229 
5230 See_Also:
5231     $(LREF parse) for parsing octal strings at runtime.
5232  */
5233 template octal(string num)
5234 if (isOctalLiteral(num))
5235 {
5236     static if ((octalFitsInInt!num && !literalIsLong!num) && !literalIsUnsigned!num)
5237         enum octal = octal!int(num);
5238     else static if ((!octalFitsInInt!num || literalIsLong!num) && !literalIsUnsigned!num)
5239         enum octal = octal!long(num);
5240     else static if ((octalFitsInInt!num && !literalIsLong!num) && literalIsUnsigned!num)
5241         enum octal = octal!uint(num);
5242     else static if ((!octalFitsInInt!(num) || literalIsLong!(num)) && literalIsUnsigned!(num))
5243         enum octal = octal!ulong(num);
5244     else
5245         static assert(false, "Unusable input " ~ num);
5246 }
5247 
5248 /// Ditto
5249 template octal(alias decimalInteger)
5250 if (is(typeof(decimalInteger)) && isIntegral!(typeof(decimalInteger)))
5251 {
5252     enum octal = convertToOctal(decimalInteger);
5253 }
5254 
5255 ///
5256 @safe unittest
5257 {
5258     // Same as 0177
5259     auto a = octal!177;
5260     // octal is a compile-time device
5261     enum b = octal!160;
5262     // Create an unsigned octal
5263     auto c = octal!"1_000_000u";
5264     // Leading zeros are allowed when converting from a string
5265     auto d = octal!"0001_200_000";
5266 }
5267 
5268 /*************************************
5269  * Convert a decimal integer to an octal integer with the same digits.
5270  * Params:
5271  *    i = integer to convert
5272  * Returns:
5273  *    octal integer with the same type and same digits
5274  */
5275 private T convertToOctal(T)(T i)
5276 {
5277     assert((i % 10) < 8);
5278     return i ? convertToOctal(i / 10) * 8 + i % 10 : 0;
5279 }
5280 
5281 /*
5282     Takes a string, num, which is an octal literal, and returns its
5283     value, in the type T specified.
5284 */
5285 private T octal(T)(const string num)
5286 {
5287     assert(isOctalLiteral(num), num ~ " is not an octal literal");
5288 
5289     T value = 0;
5290 
5291     foreach (const char s; num)
5292     {
5293         if (s < '0' || s > '7') // we only care about digits; skip the rest
5294         // safe to skip - this is checked out in the assert so these
5295         // are just suffixes
5296             continue;
5297 
5298         value *= 8;
5299         value += s - '0';
5300     }
5301 
5302     return value;
5303 }
5304 
5305 @safe unittest
5306 {
5307     int a = octal!int("10");
5308     assert(a == 8);
5309 
5310     int b = octal!int("000137");
5311     assert(b == 95);
5312 }
5313 
5314 /*
5315 Take a look at int.max and int.max+1 in octal and the logic for this
5316 function follows directly.
5317  */
5318 private template octalFitsInInt(string octalNum)
5319 {
5320     // note it is important to strip the literal of all
5321     // non-numbers. kill the suffix and underscores lest they mess up
5322     // the number of digits here that we depend on.
5323     enum bool octalFitsInInt = strippedOctalLiteral(octalNum).length < 11 ||
5324         strippedOctalLiteral(octalNum).length == 11 &&
5325         strippedOctalLiteral(octalNum)[0] == '1';
5326 }
5327 
5328 private string strippedOctalLiteral(string original)
5329 {
5330     string stripped = "";
5331     bool leading_zeros = true;
5332     foreach (c; original)
5333     {
5334         if (!('0' <= c && c <= '7'))
5335             continue;
5336         if (c == '0')
5337         {
5338             if (leading_zeros)
5339                 continue;
5340         }
5341         else
5342         {
5343             leading_zeros = false;
5344         }
5345         stripped ~= c;
5346     }
5347     if (stripped.length == 0)
5348     {
5349         assert(leading_zeros);
5350         return "0";
5351     }
5352     return stripped;
5353 }
5354 
5355 @safe unittest
5356 {
5357     static assert(strippedOctalLiteral("7") == "7");
5358     static assert(strippedOctalLiteral("123") == "123");
5359     static assert(strippedOctalLiteral("00123") == "123");
5360     static assert(strippedOctalLiteral("01230") == "1230");
5361     static assert(strippedOctalLiteral("0") == "0");
5362     static assert(strippedOctalLiteral("00_000") == "0");
5363     static assert(strippedOctalLiteral("000_000_12_300") == "12300");
5364 }
5365 
5366 private template literalIsLong(string num)
5367 {
5368     static if (num.length > 1)
5369     // can be xxL or xxLu according to spec
5370         enum literalIsLong = (num[$-1] == 'L' || num[$-2] == 'L');
5371     else
5372         enum literalIsLong = false;
5373 }
5374 
5375 private template literalIsUnsigned(string num)
5376 {
5377     static if (num.length > 1)
5378     // can be xxU or xxUL according to spec
5379         enum literalIsUnsigned = (num[$-1] == 'u' || num[$-2] == 'u')
5380             // both cases are allowed too
5381             || (num[$-1] == 'U' || num[$-2] == 'U');
5382     else
5383         enum literalIsUnsigned = false;
5384 }
5385 
5386 /*
5387 Returns if the given string is a correctly formatted octal literal.
5388 
5389 The format is specified in spec/lex.html. The leading zeros are allowed,
5390 but not required.
5391  */
5392 @safe pure nothrow @nogc
5393 private bool isOctalLiteral(const string num)
5394 {
5395     if (num.length == 0)
5396         return false;
5397 
5398     // Must start with a digit.
5399     if (num[0] < '0' || num[0] > '7')
5400         return false;
5401 
5402     foreach (i, c; num)
5403     {
5404         if (('0' <= c && c <= '7') || c == '_')  // a legal character
5405             continue;
5406 
5407         if (i < num.length - 2)
5408             return false;
5409 
5410         // gotta check for those suffixes
5411         if (c != 'U' && c != 'u' && c != 'L')
5412             return false;
5413         if (i != num.length - 1)
5414         {
5415             // if we're not the last one, the next one must
5416             // also be a suffix to be valid
5417             char c2 = num[$-1];
5418             if (c2 != 'U' && c2 != 'u' && c2 != 'L')
5419                 return false; // spam at the end of the string
5420             if (c2 == c)
5421                 return false; // repeats are disallowed
5422         }
5423     }
5424 
5425     return true;
5426 }
5427 
5428 @safe unittest
5429 {
5430     // ensure that you get the right types, even with embedded underscores
5431     auto w = octal!"100_000_000_000";
5432     static assert(!is(typeof(w) == int));
5433     auto w2 = octal!"1_000_000_000";
5434     static assert(is(typeof(w2) == int));
5435 
5436     static assert(octal!"45" == 37);
5437     static assert(octal!"0" == 0);
5438     static assert(octal!"7" == 7);
5439     static assert(octal!"10" == 8);
5440     static assert(octal!"666" == 438);
5441     static assert(octal!"0004001" == 2049);
5442     static assert(octal!"00" == 0);
5443     static assert(octal!"0_0" == 0);
5444 
5445     static assert(octal!45 == 37);
5446     static assert(octal!0 == 0);
5447     static assert(octal!7 == 7);
5448     static assert(octal!10 == 8);
5449     static assert(octal!666 == 438);
5450 
5451     static assert(octal!"66_6" == 438);
5452     static assert(octal!"0_0_66_6" == 438);
5453 
5454     static assert(octal!2520046213 == 356535435);
5455     static assert(octal!"2520046213" == 356535435);
5456 
5457     static assert(octal!17777777777 == int.max);
5458 
5459     static assert(!__traits(compiles, octal!823));
5460 
5461     static assert(!__traits(compiles, octal!"823"));
5462 
5463     static assert(!__traits(compiles, octal!"_823"));
5464     static assert(!__traits(compiles, octal!"spam"));
5465     static assert(!__traits(compiles, octal!"77%"));
5466 
5467     static assert(is(typeof(octal!"17777777777") == int));
5468     static assert(octal!"17777777777" == int.max);
5469 
5470     static assert(is(typeof(octal!"20000000000U") == ulong)); // Shouldn't this be uint?
5471     static assert(octal!"20000000000" == uint(int.max) + 1);
5472 
5473     static assert(is(typeof(octal!"777777777777777777777") == long));
5474     static assert(octal!"777777777777777777777" == long.max);
5475 
5476     static assert(is(typeof(octal!"1000000000000000000000U") == ulong));
5477     static assert(octal!"1000000000000000000000" == ulong(long.max) + 1);
5478 
5479     int a;
5480     long b;
5481 
5482     // biggest value that should fit in an it
5483     a = octal!"17777777777";
5484     assert(a == int.max);
5485     // should not fit in the int
5486     static assert(!__traits(compiles, a = octal!"20000000000"));
5487     // ... but should fit in a long
5488     b = octal!"20000000000";
5489     assert(b == 1L + int.max);
5490 
5491     b = octal!"1L";
5492     assert(b == 1);
5493     b = octal!1L;
5494     assert(b == 1);
5495 }
5496 
5497 // emplace() used to be here but was moved to druntime
5498 public import core.lifetime : emplace;
5499 
5500 // https://issues.dlang.org/show_bug.cgi?id=9559
5501 @safe unittest
5502 {
5503     import std.algorithm.iteration : map;
5504     import std.array : array;
5505     import std.typecons : Nullable;
5506     alias I = Nullable!int;
5507     auto ints = [0, 1, 2].map!(i => i & 1 ? I.init : I(i))();
5508     auto asArray = array(ints);
5509 }
5510 
5511 @system unittest //http://forum.dlang.org/post/nxbdgtdlmwscocbiypjs@forum.dlang.org
5512 {
5513     import std.array : array;
5514     import std.datetime : SysTime, UTC;
5515     import std.math.traits : isNaN;
5516 
5517     static struct A
5518     {
5519         double i;
5520     }
5521 
5522     static struct B
5523     {
5524         invariant()
5525         {
5526             if (j == 0)
5527                 assert(a.i.isNaN(), "why is 'j' zero?? and i is not NaN?");
5528             else
5529                 assert(!a.i.isNaN());
5530         }
5531         SysTime when; // comment this line avoid the breakage
5532         int j;
5533         A a;
5534     }
5535 
5536     B b1 = B.init;
5537     assert(&b1); // verify that default eyes invariants are ok;
5538 
5539     auto b2 = B(SysTime(0, UTC()), 1, A(1));
5540     assert(&b2);
5541     auto b3 = B(SysTime(0, UTC()), 1, A(1));
5542     assert(&b3);
5543 
5544     auto arr = [b2, b3];
5545 
5546     assert(arr[0].j == 1);
5547     assert(arr[1].j == 1);
5548     auto a2 = arr.array(); // << bang, invariant is raised, also if b2 and b3 are good
5549 }
5550 
5551 @safe unittest
5552 {
5553     import std.algorithm.comparison : equal;
5554     import std.algorithm.iteration : map;
5555     // Check fix for https://issues.dlang.org/show_bug.cgi?id=2971
5556     assert(equal(map!(to!int)(["42", "34", "345"]), [42, 34, 345]));
5557 }
5558 
5559 // Undocumented for the time being
5560 void toTextRange(T, W)(T value, W writer)
5561 if (isIntegral!T && isOutputRange!(W, char))
5562 {
5563     import core.internal.string : SignedStringBuf, signedToTempString,
5564                                   UnsignedStringBuf, unsignedToTempString;
5565 
5566     if (value < 0)
5567     {
5568         SignedStringBuf buf = void;
5569         put(writer, signedToTempString(value, buf));
5570     }
5571     else
5572     {
5573         UnsignedStringBuf buf = void;
5574         put(writer, unsignedToTempString(value, buf));
5575     }
5576 }
5577 
5578 @safe unittest
5579 {
5580     import std.array : appender;
5581     auto result = appender!(char[])();
5582     toTextRange(-1, result);
5583     assert(result.data == "-1");
5584 }
5585 
5586 
5587 /**
5588     Returns the corresponding _unsigned value for `x` (e.g. if `x` has type
5589     `int`, it returns $(D cast(uint) x)). The advantage compared to the cast
5590     is that you do not need to rewrite the cast if `x` later changes type
5591     (e.g from `int` to `long`).
5592 
5593     Note that the result is always mutable even if the original type was const
5594     or immutable. In order to retain the constness, use $(REF Unsigned, std,traits).
5595  */
5596 auto unsigned(T)(T x)
5597 if (isIntegral!T)
5598 {
5599     return cast() cast(Unsigned!T) x;
5600 }
5601 
5602 ///
5603 @safe unittest
5604 {
5605     import std.traits : Unsigned;
5606     immutable int s = 42;
5607     auto u1 = unsigned(s); //not qualified
5608     static assert(is(typeof(u1) == uint));
5609     Unsigned!(typeof(s)) u2 = unsigned(s); //same qualification
5610     static assert(is(typeof(u2) == immutable uint));
5611     immutable u3 = unsigned(s); //explicitly qualified
5612 }
5613 
5614 /// Ditto
5615 auto unsigned(T)(T x)
5616 if (isSomeChar!T)
5617 {
5618     // All characters are unsigned
5619     static assert(T.min == 0, T.stringof ~ ".min must be zero");
5620     return cast() x;
5621 }
5622 
5623 @safe unittest
5624 {
5625     static foreach (T; AliasSeq!(byte, ubyte))
5626     {
5627         static assert(is(typeof(unsigned(cast(T) 1)) == ubyte));
5628         static assert(is(typeof(unsigned(cast(const T) 1)) == ubyte));
5629         static assert(is(typeof(unsigned(cast(immutable T) 1)) == ubyte));
5630     }
5631 
5632     static foreach (T; AliasSeq!(short, ushort))
5633     {
5634         static assert(is(typeof(unsigned(cast(T) 1)) == ushort));
5635         static assert(is(typeof(unsigned(cast(const T) 1)) == ushort));
5636         static assert(is(typeof(unsigned(cast(immutable T) 1)) == ushort));
5637     }
5638 
5639     static foreach (T; AliasSeq!(int, uint))
5640     {
5641         static assert(is(typeof(unsigned(cast(T) 1)) == uint));
5642         static assert(is(typeof(unsigned(cast(const T) 1)) == uint));
5643         static assert(is(typeof(unsigned(cast(immutable T) 1)) == uint));
5644     }
5645 
5646     static foreach (T; AliasSeq!(long, ulong))
5647     {
5648         static assert(is(typeof(unsigned(cast(T) 1)) == ulong));
5649         static assert(is(typeof(unsigned(cast(const T) 1)) == ulong));
5650         static assert(is(typeof(unsigned(cast(immutable T) 1)) == ulong));
5651     }
5652 }
5653 
5654 @safe unittest
5655 {
5656     static foreach (T; AliasSeq!(char, wchar, dchar))
5657     {
5658         static assert(is(typeof(unsigned(cast(T)'A')) == T));
5659         static assert(is(typeof(unsigned(cast(const T)'A')) == T));
5660         static assert(is(typeof(unsigned(cast(immutable T)'A')) == T));
5661     }
5662 }
5663 
5664 
5665 /**
5666     Returns the corresponding _signed value for `x` (e.g. if `x` has type
5667     `uint`, it returns $(D cast(int) x)). The advantage compared to the cast
5668     is that you do not need to rewrite the cast if `x` later changes type
5669     (e.g from `uint` to `ulong`).
5670 
5671     Note that the result is always mutable even if the original type was const
5672     or immutable. In order to retain the constness, use $(REF Signed, std,traits).
5673  */
5674 auto signed(T)(T x)
5675 if (isIntegral!T)
5676 {
5677     return cast() cast(Signed!T) x;
5678 }
5679 
5680 ///
5681 @safe unittest
5682 {
5683     import std.traits : Signed;
5684 
5685     immutable uint u = 42;
5686     auto s1 = signed(u); //not qualified
5687     static assert(is(typeof(s1) == int));
5688     Signed!(typeof(u)) s2 = signed(u); //same qualification
5689     static assert(is(typeof(s2) == immutable int));
5690     immutable s3 = signed(u); //explicitly qualified
5691 }
5692 
5693 @system unittest
5694 {
5695     static foreach (T; AliasSeq!(byte, ubyte))
5696     {
5697         static assert(is(typeof(signed(cast(T) 1)) == byte));
5698         static assert(is(typeof(signed(cast(const T) 1)) == byte));
5699         static assert(is(typeof(signed(cast(immutable T) 1)) == byte));
5700     }
5701 
5702     static foreach (T; AliasSeq!(short, ushort))
5703     {
5704         static assert(is(typeof(signed(cast(T) 1)) == short));
5705         static assert(is(typeof(signed(cast(const T) 1)) == short));
5706         static assert(is(typeof(signed(cast(immutable T) 1)) == short));
5707     }
5708 
5709     static foreach (T; AliasSeq!(int, uint))
5710     {
5711         static assert(is(typeof(signed(cast(T) 1)) == int));
5712         static assert(is(typeof(signed(cast(const T) 1)) == int));
5713         static assert(is(typeof(signed(cast(immutable T) 1)) == int));
5714     }
5715 
5716     static foreach (T; AliasSeq!(long, ulong))
5717     {
5718         static assert(is(typeof(signed(cast(T) 1)) == long));
5719         static assert(is(typeof(signed(cast(const T) 1)) == long));
5720         static assert(is(typeof(signed(cast(immutable T) 1)) == long));
5721     }
5722 }
5723 
5724 // https://issues.dlang.org/show_bug.cgi?id=10874
5725 @safe unittest
5726 {
5727     enum Test { a = 0 }
5728     ulong l = 0;
5729     auto t = l.to!Test;
5730 }
5731 
5732 // asOriginalType
5733 /**
5734 Returns the representation of an enumerated value, i.e. the value converted to
5735 the base type of the enumeration.
5736 */
5737 OriginalType!E asOriginalType(E)(E value)
5738 if (is(E == enum))
5739 {
5740     return value;
5741 }
5742 
5743 ///
5744 @safe unittest
5745 {
5746     enum A { a = 42 }
5747     static assert(is(typeof(A.a.asOriginalType) == int));
5748     assert(A.a.asOriginalType == 42);
5749     enum B : double { a = 43 }
5750     static assert(is(typeof(B.a.asOriginalType) == double));
5751     assert(B.a.asOriginalType == 43);
5752 }
5753 
5754 /**
5755     A wrapper on top of the built-in cast operator that allows one to restrict
5756     casting of the original type of the value.
5757 
5758     A common issue with using a raw cast is that it may silently continue to
5759     compile even if the value's type has changed during refactoring,
5760     which breaks the initial assumption about the cast.
5761 
5762     Params:
5763         From  = The type to cast from. The programmer must ensure it is legal
5764                 to make this cast.
5765  */
5766 template castFrom(From)
5767 {
5768     /**
5769         Params:
5770             To    = The type _to cast _to.
5771             value = The value _to cast. It must be of type `From`,
5772                     otherwise a compile-time error is emitted.
5773 
5774         Returns:
5775             the value after the cast, returned by reference if possible.
5776      */
5777     auto ref to(To, T)(auto ref T value) @system
5778     {
5779         static assert(
5780             is(From == T),
5781             "the value to cast is not of specified type '" ~ From.stringof ~
5782                  "', it is of type '" ~ T.stringof ~ "'"
5783         );
5784 
5785         static assert(
5786             is(typeof(cast(To) value)),
5787             "can't cast from '" ~ From.stringof ~ "' to '" ~ To.stringof ~ "'"
5788         );
5789 
5790         return cast(To) value;
5791     }
5792 }
5793 
5794 ///
5795 @system unittest
5796 {
5797     // Regular cast, which has been verified to be legal by the programmer:
5798     {
5799         long x;
5800         auto y = cast(int) x;
5801     }
5802 
5803     // However this will still compile if 'x' is changed to be a pointer:
5804     {
5805         long* x;
5806         auto y = cast(int) x;
5807     }
5808 
5809     // castFrom provides a more reliable alternative to casting:
5810     {
5811         long x;
5812         auto y = castFrom!long.to!int(x);
5813     }
5814 
5815     // Changing the type of 'x' will now issue a compiler error,
5816     // allowing bad casts to be caught before it's too late:
5817     {
5818         long* x;
5819         static assert(
5820             !__traits(compiles, castFrom!long.to!int(x))
5821         );
5822 
5823         // if cast is still needed, must be changed to:
5824         auto y = castFrom!(long*).to!int(x);
5825     }
5826 }
5827 
5828 // https://issues.dlang.org/show_bug.cgi?id=16667
5829 @system unittest
5830 {
5831     ubyte[] a = ['a', 'b', 'c'];
5832     assert(castFrom!(ubyte[]).to!(string)(a) == "abc");
5833 }
5834 
5835 /**
5836 Check the correctness of a string for `hexString`.
5837 The result is true if and only if the input string is composed of whitespace
5838 characters (\f\n\r\t\v lineSep paraSep nelSep) and
5839 an even number of hexadecimal digits (regardless of the case).
5840 */
5841 @safe pure @nogc
5842 private bool isHexLiteral(String)(scope const String hexData)
5843 {
5844     import std.ascii : isHexDigit;
5845     import std.uni : lineSep, paraSep, nelSep;
5846     size_t i;
5847     foreach (const dchar c; hexData)
5848     {
5849         switch (c)
5850         {
5851             case ' ':
5852             case '\t':
5853             case '\v':
5854             case '\f':
5855             case '\r':
5856             case '\n':
5857             case lineSep:
5858             case paraSep:
5859             case nelSep:
5860                 continue;
5861 
5862             default:
5863                 break;
5864         }
5865         if (c.isHexDigit)
5866             ++i;
5867         else
5868             return false;
5869     }
5870     return !(i & 1);
5871 }
5872 
5873 @safe unittest
5874 {
5875     // test all the hex digits
5876     static assert( ("0123456789abcdefABCDEF").isHexLiteral);
5877     // empty or white strings are not valid
5878     static assert( "\r\n\t".isHexLiteral);
5879     // but are accepted if the count of hex digits is even
5880     static assert( "A\r\n\tB".isHexLiteral);
5881 }
5882 
5883 @safe unittest
5884 {
5885     import std.ascii;
5886     // empty/whites
5887     static assert( "".isHexLiteral);
5888     static assert( " \r".isHexLiteral);
5889     static assert( whitespace.isHexLiteral);
5890     static assert( ""w.isHexLiteral);
5891     static assert( " \r"w.isHexLiteral);
5892     static assert( ""d.isHexLiteral);
5893     static assert( " \r"d.isHexLiteral);
5894     static assert( "\u2028\u2029\u0085"d.isHexLiteral);
5895     // odd x strings
5896     static assert( !("5" ~ whitespace).isHexLiteral);
5897     static assert( !"123".isHexLiteral);
5898     static assert( !"1A3".isHexLiteral);
5899     static assert( !"1 23".isHexLiteral);
5900     static assert( !"\r\n\tC".isHexLiteral);
5901     static assert( !"123"w.isHexLiteral);
5902     static assert( !"1A3"w.isHexLiteral);
5903     static assert( !"1 23"w.isHexLiteral);
5904     static assert( !"\r\n\tC"w.isHexLiteral);
5905     static assert( !"123"d.isHexLiteral);
5906     static assert( !"1A3"d.isHexLiteral);
5907     static assert( !"1 23"d.isHexLiteral);
5908     static assert( !"\r\n\tC"d.isHexLiteral);
5909     // even x strings with invalid charset
5910     static assert( !"12gG".isHexLiteral);
5911     static assert( !"2A  3q".isHexLiteral);
5912     static assert( !"12gG"w.isHexLiteral);
5913     static assert( !"2A  3q"w.isHexLiteral);
5914     static assert( !"12gG"d.isHexLiteral);
5915     static assert( !"2A  3q"d.isHexLiteral);
5916     // valid x strings
5917     static assert( ("5A" ~ whitespace).isHexLiteral);
5918     static assert( ("5A 01A C FF de 1b").isHexLiteral);
5919     static assert( ("0123456789abcdefABCDEF").isHexLiteral);
5920     static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF").isHexLiteral);
5921     static assert( ("5A 01A C FF de 1b"w).isHexLiteral);
5922     static assert( ("0123456789abcdefABCDEF"w).isHexLiteral);
5923     static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF"w).isHexLiteral);
5924     static assert( ("5A 01A C FF de 1b"d).isHexLiteral);
5925     static assert( ("0123456789abcdefABCDEF"d).isHexLiteral);
5926     static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF"d).isHexLiteral);
5927     // library version allows what's pointed by https://issues.dlang.org/show_bug.cgi?id=10454
5928     static assert( ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").isHexLiteral);
5929 }
5930 
5931 /**
5932 Converts a hex literal to a string at compile time.
5933 
5934 Takes a string made of hexadecimal digits and returns
5935 the matching string by converting each pair of digits to a character.
5936 The input string can also include white characters, which can be used
5937 to keep the literal string readable in the source code.
5938 
5939 The function is intended to replace the hexadecimal literal strings
5940 starting with `'x'`, which could be removed to simplify the core language.
5941 
5942 Params:
5943     hexData = string to be converted.
5944 
5945 Returns:
5946     a `string`, a `wstring` or a `dstring`, according to the type of hexData.
5947 
5948 See_Also:
5949     Use $(REF fromHexString, std, digest) for run time conversions.
5950     Note, these functions are not drop-in replacements and have different
5951     input requirements.
5952     This template inherits its data syntax from builtin
5953     $(LINK2 $(ROOT_DIR)spec/lex.html#hex_string, hex strings).
5954     See $(REF fromHexString, std, digest) for its own respective requirements.
5955  */
5956 template hexString(string hexData)
5957 if (hexData.isHexLiteral)
5958 {
5959     enum hexString = mixin(hexToString(hexData));
5960 }
5961 
5962 /// ditto
5963 template hexString(wstring hexData)
5964 if (hexData.isHexLiteral)
5965 {
5966     enum wstring hexString = mixin(hexToString(hexData));
5967 }
5968 
5969 /// ditto
5970 template hexString(dstring hexData)
5971 if (hexData.isHexLiteral)
5972 {
5973     enum dstring hexString = mixin(hexToString(hexData));
5974 }
5975 
5976 ///
5977 @safe unittest
5978 {
5979     // conversion at compile time
5980     auto string1 = hexString!"304A314B";
5981     assert(string1 == "0J1K");
5982     auto string2 = hexString!"304A314B"w;
5983     assert(string2 == "0J1K"w);
5984     auto string3 = hexString!"304A314B"d;
5985     assert(string3 == "0J1K"d);
5986 }
5987 
5988 @safe nothrow pure private
5989 {
5990     /* These are meant to be used with CTFE.
5991      * They cause the instantiations of hexStrLiteral()
5992      * to be in Phobos, not user code.
5993      */
5994     string hexToString(string s)
5995     {
5996         return hexStrLiteral(s);
5997     }
5998 
5999     wstring hexToString(wstring s)
6000     {
6001         return hexStrLiteral(s);
6002     }
6003 
6004     dstring hexToString(dstring s)
6005     {
6006         return hexStrLiteral(s);
6007     }
6008 }
6009 
6010 /*
6011     Turn a hexadecimal string into a regular string literal.
6012     I.e. "dead beef" is transformed into "\xde\xad\xbe\xef"
6013     suitable for use in a mixin.
6014     Params:
6015         hexData is string, wstring, or dstring and validated by isHexLiteral()
6016  */
6017 @trusted nothrow pure
6018 private auto hexStrLiteral(String)(scope String hexData)
6019 {
6020     import std.ascii : isHexDigit;
6021     alias C = Unqual!(ElementEncodingType!String);    // char, wchar or dchar
6022     C[] result;
6023     result.length = 1 + hexData.length * 2 + 1;       // don't forget the " "
6024     /* Use a pointer because we know it won't overrun,
6025      * and this will reduce the size of the function substantially
6026      * by not doing the array bounds checks.
6027      * This is why this function is @trusted.
6028      */
6029     auto r = result.ptr;
6030     r[0] = '"';
6031     size_t cnt = 0;
6032     foreach (c; hexData)
6033     {
6034         if (c.isHexDigit)
6035         {
6036             if ((cnt & 1) == 0)
6037             {
6038                 r[1 + cnt]     = '\\';
6039                 r[1 + cnt + 1] = 'x';
6040                 cnt += 2;
6041             }
6042             r[1 + cnt] = c;
6043             ++cnt;
6044         }
6045     }
6046     r[1 + cnt] = '"';
6047     result.length = 1 + cnt + 1;        // trim off any excess length
6048     return result;
6049 }
6050 
6051 
6052 @safe unittest
6053 {
6054     // compile time
6055     assert(hexString!"46 47 48 49 4A 4B" == "FGHIJK");
6056     assert(hexString!"30\r\n\t\f\v31 32 33 32 31 30" == "0123210");
6057     assert(hexString!"ab cd" == hexString!"ABCD");
6058 }
6059 
6060 
6061 /**
6062  * Convert integer to a range of characters.
6063  * Intended to be lightweight and fast.
6064  *
6065  * Params:
6066  *      radix = 2, 8, 10, 16
6067  *      Char = character type for output
6068  *      letterCase = lower for deadbeef, upper for DEADBEEF
6069  *      value = integer to convert. Can be ubyte, ushort, uint or ulong. If radix
6070  *              is 10, can also be byte, short, int or long.
6071  * Returns:
6072  *      Random access range with slicing and everything
6073  */
6074 
6075 auto toChars(ubyte radix = 10, Char = char, LetterCase letterCase = LetterCase.lower, T)(T value)
6076     pure nothrow @nogc @safe
6077 if ((radix == 2 || radix == 8 || radix == 10 || radix == 16) &&
6078         isIntegral!T && (radix == 10 || isUnsigned!T))
6079 {
6080     alias UT = Unqual!T;
6081 
6082     static if (radix == 10)
6083     {
6084         /* uint.max  is 42_9496_7295
6085          *  int.max  is 21_4748_3647
6086          * ulong.max is 1844_6744_0737_0955_1615
6087          *  long.max is  922_3372_0368_5477_5807
6088          */
6089         static struct Result
6090         {
6091             void initialize(UT value)
6092             {
6093                 import core.internal.string : signedToTempString, unsignedToTempString;
6094 
6095                 char[] t = value < 0
6096                     ?   signedToTempString!(10, false, char)(value, buf)
6097                     : unsignedToTempString!(10, false, char)(value, buf);
6098 
6099                 lwr = cast(uint) (buf.length - t.length);
6100                 upr = cast(uint) buf.length;
6101             }
6102 
6103             @property size_t length() { return upr - lwr; }
6104 
6105             alias opDollar = length;
6106 
6107             @property bool empty() { return upr == lwr; }
6108 
6109             @property Char front() { return buf[lwr]; }
6110 
6111             void popFront() { ++lwr; }
6112 
6113             @property Char back() { return buf[upr - 1]; }
6114 
6115             void popBack() { --upr; }
6116 
6117             @property Result save() { return this; }
6118 
6119             Char opIndex(size_t i) { return buf[lwr + i]; }
6120 
6121             Result opSlice(size_t lwr, size_t upr)
6122             {
6123                 Result result = void;
6124                 result.buf = buf;
6125                 result.lwr = cast(uint)(this.lwr + lwr);
6126                 result.upr = cast(uint)(this.lwr + upr);
6127                 return result;
6128             }
6129 
6130           private:
6131             uint lwr = void, upr = void;
6132             char[(UT.sizeof == 4) ? 10 + isSigned!T : 20] buf = void;
6133         }
6134 
6135         Result result;
6136         result.initialize(value);
6137         return result;
6138     }
6139     else
6140     {
6141         static if (radix == 2)
6142             enum SHIFT = 1;
6143         else static if (radix == 8)
6144             enum SHIFT = 3;
6145         else static if (radix == 16)
6146             enum SHIFT = 4;
6147         else
6148             static assert(false, "radix must be 2, 8, 10, or 16");
6149         static struct Result
6150         {
6151             this(UT value)
6152             {
6153                 this.value = value;
6154 
6155                 ubyte len = 1;
6156                 while (value >>>= SHIFT)
6157                    ++len;
6158                 this.len = len;
6159             }
6160 
6161             @property size_t length() { return len; }
6162 
6163             @property bool empty() { return len == 0; }
6164 
6165             @property Char front() { return opIndex(0); }
6166 
6167             void popFront() { --len; }
6168 
6169             @property Char back() { return opIndex(len - 1); }
6170 
6171             void popBack()
6172             {
6173                 value >>>= SHIFT;
6174                 --len;
6175             }
6176 
6177             @property Result save() { return this; }
6178 
6179             Char opIndex(size_t i)
6180             {
6181                 Char c = (value >>> ((len - i - 1) * SHIFT)) & ((1 << SHIFT) - 1);
6182                 return cast(Char)((radix < 10 || c < 10) ? c + '0'
6183                                                          : (letterCase == LetterCase.upper ? c + 'A' - 10
6184                                                                                            : c + 'a' - 10));
6185             }
6186 
6187             Result opSlice(size_t lwr, size_t upr)
6188             {
6189                 Result result = void;
6190                 result.value = value >>> ((len - upr) * SHIFT);
6191                 result.len = cast(ubyte)(upr - lwr);
6192                 return result;
6193             }
6194 
6195           private:
6196             UT value;
6197             ubyte len;
6198         }
6199 
6200         return Result(value);
6201     }
6202 }
6203 
6204 ///
6205 @safe unittest
6206 {
6207     import std.algorithm.comparison : equal;
6208 
6209     assert(toChars(1).equal("1"));
6210     assert(toChars(1_000_000).equal("1000000"));
6211 
6212     assert(toChars!(2)(2U).equal("10"));
6213     assert(toChars!(16)(255U).equal("ff"));
6214     assert(toChars!(16, char, LetterCase.upper)(255U).equal("FF"));
6215 }
6216 
6217 
6218 @safe unittest
6219 {
6220     import std.array;
6221     import std.range;
6222 
6223     assert(toChars(123) == toChars(123));
6224 
6225     {
6226         assert(toChars!2(ubyte(0)).array == "0");
6227         assert(toChars!2(ushort(0)).array == "0");
6228         assert(toChars!2(0u).array == "0");
6229         assert(toChars!2(0Lu).array == "0");
6230         assert(toChars!2(ubyte(1)).array == "1");
6231         assert(toChars!2(ushort(1)).array == "1");
6232         assert(toChars!2(1u).array == "1");
6233         assert(toChars!2(1Lu).array == "1");
6234 
6235         auto r = toChars!2(2u);
6236         assert(r.length == 2);
6237         assert(r[0] == '1');
6238         assert(r[1 .. 2].array == "0");
6239         auto s = r.save;
6240         assert(r.array == "10");
6241         assert(s.retro.array == "01");
6242     }
6243     {
6244         assert(toChars!8(ubyte(0)).array == "0");
6245         assert(toChars!8(ushort(0)).array == "0");
6246         assert(toChars!8(0u).array == "0");
6247         assert(toChars!8(0Lu).array == "0");
6248         assert(toChars!8(1u).array == "1");
6249         assert(toChars!8(1234567Lu).array == "4553207");
6250         assert(toChars!8(ubyte.max).array == "377");
6251         assert(toChars!8(ushort.max).array == "177777");
6252 
6253         auto r = toChars!8(8u);
6254         assert(r.length == 2);
6255         assert(r[0] == '1');
6256         assert(r[1 .. 2].array == "0");
6257         auto s = r.save;
6258         assert(r.array == "10");
6259         assert(s.retro.array == "01");
6260     }
6261     {
6262         assert(toChars!10(ubyte(0)).array == "0");
6263         assert(toChars!10(ushort(0)).array == "0");
6264         assert(toChars!10(0u).array == "0");
6265         assert(toChars!10(0Lu).array == "0");
6266         assert(toChars!10(1u).array == "1");
6267         assert(toChars!10(1234567Lu).array == "1234567");
6268         assert(toChars!10(ubyte.max).array == "255");
6269         assert(toChars!10(ushort.max).array == "65535");
6270         assert(toChars!10(uint.max).array == "4294967295");
6271         assert(toChars!10(ulong.max).array == "18446744073709551615");
6272 
6273         auto r = toChars(10u);
6274         assert(r.length == 2);
6275         assert(r[0] == '1');
6276         assert(r[1 .. 2].array == "0");
6277         auto s = r.save;
6278         assert(r.array == "10");
6279         assert(s.retro.array == "01");
6280     }
6281     {
6282         assert(toChars!10(0).array == "0");
6283         assert(toChars!10(0L).array == "0");
6284         assert(toChars!10(1).array == "1");
6285         assert(toChars!10(1234567L).array == "1234567");
6286         assert(toChars!10(byte.max).array == "127");
6287         assert(toChars!10(short.max).array == "32767");
6288         assert(toChars!10(int.max).array == "2147483647");
6289         assert(toChars!10(long.max).array == "9223372036854775807");
6290         assert(toChars!10(-byte.max).array == "-127");
6291         assert(toChars!10(-short.max).array == "-32767");
6292         assert(toChars!10(-int.max).array == "-2147483647");
6293         assert(toChars!10(-long.max).array == "-9223372036854775807");
6294         assert(toChars!10(byte.min).array == "-128");
6295         assert(toChars!10(short.min).array == "-32768");
6296         assert(toChars!10(int.min).array == "-2147483648");
6297         assert(toChars!10(long.min).array == "-9223372036854775808");
6298 
6299         auto r = toChars!10(10);
6300         assert(r.length == 2);
6301         assert(r[0] == '1');
6302         assert(r[1 .. 2].array == "0");
6303         auto s = r.save;
6304         assert(r.array == "10");
6305         assert(s.retro.array == "01");
6306     }
6307     {
6308         assert(toChars!(16)(0u).array == "0");
6309         assert(toChars!(16)(0Lu).array == "0");
6310         assert(toChars!(16)(10u).array == "a");
6311         assert(toChars!(16, char, LetterCase.upper)(0x12AF34567Lu).array == "12AF34567");
6312         assert(toChars!(16)(ubyte(0)).array == "0");
6313         assert(toChars!(16)(ushort(0)).array == "0");
6314         assert(toChars!(16)(ubyte.max).array == "ff");
6315         assert(toChars!(16)(ushort.max).array == "ffff");
6316 
6317         auto r = toChars!(16)(16u);
6318         assert(r.length == 2);
6319         assert(r[0] == '1');
6320         assert(r[1 .. 2].array == "0");
6321         auto s = r.save;
6322         assert(r.array == "10");
6323         assert(s.retro.array == "01");
6324     }
6325 }
6326 
6327 @safe unittest // opSlice (https://issues.dlang.org/show_bug.cgi?id=16192)
6328 {
6329     import std.meta : AliasSeq;
6330 
6331     static struct Test { ubyte radix; uint number; }
6332 
6333     alias tests = AliasSeq!(
6334         Test(2, 0b1_0110_0111u),
6335         Test(2, 0b10_1100_1110u),
6336         Test(8, octal!123456701u),
6337         Test(8, octal!1234567012u),
6338         Test(10, 123456789u),
6339         Test(10, 1234567890u),
6340         Test(16, 0x789ABCDu),
6341         Test(16, 0x789ABCDEu),
6342     );
6343 
6344     foreach (test; tests)
6345     {
6346         enum ubyte radix = test.radix;
6347         auto original = toChars!radix(test.number);
6348 
6349         // opSlice vs popFront
6350         auto r = original.save;
6351         size_t i = 0;
6352         for (; !r.empty; r.popFront(), ++i)
6353         {
6354             assert(original[i .. original.length].tupleof == r.tupleof);
6355                 // tupleof is used to work around https://issues.dlang.org/show_bug.cgi?id=16216.
6356         }
6357 
6358         // opSlice vs popBack
6359         r = original.save;
6360         i = 0;
6361         for (; !r.empty; r.popBack(), ++i)
6362         {
6363             assert(original[0 .. original.length - i].tupleof == r.tupleof);
6364         }
6365 
6366         // opSlice vs both popFront and popBack
6367         r = original.save;
6368         i = 0;
6369         for (; r.length >= 2; r.popFront(), r.popBack(), ++i)
6370         {
6371             assert(original[i .. original.length - i].tupleof == r.tupleof);
6372         }
6373     }
6374 }
6375 
6376 // Converts an unsigned integer to a compile-time string constant.
6377 package enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
6378 
6379 // Check that .stringof does what we expect, since it's not guaranteed by the
6380 // language spec.
6381 @safe /*@betterC*/ unittest
6382 {
6383     assert(toCtString!0 == "0");
6384     assert(toCtString!123456 == "123456");
6385 }
6386 
6387 /**
6388  * Takes the raw bits of a value and reinterprets them as a different type.
6389  *
6390  * Params:
6391  *   T = the new type.
6392  *   value = the value to reinterpret.
6393  *
6394  * Returns: a reference to the reinterpreted value.
6395  */
6396 pragma(inline, true)
6397 ref T bitCast(T, S)(ref S value)
6398 if (T.sizeof <= S.sizeof)
6399 {
6400     return *cast(T*) &value;
6401 }
6402 
6403 ///
6404 @safe unittest
6405 {
6406     uint n = 0xDEADBEEF;
6407 
6408     version (LittleEndian)
6409         assert(n.bitCast!(ubyte[4]) == [0xEF, 0xBE, 0xAD, 0xDE]);
6410     version (BigEndian)
6411         assert(n.bitCast!(ubyte[4]) == [0xDE, 0xAD, 0xBE, 0xEF]);
6412 }
6413 
6414 // Sizes must be compatible
6415 @safe unittest
6416 {
6417     uint n;
6418 
6419     assert(!__traits(compiles, n.bitCast!ulong));
6420 }