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