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