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