/std/conv.d

http://github.com/jcd/phobos · D · 4888 lines · 3689 code · 493 blank · 706 comment · 935 complexity · 9f8975efc579f42aff691130644fc5ba MD5 · raw file

Large files are truncated click here to view the full file

  1. // Written in the D programming language.
  2. /**
  3. A one-stop shop for converting values from one type to another.
  4. Copyright: Copyright Digital Mars 2007-.
  5. License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
  6. Authors: $(WEB digitalmars.com, Walter Bright),
  7. $(WEB erdani.org, Andrei Alexandrescu),
  8. Shin Fujishiro,
  9. Adam D. Ruppe,
  10. Kenji Hara
  11. Source: $(PHOBOSSRC std/_conv.d)
  12. Macros:
  13. WIKI = Phobos/StdConv
  14. */
  15. module std.conv;
  16. import core.stdc.string;
  17. import std.algorithm, std.array, std.ascii, std.exception, std.range,
  18. std.string, std.traits, std.typecons, std.typetuple, std.uni,
  19. std.utf;
  20. import std.format;
  21. //debug=conv; // uncomment to turn on debugging printf's
  22. /* ************* Exceptions *************** */
  23. /**
  24. * Thrown on conversion errors.
  25. */
  26. class ConvException : Exception
  27. {
  28. @safe pure nothrow
  29. this(string s, string fn = __FILE__, size_t ln = __LINE__)
  30. {
  31. super(s, fn, ln);
  32. }
  33. }
  34. private string convError_unexpected(S)(S source)
  35. {
  36. return source.empty ? "end of input" : text("'", source.front, "'");
  37. }
  38. private auto convError(S, T)(S source, string fn = __FILE__, size_t ln = __LINE__)
  39. {
  40. return new ConvException(
  41. text("Unexpected ", convError_unexpected(source),
  42. " when converting from type "~S.stringof~" to type "~T.stringof),
  43. fn, ln);
  44. }
  45. private auto convError(S, T)(S source, int radix, string fn = __FILE__, size_t ln = __LINE__)
  46. {
  47. return new ConvException(
  48. text("Unexpected ", convError_unexpected(source),
  49. " when converting from type "~S.stringof~" base ", radix,
  50. " to type "~T.stringof),
  51. fn, ln);
  52. }
  53. @safe pure/* nothrow*/ // lazy parameter bug
  54. private auto parseError(lazy string msg, string fn = __FILE__, size_t ln = __LINE__)
  55. {
  56. return new ConvException(text("Can't parse string: ", msg), fn, ln);
  57. }
  58. private void parseCheck(alias source)(dchar c, string fn = __FILE__, size_t ln = __LINE__)
  59. {
  60. if (source.empty)
  61. throw parseError(text("unexpected end of input when expecting", "\"", c, "\""));
  62. if (source.front != c)
  63. throw parseError(text("\"", c, "\" is missing"), fn, ln);
  64. source.popFront();
  65. }
  66. private
  67. {
  68. template isImaginary(T)
  69. {
  70. enum bool isImaginary = staticIndexOf!(Unqual!T,
  71. ifloat, idouble, ireal) >= 0;
  72. }
  73. template isComplex(T)
  74. {
  75. enum bool isComplex = staticIndexOf!(Unqual!T,
  76. cfloat, cdouble, creal) >= 0;
  77. }
  78. template isNarrowInteger(T)
  79. {
  80. enum bool isNarrowInteger = staticIndexOf!(Unqual!T,
  81. byte, ubyte, short, ushort) >= 0;
  82. }
  83. T toStr(T, S)(S src)
  84. if (isSomeString!T)
  85. {
  86. import std.format : FormatSpec, formatValue;
  87. auto w = appender!T();
  88. FormatSpec!(ElementEncodingType!T) f;
  89. formatValue(w, src, f);
  90. return w.data;
  91. }
  92. template isExactSomeString(T)
  93. {
  94. enum isExactSomeString = isSomeString!T && !is(T == enum);
  95. }
  96. template isEnumStrToStr(S, T)
  97. {
  98. enum isEnumStrToStr = isImplicitlyConvertible!(S, T) &&
  99. is(S == enum) && isExactSomeString!T;
  100. }
  101. template isNullToStr(S, T)
  102. {
  103. enum isNullToStr = isImplicitlyConvertible!(S, T) &&
  104. (is(Unqual!S == typeof(null))) && isExactSomeString!T;
  105. }
  106. template isRawStaticArray(T, A...)
  107. {
  108. enum isRawStaticArray =
  109. A.length == 0 &&
  110. isStaticArray!T &&
  111. !is(T == class) &&
  112. !is(T == interface) &&
  113. !is(T == struct) &&
  114. !is(T == union);
  115. }
  116. }
  117. /**
  118. * Thrown on conversion overflow errors.
  119. */
  120. class ConvOverflowException : ConvException
  121. {
  122. @safe pure nothrow
  123. this(string s, string fn = __FILE__, size_t ln = __LINE__)
  124. {
  125. super(s, fn, ln);
  126. }
  127. }
  128. /**
  129. The $(D_PARAM to) family of functions converts a value from type
  130. $(D_PARAM Source) to type $(D_PARAM Target). The source type is
  131. deduced and the target type must be specified, for example the
  132. expression $(D_PARAM to!int(42.0)) converts the number 42 from
  133. $(D_PARAM double) to $(D_PARAM int). The conversion is "safe", i.e.,
  134. it checks for overflow; $(D_PARAM to!int(4.2e10)) would throw the
  135. $(D_PARAM ConvOverflowException) exception. Overflow checks are only
  136. inserted when necessary, e.g., $(D_PARAM to!double(42)) does not do
  137. any checking because any int fits in a double.
  138. Converting a value to its own type (useful mostly for generic code)
  139. simply returns its argument.
  140. Example:
  141. -------------------------
  142. int a = 42;
  143. auto b = to!int(a); // b is int with value 42
  144. auto c = to!double(3.14); // c is double with value 3.14
  145. -------------------------
  146. Converting among numeric types is a safe way to cast them around.
  147. Conversions from floating-point types to integral types allow loss of
  148. precision (the fractional part of a floating-point number). The
  149. conversion is truncating towards zero, the same way a cast would
  150. truncate. (To round a floating point value when casting to an
  151. integral, use $(D_PARAM roundTo).)
  152. Examples:
  153. -------------------------
  154. int a = 420;
  155. auto b = to!long(a); // same as long b = a;
  156. auto c = to!byte(a / 10); // fine, c = 42
  157. auto d = to!byte(a); // throw ConvOverflowException
  158. double e = 4.2e6;
  159. auto f = to!int(e); // f == 4200000
  160. e = -3.14;
  161. auto g = to!uint(e); // fails: floating-to-integral negative overflow
  162. e = 3.14;
  163. auto h = to!uint(e); // h = 3
  164. e = 3.99;
  165. h = to!uint(a); // h = 3
  166. e = -3.99;
  167. f = to!int(a); // f = -3
  168. -------------------------
  169. Conversions from integral types to floating-point types always
  170. succeed, but might lose accuracy. The largest integers with a
  171. predecessor representable in floating-point format are 2^24-1 for
  172. float, 2^53-1 for double, and 2^64-1 for $(D_PARAM real) (when
  173. $(D_PARAM real) is 80-bit, e.g. on Intel machines).
  174. Example:
  175. -------------------------
  176. int a = 16_777_215; // 2^24 - 1, largest proper integer representable as float
  177. assert(to!int(to!float(a)) == a);
  178. assert(to!int(to!float(-a)) == -a);
  179. a += 2;
  180. assert(to!int(to!float(a)) == a); // fails!
  181. -------------------------
  182. Conversions from string to numeric types differ from the C equivalents
  183. $(D_PARAM atoi()) and $(D_PARAM atol()) by checking for overflow and
  184. not allowing whitespace.
  185. For conversion of strings to signed types, the grammar recognized is:
  186. <pre>
  187. $(I Integer): $(I Sign UnsignedInteger)
  188. $(I UnsignedInteger)
  189. $(I Sign):
  190. $(B +)
  191. $(B -)
  192. </pre>
  193. For conversion to unsigned types, the grammar recognized is:
  194. <pre>
  195. $(I UnsignedInteger):
  196. $(I DecimalDigit)
  197. $(I DecimalDigit) $(I UnsignedInteger)
  198. </pre>
  199. Converting an array to another array type works by converting each
  200. element in turn. Associative arrays can be converted to associative
  201. arrays as long as keys and values can in turn be converted.
  202. Example:
  203. -------------------------
  204. int[] a = ([1, 2, 3]).dup;
  205. auto b = to!(float[])(a);
  206. assert(b == [1.0f, 2, 3]);
  207. string str = "1 2 3 4 5 6";
  208. auto numbers = to!(double[])(split(str));
  209. assert(numbers == [1.0, 2, 3, 4, 5, 6]);
  210. int[string] c;
  211. c["a"] = 1;
  212. c["b"] = 2;
  213. auto d = to!(double[wstring])(c);
  214. assert(d["a"w] == 1 && d["b"w] == 2);
  215. -------------------------
  216. Conversions operate transitively, meaning that they work on arrays and
  217. associative arrays of any complexity:
  218. -------------------------
  219. int[string][double[int[]]] a;
  220. ...
  221. auto b = to!(short[wstring][string[double[]]])(a);
  222. -------------------------
  223. This conversion works because $(D_PARAM to!short) applies to an
  224. $(D_PARAM int), $(D_PARAM to!wstring) applies to a $(D_PARAM
  225. string), $(D_PARAM to!string) applies to a $(D_PARAM double), and
  226. $(D_PARAM to!(double[])) applies to an $(D_PARAM int[]). The
  227. conversion might throw an exception because $(D_PARAM to!short)
  228. might fail the range check.
  229. */
  230. /**
  231. Entry point that dispatches to the appropriate conversion
  232. primitive. Client code normally calls $(D _to!TargetType(value))
  233. (and not some variant of $(D toImpl)).
  234. */
  235. template to(T)
  236. {
  237. T to(A...)(A args)
  238. if (!isRawStaticArray!A)
  239. {
  240. return toImpl!T(args);
  241. }
  242. // Fix issue 6175
  243. T to(S)(ref S arg)
  244. if (isRawStaticArray!S)
  245. {
  246. return toImpl!T(arg);
  247. }
  248. }
  249. // Tests for issue 6175
  250. @safe pure unittest
  251. {
  252. char[9] sarr = "blablabla";
  253. auto darr = to!(char[])(sarr);
  254. assert(sarr.ptr == darr.ptr);
  255. assert(sarr.length == darr.length);
  256. }
  257. // Tests for issue 7348
  258. @safe pure unittest
  259. {
  260. assert(to!string(null) == "null");
  261. assert(text(null) == "null");
  262. }
  263. // Tests for issue 11390
  264. @safe pure unittest
  265. {
  266. const(typeof(null)) ctn;
  267. immutable(typeof(null)) itn;
  268. assert(to!string(ctn) == "null");
  269. assert(to!string(itn) == "null");
  270. }
  271. // Tests for issue 8729: do NOT skip leading WS
  272. @safe pure unittest
  273. {
  274. foreach (T; TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong))
  275. {
  276. assertThrown!ConvException(to!T(" 0"));
  277. assertThrown!ConvException(to!T(" 0", 8));
  278. }
  279. foreach (T; TypeTuple!(float, double, real))
  280. {
  281. assertThrown!ConvException(to!T(" 0"));
  282. }
  283. assertThrown!ConvException(to!bool(" true"));
  284. alias NullType = typeof(null);
  285. assertThrown!ConvException(to!NullType(" null"));
  286. alias ARR = int[];
  287. assertThrown!ConvException(to!ARR(" [1]"));
  288. alias AA = int[int];
  289. assertThrown!ConvException(to!AA(" [1:1]"));
  290. }
  291. /**
  292. If the source type is implicitly convertible to the target type, $(D
  293. to) simply performs the implicit conversion.
  294. */
  295. T toImpl(T, S)(S value)
  296. if (isImplicitlyConvertible!(S, T) &&
  297. !isEnumStrToStr!(S, T) && !isNullToStr!(S, T))
  298. {
  299. template isSignedInt(T)
  300. {
  301. enum isSignedInt = isIntegral!T && isSigned!T;
  302. }
  303. alias isUnsignedInt = isUnsigned;
  304. // Conversion from integer to integer, and changing its sign
  305. static if (isUnsignedInt!S && isSignedInt!T && S.sizeof == T.sizeof)
  306. { // unsigned to signed & same size
  307. enforce(value <= cast(S)T.max,
  308. new ConvOverflowException("Conversion positive overflow"));
  309. }
  310. else static if (isSignedInt!S && isUnsignedInt!T)
  311. { // signed to unsigned
  312. enforce(0 <= value,
  313. new ConvOverflowException("Conversion negative overflow"));
  314. }
  315. return value;
  316. }
  317. @safe pure unittest
  318. {
  319. enum E { a } // Issue 9523 - Allow identity enum conversion
  320. auto e = to!E(E.a);
  321. assert(e == E.a);
  322. }
  323. @safe pure unittest
  324. {
  325. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  326. int a = 42;
  327. auto b = to!long(a);
  328. assert(a == b);
  329. }
  330. // Tests for issue 6377
  331. @safe pure unittest
  332. {
  333. // Conversion between same size
  334. foreach (S; TypeTuple!(byte, short, int, long))
  335. {
  336. alias Unsigned!S U;
  337. foreach (Sint; TypeTuple!(S, const S, immutable S))
  338. foreach (Uint; TypeTuple!(U, const U, immutable U))
  339. {
  340. // positive overflow
  341. Uint un = Uint.max;
  342. assertThrown!ConvOverflowException(to!Sint(un),
  343. text(Sint.stringof, ' ', Uint.stringof, ' ', un));
  344. // negative overflow
  345. Sint sn = -1;
  346. assertThrown!ConvOverflowException(to!Uint(sn),
  347. text(Sint.stringof, ' ', Uint.stringof, ' ', un));
  348. }
  349. }
  350. // Conversion between different size
  351. foreach (i, S1; TypeTuple!(byte, short, int, long))
  352. foreach ( S2; TypeTuple!(byte, short, int, long)[i+1..$])
  353. {
  354. alias Unsigned!S1 U1;
  355. alias Unsigned!S2 U2;
  356. static assert(U1.sizeof < S2.sizeof);
  357. // small unsigned to big signed
  358. foreach (Uint; TypeTuple!(U1, const U1, immutable U1))
  359. foreach (Sint; TypeTuple!(S2, const S2, immutable S2))
  360. {
  361. Uint un = Uint.max;
  362. assertNotThrown(to!Sint(un));
  363. assert(to!Sint(un) == un);
  364. }
  365. // big unsigned to small signed
  366. foreach (Uint; TypeTuple!(U2, const U2, immutable U2))
  367. foreach (Sint; TypeTuple!(S1, const S1, immutable S1))
  368. {
  369. Uint un = Uint.max;
  370. assertThrown(to!Sint(un));
  371. }
  372. static assert(S1.sizeof < U2.sizeof);
  373. // small signed to big unsigned
  374. foreach (Sint; TypeTuple!(S1, const S1, immutable S1))
  375. foreach (Uint; TypeTuple!(U2, const U2, immutable U2))
  376. {
  377. Sint sn = -1;
  378. assertThrown!ConvOverflowException(to!Uint(sn));
  379. }
  380. // big signed to small unsigned
  381. foreach (Sint; TypeTuple!(S2, const S2, immutable S2))
  382. foreach (Uint; TypeTuple!(U1, const U1, immutable U1))
  383. {
  384. Sint sn = -1;
  385. assertThrown!ConvOverflowException(to!Uint(sn));
  386. }
  387. }
  388. }
  389. /*
  390. Converting static arrays forwards to their dynamic counterparts.
  391. */
  392. T toImpl(T, S)(ref S s)
  393. if (isRawStaticArray!S)
  394. {
  395. return toImpl!(T, typeof(s[0])[])(s);
  396. }
  397. @safe pure unittest
  398. {
  399. char[4] test = ['a', 'b', 'c', 'd'];
  400. static assert(!isInputRange!(Unqual!(char[4])));
  401. assert(to!string(test) == test);
  402. }
  403. /**
  404. When source type supports member template function opCast, is is used.
  405. */
  406. T toImpl(T, S)(S value)
  407. if (!isImplicitlyConvertible!(S, T) &&
  408. is(typeof(S.init.opCast!T()) : T) &&
  409. !isExactSomeString!T)
  410. {
  411. return value.opCast!T();
  412. }
  413. @safe pure unittest
  414. {
  415. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  416. class B
  417. {
  418. T opCast(T)() { return 43; }
  419. }
  420. auto b = new B;
  421. assert(to!int(b) == 43);
  422. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  423. struct S
  424. {
  425. T opCast(T)() { return 43; }
  426. }
  427. auto s = S();
  428. assert(to!int(s) == 43);
  429. }
  430. /**
  431. When target type supports 'converting construction', it is used.
  432. $(UL $(LI If target type is struct, $(D T(value)) is used.)
  433. $(LI If target type is class, $(D new T(value)) is used.))
  434. */
  435. T toImpl(T, S)(S value)
  436. if (!isImplicitlyConvertible!(S, T) &&
  437. is(T == struct) && is(typeof(T(value))))
  438. {
  439. return T(value);
  440. }
  441. // Bugzilla 3961
  442. @safe pure unittest
  443. {
  444. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  445. struct Int
  446. {
  447. int x;
  448. }
  449. Int i = to!Int(1);
  450. static struct Int2
  451. {
  452. int x;
  453. this(int x) @safe pure { this.x = x; }
  454. }
  455. Int2 i2 = to!Int2(1);
  456. static struct Int3
  457. {
  458. int x;
  459. static Int3 opCall(int x) @safe pure
  460. {
  461. Int3 i;
  462. i.x = x;
  463. return i;
  464. }
  465. }
  466. Int3 i3 = to!Int3(1);
  467. }
  468. // Bugzilla 6808
  469. @safe pure unittest
  470. {
  471. static struct FakeBigInt
  472. {
  473. this(string s) @safe pure {}
  474. }
  475. string s = "101";
  476. auto i3 = to!FakeBigInt(s);
  477. }
  478. /// ditto
  479. T toImpl(T, S)(S value)
  480. if (!isImplicitlyConvertible!(S, T) &&
  481. is(T == class) && is(typeof(new T(value))))
  482. {
  483. return new T(value);
  484. }
  485. @safe pure unittest
  486. {
  487. static struct S
  488. {
  489. int x;
  490. }
  491. static class C
  492. {
  493. int x;
  494. this(int x) @safe pure { this.x = x; }
  495. }
  496. static class B
  497. {
  498. int value;
  499. this(S src) @safe pure { value = src.x; }
  500. this(C src) @safe pure { value = src.x; }
  501. }
  502. S s = S(1);
  503. auto b1 = to!B(s); // == new B(s)
  504. assert(b1.value == 1);
  505. C c = new C(2);
  506. auto b2 = to!B(c); // == new B(c)
  507. assert(b2.value == 2);
  508. auto c2 = to!C(3); // == new C(3)
  509. assert(c2.x == 3);
  510. }
  511. @safe pure unittest
  512. {
  513. struct S
  514. {
  515. class A
  516. {
  517. this(B b) @safe pure {}
  518. }
  519. class B : A
  520. {
  521. this() @safe pure { super(this); }
  522. }
  523. }
  524. S.B b = new S.B();
  525. S.A a = to!(S.A)(b); // == cast(S.A)b
  526. // (do not run construction conversion like new S.A(b))
  527. assert(b is a);
  528. static class C : Object
  529. {
  530. this() @safe pure {}
  531. this(Object o) @safe pure {}
  532. }
  533. Object oc = new C();
  534. C a2 = to!C(oc); // == new C(a)
  535. // Construction conversion overrides down-casting conversion
  536. assert(a2 !is a); //
  537. }
  538. /**
  539. Object-to-object conversions by dynamic casting throw exception when the source is
  540. non-null and the target is null.
  541. */
  542. T toImpl(T, S)(S value)
  543. if (!isImplicitlyConvertible!(S, T) &&
  544. (is(S == class) || is(S == interface)) && !is(typeof(value.opCast!T()) : T) &&
  545. (is(T == class) || is(T == interface)) && !is(typeof(new T(value))))
  546. {
  547. static if (is(T == immutable))
  548. {
  549. // immutable <- immutable
  550. enum isModConvertible = is(S == immutable);
  551. }
  552. else static if (is(T == const))
  553. {
  554. static if (is(T == shared))
  555. {
  556. // shared const <- shared
  557. // shared const <- shared const
  558. // shared const <- immutable
  559. enum isModConvertible = is(S == shared) || is(S == immutable);
  560. }
  561. else
  562. {
  563. // const <- mutable
  564. // const <- immutable
  565. enum isModConvertible = !is(S == shared);
  566. }
  567. }
  568. else
  569. {
  570. static if (is(T == shared))
  571. {
  572. // shared <- shared mutable
  573. enum isModConvertible = is(S == shared) && !is(S == const);
  574. }
  575. else
  576. {
  577. // (mutable) <- (mutable)
  578. enum isModConvertible = is(Unqual!S == S);
  579. }
  580. }
  581. static assert(isModConvertible, "Bad modifier conversion: "~S.stringof~" to "~T.stringof);
  582. auto result = ()@trusted{ return cast(T) value; }();
  583. if (!result && value)
  584. {
  585. throw new ConvException("Cannot convert object of static type "
  586. ~S.classinfo.name~" and dynamic type "~value.classinfo.name
  587. ~" to type "~T.classinfo.name);
  588. }
  589. return result;
  590. }
  591. @safe pure unittest
  592. {
  593. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  594. // Testing object conversions
  595. class A {}
  596. class B : A {}
  597. class C : A {}
  598. A a1 = new A, a2 = new B, a3 = new C;
  599. assert(to!B(a2) is a2);
  600. assert(to!C(a3) is a3);
  601. assertThrown!ConvException(to!B(a3));
  602. }
  603. // Unittest for 6288
  604. @safe pure unittest
  605. {
  606. template Identity(T) { alias T Identity; }
  607. template toConst(T) { alias const(T) toConst; }
  608. template toShared(T) { alias shared(T) toShared; }
  609. template toSharedConst(T) { alias shared(const(T)) toSharedConst; }
  610. template toImmutable(T) { alias immutable(T) toImmutable; }
  611. template AddModifier(int n) if (0 <= n && n < 5)
  612. {
  613. static if (n == 0) alias Identity AddModifier;
  614. else static if (n == 1) alias toConst AddModifier;
  615. else static if (n == 2) alias toShared AddModifier;
  616. else static if (n == 3) alias toSharedConst AddModifier;
  617. else static if (n == 4) alias toImmutable AddModifier;
  618. }
  619. interface I {}
  620. interface J {}
  621. class A {}
  622. class B : A {}
  623. class C : B, I, J {}
  624. class D : I {}
  625. foreach (m1; TypeTuple!(0,1,2,3,4)) // enumerate modifiers
  626. foreach (m2; TypeTuple!(0,1,2,3,4)) // ditto
  627. {
  628. alias AddModifier!m1 srcmod;
  629. alias AddModifier!m2 tgtmod;
  630. //pragma(msg, srcmod!Object, " -> ", tgtmod!Object, ", convertible = ",
  631. // isImplicitlyConvertible!(srcmod!Object, tgtmod!Object));
  632. // Compile time convertible equals to modifier convertible.
  633. static if (isImplicitlyConvertible!(srcmod!Object, tgtmod!Object))
  634. {
  635. // Test runtime conversions: class to class, class to interface,
  636. // interface to class, and interface to interface
  637. // Check that the runtime conversion to succeed
  638. srcmod!A ac = new srcmod!C();
  639. srcmod!I ic = new srcmod!C();
  640. assert(to!(tgtmod!C)(ac) !is null); // A(c) to C
  641. assert(to!(tgtmod!I)(ac) !is null); // A(c) to I
  642. assert(to!(tgtmod!C)(ic) !is null); // I(c) to C
  643. assert(to!(tgtmod!J)(ic) !is null); // I(c) to J
  644. // Check that the runtime conversion fails
  645. srcmod!A ab = new srcmod!B();
  646. srcmod!I id = new srcmod!D();
  647. assertThrown(to!(tgtmod!C)(ab)); // A(b) to C
  648. assertThrown(to!(tgtmod!I)(ab)); // A(b) to I
  649. assertThrown(to!(tgtmod!C)(id)); // I(d) to C
  650. assertThrown(to!(tgtmod!J)(id)); // I(d) to J
  651. }
  652. else
  653. {
  654. // Check that the conversion is rejected statically
  655. static assert(!is(typeof(to!(tgtmod!C)(srcmod!A.init)))); // A to C
  656. static assert(!is(typeof(to!(tgtmod!I)(srcmod!A.init)))); // A to I
  657. static assert(!is(typeof(to!(tgtmod!C)(srcmod!I.init)))); // I to C
  658. static assert(!is(typeof(to!(tgtmod!J)(srcmod!I.init)))); // I to J
  659. }
  660. }
  661. }
  662. /**
  663. Stringize conversion from all types is supported.
  664. $(UL
  665. $(LI String _to string conversion works for any two string types having
  666. ($(D char), $(D wchar), $(D dchar)) character widths and any
  667. combination of qualifiers (mutable, $(D const), or $(D immutable)).)
  668. $(LI Converts array (other than strings) to string.
  669. Each element is converted by calling $(D to!T).)
  670. $(LI Associative array to string conversion.
  671. Each element is printed by calling $(D to!T).)
  672. $(LI Object to string conversion calls $(D toString) against the object or
  673. returns $(D "null") if the object is null.)
  674. $(LI Struct to string conversion calls $(D toString) against the struct if
  675. it is defined.)
  676. $(LI For structs that do not define $(D toString), the conversion to string
  677. produces the list of fields.)
  678. $(LI Enumerated types are converted to strings as their symbolic names.)
  679. $(LI Boolean values are printed as $(D "true") or $(D "false").)
  680. $(LI $(D char), $(D wchar), $(D dchar) to a string type.)
  681. $(LI Unsigned or signed integers to strings.
  682. $(DL $(DT [special case])
  683. $(DD Convert integral value to string in $(D_PARAM radix) radix.
  684. radix must be a value from 2 to 36.
  685. value is treated as a signed value only if radix is 10.
  686. The characters A through Z are used to represent values 10 through 36
  687. and their case is determined by the $(D_PARAM letterCase) parameter.)))
  688. $(LI All floating point types to all string types.)
  689. $(LI Pointer to string conversions prints the pointer as a $(D size_t) value.
  690. If pointer is $(D char*), treat it as C-style strings.
  691. In that case, this function is $(D @system).))
  692. */
  693. T toImpl(T, S)(S value)
  694. if (!(isImplicitlyConvertible!(S, T) &&
  695. !isEnumStrToStr!(S, T) && !isNullToStr!(S, T)) &&
  696. isExactSomeString!T)
  697. {
  698. static if (isExactSomeString!S && value[0].sizeof == ElementEncodingType!T.sizeof)
  699. {
  700. // string-to-string with incompatible qualifier conversion
  701. static if (is(ElementEncodingType!T == immutable))
  702. {
  703. // conversion (mutable|const) -> immutable
  704. return value.idup;
  705. }
  706. else
  707. {
  708. // conversion (immutable|const) -> mutable
  709. return value.dup;
  710. }
  711. }
  712. else static if (isExactSomeString!S)
  713. {
  714. // other string-to-string
  715. //Use Appender directly instead of toStr, which also uses a formatedWrite
  716. auto w = appender!T();
  717. w.put(value);
  718. return w.data;
  719. }
  720. else static if (isIntegral!S && !is(S == enum))
  721. {
  722. // other integral-to-string conversions with default radix
  723. return toImpl!(T, S)(value, 10);
  724. }
  725. else static if (is(S == void[]) || is(S == const(void)[]) || is(S == immutable(void)[]))
  726. {
  727. // Converting void array to string
  728. alias Unqual!(ElementEncodingType!T) Char;
  729. auto raw = cast(const(ubyte)[]) value;
  730. enforce(raw.length % Char.sizeof == 0,
  731. new ConvException("Alignment mismatch in converting a "
  732. ~ S.stringof ~ " to a "
  733. ~ T.stringof));
  734. auto result = new Char[raw.length / Char.sizeof];
  735. ()@trusted{ memcpy(result.ptr, value.ptr, value.length); }();
  736. return cast(T) result;
  737. }
  738. else static if (isPointer!S && is(S : const(char)*))
  739. {
  740. // It is unsafe because we cannot guarantee that the pointer is null terminated.
  741. return value ? cast(T) value[0 .. strlen(value)].dup : cast(string)null;
  742. }
  743. else static if (isSomeString!T && is(S == enum))
  744. {
  745. static if (isSwitchable!(OriginalType!S) && EnumMembers!S.length <= 50)
  746. {
  747. switch(value)
  748. {
  749. foreach (I, member; NoDuplicates!(EnumMembers!S))
  750. {
  751. case member:
  752. return to!T(enumRep!(immutable(T), S, I));
  753. }
  754. default:
  755. }
  756. }
  757. else
  758. {
  759. foreach (I, member; EnumMembers!S)
  760. {
  761. if (value == member)
  762. return to!T(enumRep!(immutable(T), S, I));
  763. }
  764. }
  765. import std.format : FormatSpec, formatValue;
  766. //Default case, delegate to format
  767. //Note: we don't call toStr directly, to avoid duplicate work.
  768. auto app = appender!T();
  769. app.put("cast(");
  770. app.put(S.stringof);
  771. app.put(')');
  772. FormatSpec!char f;
  773. formatValue(app, cast(OriginalType!S)value, f);
  774. return app.data;
  775. }
  776. else
  777. {
  778. // other non-string values runs formatting
  779. return toStr!T(value);
  780. }
  781. }
  782. /*
  783. Check whether type $(D T) can be used in a switch statement.
  784. This is useful for compile-time generation of switch case statements.
  785. */
  786. private template isSwitchable(E)
  787. {
  788. enum bool isSwitchable = is(typeof({
  789. switch (E.init) { default: }
  790. }));
  791. }
  792. //
  793. unittest
  794. {
  795. static assert(isSwitchable!int);
  796. static assert(!isSwitchable!double);
  797. static assert(!isSwitchable!real);
  798. }
  799. //Static representation of the index I of the enum S,
  800. //In representation T.
  801. //T must be an immutable string (avoids un-necessary initializations).
  802. private template enumRep(T, S, size_t I)
  803. if (is (T == immutable) && isExactSomeString!T && is(S == enum))
  804. {
  805. static T enumRep = to!T(__traits(allMembers, S)[I]);
  806. }
  807. @safe pure unittest
  808. {
  809. void dg()
  810. {
  811. // string to string conversion
  812. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  813. alias TypeTuple!(char, wchar, dchar) Chars;
  814. foreach (LhsC; Chars)
  815. {
  816. alias TypeTuple!(LhsC[], const(LhsC)[], immutable(LhsC)[]) LhStrings;
  817. foreach (Lhs; LhStrings)
  818. {
  819. foreach (RhsC; Chars)
  820. {
  821. alias TypeTuple!(RhsC[], const(RhsC)[], immutable(RhsC)[])
  822. RhStrings;
  823. foreach (Rhs; RhStrings)
  824. {
  825. Lhs s1 = to!Lhs("wyda");
  826. Rhs s2 = to!Rhs(s1);
  827. //writeln(Lhs.stringof, " -> ", Rhs.stringof);
  828. assert(s1 == to!Lhs(s2));
  829. }
  830. }
  831. }
  832. }
  833. foreach (T; Chars)
  834. {
  835. foreach (U; Chars)
  836. {
  837. T[] s1 = to!(T[])("Hello, world!");
  838. auto s2 = to!(U[])(s1);
  839. assert(s1 == to!(T[])(s2));
  840. auto s3 = to!(const(U)[])(s1);
  841. assert(s1 == to!(T[])(s3));
  842. auto s4 = to!(immutable(U)[])(s1);
  843. assert(s1 == to!(T[])(s4));
  844. }
  845. }
  846. }
  847. dg();
  848. assertCTFEable!dg;
  849. }
  850. @safe pure unittest
  851. {
  852. // Conversion reinterpreting void array to string
  853. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  854. auto a = "abcx"w;
  855. const(void)[] b = a;
  856. assert(b.length == 8);
  857. auto c = to!(wchar[])(b);
  858. assert(c == "abcx");
  859. }
  860. @system pure unittest
  861. {
  862. // char* to string conversion
  863. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  864. debug(conv) printf("string.to!string(char*).unittest\n");
  865. assert(to!string(cast(char*) null) == "");
  866. assert(to!string("foo\0".ptr) == "foo");
  867. }
  868. @safe pure unittest
  869. {
  870. // Conversion representing bool value with string
  871. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  872. bool b;
  873. assert(to!string(b) == "false");
  874. b = true;
  875. assert(to!string(b) == "true");
  876. }
  877. @safe pure unittest
  878. {
  879. // Conversion representing character value with string
  880. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  881. alias TypeTuple!(
  882. char, const( char), immutable( char),
  883. wchar, const(wchar), immutable(wchar),
  884. dchar, const(dchar), immutable(dchar)) AllChars;
  885. foreach (Char1; AllChars)
  886. {
  887. foreach (Char2; AllChars)
  888. {
  889. Char1 c = 'a';
  890. assert(to!(Char2[])(c)[0] == c);
  891. }
  892. uint x = 4;
  893. assert(to!(Char1[])(x) == "4");
  894. }
  895. string s = "foo";
  896. string s2;
  897. foreach (char c; s)
  898. {
  899. s2 ~= to!string(c);
  900. }
  901. //printf("%.*s", s2);
  902. assert(s2 == "foo");
  903. }
  904. @safe pure unittest
  905. {
  906. // Conversion representing integer values with string
  907. foreach (Int; TypeTuple!(ubyte, ushort, uint, ulong))
  908. {
  909. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  910. debug(conv) printf("string.to!string(%.*s).unittest\n", Int.stringof.length, Int.stringof.ptr);
  911. assert(to!string(to!Int(0)) == "0");
  912. assert(to!string(to!Int(9)) == "9");
  913. assert(to!string(to!Int(123)) == "123");
  914. }
  915. foreach (Int; TypeTuple!(byte, short, int, long))
  916. {
  917. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  918. debug(conv) printf("string.to!string(%.*s).unittest\n", Int.stringof.length, Int.stringof.ptr);
  919. assert(to!string(to!Int(0)) == "0");
  920. assert(to!string(to!Int(9)) == "9");
  921. assert(to!string(to!Int(123)) == "123");
  922. assert(to!string(to!Int(-0)) == "0");
  923. assert(to!string(to!Int(-9)) == "-9");
  924. assert(to!string(to!Int(-123)) == "-123");
  925. assert(to!string(to!(const Int)(6)) == "6");
  926. }
  927. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  928. assert(wtext(int.max) == "2147483647"w);
  929. assert(wtext(int.min) == "-2147483648"w);
  930. assert(to!string(0L) == "0");
  931. assertCTFEable!(
  932. {
  933. assert(to!string(1uL << 62) == "4611686018427387904");
  934. assert(to!string(0x100000000) == "4294967296");
  935. assert(to!string(-138L) == "-138");
  936. });
  937. }
  938. @safe pure unittest
  939. {
  940. // Conversion representing dynamic/static array with string
  941. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  942. long[] b = [ 1, 3, 5 ];
  943. auto s = to!string(b);
  944. assert(to!string(b) == "[1, 3, 5]", s);
  945. }
  946. /*@safe pure */unittest // sprintf issue
  947. {
  948. double[2] a = [ 1.5, 2.5 ];
  949. assert(to!string(a) == "[1.5, 2.5]");
  950. }
  951. /*@safe pure */unittest
  952. {
  953. // Conversion representing associative array with string
  954. int[string] a = ["0":1, "1":2];
  955. assert(to!string(a) == `["0":1, "1":2]`);
  956. }
  957. unittest
  958. {
  959. // Conversion representing class object with string
  960. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  961. class A
  962. {
  963. override string toString() const { return "an A"; }
  964. }
  965. A a;
  966. assert(to!string(a) == "null");
  967. a = new A;
  968. assert(to!string(a) == "an A");
  969. // Bug 7660
  970. class C { override string toString() const { return "C"; } }
  971. struct S { C c; alias c this; }
  972. S s; s.c = new C();
  973. assert(to!string(s) == "C");
  974. }
  975. unittest
  976. {
  977. // Conversion representing struct object with string
  978. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  979. struct S1
  980. {
  981. string toString() { return "wyda"; }
  982. }
  983. assert(to!string(S1()) == "wyda");
  984. struct S2
  985. {
  986. int a = 42;
  987. float b = 43.5;
  988. }
  989. S2 s2;
  990. assert(to!string(s2) == "S2(42, 43.5)");
  991. // Test for issue 8080
  992. struct S8080
  993. {
  994. short[4] data;
  995. alias data this;
  996. string toString() { return "<S>"; }
  997. }
  998. S8080 s8080;
  999. assert(to!string(s8080) == "<S>");
  1000. }
  1001. unittest
  1002. {
  1003. // Conversion representing enum value with string
  1004. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  1005. enum EB : bool { a = true }
  1006. enum EU : uint { a = 0, b = 1, c = 2 } // base type is unsigned
  1007. enum EI : int { a = -1, b = 0, c = 1 } // base type is signed (bug 7909)
  1008. enum EF : real { a = 1.414, b = 1.732, c = 2.236 }
  1009. enum EC : char { a = 'x', b = 'y' }
  1010. enum ES : string { a = "aaa", b = "bbb" }
  1011. foreach (E; TypeTuple!(EB, EU, EI, EF, EC, ES))
  1012. {
  1013. assert(to! string(E.a) == "a"c);
  1014. assert(to!wstring(E.a) == "a"w);
  1015. assert(to!dstring(E.a) == "a"d);
  1016. }
  1017. // Test an value not corresponding to an enum member.
  1018. auto o = cast(EU)5;
  1019. assert(to! string(o) == "cast(EU)5"c);
  1020. assert(to!wstring(o) == "cast(EU)5"w);
  1021. assert(to!dstring(o) == "cast(EU)5"d);
  1022. }
  1023. unittest
  1024. {
  1025. enum E
  1026. {
  1027. foo,
  1028. bar,
  1029. doo = foo, // check duplicate switch statements
  1030. }
  1031. foreach (S; TypeTuple!(string, wstring, dstring, const(char[]), const(wchar[]), const(dchar[])))
  1032. {
  1033. auto s1 = to!S(E.foo);
  1034. auto s2 = to!S(E.foo);
  1035. assert(s1 == s2);
  1036. // ensure we don't allocate when it's unnecessary
  1037. assert(s1 is s2);
  1038. }
  1039. foreach (S; TypeTuple!(char[], wchar[], dchar[]))
  1040. {
  1041. auto s1 = to!S(E.foo);
  1042. auto s2 = to!S(E.foo);
  1043. assert(s1 == s2);
  1044. // ensure each mutable array is unique
  1045. assert(s1 !is s2);
  1046. }
  1047. }
  1048. /// ditto
  1049. @trusted pure T toImpl(T, S)(S value, uint radix, LetterCase letterCase = LetterCase.upper)
  1050. if (isIntegral!S &&
  1051. isExactSomeString!T)
  1052. in
  1053. {
  1054. assert(radix >= 2 && radix <= 36);
  1055. }
  1056. body
  1057. {
  1058. alias EEType = Unqual!(ElementEncodingType!T);
  1059. T toStringRadixConvert(size_t bufLen, uint radix = 0, bool neg = false)(uint runtimeRadix = 0)
  1060. {
  1061. static if (neg)
  1062. ulong div = void, mValue = unsigned(-value);
  1063. else
  1064. Unsigned!(Unqual!S) div = void, mValue = unsigned(value);
  1065. size_t index = bufLen;
  1066. EEType[bufLen] buffer = void;
  1067. char baseChar = letterCase == LetterCase.lower ? 'a' : 'A';
  1068. char mod = void;
  1069. do
  1070. {
  1071. static if (radix == 0)
  1072. {
  1073. div = cast(S)(mValue / runtimeRadix );
  1074. mod = cast(ubyte)(mValue % runtimeRadix);
  1075. mod += mod < 10 ? '0' : baseChar - 10;
  1076. }
  1077. else static if (radix > 10)
  1078. {
  1079. div = cast(S)(mValue / radix );
  1080. mod = cast(ubyte)(mValue % radix);
  1081. mod += mod < 10 ? '0' : baseChar - 10;
  1082. }
  1083. else
  1084. {
  1085. div = cast(S)(mValue / radix);
  1086. mod = mValue % radix + '0';
  1087. }
  1088. buffer[--index] = cast(char)mod;
  1089. mValue = div;
  1090. } while (mValue);
  1091. static if (neg)
  1092. {
  1093. buffer[--index] = '-';
  1094. }
  1095. return cast(T)buffer[index .. $].dup;
  1096. }
  1097. enforce(radix >= 2 && radix <= 36, new ConvException("Radix error"));
  1098. switch(radix)
  1099. {
  1100. case 10:
  1101. if (value < 0)
  1102. return toStringRadixConvert!(S.sizeof * 3 + 1, 10, true)();
  1103. else
  1104. return toStringRadixConvert!(S.sizeof * 3, 10)();
  1105. case 16:
  1106. return toStringRadixConvert!(S.sizeof * 2, 16)();
  1107. case 2:
  1108. return toStringRadixConvert!(S.sizeof * 8, 2)();
  1109. case 8:
  1110. return toStringRadixConvert!(S.sizeof * 3, 8)();
  1111. default:
  1112. return toStringRadixConvert!(S.sizeof * 6)(radix);
  1113. }
  1114. }
  1115. @safe pure unittest
  1116. {
  1117. foreach (Int; TypeTuple!(uint, ulong))
  1118. {
  1119. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  1120. debug(conv) printf("string.to!string(%.*s, uint).unittest\n", Int.stringof.length, Int.stringof.ptr);
  1121. assert(to!string(to!Int(16), 16) == "10");
  1122. assert(to!string(to!Int(15), 2u) == "1111");
  1123. assert(to!string(to!Int(1), 2u) == "1");
  1124. assert(to!string(to!Int(0x1234AF), 16u) == "1234AF");
  1125. assert(to!string(to!Int(0x1234BCD), 16u, LetterCase.upper) == "1234BCD");
  1126. assert(to!string(to!Int(0x1234AF), 16u, LetterCase.lower) == "1234af");
  1127. }
  1128. foreach (Int; TypeTuple!(int, long))
  1129. {
  1130. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  1131. debug(conv) printf("string.to!string(%.*s, uint).unittest\n", Int.stringof.length, Int.stringof.ptr);
  1132. assert(to!string(to!Int(-10), 10u) == "-10");
  1133. }
  1134. assert(to!string(cast(byte)-10, 16) == "F6");
  1135. assert(to!string(long.min) == "-9223372036854775808");
  1136. assert(to!string(long.max) == "9223372036854775807");
  1137. }
  1138. /**
  1139. Narrowing numeric-numeric conversions throw when the value does not
  1140. fit in the narrower type.
  1141. */
  1142. T toImpl(T, S)(S value)
  1143. if (!isImplicitlyConvertible!(S, T) &&
  1144. (isNumeric!S || isSomeChar!S || isBoolean!S) &&
  1145. (isNumeric!T || isSomeChar!T || isBoolean!T) && !is(T == enum))
  1146. {
  1147. enum sSmallest = mostNegative!S;
  1148. enum tSmallest = mostNegative!T;
  1149. static if (sSmallest < 0)
  1150. {
  1151. // possible underflow converting from a signed
  1152. static if (tSmallest == 0)
  1153. {
  1154. immutable good = value >= 0;
  1155. }
  1156. else
  1157. {
  1158. static assert(tSmallest < 0);
  1159. immutable good = value >= tSmallest;
  1160. }
  1161. if (!good)
  1162. throw new ConvOverflowException("Conversion negative overflow");
  1163. }
  1164. static if (S.max > T.max)
  1165. {
  1166. // possible overflow
  1167. if (value > T.max)
  1168. throw new ConvOverflowException("Conversion positive overflow");
  1169. }
  1170. return (ref value)@trusted{ return cast(T) value; }(value);
  1171. }
  1172. @safe pure unittest
  1173. {
  1174. dchar a = ' ';
  1175. assert(to!char(a) == ' ');
  1176. a = 300;
  1177. assert(collectException(to!char(a)));
  1178. dchar from0 = 'A';
  1179. char to0 = to!char(from0);
  1180. wchar from1 = 'A';
  1181. char to1 = to!char(from1);
  1182. char from2 = 'A';
  1183. char to2 = to!char(from2);
  1184. char from3 = 'A';
  1185. wchar to3 = to!wchar(from3);
  1186. char from4 = 'A';
  1187. dchar to4 = to!dchar(from4);
  1188. }
  1189. unittest
  1190. {
  1191. // Narrowing conversions from enum -> integral should be allowed, but they
  1192. // should throw at runtime if the enum value doesn't fit in the target
  1193. // type.
  1194. enum E1 : ulong { A = 1, B = 1UL<<48, C = 0 }
  1195. assert(to!int(E1.A) == 1);
  1196. assert(to!bool(E1.A) == true);
  1197. assertThrown!ConvOverflowException(to!int(E1.B)); // E1.B overflows int
  1198. assertThrown!ConvOverflowException(to!bool(E1.B)); // E1.B overflows bool
  1199. assert(to!bool(E1.C) == false);
  1200. enum E2 : long { A = -1L<<48, B = -1<<31, C = 1<<31 }
  1201. assertThrown!ConvOverflowException(to!int(E2.A)); // E2.A overflows int
  1202. assertThrown!ConvOverflowException(to!uint(E2.B)); // E2.B overflows uint
  1203. assert(to!int(E2.B) == -1<<31); // but does not overflow int
  1204. assert(to!int(E2.C) == 1<<31); // E2.C does not overflow int
  1205. enum E3 : int { A = -1, B = 1, C = 255, D = 0 }
  1206. assertThrown!ConvOverflowException(to!ubyte(E3.A));
  1207. assertThrown!ConvOverflowException(to!bool(E3.A));
  1208. assert(to!byte(E3.A) == -1);
  1209. assert(to!byte(E3.B) == 1);
  1210. assert(to!ubyte(E3.C) == 255);
  1211. assert(to!bool(E3.B) == true);
  1212. assertThrown!ConvOverflowException(to!byte(E3.C));
  1213. assertThrown!ConvOverflowException(to!bool(E3.C));
  1214. assert(to!bool(E3.D) == false);
  1215. }
  1216. /**
  1217. Array-to-array conversion (except when target is a string type)
  1218. converts each element in turn by using $(D to).
  1219. */
  1220. T toImpl(T, S)(S value)
  1221. if (!isImplicitlyConvertible!(S, T) &&
  1222. !isSomeString!S && isDynamicArray!S &&
  1223. !isExactSomeString!T && isArray!T)
  1224. {
  1225. alias E = typeof(T.init[0]);
  1226. auto w = appender!(E[])();
  1227. w.reserve(value.length);
  1228. foreach (i, ref e; value)
  1229. {
  1230. w.put(to!E(e));
  1231. }
  1232. return w.data;
  1233. }
  1234. @safe pure unittest
  1235. {
  1236. // array to array conversions
  1237. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  1238. uint[] a = ([ 1u, 2, 3 ]).dup;
  1239. auto b = to!(float[])(a);
  1240. assert(b == [ 1.0f, 2, 3 ]);
  1241. //auto c = to!(string[])(b);
  1242. //assert(c[0] == "1" && c[1] == "2" && c[2] == "3");
  1243. immutable(int)[3] d = [ 1, 2, 3 ];
  1244. b = to!(float[])(d);
  1245. assert(b == [ 1.0f, 2, 3 ]);
  1246. uint[][] e = [ a, a ];
  1247. auto f = to!(float[][])(e);
  1248. assert(f[0] == b && f[1] == b);
  1249. // Test for bug 8264
  1250. struct Wrap
  1251. {
  1252. string wrap;
  1253. alias wrap this;
  1254. }
  1255. Wrap[] warr = to!(Wrap[])(["foo", "bar"]); // should work
  1256. }
  1257. /*@safe pure */unittest
  1258. {
  1259. auto b = [ 1.0f, 2, 3 ];
  1260. auto c = to!(string[])(b);
  1261. assert(c[0] == "1" && c[1] == "2" && c[2] == "3");
  1262. }
  1263. /**
  1264. Associative array to associative array conversion converts each key
  1265. and each value in turn.
  1266. */
  1267. T toImpl(T, S)(S value)
  1268. if (isAssociativeArray!S &&
  1269. isAssociativeArray!T && !is(T == enum))
  1270. {
  1271. /* This code is potentially unsafe.
  1272. */
  1273. alias KeyType!T K2;
  1274. alias ValueType!T V2;
  1275. // While we are "building" the AA, we need to unqualify its values, and only re-qualify at the end
  1276. Unqual!V2[K2] result;
  1277. foreach (k1, v1; value)
  1278. {
  1279. // Cast values temporarily to Unqual!V2 to store them to result variable
  1280. result[to!K2(k1)] = cast(Unqual!V2) to!V2(v1);
  1281. }
  1282. // Cast back to original type
  1283. return cast(T)result;
  1284. }
  1285. @safe /*pure */unittest
  1286. {
  1287. // hash to hash conversions
  1288. int[string] a;
  1289. a["0"] = 1;
  1290. a["1"] = 2;
  1291. auto b = to!(double[dstring])(a);
  1292. assert(b["0"d] == 1 && b["1"d] == 2);
  1293. }
  1294. @safe /*pure */unittest // Bugzilla 8705, from doc
  1295. {
  1296. int[string][double[int[]]] a;
  1297. auto b = to!(short[wstring][string[double[]]])(a);
  1298. a = [null:["hello":int.max]];
  1299. assertThrown!ConvOverflowException(to!(short[wstring][string[double[]]])(a));
  1300. }
  1301. version(none) // masked by unexpected linker error in posix platforms
  1302. unittest // Extra cases for AA with qualifiers conversion
  1303. {
  1304. int[][int[]] a;// = [[], []];
  1305. auto b = to!(immutable(short[])[immutable short[]])(a);
  1306. double[dstring][int[long[]]] c;
  1307. auto d = to!(immutable(short[immutable wstring])[immutable string[double[]]])(c);
  1308. }
  1309. private void testIntegralToFloating(Integral, Floating)()
  1310. {
  1311. Integral a = 42;
  1312. auto b = to!Floating(a);
  1313. assert(a == b);
  1314. assert(a == to!Integral(b));
  1315. }
  1316. private void testFloatingToIntegral(Floating, Integral)()
  1317. {
  1318. bool convFails(Source, Target, E)(Source src)
  1319. {
  1320. try
  1321. auto t = to!Target(src);
  1322. catch (E)
  1323. return true;
  1324. return false;
  1325. }
  1326. // convert some value
  1327. Floating a = 4.2e1;
  1328. auto b = to!Integral(a);
  1329. assert(is(typeof(b) == Integral) && b == 42);
  1330. // convert some negative value (if applicable)
  1331. a = -4.2e1;
  1332. static if (Integral.min < 0)
  1333. {
  1334. b = to!Integral(a);
  1335. assert(is(typeof(b) == Integral) && b == -42);
  1336. }
  1337. else
  1338. {
  1339. // no go for unsigned types
  1340. assert(convFails!(Floating, Integral, ConvOverflowException)(a));
  1341. }
  1342. // convert to the smallest integral value
  1343. a = 0.0 + Integral.min;
  1344. static if (Integral.min < 0)
  1345. {
  1346. a = -a; // -Integral.min not representable as an Integral
  1347. assert(convFails!(Floating, Integral, ConvOverflowException)(a)
  1348. || Floating.sizeof <= Integral.sizeof);
  1349. }
  1350. a = 0.0 + Integral.min;
  1351. assert(to!Integral(a) == Integral.min);
  1352. --a; // no more representable as an Integral
  1353. assert(convFails!(Floating, Integral, ConvOverflowException)(a)
  1354. || Floating.sizeof <= Integral.sizeof);
  1355. a = 0.0 + Integral.max;
  1356. // fwritefln(stderr, "%s a=%g, %s conv=%s", Floating.stringof, a,
  1357. // Integral.stringof, to!Integral(a));
  1358. assert(to!Integral(a) == Integral.max || Floating.sizeof <= Integral.sizeof);
  1359. ++a; // no more representable as an Integral
  1360. assert(convFails!(Floating, Integral, ConvOverflowException)(a)
  1361. || Floating.sizeof <= Integral.sizeof);
  1362. // convert a value with a fractional part
  1363. a = 3.14;
  1364. assert(to!Integral(a) == 3);
  1365. a = 3.99;
  1366. assert(to!Integral(a) == 3);
  1367. static if (Integral.min < 0)
  1368. {
  1369. a = -3.14;
  1370. assert(to!Integral(a) == -3);
  1371. a = -3.99;
  1372. assert(to!Integral(a) == -3);
  1373. }
  1374. }
  1375. @safe pure unittest
  1376. {
  1377. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  1378. alias AllInts = TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong);
  1379. alias AllFloats = TypeTuple!(float, double, real);
  1380. alias AllNumerics = TypeTuple!(AllInts, AllFloats);
  1381. // test with same type
  1382. {
  1383. foreach (T; AllNumerics)
  1384. {
  1385. T a = 42;
  1386. auto b = to!T(a);
  1387. assert(is(typeof(a) == typeof(b)) && a == b);
  1388. }
  1389. }
  1390. // test that floating-point numbers convert properly to largest ints
  1391. // see http://oregonstate.edu/~peterseb/mth351/docs/351s2001_fp80x87.html
  1392. // look for "largest fp integer with a predecessor"
  1393. {
  1394. // float
  1395. int a = 16_777_215; // 2^24 - 1
  1396. assert(to!int(to!float(a)) == a);
  1397. assert(to!int(to!float(-a)) == -a);
  1398. // double
  1399. long b = 9_007_199_254_740_991; // 2^53 - 1
  1400. assert(to!long(to!double(b)) == b);
  1401. assert(to!long(to!double(-b)) == -b);
  1402. // real
  1403. // @@@ BUG IN COMPILER @@@
  1404. // ulong c = 18_446_744_073_709_551_615UL; // 2^64 - 1
  1405. // assert(to!ulong(to!real(c)) == c);
  1406. // assert(to!ulong(-to!real(c)) == c);
  1407. }
  1408. // test conversions floating => integral
  1409. {
  1410. // AllInts[0 .. $ - 1] should be AllInts
  1411. // @@@ BUG IN COMPILER @@@
  1412. foreach (Integral; AllInts[0 .. $ - 1])
  1413. {
  1414. foreach (Floating; AllFloats)
  1415. {
  1416. testFloatingToIntegral!(Floating, Integral)();
  1417. }
  1418. }
  1419. }
  1420. // test conversion integral => floating
  1421. {
  1422. foreach (Integral; AllInts[0 .. $ - 1])
  1423. {
  1424. foreach (Floating; AllFloats)
  1425. {
  1426. testIntegralToFloating!(Integral, Floating)();
  1427. }
  1428. }
  1429. }
  1430. // test parsing
  1431. {
  1432. foreach (T; AllNumerics)
  1433. {
  1434. // from type immutable(char)[2]
  1435. auto a = to!T("42");
  1436. assert(a == 42);
  1437. // from type char[]
  1438. char[] s1 = "42".dup;
  1439. a = to!T(s1);
  1440. assert(a == 42);
  1441. // from type char[2]
  1442. char[2] s2;
  1443. s2[] = "42";
  1444. a = to!T(s2);
  1445. assert(a == 42);
  1446. // from type immutable(wchar)[2]
  1447. a = to!T("42"w);
  1448. assert(a == 42);
  1449. }
  1450. }
  1451. }
  1452. /*@safe pure */unittest
  1453. {
  1454. alias AllInts = TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong);
  1455. alias AllFloats = TypeTuple!(float, double, real);
  1456. alias AllNumerics = TypeTuple!(AllInts, AllFloats);
  1457. // test conversions to string
  1458. {
  1459. foreach (T; AllNumerics)
  1460. {
  1461. T a = 42;
  1462. assert(to!string(a) == "42");
  1463. //assert(to!wstring(a) == "42"w);
  1464. //assert(to!dstring(a) == "42"d);
  1465. // array test
  1466. // T[] b = new T[2];
  1467. // b[0] = 42;
  1468. // b[1] = 33;
  1469. // assert(to!string(b) == "[42,33]");
  1470. }
  1471. }
  1472. // test array to string conversion
  1473. foreach (T ; AllNumerics)
  1474. {
  1475. auto a = [to!T(1), 2, 3];
  1476. assert(to!string(a) == "[1, 2, 3]");
  1477. }
  1478. // test enum to int conversion
  1479. // enum Testing { Test1, Test2 };
  1480. // Testing t;
  1481. // auto a = to!string(t);
  1482. // assert(a == "0");
  1483. }
  1484. /**
  1485. String to non-string conversion runs parsing.
  1486. $(UL
  1487. $(LI When the source is a wide string, it is first converted to a narrow
  1488. string and then parsed.)
  1489. $(LI When the source is a narrow string, normal text parsing occurs.))
  1490. */
  1491. T toImpl(T, S)(S value)
  1492. if ( isExactSomeString!S && isDynamicArray!S &&
  1493. !isExactSomeString!T && is(typeof(parse!T(value))))
  1494. {
  1495. scope(success)
  1496. {
  1497. if (value.length)
  1498. {
  1499. throw convError!(S, T)(value);
  1500. }
  1501. }
  1502. return parse!T(value);
  1503. }
  1504. /// ditto
  1505. T toImpl(T, S)(S value, uint radix)
  1506. if ( isExactSomeString!S && isDynamicArray!S &&
  1507. !isExactSomeString!T && is(typeof(parse!T(value, radix))))
  1508. {
  1509. scope(success)
  1510. {
  1511. if (value.length)
  1512. {
  1513. throw convError!(S, T)(value);
  1514. }
  1515. }
  1516. return parse!T(value, radix);
  1517. }
  1518. @safe pure unittest
  1519. {
  1520. // Issue 6668 - ensure no collaterals thrown
  1521. try { to!uint("-1"); }
  1522. catch (ConvException e) { assert(e.next is null); }
  1523. }
  1524. @safe pure unittest
  1525. {
  1526. debug(conv) scope(success) writeln("unittest @", __FILE__, ":", __LINE__, " succeeded.");
  1527. foreach (Str; TypeTuple!(string, wstring, dstring))
  1528. {
  1529. Str a = "123";
  1530. assert(to!int(a) == 123);
  1531. assert(to!double(a) == 123);
  1532. }
  1533. // 6255
  1534. auto n = to!int("FF", 16);
  1535. assert(n == 255);
  1536. }
  1537. /**
  1538. Convert a value that is implicitly convertible to the enum base type
  1539. into an Enum value. If the value does not match any enum member values
  1540. a ConvException is thrown.
  1541. Enums with floating-point or string base types are not…