The OpenD Programming Language

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))
4852                 || isSomeString!(typeof(arg))
4853                 || ( isInputRange!(typeof(arg)) && isSomeChar!(ElementType!(typeof(arg))) )
4854             )
4855                 app.put(arg);
4856             else static if (
4857 
4858                 is(immutable typeof(arg) == immutable uint) || is(immutable typeof(arg) == immutable ulong) ||
4859                 is(immutable typeof(arg) == immutable int) || is(immutable typeof(arg) == immutable long)
4860             )
4861                 // https://issues.dlang.org/show_bug.cgi?id=17712#c15
4862                 app.put(textImpl!(S)(arg));
4863             else
4864                 app.put(to!S(arg));
4865         }
4866 
4867         return app.data;
4868     }
4869 }
4870 
4871 
4872 /***************************************************************
4873 The `octal` facility provides a means to declare a number in base 8.
4874 Using `octal!177` or `octal!"177"` for 127 represented in octal
4875 (same as 0177 in C).
4876 
4877 The rules for strings are the usual for literals: If it can fit in an
4878 `int`, it is an `int`. Otherwise, it is a `long`. But, if the
4879 user specifically asks for a `long` with the `L` suffix, always
4880 give the `long`. Give an unsigned iff it is asked for with the $(D
4881 U) or `u` suffix. _Octals created from integers preserve the type
4882 of the passed-in integral.
4883 
4884 See_Also:
4885     $(LREF parse) for parsing octal strings at runtime.
4886  */
4887 template octal(string num)
4888 if (isOctalLiteral(num))
4889 {
4890     static if ((octalFitsInInt!num && !literalIsLong!num) && !literalIsUnsigned!num)
4891         enum octal = octal!int(num);
4892     else static if ((!octalFitsInInt!num || literalIsLong!num) && !literalIsUnsigned!num)
4893         enum octal = octal!long(num);
4894     else static if ((octalFitsInInt!num && !literalIsLong!num) && literalIsUnsigned!num)
4895         enum octal = octal!uint(num);
4896     else static if ((!octalFitsInInt!(num) || literalIsLong!(num)) && literalIsUnsigned!(num))
4897         enum octal = octal!ulong(num);
4898     else
4899         static assert(false, "Unusable input " ~ num);
4900 }
4901 
4902 /// Ditto
4903 template octal(alias decimalInteger)
4904 if (is(typeof(decimalInteger)) && isIntegral!(typeof(decimalInteger)))
4905 {
4906     enum octal = convertToOctal(decimalInteger);
4907 }
4908 
4909 ///
4910 @safe unittest
4911 {
4912     // Same as 0177
4913     auto a = octal!177;
4914     // octal is a compile-time device
4915     enum b = octal!160;
4916     // Create an unsigned octal
4917     auto c = octal!"1_000_000u";
4918     // Leading zeros are allowed when converting from a string
4919     auto d = octal!"0001_200_000";
4920 }
4921 
4922 /*************************************
4923  * Convert a decimal integer to an octal integer with the same digits.
4924  * Params:
4925  *    i = integer to convert
4926  * Returns:
4927  *    octal integer with the same type and same digits
4928  */
4929 private T convertToOctal(T)(T i)
4930 {
4931     assert((i % 10) < 8);
4932     return i ? convertToOctal(i / 10) * 8 + i % 10 : 0;
4933 }
4934 
4935 /*
4936     Takes a string, num, which is an octal literal, and returns its
4937     value, in the type T specified.
4938 */
4939 private T octal(T)(const string num)
4940 {
4941     assert(isOctalLiteral(num), num ~ " is not an octal literal");
4942 
4943     T value = 0;
4944 
4945     foreach (const char s; num)
4946     {
4947         if (s < '0' || s > '7') // we only care about digits; skip the rest
4948         // safe to skip - this is checked out in the assert so these
4949         // are just suffixes
4950             continue;
4951 
4952         value *= 8;
4953         value += s - '0';
4954     }
4955 
4956     return value;
4957 }
4958 
4959 @safe unittest
4960 {
4961     int a = octal!int("10");
4962     assert(a == 8);
4963 
4964     int b = octal!int("000137");
4965     assert(b == 95);
4966 }
4967 
4968 /*
4969 Take a look at int.max and int.max+1 in octal and the logic for this
4970 function follows directly.
4971  */
4972 private template octalFitsInInt(string octalNum)
4973 {
4974     // note it is important to strip the literal of all
4975     // non-numbers. kill the suffix and underscores lest they mess up
4976     // the number of digits here that we depend on.
4977     enum bool octalFitsInInt = strippedOctalLiteral(octalNum).length < 11 ||
4978         strippedOctalLiteral(octalNum).length == 11 &&
4979         strippedOctalLiteral(octalNum)[0] == '1';
4980 }
4981 
4982 private string strippedOctalLiteral(string original)
4983 {
4984     string stripped = "";
4985     bool leading_zeros = true;
4986     foreach (c; original)
4987     {
4988         if (!('0' <= c && c <= '7'))
4989             continue;
4990         if (c == '0')
4991         {
4992             if (leading_zeros)
4993                 continue;
4994         }
4995         else
4996         {
4997             leading_zeros = false;
4998         }
4999         stripped ~= c;
5000     }
5001     if (stripped.length == 0)
5002     {
5003         assert(leading_zeros);
5004         return "0";
5005     }
5006     return stripped;
5007 }
5008 
5009 @safe unittest
5010 {
5011     static assert(strippedOctalLiteral("7") == "7");
5012     static assert(strippedOctalLiteral("123") == "123");
5013     static assert(strippedOctalLiteral("00123") == "123");
5014     static assert(strippedOctalLiteral("01230") == "1230");
5015     static assert(strippedOctalLiteral("0") == "0");
5016     static assert(strippedOctalLiteral("00_000") == "0");
5017     static assert(strippedOctalLiteral("000_000_12_300") == "12300");
5018 }
5019 
5020 private template literalIsLong(string num)
5021 {
5022     static if (num.length > 1)
5023     // can be xxL or xxLu according to spec
5024         enum literalIsLong = (num[$-1] == 'L' || num[$-2] == 'L');
5025     else
5026         enum literalIsLong = false;
5027 }
5028 
5029 private template literalIsUnsigned(string num)
5030 {
5031     static if (num.length > 1)
5032     // can be xxU or xxUL according to spec
5033         enum literalIsUnsigned = (num[$-1] == 'u' || num[$-2] == 'u')
5034             // both cases are allowed too
5035             || (num[$-1] == 'U' || num[$-2] == 'U');
5036     else
5037         enum literalIsUnsigned = false;
5038 }
5039 
5040 /*
5041 Returns if the given string is a correctly formatted octal literal.
5042 
5043 The format is specified in spec/lex.html. The leading zeros are allowed,
5044 but not required.
5045  */
5046 @safe pure nothrow @nogc
5047 private bool isOctalLiteral(const string num)
5048 {
5049     if (num.length == 0)
5050         return false;
5051 
5052     // Must start with a digit.
5053     if (num[0] < '0' || num[0] > '7')
5054         return false;
5055 
5056     foreach (i, c; num)
5057     {
5058         if (('0' <= c && c <= '7') || c == '_')  // a legal character
5059             continue;
5060 
5061         if (i < num.length - 2)
5062             return false;
5063 
5064         // gotta check for those suffixes
5065         if (c != 'U' && c != 'u' && c != 'L')
5066             return false;
5067         if (i != num.length - 1)
5068         {
5069             // if we're not the last one, the next one must
5070             // also be a suffix to be valid
5071             char c2 = num[$-1];
5072             if (c2 != 'U' && c2 != 'u' && c2 != 'L')
5073                 return false; // spam at the end of the string
5074             if (c2 == c)
5075                 return false; // repeats are disallowed
5076         }
5077     }
5078 
5079     return true;
5080 }
5081 
5082 @safe unittest
5083 {
5084     // ensure that you get the right types, even with embedded underscores
5085     auto w = octal!"100_000_000_000";
5086     static assert(!is(typeof(w) == int));
5087     auto w2 = octal!"1_000_000_000";
5088     static assert(is(typeof(w2) == int));
5089 
5090     static assert(octal!"45" == 37);
5091     static assert(octal!"0" == 0);
5092     static assert(octal!"7" == 7);
5093     static assert(octal!"10" == 8);
5094     static assert(octal!"666" == 438);
5095     static assert(octal!"0004001" == 2049);
5096     static assert(octal!"00" == 0);
5097     static assert(octal!"0_0" == 0);
5098 
5099     static assert(octal!45 == 37);
5100     static assert(octal!0 == 0);
5101     static assert(octal!7 == 7);
5102     static assert(octal!10 == 8);
5103     static assert(octal!666 == 438);
5104 
5105     static assert(octal!"66_6" == 438);
5106     static assert(octal!"0_0_66_6" == 438);
5107 
5108     static assert(octal!2520046213 == 356535435);
5109     static assert(octal!"2520046213" == 356535435);
5110 
5111     static assert(octal!17777777777 == int.max);
5112 
5113     static assert(!__traits(compiles, octal!823));
5114 
5115     static assert(!__traits(compiles, octal!"823"));
5116 
5117     static assert(!__traits(compiles, octal!"_823"));
5118     static assert(!__traits(compiles, octal!"spam"));
5119     static assert(!__traits(compiles, octal!"77%"));
5120 
5121     static assert(is(typeof(octal!"17777777777") == int));
5122     static assert(octal!"17777777777" == int.max);
5123 
5124     static assert(is(typeof(octal!"20000000000U") == ulong)); // Shouldn't this be uint?
5125     static assert(octal!"20000000000" == uint(int.max) + 1);
5126 
5127     static assert(is(typeof(octal!"777777777777777777777") == long));
5128     static assert(octal!"777777777777777777777" == long.max);
5129 
5130     static assert(is(typeof(octal!"1000000000000000000000U") == ulong));
5131     static assert(octal!"1000000000000000000000" == ulong(long.max) + 1);
5132 
5133     int a;
5134     long b;
5135 
5136     // biggest value that should fit in an it
5137     a = octal!"17777777777";
5138     assert(a == int.max);
5139     // should not fit in the int
5140     static assert(!__traits(compiles, a = octal!"20000000000"));
5141     // ... but should fit in a long
5142     b = octal!"20000000000";
5143     assert(b == 1L + int.max);
5144 
5145     b = octal!"1L";
5146     assert(b == 1);
5147     b = octal!1L;
5148     assert(b == 1);
5149 }
5150 
5151 // emplace() used to be here but was moved to druntime
5152 public import core.lifetime : emplace;
5153 
5154 // https://issues.dlang.org/show_bug.cgi?id=9559
5155 @safe unittest
5156 {
5157     import std.algorithm.iteration : map;
5158     import std.array : array;
5159     import std.typecons : Nullable;
5160     alias I = Nullable!int;
5161     auto ints = [0, 1, 2].map!(i => i & 1 ? I.init : I(i))();
5162     auto asArray = array(ints);
5163 }
5164 
5165 @system unittest //http://forum.dlang.org/post/nxbdgtdlmwscocbiypjs@forum.dlang.org
5166 {
5167     import std.array : array;
5168     import std.datetime : SysTime, UTC;
5169     import std.math.traits : isNaN;
5170 
5171     static struct A
5172     {
5173         double i;
5174     }
5175 
5176     static struct B
5177     {
5178         invariant()
5179         {
5180             if (j == 0)
5181                 assert(a.i.isNaN(), "why is 'j' zero?? and i is not NaN?");
5182             else
5183                 assert(!a.i.isNaN());
5184         }
5185         SysTime when; // comment this line avoid the breakage
5186         int j;
5187         A a;
5188     }
5189 
5190     B b1 = B.init;
5191     assert(&b1); // verify that default eyes invariants are ok;
5192 
5193     auto b2 = B(SysTime(0, UTC()), 1, A(1));
5194     assert(&b2);
5195     auto b3 = B(SysTime(0, UTC()), 1, A(1));
5196     assert(&b3);
5197 
5198     auto arr = [b2, b3];
5199 
5200     assert(arr[0].j == 1);
5201     assert(arr[1].j == 1);
5202     auto a2 = arr.array(); // << bang, invariant is raised, also if b2 and b3 are good
5203 }
5204 
5205 @safe unittest
5206 {
5207     import std.algorithm.comparison : equal;
5208     import std.algorithm.iteration : map;
5209     // Check fix for https://issues.dlang.org/show_bug.cgi?id=2971
5210     assert(equal(map!(to!int)(["42", "34", "345"]), [42, 34, 345]));
5211 }
5212 
5213 // Undocumented for the time being
5214 void toTextRange(T, W)(T value, W writer)
5215 if (isIntegral!T && isOutputRange!(W, char))
5216 {
5217     import core.internal.string : SignedStringBuf, signedToTempString,
5218                                   UnsignedStringBuf, unsignedToTempString;
5219 
5220     if (value < 0)
5221     {
5222         SignedStringBuf buf = void;
5223         put(writer, signedToTempString(value, buf));
5224     }
5225     else
5226     {
5227         UnsignedStringBuf buf = void;
5228         put(writer, unsignedToTempString(value, buf));
5229     }
5230 }
5231 
5232 @safe unittest
5233 {
5234     import std.array : appender;
5235     auto result = appender!(char[])();
5236     toTextRange(-1, result);
5237     assert(result.data == "-1");
5238 }
5239 
5240 
5241 /**
5242     Returns the corresponding _unsigned value for `x` (e.g. if `x` has type
5243     `int`, it returns $(D cast(uint) x)). The advantage compared to the cast
5244     is that you do not need to rewrite the cast if `x` later changes type
5245     (e.g from `int` to `long`).
5246 
5247     Note that the result is always mutable even if the original type was const
5248     or immutable. In order to retain the constness, use $(REF Unsigned, std,traits).
5249  */
5250 auto unsigned(T)(T x)
5251 if (isIntegral!T)
5252 {
5253     return cast(Unqual!(Unsigned!T))x;
5254 }
5255 
5256 ///
5257 @safe unittest
5258 {
5259     import std.traits : Unsigned;
5260     immutable int s = 42;
5261     auto u1 = unsigned(s); //not qualified
5262     static assert(is(typeof(u1) == uint));
5263     Unsigned!(typeof(s)) u2 = unsigned(s); //same qualification
5264     static assert(is(typeof(u2) == immutable uint));
5265     immutable u3 = unsigned(s); //explicitly qualified
5266 }
5267 
5268 /// Ditto
5269 auto unsigned(T)(T x)
5270 if (isSomeChar!T)
5271 {
5272     // All characters are unsigned
5273     static assert(T.min == 0, T.stringof ~ ".min must be zero");
5274     return cast(Unqual!T) x;
5275 }
5276 
5277 @safe unittest
5278 {
5279     static foreach (T; AliasSeq!(byte, ubyte))
5280     {
5281         static assert(is(typeof(unsigned(cast(T) 1)) == ubyte));
5282         static assert(is(typeof(unsigned(cast(const T) 1)) == ubyte));
5283         static assert(is(typeof(unsigned(cast(immutable T) 1)) == ubyte));
5284     }
5285 
5286     static foreach (T; AliasSeq!(short, ushort))
5287     {
5288         static assert(is(typeof(unsigned(cast(T) 1)) == ushort));
5289         static assert(is(typeof(unsigned(cast(const T) 1)) == ushort));
5290         static assert(is(typeof(unsigned(cast(immutable T) 1)) == ushort));
5291     }
5292 
5293     static foreach (T; AliasSeq!(int, uint))
5294     {
5295         static assert(is(typeof(unsigned(cast(T) 1)) == uint));
5296         static assert(is(typeof(unsigned(cast(const T) 1)) == uint));
5297         static assert(is(typeof(unsigned(cast(immutable T) 1)) == uint));
5298     }
5299 
5300     static foreach (T; AliasSeq!(long, ulong))
5301     {
5302         static assert(is(typeof(unsigned(cast(T) 1)) == ulong));
5303         static assert(is(typeof(unsigned(cast(const T) 1)) == ulong));
5304         static assert(is(typeof(unsigned(cast(immutable T) 1)) == ulong));
5305     }
5306 }
5307 
5308 @safe unittest
5309 {
5310     static foreach (T; AliasSeq!(char, wchar, dchar))
5311     {
5312         static assert(is(typeof(unsigned(cast(T)'A')) == T));
5313         static assert(is(typeof(unsigned(cast(const T)'A')) == T));
5314         static assert(is(typeof(unsigned(cast(immutable T)'A')) == T));
5315     }
5316 }
5317 
5318 
5319 /**
5320     Returns the corresponding _signed value for `x` (e.g. if `x` has type
5321     `uint`, it returns $(D cast(int) x)). The advantage compared to the cast
5322     is that you do not need to rewrite the cast if `x` later changes type
5323     (e.g from `uint` to `ulong`).
5324 
5325     Note that the result is always mutable even if the original type was const
5326     or immutable. In order to retain the constness, use $(REF Signed, std,traits).
5327  */
5328 auto signed(T)(T x)
5329 if (isIntegral!T)
5330 {
5331     return cast(Unqual!(Signed!T))x;
5332 }
5333 
5334 ///
5335 @safe unittest
5336 {
5337     import std.traits : Signed;
5338 
5339     immutable uint u = 42;
5340     auto s1 = signed(u); //not qualified
5341     static assert(is(typeof(s1) == int));
5342     Signed!(typeof(u)) s2 = signed(u); //same qualification
5343     static assert(is(typeof(s2) == immutable int));
5344     immutable s3 = signed(u); //explicitly qualified
5345 }
5346 
5347 @system unittest
5348 {
5349     static foreach (T; AliasSeq!(byte, ubyte))
5350     {
5351         static assert(is(typeof(signed(cast(T) 1)) == byte));
5352         static assert(is(typeof(signed(cast(const T) 1)) == byte));
5353         static assert(is(typeof(signed(cast(immutable T) 1)) == byte));
5354     }
5355 
5356     static foreach (T; AliasSeq!(short, ushort))
5357     {
5358         static assert(is(typeof(signed(cast(T) 1)) == short));
5359         static assert(is(typeof(signed(cast(const T) 1)) == short));
5360         static assert(is(typeof(signed(cast(immutable T) 1)) == short));
5361     }
5362 
5363     static foreach (T; AliasSeq!(int, uint))
5364     {
5365         static assert(is(typeof(signed(cast(T) 1)) == int));
5366         static assert(is(typeof(signed(cast(const T) 1)) == int));
5367         static assert(is(typeof(signed(cast(immutable T) 1)) == int));
5368     }
5369 
5370     static foreach (T; AliasSeq!(long, ulong))
5371     {
5372         static assert(is(typeof(signed(cast(T) 1)) == long));
5373         static assert(is(typeof(signed(cast(const T) 1)) == long));
5374         static assert(is(typeof(signed(cast(immutable T) 1)) == long));
5375     }
5376 }
5377 
5378 // https://issues.dlang.org/show_bug.cgi?id=10874
5379 @safe unittest
5380 {
5381     enum Test { a = 0 }
5382     ulong l = 0;
5383     auto t = l.to!Test;
5384 }
5385 
5386 // asOriginalType
5387 /**
5388 Returns the representation of an enumerated value, i.e. the value converted to
5389 the base type of the enumeration.
5390 */
5391 OriginalType!E asOriginalType(E)(E value)
5392 if (is(E == enum))
5393 {
5394     return value;
5395 }
5396 
5397 ///
5398 @safe unittest
5399 {
5400     enum A { a = 42 }
5401     static assert(is(typeof(A.a.asOriginalType) == int));
5402     assert(A.a.asOriginalType == 42);
5403     enum B : double { a = 43 }
5404     static assert(is(typeof(B.a.asOriginalType) == double));
5405     assert(B.a.asOriginalType == 43);
5406 }
5407 
5408 /**
5409     A wrapper on top of the built-in cast operator that allows one to restrict
5410     casting of the original type of the value.
5411 
5412     A common issue with using a raw cast is that it may silently continue to
5413     compile even if the value's type has changed during refactoring,
5414     which breaks the initial assumption about the cast.
5415 
5416     Params:
5417         From  = The type to cast from. The programmer must ensure it is legal
5418                 to make this cast.
5419  */
5420 template castFrom(From)
5421 {
5422     /**
5423         Params:
5424             To    = The type _to cast _to.
5425             value = The value _to cast. It must be of type `From`,
5426                     otherwise a compile-time error is emitted.
5427 
5428         Returns:
5429             the value after the cast, returned by reference if possible.
5430      */
5431     auto ref to(To, T)(auto ref T value) @system
5432     {
5433         static assert(
5434             is(From == T),
5435             "the value to cast is not of specified type '" ~ From.stringof ~
5436                  "', it is of type '" ~ T.stringof ~ "'"
5437         );
5438 
5439         static assert(
5440             is(typeof(cast(To) value)),
5441             "can't cast from '" ~ From.stringof ~ "' to '" ~ To.stringof ~ "'"
5442         );
5443 
5444         return cast(To) value;
5445     }
5446 }
5447 
5448 ///
5449 @system unittest
5450 {
5451     // Regular cast, which has been verified to be legal by the programmer:
5452     {
5453         long x;
5454         auto y = cast(int) x;
5455     }
5456 
5457     // However this will still compile if 'x' is changed to be a pointer:
5458     {
5459         long* x;
5460         auto y = cast(int) x;
5461     }
5462 
5463     // castFrom provides a more reliable alternative to casting:
5464     {
5465         long x;
5466         auto y = castFrom!long.to!int(x);
5467     }
5468 
5469     // Changing the type of 'x' will now issue a compiler error,
5470     // allowing bad casts to be caught before it's too late:
5471     {
5472         long* x;
5473         static assert(
5474             !__traits(compiles, castFrom!long.to!int(x))
5475         );
5476 
5477         // if cast is still needed, must be changed to:
5478         auto y = castFrom!(long*).to!int(x);
5479     }
5480 }
5481 
5482 // https://issues.dlang.org/show_bug.cgi?id=16667
5483 @system unittest
5484 {
5485     ubyte[] a = ['a', 'b', 'c'];
5486     assert(castFrom!(ubyte[]).to!(string)(a) == "abc");
5487 }
5488 
5489 /**
5490 Check the correctness of a string for `hexString`.
5491 The result is true if and only if the input string is composed of whitespace
5492 characters (\f\n\r\t\v lineSep paraSep nelSep) and
5493 an even number of hexadecimal digits (regardless of the case).
5494 */
5495 @safe pure @nogc
5496 private bool isHexLiteral(String)(scope const String hexData)
5497 {
5498     import std.ascii : isHexDigit;
5499     import std.uni : lineSep, paraSep, nelSep;
5500     size_t i;
5501     foreach (const dchar c; hexData)
5502     {
5503         switch (c)
5504         {
5505             case ' ':
5506             case '\t':
5507             case '\v':
5508             case '\f':
5509             case '\r':
5510             case '\n':
5511             case lineSep:
5512             case paraSep:
5513             case nelSep:
5514                 continue;
5515 
5516             default:
5517                 break;
5518         }
5519         if (c.isHexDigit)
5520             ++i;
5521         else
5522             return false;
5523     }
5524     return !(i & 1);
5525 }
5526 
5527 @safe unittest
5528 {
5529     // test all the hex digits
5530     static assert( ("0123456789abcdefABCDEF").isHexLiteral);
5531     // empty or white strings are not valid
5532     static assert( "\r\n\t".isHexLiteral);
5533     // but are accepted if the count of hex digits is even
5534     static assert( "A\r\n\tB".isHexLiteral);
5535 }
5536 
5537 @safe unittest
5538 {
5539     import std.ascii;
5540     // empty/whites
5541     static assert( "".isHexLiteral);
5542     static assert( " \r".isHexLiteral);
5543     static assert( whitespace.isHexLiteral);
5544     static assert( ""w.isHexLiteral);
5545     static assert( " \r"w.isHexLiteral);
5546     static assert( ""d.isHexLiteral);
5547     static assert( " \r"d.isHexLiteral);
5548     static assert( "\u2028\u2029\u0085"d.isHexLiteral);
5549     // odd x strings
5550     static assert( !("5" ~ whitespace).isHexLiteral);
5551     static assert( !"123".isHexLiteral);
5552     static assert( !"1A3".isHexLiteral);
5553     static assert( !"1 23".isHexLiteral);
5554     static assert( !"\r\n\tC".isHexLiteral);
5555     static assert( !"123"w.isHexLiteral);
5556     static assert( !"1A3"w.isHexLiteral);
5557     static assert( !"1 23"w.isHexLiteral);
5558     static assert( !"\r\n\tC"w.isHexLiteral);
5559     static assert( !"123"d.isHexLiteral);
5560     static assert( !"1A3"d.isHexLiteral);
5561     static assert( !"1 23"d.isHexLiteral);
5562     static assert( !"\r\n\tC"d.isHexLiteral);
5563     // even x strings with invalid charset
5564     static assert( !"12gG".isHexLiteral);
5565     static assert( !"2A  3q".isHexLiteral);
5566     static assert( !"12gG"w.isHexLiteral);
5567     static assert( !"2A  3q"w.isHexLiteral);
5568     static assert( !"12gG"d.isHexLiteral);
5569     static assert( !"2A  3q"d.isHexLiteral);
5570     // valid x strings
5571     static assert( ("5A" ~ whitespace).isHexLiteral);
5572     static assert( ("5A 01A C FF de 1b").isHexLiteral);
5573     static assert( ("0123456789abcdefABCDEF").isHexLiteral);
5574     static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF").isHexLiteral);
5575     static assert( ("5A 01A C FF de 1b"w).isHexLiteral);
5576     static assert( ("0123456789abcdefABCDEF"w).isHexLiteral);
5577     static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF"w).isHexLiteral);
5578     static assert( ("5A 01A C FF de 1b"d).isHexLiteral);
5579     static assert( ("0123456789abcdefABCDEF"d).isHexLiteral);
5580     static assert( (" 012 34 5 6789 abcd ef\rAB\nCDEF"d).isHexLiteral);
5581     // library version allows what's pointed by https://issues.dlang.org/show_bug.cgi?id=10454
5582     static assert( ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF").isHexLiteral);
5583 }
5584 
5585 /**
5586 Converts a hex literal to a string at compile time.
5587 
5588 Takes a string made of hexadecimal digits and returns
5589 the matching string by converting each pair of digits to a character.
5590 The input string can also include white characters, which can be used
5591 to keep the literal string readable in the source code.
5592 
5593 The function is intended to replace the hexadecimal literal strings
5594 starting with `'x'`, which could be removed to simplify the core language.
5595 
5596 Params:
5597     hexData = string to be converted.
5598 
5599 Returns:
5600     a `string`, a `wstring` or a `dstring`, according to the type of hexData.
5601  */
5602 template hexString(string hexData)
5603 if (hexData.isHexLiteral)
5604 {
5605     enum hexString = mixin(hexToString(hexData));
5606 }
5607 
5608 /// ditto
5609 template hexString(wstring hexData)
5610 if (hexData.isHexLiteral)
5611 {
5612     enum wstring hexString = mixin(hexToString(hexData));
5613 }
5614 
5615 /// ditto
5616 template hexString(dstring hexData)
5617 if (hexData.isHexLiteral)
5618 {
5619     enum dstring hexString = mixin(hexToString(hexData));
5620 }
5621 
5622 ///
5623 @safe unittest
5624 {
5625     // conversion at compile time
5626     auto string1 = hexString!"304A314B";
5627     assert(string1 == "0J1K");
5628     auto string2 = hexString!"304A314B"w;
5629     assert(string2 == "0J1K"w);
5630     auto string3 = hexString!"304A314B"d;
5631     assert(string3 == "0J1K"d);
5632 }
5633 
5634 @safe nothrow pure private
5635 {
5636     /* These are meant to be used with CTFE.
5637      * They cause the instantiations of hexStrLiteral()
5638      * to be in Phobos, not user code.
5639      */
5640     string hexToString(string s)
5641     {
5642         return hexStrLiteral(s);
5643     }
5644 
5645     wstring hexToString(wstring s)
5646     {
5647         return hexStrLiteral(s);
5648     }
5649 
5650     dstring hexToString(dstring s)
5651     {
5652         return hexStrLiteral(s);
5653     }
5654 }
5655 
5656 /*
5657     Turn a hexadecimal string into a regular string literal.
5658     I.e. "dead beef" is transformed into "\xde\xad\xbe\xef"
5659     suitable for use in a mixin.
5660     Params:
5661         hexData is string, wstring, or dstring and validated by isHexLiteral()
5662  */
5663 @trusted nothrow pure
5664 private auto hexStrLiteral(String)(scope String hexData)
5665 {
5666     import std.ascii : isHexDigit;
5667     alias C = Unqual!(ElementEncodingType!String);    // char, wchar or dchar
5668     C[] result;
5669     result.length = 1 + hexData.length * 2 + 1;       // don't forget the " "
5670     /* Use a pointer because we know it won't overrun,
5671      * and this will reduce the size of the function substantially
5672      * by not doing the array bounds checks.
5673      * This is why this function is @trusted.
5674      */
5675     auto r = result.ptr;
5676     r[0] = '"';
5677     size_t cnt = 0;
5678     foreach (c; hexData)
5679     {
5680         if (c.isHexDigit)
5681         {
5682             if ((cnt & 1) == 0)
5683             {
5684                 r[1 + cnt]     = '\\';
5685                 r[1 + cnt + 1] = 'x';
5686                 cnt += 2;
5687             }
5688             r[1 + cnt] = c;
5689             ++cnt;
5690         }
5691     }
5692     r[1 + cnt] = '"';
5693     result.length = 1 + cnt + 1;        // trim off any excess length
5694     return result;
5695 }
5696 
5697 
5698 @safe unittest
5699 {
5700     // compile time
5701     assert(hexString!"46 47 48 49 4A 4B" == "FGHIJK");
5702     assert(hexString!"30\r\n\t\f\v31 32 33 32 31 30" == "0123210");
5703     assert(hexString!"ab cd" == hexString!"ABCD");
5704 }
5705 
5706 
5707 /**
5708  * Convert integer to a range of characters.
5709  * Intended to be lightweight and fast.
5710  *
5711  * Params:
5712  *      radix = 2, 8, 10, 16
5713  *      Char = character type for output
5714  *      letterCase = lower for deadbeef, upper for DEADBEEF
5715  *      value = integer to convert. Can be ubyte, ushort, uint or ulong. If radix
5716  *              is 10, can also be byte, short, int or long.
5717  * Returns:
5718  *      Random access range with slicing and everything
5719  */
5720 
5721 auto toChars(ubyte radix = 10, Char = char, LetterCase letterCase = LetterCase.lower, T)(T value)
5722     pure nothrow @nogc @safe
5723 if ((radix == 2 || radix == 8 || radix == 10 || radix == 16) &&
5724         isIntegral!T && (radix == 10 || isUnsigned!T))
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(ubyte(0)).array == "0");
5873         assert(toChars!2(ushort(0)).array == "0");
5874         assert(toChars!2(0u).array == "0");
5875         assert(toChars!2(0Lu).array == "0");
5876         assert(toChars!2(ubyte(1)).array == "1");
5877         assert(toChars!2(ushort(1)).array == "1");
5878         assert(toChars!2(1u).array == "1");
5879         assert(toChars!2(1Lu).array == "1");
5880 
5881         auto r = toChars!2(2u);
5882         assert(r.length == 2);
5883         assert(r[0] == '1');
5884         assert(r[1 .. 2].array == "0");
5885         auto s = r.save;
5886         assert(r.array == "10");
5887         assert(s.retro.array == "01");
5888     }
5889     {
5890         assert(toChars!8(ubyte(0)).array == "0");
5891         assert(toChars!8(ushort(0)).array == "0");
5892         assert(toChars!8(0u).array == "0");
5893         assert(toChars!8(0Lu).array == "0");
5894         assert(toChars!8(1u).array == "1");
5895         assert(toChars!8(1234567Lu).array == "4553207");
5896         assert(toChars!8(ubyte.max).array == "377");
5897         assert(toChars!8(ushort.max).array == "177777");
5898 
5899         auto r = toChars!8(8u);
5900         assert(r.length == 2);
5901         assert(r[0] == '1');
5902         assert(r[1 .. 2].array == "0");
5903         auto s = r.save;
5904         assert(r.array == "10");
5905         assert(s.retro.array == "01");
5906     }
5907     {
5908         assert(toChars!10(ubyte(0)).array == "0");
5909         assert(toChars!10(ushort(0)).array == "0");
5910         assert(toChars!10(0u).array == "0");
5911         assert(toChars!10(0Lu).array == "0");
5912         assert(toChars!10(1u).array == "1");
5913         assert(toChars!10(1234567Lu).array == "1234567");
5914         assert(toChars!10(ubyte.max).array == "255");
5915         assert(toChars!10(ushort.max).array == "65535");
5916         assert(toChars!10(uint.max).array == "4294967295");
5917         assert(toChars!10(ulong.max).array == "18446744073709551615");
5918 
5919         auto r = toChars(10u);
5920         assert(r.length == 2);
5921         assert(r[0] == '1');
5922         assert(r[1 .. 2].array == "0");
5923         auto s = r.save;
5924         assert(r.array == "10");
5925         assert(s.retro.array == "01");
5926     }
5927     {
5928         assert(toChars!10(0).array == "0");
5929         assert(toChars!10(0L).array == "0");
5930         assert(toChars!10(1).array == "1");
5931         assert(toChars!10(1234567L).array == "1234567");
5932         assert(toChars!10(byte.max).array == "127");
5933         assert(toChars!10(short.max).array == "32767");
5934         assert(toChars!10(int.max).array == "2147483647");
5935         assert(toChars!10(long.max).array == "9223372036854775807");
5936         assert(toChars!10(-byte.max).array == "-127");
5937         assert(toChars!10(-short.max).array == "-32767");
5938         assert(toChars!10(-int.max).array == "-2147483647");
5939         assert(toChars!10(-long.max).array == "-9223372036854775807");
5940         assert(toChars!10(byte.min).array == "-128");
5941         assert(toChars!10(short.min).array == "-32768");
5942         assert(toChars!10(int.min).array == "-2147483648");
5943         assert(toChars!10(long.min).array == "-9223372036854775808");
5944 
5945         auto r = toChars!10(10);
5946         assert(r.length == 2);
5947         assert(r[0] == '1');
5948         assert(r[1 .. 2].array == "0");
5949         auto s = r.save;
5950         assert(r.array == "10");
5951         assert(s.retro.array == "01");
5952     }
5953     {
5954         assert(toChars!(16)(0u).array == "0");
5955         assert(toChars!(16)(0Lu).array == "0");
5956         assert(toChars!(16)(10u).array == "a");
5957         assert(toChars!(16, char, LetterCase.upper)(0x12AF34567Lu).array == "12AF34567");
5958         assert(toChars!(16)(ubyte(0)).array == "0");
5959         assert(toChars!(16)(ushort(0)).array == "0");
5960         assert(toChars!(16)(ubyte.max).array == "ff");
5961         assert(toChars!(16)(ushort.max).array == "ffff");
5962 
5963         auto r = toChars!(16)(16u);
5964         assert(r.length == 2);
5965         assert(r[0] == '1');
5966         assert(r[1 .. 2].array == "0");
5967         auto s = r.save;
5968         assert(r.array == "10");
5969         assert(s.retro.array == "01");
5970     }
5971 }
5972 
5973 @safe unittest // opSlice (https://issues.dlang.org/show_bug.cgi?id=16192)
5974 {
5975     import std.meta : AliasSeq;
5976 
5977     static struct Test { ubyte radix; uint number; }
5978 
5979     alias tests = AliasSeq!(
5980         Test(2, 0b1_0110_0111u),
5981         Test(2, 0b10_1100_1110u),
5982         Test(8, octal!123456701u),
5983         Test(8, octal!1234567012u),
5984         Test(10, 123456789u),
5985         Test(10, 1234567890u),
5986         Test(16, 0x789ABCDu),
5987         Test(16, 0x789ABCDEu),
5988     );
5989 
5990     foreach (test; tests)
5991     {
5992         enum ubyte radix = test.radix;
5993         auto original = toChars!radix(test.number);
5994 
5995         // opSlice vs popFront
5996         auto r = original.save;
5997         size_t i = 0;
5998         for (; !r.empty; r.popFront(), ++i)
5999         {
6000             assert(original[i .. original.length].tupleof == r.tupleof);
6001                 // tupleof is used to work around https://issues.dlang.org/show_bug.cgi?id=16216.
6002         }
6003 
6004         // opSlice vs popBack
6005         r = original.save;
6006         i = 0;
6007         for (; !r.empty; r.popBack(), ++i)
6008         {
6009             assert(original[0 .. original.length - i].tupleof == r.tupleof);
6010         }
6011 
6012         // opSlice vs both popFront and popBack
6013         r = original.save;
6014         i = 0;
6015         for (; r.length >= 2; r.popFront(), r.popBack(), ++i)
6016         {
6017             assert(original[i .. original.length - i].tupleof == r.tupleof);
6018         }
6019     }
6020 }
6021 
6022 // Converts an unsigned integer to a compile-time string constant.
6023 package enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
6024 
6025 // Check that .stringof does what we expect, since it's not guaranteed by the
6026 // language spec.
6027 @safe /*@betterC*/ unittest
6028 {
6029     assert(toCtString!0 == "0");
6030     assert(toCtString!123456 == "123456");
6031 }