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