Changeset 1747
- Timestamp:
- 07/12/10 00:48:49 (14 years ago)
- Files:
-
- trunk/phobos/std/conv.d (modified) (24 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/phobos/std/conv.d
r1733 r1747 1 1 // Written in the D programming language. 2 2 3 3 /** 4 4 A one-stop shop for converting values from one type to another. 5 5 6 Copyright: Copyright Digital Mars 2007 - 2009.6 Copyright: Copyright Digital Mars 2007-. 7 7 8 8 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 9 9 10 10 Authors: $(WEB digitalmars.com, Walter Bright), 11 11 $(WEB erdani.org, Andrei Alexandrescu), 12 12 Shin Fujishiro, 13 13 Adam D. Ruppe 14 14 15 Copyright Digital Mars 2007 - 2009. 16 Distributed under the Boost Software License, Version 1.0. 17 (See accompanying file LICENSE_1_0.txt or copy at 18 http://www.boost.org/LICENSE_1_0.txt) 15 Copyright: Copyright Digital Mars 2007-. 19 16 */ 20 17 module std.conv; 21 18 22 19 import core.stdc.math : ldexpl; 23 20 import core.memory, core.stdc.errno, core.stdc.string, 24 21 core.stdc.stdlib; 25 import std.a rray, std.ctype, std.exception, std.math, std.range, std.stdio,26 std.st ring, std.traits, std.typecons, std.typetuple, std.utf;22 import std.algorithm, std.array, std.ctype, std.exception, std.math, std.range, 23 std.stdio, std.string, std.traits, std.typecons, std.typetuple, std.utf; 27 24 import std.metastrings; 28 25 29 26 //debug=conv; // uncomment to turn on debugging printf's 30 27 31 28 /* ************* Exceptions *************** */ 32 29 33 30 /** 34 31 * Thrown on conversion errors. 35 32 */ 36 33 class ConvError : Error 37 34 { 38 35 this(string s) 39 36 { 40 37 super(s); 41 38 } 42 // static void raise(S, T)(S source) 43 // { 44 // throw new ConvError(cast(string) 45 // ("Can't convert value `"~to!(string)(source)~"' of type " 46 // ~S.stringof~" to type "~T.stringof)); 47 // } 48 } 49 50 private void conv_error(S, T, string f = __FILE__, uint ln = __LINE__) 51 (S source) 39 } 40 41 private void convError(S, T, string f = __FILE__, uint ln = __LINE__)(S source) 52 42 { 53 43 throw new ConvError(cast(string) 54 44 ("std.conv("~to!string(ln) 55 45 ~"): Can't convert value `"~to!(string)(source)~"' of type " 56 46 ~S.stringof~" to type "~T.stringof)); 57 47 } 58 48 59 49 /** 60 50 * Thrown on conversion overflow errors. 61 51 */ … … 76 66 private template implicitlyConverts(S, T) 77 67 { 78 68 enum bool implicitlyConverts = T.sizeof >= S.sizeof 79 69 && is(typeof({S s; T t = s;}())); 80 70 } 81 71 82 72 unittest 83 73 { 84 74 assert(!implicitlyConverts!(const(char)[], string)); 85 75 assert(implicitlyConverts!(string, const(char)[])); 76 } 77 78 /** 79 Entry point that dispatches to the appropriate conversion 80 primitive. Client code normally calls $(D _to!TargetType(value)) 81 (and not some variant of $(D toImpl)). 82 */ 83 template to(T) 84 { 85 T to(A...)(A args) { return toImpl!T(args); } 86 86 } 87 87 88 88 /** 89 89 String _to string conversion works for any two string types having 90 90 ($(D char), $(D wchar), $(D dchar)) character widths and any 91 91 combination of qualifiers (mutable, $(D const), or $(D immutable)). 92 92 93 93 Example: 94 94 ---- 95 95 char[] a = "abc"; 96 96 auto b = to!(immutable(dchar)[])(a); 97 97 assert(b == "abc"w); 98 98 ---- 99 99 */ 100 T to (T, S)(S s) if (!implicitlyConverts!(S, T) && isSomeString!(T)100 T toImpl(T, S)(S s) if (!implicitlyConverts!(S, T) && isSomeString!(T) 101 101 && isSomeString!(S)) 102 102 { 103 103 // string-to-string conversion 104 104 static if (s[0].sizeof == T[0].sizeof) { 105 105 // same width, only qualifier conversion 106 106 enum tIsConst = is(T == const(char)[]) || is(T == const(wchar)[]) 107 107 || is(T == const(dchar)[]); 108 108 enum tIsInvariant = is(T == immutable(char)[]) 109 109 || is(T == immutable(wchar)[]) || is(T == immutable(dchar)[]); 110 110 static if (tIsConst) { … … 137 137 { 138 138 alias TypeTuple!(LhsC[], const(LhsC)[], immutable(LhsC)[]) LhStrings; 139 139 foreach (Lhs; LhStrings) 140 140 { 141 141 foreach (RhsC; Chars) 142 142 { 143 143 alias TypeTuple!(RhsC[], const(RhsC)[], immutable(RhsC)[]) 144 144 RhStrings; 145 145 foreach (Rhs; RhStrings) 146 146 { 147 Lhs s1 = to! (Lhs)("wyda");148 Rhs s2 = to! (Rhs)(s1);147 Lhs s1 = to!Lhs("wyda"); 148 Rhs s2 = to!Rhs(s1); 149 149 //writeln(Lhs.stringof, " -> ", Rhs.stringof); 150 assert(s1 == to! (Lhs)(s2));150 assert(s1 == to!Lhs(s2)); 151 151 } 152 152 } 153 153 } 154 154 } 155 155 } 156 156 157 157 /** 158 158 Converts array (other than strings) to string. The left bracket, 159 159 separator, and right bracket are configurable. Each element is 160 160 converted by calling $(D to!T). 161 161 */ 162 T to (T, S)(S s, in T leftBracket = "[", in T separator = " ",162 T toImpl(T, S)(S s, in T leftBracket = "[", in T separator = " ", 163 163 in T rightBracket = "]") 164 164 if (isSomeString!(T) && !isSomeString!(S) && isArray!(S)) 165 165 { 166 166 alias Unqual!(typeof(T.init[0])) Char; 167 167 // array-to-string conversion 168 168 static if (is(S == void[]) 169 169 || is(S == const(void)[]) || is(S == immutable(void)[])) { 170 170 auto raw = cast(const(ubyte)[]) s; 171 171 enforce(raw.length % Char.sizeof == 0, "Alignment mismatch" 172 172 " in converting a " ~ S.stringof ~ " to a " ~ T.stringof); … … 194 194 double[2] a = [ 1.5, 2.5 ]; 195 195 //writeln(to!string(a)); 196 196 assert(to!string(a) == "[1.5 2.5]"); 197 197 } 198 198 199 199 /** 200 200 Associative array to string conversion. The left bracket, key-value 201 201 separator, element separator, and right bracket are configurable. 202 202 Each element is printed by calling $(D to!T). 203 203 */ 204 T to (T, S)(S s, in T leftBracket = "[", in T keyval = ":",204 T toImpl(T, S)(S s, in T leftBracket = "[", in T keyval = ":", 205 205 in T separator = ", ", in T rightBracket = "]") 206 206 if (isAssociativeArray!(S) && isSomeString!(T)) 207 207 { 208 208 alias Unqual!(typeof(T.init[0])) Char; 209 209 auto result = appender!(Char[])(); 210 210 // hash-to-string conversion 211 211 result.put(leftBracket); 212 212 bool first = true; 213 213 foreach (k, v; s) { 214 214 if (!first) result.put(separator); … … 218 218 result.put(to!(T)(v)); 219 219 } 220 220 result.put(rightBracket); 221 221 return cast(T) result.data; 222 222 } 223 223 224 224 /** 225 225 Object to string conversion calls $(D toString) against the object or 226 226 returns $(D nullstr) if the object is null. 227 227 */ 228 T to (T, S)(S s, in T nullstr = "null")228 T toImpl(T, S)(S s, in T nullstr = "null") 229 229 if (is(S : Object) && isSomeString!(T)) 230 230 { 231 231 if (!s) return nullstr; 232 232 return to!(T)(s.toString); 233 233 } 234 234 235 235 unittest 236 236 { 237 237 class A { override string toString() { return "an A"; } } 238 238 A a; 239 239 assert(to!string(a) == "null"); 240 240 a = new A; 241 241 assert(to!string(a) == "an A"); 242 242 } 243 243 244 244 /** 245 245 Struct to string conversion calls $(D toString) against the struct if 246 246 it is defined. 247 247 */ 248 T to (T, S)(S s)248 T toImpl(T, S)(S s) 249 249 if (is(S == struct) && isSomeString!(T) && is(typeof(&S.init.toString))) 250 250 { 251 251 return to!T(s.toString); 252 252 } 253 253 254 254 unittest 255 255 { 256 256 struct S { string toString() { return "wyda"; } } 257 257 assert(to!string(S()) == "wyda"); 258 258 } 259 259 260 260 /** 261 261 For structs that do not define $(D toString), the conversion to string 262 262 produces the list of fields. 263 263 */ 264 T to (T, S)(S s, in T left = S.stringof~"(", in T separator = ", ",264 T toImpl(T, S)(S s, in T left = S.stringof~"(", in T separator = ", ", 265 265 in T right = ")") 266 266 if (is(S == struct) && isSomeString!(T) && !is(typeof(&S.init.toString))) 267 267 { 268 268 Tuple!(FieldTypeTuple!(S)) * t = void; 269 269 static if ((*t).sizeof == S.sizeof) 270 270 { 271 271 // ok, attempt to forge the tuple 272 272 t = cast(typeof(t)) &s; 273 273 alias Unqual!(typeof(T.init[0])) Char; 274 274 auto app = appender!(Char[])(); … … 291 291 unittest 292 292 { 293 293 struct S { int a = 42; float b = 43.5; } 294 294 S s; 295 295 assert(to!string(s) == "S(42, 43.5)"); 296 296 } 297 297 298 298 /** 299 299 Enumerated types are converted to strings as their symbolic names. 300 300 */ 301 T to (T, S)(S s) if (is(S == enum) && isSomeString!(T)301 T toImpl(T, S)(S s) if (is(S == enum) && isSomeString!(T) 302 302 && !implicitlyConverts!(S, T)) 303 303 { 304 304 mixin (enumToStringImpl!(S).code); 305 305 } 306 306 307 307 // internal 308 308 private template enumToStringImpl(Enum) 309 309 { 310 310 template generate(alias members) 311 311 { … … 344 344 assert(0); 345 345 } 346 346 catch (ConvError e) 347 347 { 348 348 } 349 349 } 350 350 351 351 /** 352 352 A $(D typedef Type Symbol) is converted to string as $(D "Type(value)"). 353 353 */ 354 T to (T, S)(S s, in T left = S.stringof~"(", in T right = ")")354 T toImpl(T, S)(S s, in T left = S.stringof~"(", in T right = ")") 355 355 if (is(S == typedef) && isSomeString!(T)) 356 356 { 357 357 static if (is(S Original == typedef)) { 358 358 // typedef 359 359 return left ~ to!(T)(cast(Original) s) ~ right; 360 360 } 361 361 } 362 362 363 363 unittest 364 364 { … … 489 489 conversion might throw an exception because $(D_PARAM to!(short)) 490 490 might fail the range check. 491 491 492 492 Macros: WIKI=Phobos/StdConv 493 493 */ 494 494 495 495 /** 496 496 If the source type is implicitly convertible to the target type, $(D 497 497 to) simply performs the implicit conversion. 498 498 */ 499 Target to (Target, Source)(Source value) if (implicitlyConverts!(Source, Target))499 Target toImpl(Target, Source)(Source value) if (implicitlyConverts!(Source, Target)) 500 500 { 501 501 return value; 502 502 } 503 503 504 504 unittest 505 505 { 506 506 int a = 42; 507 507 auto b = to!long(a); 508 508 assert(a == b); 509 509 } 510 510 511 511 /** 512 512 Boolean values are printed as $(D "true") or $(D "false"). 513 513 */ 514 T to (T, S)(S b) if (is(Unqual!S == bool) && isSomeString!(T))514 T toImpl(T, S)(S b) if (is(Unqual!S == bool) && isSomeString!(T)) 515 515 { 516 516 return to!T(b ? "true" : "false"); 517 517 } 518 518 519 519 unittest 520 520 { 521 521 bool b; 522 522 assert(to!string(b) == "false"); 523 523 b = true; 524 524 assert(to!string(b) == "true"); 525 525 } 526 526 527 527 528 528 /** 529 529 When the source is a wide string, it is first converted to a narrow 530 530 string and then parsed. 531 531 */ 532 T to (T, S)(S value) if ((is(S : const(wchar)[]) || is(S : const(dchar)[]))532 T toImpl(T, S)(S value) if ((is(S : const(wchar)[]) || is(S : const(dchar)[])) 533 533 && !isSomeString!(T)) 534 534 { 535 535 // todo: improve performance 536 536 return parseString!(T)(toUTF8(value)); 537 537 } 538 538 539 539 /** 540 540 When the source is a narrow string, normal text parsing occurs. 541 541 */ 542 T to (T, S)(S value) if (is(S : const(char)[]) && !isSomeString!(T))542 T toImpl(T, S)(S value) if (is(S : const(char)[]) && !isSomeString!(T)) 543 543 { 544 544 return parseString!(T)(value); 545 545 } 546 546 547 547 unittest 548 548 { 549 549 foreach (Char; TypeTuple!(char, wchar, dchar)) 550 550 { 551 551 auto a = to!(Char[])("123"); 552 552 assert(to!int(a) == 123); 553 553 assert(to!double(a) == 123); 554 554 } 555 555 } 556 556 557 557 /** 558 558 Object-to-object conversions throw exception when the source is 559 559 non-null and the target is null. 560 560 */ 561 T to (T, S)(S value) if (is(S : Object) && is(T : Object))561 T toImpl(T, S)(S value) if (is(S : Object) && is(T : Object)) 562 562 { 563 563 auto result = cast(T) value; 564 564 if (!result && value) 565 565 { 566 566 throw new ConvError("Cannot convert object of static type " 567 567 ~S.classinfo.name~" and dynamic type "~value.classinfo.name 568 568 ~" to type "~T.classinfo.name); 569 569 } 570 570 return result; 571 571 } … … 603 603 ... 604 604 } 605 605 606 606 unittest 607 607 { 608 608 auto d = new Date; 609 609 auto ts = to!long(d); // same as d.to!long() 610 610 } 611 611 ---- 612 612 */ 613 T to (T, S)(S value) if (is(S : Object) && !is(T : Object) && !isSomeString!T613 T toImpl(T, S)(S value) if (is(S : Object) && !is(T : Object) && !isSomeString!T 614 614 && is(typeof(S.init.to!(T)()) : T)) 615 615 { 616 616 return value.to!T(); 617 617 } 618 618 619 619 unittest 620 620 { 621 621 class B { T to(T)() { return 43; } } 622 622 auto b = new B; 623 623 assert(to!int(b) == 43); 624 624 } 625 625 626 626 /** 627 627 Narrowing numeric-numeric conversions throw when the value does not 628 628 fit in the narrower type. 629 629 */ 630 T to (T, S)(S value)630 T toImpl(T, S)(S value) 631 631 if (!implicitlyConverts!(S, T) 632 632 && std.traits.isNumeric!(S) && std.traits.isNumeric!(T)) 633 633 { 634 634 enum sSmallest = mostNegative!(S); 635 635 enum tSmallest = mostNegative!(T); 636 636 static if (sSmallest < 0) { 637 637 // possible underflow converting from a signed 638 638 static if (tSmallest == 0) { 639 639 immutable good = value >= 0; 640 640 } else { … … 649 649 } 650 650 return cast(T) value; 651 651 } 652 652 653 653 private T parseString(T)(const(char)[] v) 654 654 { 655 655 scope(exit) 656 656 { 657 657 if (v.length) 658 658 { 659 conv _error!(const(char)[], T)(v);659 convError!(const(char)[], T)(v); 660 660 } 661 661 } 662 662 return parse!(T)(v); 663 663 } 664 664 665 665 /** 666 666 Array-to-array conversion (except when target is a string type) 667 667 converts each element in turn by using $(D to). 668 668 */ 669 T to (T, S)(S src) if (isArray!(S) && isArray!(T) && !isSomeString!(T)669 T toImpl(T, S)(S src) if (isArray!(S) && isArray!(T) && !isSomeString!(T) 670 670 && !implicitlyConverts!(S, T)) 671 671 { 672 672 alias typeof(T.init[0]) E; 673 673 auto result = new E[src.length]; 674 674 foreach (i, e; src) { 675 675 /* Temporarily cast to mutable type, so we can get it initialized, 676 676 * this is ok because there are no other references to result[] 677 677 */ 678 678 cast()(result[i]) = to!(E)(e); 679 679 } … … 693 693 assert(b == [ 1.0f, 2, 3 ]); 694 694 uint[][] e = [ a, a ]; 695 695 auto f = to!(float[][])(e); 696 696 assert(f[0] == b && f[1] == b); 697 697 } 698 698 699 699 /** 700 700 Associative array to associative array conversion converts each key 701 701 and each value in turn. 702 702 */ 703 T to (T, S)(S src)703 T toImpl(T, S)(S src) 704 704 if (isAssociativeArray!(S) && isAssociativeArray!(T)) 705 705 { 706 706 alias typeof(T.keys[0]) K2; 707 707 alias typeof(T.values[0]) V2; 708 708 T result; 709 709 foreach (k1, v1; src) 710 710 { 711 711 result[to!(K2)(k1)] = to!(V2)(v1); 712 712 } 713 713 return result; … … 960 960 Target parse(Target, Source)(ref Source s) 961 961 if (isSomeChar!(ElementType!Source) && isIntegral!Target) 962 962 { 963 963 static if (Target.sizeof < int.sizeof) 964 964 { 965 965 // smaller types are handled like integers 966 966 auto v = parse!(Select!(Target.min < 0, int, uint), Source)(s); 967 967 auto result = cast(Target) v; 968 968 if (result != v) 969 969 { 970 conv _error!(Source, Target)(s);970 convError!(Source, Target)(s); 971 971 } 972 972 return result; 973 973 } 974 974 else 975 975 { 976 976 // Larger than int types 977 977 // immutable length = s.length; 978 978 // if (!length) 979 979 // goto Lerr; 980 980 if (s.empty) goto Lerr; … … 1026 1026 { 1027 1027 if (sign == -1) 1028 1028 { 1029 1029 v = -v; 1030 1030 } 1031 1031 } 1032 1032 return v; 1033 1033 Loverflow: 1034 1034 ConvOverflowError.raise("Overflow in integral conversion"); 1035 1035 Lerr: 1036 conv _error!(Source, Target)(s);1036 convError!(Source, Target)(s); 1037 1037 return 0; 1038 1038 } 1039 1039 } 1040 1040 1041 1041 Target parse(Target, Source)(ref Source s) 1042 1042 if (isSomeString!Source && is(Target == enum)) 1043 1043 { 1044 1044 mixin(enumFromStringImpl!Target.code); 1045 1045 } 1046 1046 … … 1401 1401 if (s.length >= 4 && icmp(s[0 .. 4], "true")==0) 1402 1402 { 1403 1403 s = s[4 .. $]; 1404 1404 return true; 1405 1405 } 1406 1406 if (s.length >= 5 && icmp(s[0 .. 5], "false")==0) 1407 1407 { 1408 1408 s = s[5 .. $]; 1409 1409 return false; 1410 1410 } 1411 conv _error!(Source, Target)(s);1411 convError!(Source, Target)(s); 1412 1412 assert(0); 1413 1413 } 1414 1414 1415 1415 1416 1416 // Parsing typedefs forwards to their host types 1417 1417 Target parse(Target, Source)(ref Source s) 1418 1418 if (isSomeString!Source && is(Target == typedef)) 1419 1419 { 1420 1420 static if (is(Target T == typedef)) 1421 1421 return cast(Target) parse!T(s); … … 2468 2468 // incorrectly. 2469 2469 //if (cf > cfloat.max) 2470 2470 // goto Loverflow; 2471 2471 2472 2472 return cf; 2473 2473 2474 2474 Loverflow: 2475 2475 conv_overflow(s); 2476 2476 2477 2477 Lerr: 2478 conv _error(s);2478 convError(s); 2479 2479 return cast(cfloat)0.0e-0+0i; 2480 2480 } 2481 2481 2482 2482 unittest 2483 2483 { 2484 2484 debug(conv) writefln("conv.toCfloat.unittest"); 2485 2485 cfloat cf; 2486 2486 2487 2487 cf = toCfloat(to!string("1.2345e-5+0i")); 2488 2488 assert(to!string(cf) == to!string(1.2345e-5+0i)); … … 2543 2543 //Disabled, waiting on a bug fix. 2544 2544 //if (cd > cdouble.max) //same problem the toCfloat() having 2545 2545 // goto Loverflow; 2546 2546 2547 2547 return cd; 2548 2548 2549 2549 Loverflow: 2550 2550 conv_overflow(s); 2551 2551 2552 2552 Lerr: 2553 conv _error(s);2553 convError(s); 2554 2554 return cast(cdouble)0.0e-0+0i; 2555 2555 } 2556 2556 2557 2557 unittest 2558 2558 { 2559 2559 debug(conv) writefln("conv.toCdouble.unittest"); 2560 2560 cdouble cd; 2561 2561 2562 2562 cd = toCdouble(to!string("1.2345e-5+0i")); 2563 2563 assert(to!string( cd ) == to!string(1.2345e-5+0i)); … … 2619 2619 if (s1 =="nan" && s2 == "nani") 2620 2620 cr = creal.nan; 2621 2621 else if (r2 != 0.0) 2622 2622 cr = cast(creal)(r1 + (r2 * 1.0i)); 2623 2623 else 2624 2624 cr = cast(creal)(r1 + 0.0i); 2625 2625 2626 2626 return cr; 2627 2627 2628 2628 Lerr: 2629 conv _error(s);2629 convError(s); 2630 2630 return cast(creal)0.0e-0+0i; 2631 2631 } 2632 2632 2633 2633 unittest 2634 2634 { 2635 2635 debug(conv) writefln("conv.toCreal.unittest"); 2636 2636 creal cr; 2637 2637 2638 2638 cr = toCreal(to!string("1.2345e-5+0i")); 2639 2639 assert(to!string(cr) == to!string(1.2345e-5+0i)); … … 2805 2805 if (isnan(r1a)) 2806 2806 return cast(bool)isnan(r2b); 2807 2807 2808 2808 if (isnan(r2b)) 2809 2809 return 0; 2810 2810 2811 2811 return feq(r1a, r2b, 0.000001L); 2812 2812 } 2813 2813 2814 2814 /// Small unsigned integers to strings. 2815 T to (T, S)(S value) if (isIntegral!S && S.min == 02815 T toImpl(T, S)(S value) if (isIntegral!S && S.min == 0 2816 2816 && S.sizeof < uint.sizeof && isSomeString!T) 2817 2817 { 2818 2818 return to!T(cast(uint) value); 2819 2819 } 2820 2820 2821 2821 /// Small signed integers to strings. 2822 T to (T, S)(S value) if (isIntegral!S && S.min < 02822 T toImpl(T, S)(S value) if (isIntegral!S && S.min < 0 2823 2823 && S.sizeof < int.sizeof && isSomeString!T) 2824 2824 { 2825 2825 return to!T(cast(int) value); 2826 2826 } 2827 2827 2828 2828 /// Unsigned integers (uint and ulong) to string. 2829 T to (T, S)(S input)2829 T toImpl(T, S)(S input) 2830 2830 if (staticIndexOf!(Unqual!S, uint, ulong) >= 0 && isSomeString!T) 2831 2831 { 2832 2832 Unqual!S value = input; 2833 2833 alias Unqual!(typeof(T.init[0])) Char; 2834 2834 static if (is(typeof(T.init[0]) == const) || 2835 2835 is(typeof(T.init[0]) == immutable)) 2836 2836 { 2837 2837 if (value < 10) 2838 2838 { 2839 2839 static immutable Char[10] digits = "0123456789"; … … 2874 2874 } 2875 2875 2876 2876 unittest 2877 2877 { 2878 2878 assert(wtext(int.max) == "2147483647"w); 2879 2879 assert(wtext(int.min) == "-2147483648"w); 2880 2880 assert(to!string(0L) == "0"); 2881 2881 } 2882 2882 2883 2883 /// $(D char), $(D wchar), $(D dchar) to a string type. 2884 T to (T, S)(S c) if (staticIndexOf!(Unqual!S, char, wchar, dchar) >= 02884 T toImpl(T, S)(S c) if (staticIndexOf!(Unqual!S, char, wchar, dchar) >= 0 2885 2885 && isSomeString!(T)) 2886 2886 { 2887 2887 alias typeof(T.init[0]) Char; 2888 2888 static if (Char.sizeof >= S.sizeof) 2889 2889 { 2890 2890 return [ c ]; 2891 2891 } 2892 2892 else 2893 2893 { 2894 2894 Unqual!Char[] result; … … 2911 2911 { 2912 2912 Char1 c = 'a'; 2913 2913 assert(to!(Char2[])(c)[0] == c); 2914 2914 } 2915 2915 uint x = 4; 2916 2916 assert(to!(Char1[])(x) == "4"); 2917 2917 } 2918 2918 } 2919 2919 2920 2920 /// Signed values ($(D int) and $(D long)). 2921 T to (T, S)(S value)2921 T toImpl(T, S)(S value) 2922 2922 if (staticIndexOf!(Unqual!S, int, long) >= 0 && isSomeString!T) 2923 2923 { 2924 2924 if (value >= 0) 2925 2925 return to!T(cast(Unsigned!(S)) value); 2926 2926 alias Unqual!(typeof(T.init[0])) Char; 2927 2927 2928 2928 // Cache read-only data only for const and immutable - mutable 2929 2929 // data is supposed to use allocation in all cases 2930 2930 static if (is(ElementType!T == const) || is(ElementType!T == immutable)) 2931 2931 { … … 2982 2982 r = to!string(-123L); 2983 2983 i = cmp(r, "-123"); 2984 2984 assert(i == 0); 2985 2985 2986 2986 const h = 6; 2987 2987 string s = to!string(h); 2988 2988 assert(s == "6"); 2989 2989 } 2990 2990 2991 2991 /// C-style strings 2992 T to (T, S)(S s) if (is(S : const(char)*) && isSomeString!(T))2992 T toImpl(T, S)(S s) if (is(S : const(char)*) && isSomeString!(T)) 2993 2993 { 2994 2994 return s ? cast(T) s[0 .. strlen(s)].dup : cast(string)null; 2995 2995 } 2996 2996 2997 2997 /// $(D float) to all string types. 2998 T to (T, S)(S f) if (is(Unqual!S == float) && isSomeString!(T))2998 T toImpl(T, S)(S f) if (is(Unqual!S == float) && isSomeString!(T)) 2999 2999 { 3000 3000 return to!T(cast(double) f); 3001 3001 } 3002 3002 3003 3003 /// $(D double) to all string types. 3004 T to (T, S)(S d) if (is(Unqual!S == double) && isSomeString!(T))3004 T toImpl(T, S)(S d) if (is(Unqual!S == double) && isSomeString!(T)) 3005 3005 { 3006 3006 //alias Unqual!(ElementType!T) Char; 3007 3007 char[20] buffer; 3008 3008 int len = sprintf(buffer.ptr, "%g", d); 3009 3009 return to!T(buffer[0 .. len].dup); 3010 3010 } 3011 3011 3012 3012 /// $(D real) to all string types. 3013 T to (T, S)(S r) if (is(Unqual!S == real) && isSomeString!(T))3013 T toImpl(T, S)(S r) if (is(Unqual!S == real) && isSomeString!(T)) 3014 3014 { 3015 3015 char[20] buffer; 3016 3016 int len = sprintf(buffer.ptr, "%Lg", r); 3017 3017 return to!T(buffer[0 .. len].dup); 3018 3018 } 3019 3019 3020 3020 /// $(D ifloat) to all string types. 3021 T to (T, S)(S f) if (is(Unqual!S == ifloat) && isSomeString!(T))3021 T toImpl(T, S)(S f) if (is(Unqual!S == ifloat) && isSomeString!(T)) 3022 3022 { 3023 3023 return to!T(cast(idouble) f); 3024 3024 } 3025 3025 3026 3026 /// $(D idouble) to all string types. 3027 T to (T, S)(S d) if (is(Unqual!S == idouble) && isSomeString!(T))3027 T toImpl(T, S)(S d) if (is(Unqual!S == idouble) && isSomeString!(T)) 3028 3028 { 3029 3029 char[21] buffer; 3030 3030 int len = sprintf(buffer.ptr, "%gi", d); 3031 3031 return to!T(buffer[0 .. len].dup); 3032 3032 } 3033 3033 3034 3034 /// $(D ireal) to all string types. 3035 T to (T, S)(S r) if (is(Unqual!S == ireal) && isSomeString!(T))3035 T toImpl(T, S)(S r) if (is(Unqual!S == ireal) && isSomeString!(T)) 3036 3036 { 3037 3037 char[21] buffer; 3038 3038 int len = sprintf(buffer.ptr, "%Lgi", r); 3039 3039 //assert(len < buffer.length); // written bytes is len + 1 3040 3040 return to!T(buffer[0 .. len].dup); 3041 3041 } 3042 3042 3043 3043 /// $(D cfloat) to all string types. 3044 T to (T, S)(S f) if (is(Unqual!S == cfloat) && isSomeString!(T))3044 T toImpl(T, S)(S f) if (is(Unqual!S == cfloat) && isSomeString!(T)) 3045 3045 { 3046 3046 return to!string(cast(cdouble) f); 3047 3047 } 3048 3048 3049 3049 /// $(D cdouble) to all string types. 3050 T to (T, S)(S d) if (is(Unqual!S == cdouble) && isSomeString!(T))3050 T toImpl(T, S)(S d) if (is(Unqual!S == cdouble) && isSomeString!(T)) 3051 3051 { 3052 3052 char[20 + 1 + 20 + 1] buffer; 3053 3053 3054 3054 int len = sprintf(buffer.ptr, "%g+%gi", d.re, d.im); 3055 3055 return to!T(buffer[0 .. len]); 3056 3056 } 3057 3057 3058 3058 /// $(D creal) to all string types. 3059 T to (T, S)(S r) if (is(Unqual!S == creal) && isSomeString!(T))3059 T toImpl(T, S)(S r) if (is(Unqual!S == creal) && isSomeString!(T)) 3060 3060 { 3061 3061 char[20 + 1 + 20 + 1] buffer; 3062 3062 int len = sprintf(buffer.ptr, "%Lg+%Lgi", r.re, r.im); 3063 3063 return to!T(buffer[0 .. len].dup); 3064 3064 } 3065 3065 3066 3066 /****************************************** 3067 3067 * Convert value to string in _radix radix. 3068 3068 * 3069 3069 * radix must be a value from 2 to 36. 3070 3070 * value is treated as a signed value only if radix is 10. 3071 3071 * The characters A through Z are used to represent values 10 through 36. 3072 3072 */ 3073 T to (T, S)(S value, uint radix)3073 T toImpl(T, S)(S value, uint radix) 3074 3074 if (isIntegral!(Unqual!S) && !is(Unqual!S == ulong) && isSomeString!(T)) 3075 3075 { 3076 3076 enforce(radix >= 2 && radix <= 36); 3077 3077 if (radix == 10) 3078 3078 return to!string(value); // handle signed cases only for radix 10 3079 3079 return to!string(cast(ulong) value, radix); 3080 3080 } 3081 3081 3082 3082 /// ditto 3083 T to (T, S)(S value, uint radix)3083 T toImpl(T, S)(S value, uint radix) 3084 3084 if (is(Unqual!S == ulong) && isSomeString!(T)) 3085 3085 in 3086 3086 { 3087 3087 assert(radix >= 2 && radix <= 36); 3088 3088 } 3089 3089 body 3090 3090 { 3091 3091 char[value.sizeof * 8] buffer; 3092 3092 uint i = buffer.length; 3093 3093 … … 3335 3335 assert(i == 0); 3336 3336 3337 3337 r = to!string(123u); 3338 3338 i = cmp(r, "123"); 3339 3339 assert(i == 0); 3340 3340 } 3341 3341 3342 3342 /** 3343 3343 Pointer to string conversions prints the pointer as a $(D size_t) value. 3344 3344 */ 3345 T to (T, S)(S value)3345 T toImpl(T, S)(S value) 3346 3346 if (isPointer!S && !isSomeChar!(typeof(*S.init)) && isSomeString!T) 3347 3347 { 3348 3348 return to!T(cast(size_t) value, 16u); 3349 3349 } 3350 3350 3351 3351 private S textImpl(S, U...)(U args) 3352 3352 { 3353 3353 S result; 3354 3354 foreach (i, arg; args) 3355 3355 { … … 3613 3613 3614 3614 // this should pass, but it doesn't, since the int converter 3615 3615 // doesn't pass along its suffix to helper templates 3616 3616 3617 3617 //static assert(!__traits(compiles, a = octal!1L)); 3618 3618 3619 3619 static assert(__traits(compiles, b = octal!"1L")); 3620 3620 static assert(__traits(compiles, b = octal!1L)); 3621 3621 } 3622 3622 3623 T to (T, S)(S src) if (is(T == struct) && is(typeof(T(src))))3623 T toImpl(T, S)(S src) if (is(T == struct) && is(typeof(T(src)))) 3624 3624 { 3625 3625 return T(src); 3626 3626 } 3627 3627 3628 3628 // Bugzilla 3961 3629 3629 unittest 3630 3630 { 3631 3631 struct Int { int x; } 3632 3632 Int i = to!Int(1); 3633 3633 } … … 3698 3698 double x = 5, y = 6; 3699 3699 this(int a, int b) { assert(x == 5 && y == 6); x = a; y = b; } 3700 3700 } 3701 3701 3702 3702 auto s1 = new void[S.sizeof]; 3703 3703 auto s2 = S(42, 43); 3704 3704 assert(*emplace!S(s1, s2) == s2); 3705 3705 assert(*emplace!S(s1, 44, 45) == S(44, 45)); 3706 3706 } 3707 3707 3708 unittest 3709 { 3710 // Check fix for http://d.puremagic.com/issues/show_bug.cgi?id=2971 3711 assert(equal(map!(to!int)(["42", "34", "345"]), [42, 34, 345])); 3712 } 3713
