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