// Written in the D programming language. /* Copyright: Copyright The D Language Foundation 2000-2013. License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP walterbright.com, Walter Bright), $(HTTP erdani.com, Andrei Alexandrescu), and Kenji Hara Source: $(PHOBOSSRC std/format/internal/write.d) */module std.format.internal.write; import std.format.spec : FormatSpec;import std.range.primitives : isInputRange;import std.traits; version (StdUnittest){ import std.exception : assertCTFEable; import std.format : format;} package(std.format): /* `bool`s are formatted as `"true"` or `"false"` with `%s` and as `1` or `0` with integral-specific format specs. */void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f)if (is(BooleanTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)){ BooleanTypeOf!T val = obj; if (f.spec == 's') writeAligned(w, val ? "true" : "false", f); else formatValueImpl(w, cast(byte) val, f);} @safe pure unittest{ assertCTFEable!( { formatTest(false, "false"); formatTest(true, "true"); });} @safe unittest{ struct S1 { bool val; alias val this; } struct S2 { bool val; alias val this; string toString() const { return "S"; } } formatTest(S1(false), "false"); formatTest(S1(true), "true"); formatTest(S2(false), "S"); formatTest(S2(true), "S");} @safe pure unittest{ string t1 = format("[%6s] [%6s] [%-6s]", true, false, true); assert(t1 == "[ true] [ false] [true ]"); string t2 = format("[%3s] [%-2s]", true, false); assert(t2 == "[true] [false]");} // https://issues.dlang.org/show_bug.cgi?id=20534@safe pure unittest{ assert(format("%r",false) == "\0");} @safe pure unittest{ assert(format("%07s",true) == " true");} @safe pure unittest{ assert(format("%=8s",true) == " true "); assert(format("%=9s",false) == " false "); assert(format("%=9s",true) == " true "); assert(format("%-=9s",true) == " true "); assert(format("%=10s",false) == " false "); assert(format("%-=10s",false) == " false ");} /* `null` literal is formatted as `"null"` */void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f)if (is(immutable T == immutable typeof(null)) && !is(T == enum) && !hasToString!(T, Char)){ import std.format : enforceFmt; const spec = f.spec; enforceFmt(spec == 's', "null literal cannot match %" ~ spec); writeAligned(w, "null", f);} @safe pure unittest{ import std.exception : collectExceptionMsg; import std.format : FormatException; import std.range.primitives : back; assert(collectExceptionMsg!FormatException(format("%p", null)).back == 'p'); assertCTFEable!( { formatTest(null, "null"); });} @safe pure unittest{ string t = format("[%6s] [%-6s]", null, null); assert(t == "[ null] [null ]");} /* Integrals are formatted like $(REF printf, core, stdc, stdio). */void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f)if (is(IntegralTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)){ alias U = IntegralTypeOf!T; U val = obj; // Extracting alias this may be impure/system/may-throw if (f.spec == 'r') { // raw write, skip all else and write the thing auto raw = (ref val) @trusted { return (cast(const char*) &val)[0 .. val.sizeof]; }(val); import std.range.primitives : put; if (needToSwapEndianess(f)) foreach_reverse (c; raw) put(w, c); else foreach (c; raw) put(w, c); return; } static if (isSigned!U) { const negative = val < 0 && f.spec != 'x' && f.spec != 'X' && f.spec != 'b' && f.spec != 'o' && f.spec != 'u'; ulong arg = negative ? -cast(ulong) val : val; } else { const negative = false; ulong arg = val; } arg &= Unsigned!U.max; formatValueImplUlong!(Writer, Char)(w, arg, negative, f);} // Helper function for `formatValueImpl` that avoids template bloatprivate void formatValueImplUlong(Writer, Char)(auto ref Writer w, ulong arg, in bool negative, scope const ref FormatSpec!Char f){ immutable uint base = baseOfSpec(f.spec); const bool zero = arg == 0; char[64] digits = void; size_t pos = digits.length - 1; do { /* `cast(char)` is needed because value range propagation (VRP) cannot * analyze `base` because it’s computed in a separate function * (`baseOfSpec`). */ digits[pos--] = cast(char) ('0' + arg % base); if (base > 10 && digits[pos + 1] > '9') digits[pos + 1] += ((f.spec == 'x' || f.spec == 'a') ? 'a' : 'A') - '0' - 10; arg /= base; } while (arg > 0); char[3] prefix = void; size_t left = 2; size_t right = 2; // add sign if (f.spec != 'x' && f.spec != 'X' && f.spec != 'b' && f.spec != 'o' && f.spec != 'u') { if (negative) prefix[right++] = '-'; else if (f.flPlus) prefix[right++] = '+'; else if (f.flSpace) prefix[right++] = ' '; } // not a floating point like spec if (f.spec == 'x' || f.spec == 'X' || f.spec == 'b' || f.spec == 'o' || f.spec == 'u' || f.spec == 'd' || f.spec == 's') { if (f.flHash && (base == 16) && !zero) { prefix[--left] = f.spec; prefix[--left] = '0'; } if (f.flHash && (base == 8) && !zero && (digits.length - (pos + 1) >= f.precision || f.precision == f.UNSPECIFIED)) prefix[--left] = '0'; writeAligned(w, prefix[left .. right], digits[pos + 1 .. $], "", f, true); return; } FormatSpec!Char fs = f; if (f.precision == f.UNSPECIFIED) fs.precision = cast(typeof(fs.precision)) (digits.length - pos - 2); // %f like output if (f.spec == 'f' || f.spec == 'F' || ((f.spec == 'g' || f.spec == 'G') && (fs.precision >= digits.length - pos - 2))) { if (f.precision == f.UNSPECIFIED) fs.precision = 0; writeAligned(w, prefix[left .. right], digits[pos + 1 .. $], ".", "", fs, (f.spec == 'g' || f.spec == 'G') ? PrecisionType.allDigits : PrecisionType.fractionalDigits); return; } import std.algorithm.searching : all; // at least one digit for %g if ((f.spec == 'g' || f.spec == 'G') && fs.precision == 0) fs.precision = 1; // rounding size_t digit_end = pos + fs.precision + ((f.spec == 'g' || f.spec == 'G') ? 1 : 2); if (digit_end <= digits.length) { RoundingClass rt = RoundingClass.ZERO; if (digit_end < digits.length) { auto tie = (f.spec == 'a' || f.spec == 'A') ? '8' : '5'; if (digits[digit_end] >= tie) { rt = RoundingClass.UPPER; if (digits[digit_end] == tie && digits[digit_end + 1 .. $].all!(a => a == '0')) rt = RoundingClass.FIVE; } else { rt = RoundingClass.LOWER; if (digits[digit_end .. $].all!(a => a == '0')) rt = RoundingClass.ZERO; } } if (round(digits, pos + 1, digit_end, rt, negative, f.spec == 'a' ? 'f' : (f.spec == 'A' ? 'F' : '9'))) { pos--; digit_end--; } } // convert to scientific notation char[1] int_digit = void; int_digit[0] = digits[pos + 1]; digits[pos + 1] = '.'; char[4] suffix = void; if (f.spec == 'e' || f.spec == 'E' || f.spec == 'g' || f.spec == 'G') { suffix[0] = (f.spec == 'e' || f.spec == 'g') ? 'e' : 'E'; suffix[1] = '+'; suffix[2] = cast(char) ('0' + (digits.length - pos - 2) / 10); suffix[3] = cast(char) ('0' + (digits.length - pos - 2) % 10); } else { if (right == 3) prefix[0] = prefix[2]; prefix[1] = '0'; prefix[2] = f.spec == 'a' ? 'x' : 'X'; left = right == 3 ? 0 : 1; right = 3; suffix[0] = f.spec == 'a' ? 'p' : 'P'; suffix[1] = '+'; suffix[2] = cast(char) ('0' + ((digits.length - pos - 2) * 4) / 10); suffix[3] = cast(char) ('0' + ((digits.length - pos - 2) * 4) % 10); } import std.algorithm.comparison : min; // remove trailing zeros if ((f.spec == 'g' || f.spec == 'G') && !f.flHash) { digit_end = min(digit_end, digits.length); while (digit_end > pos + 1 && (digits[digit_end - 1] == '0' || digits[digit_end - 1] == '.')) digit_end--; } writeAligned(w, prefix[left .. right], int_digit[0 .. $], digits[pos + 1 .. min(digit_end, $)], suffix[0 .. $], fs, (f.spec == 'g' || f.spec == 'G') ? PrecisionType.allDigits : PrecisionType.fractionalDigits);} private uint baseOfSpec(in char spec) @safe pure{ typeof(return) base = spec == 'x' || spec == 'X' || spec == 'a' || spec == 'A' ? 16 : spec == 'o' ? 8 : spec == 'b' ? 2 : spec == 's' || spec == 'd' || spec == 'u' || spec == 'e' || spec == 'E' || spec == 'f' || spec == 'F' || spec == 'g' || spec == 'G' ? 10 : 0; import std.format : enforceFmt; enforceFmt(base > 0, "incompatible format character for integral argument: %" ~ spec); return base;} @safe pure unittest{ assertCTFEable!( { formatTest(byte.min, "-128"); formatTest(byte.max, "127"); formatTest(short.min, "-32768"); formatTest(short.max, "32767"); formatTest(int.min, "-2147483648"); formatTest(int.max, "2147483647"); formatTest(long.min, "-9223372036854775808"); formatTest(long.max, "9223372036854775807"); formatTest(ubyte.min, "0"); formatTest(ubyte.max, "255"); formatTest(ushort.min, "0"); formatTest(ushort.max, "65535"); formatTest(uint.min, "0"); formatTest(uint.max, "4294967295"); formatTest(ulong.min, "0"); formatTest(ulong.max, "18446744073709551615"); });} // https://issues.dlang.org/show_bug.cgi?id=18838@safe pure unittest{ assert("%12,d".format(0) == " 0");} @safe pure unittest{ import std.exception : collectExceptionMsg; import std.format : FormatException; import std.range.primitives : back; assert(collectExceptionMsg!FormatException(format("%c", 5)).back == 'c'); assertCTFEable!( { formatTest(9, "9"); formatTest(10, "10"); });} @safe unittest{ struct S1 { long val; alias val this; } struct S2 { long val; alias val this; string toString() const { return "S"; } } formatTest(S1(10), "10"); formatTest(S2(10), "S");} // https://issues.dlang.org/show_bug.cgi?id=20064@safe unittest{ assert(format( "%03,d", 1234) == "1,234"); assert(format( "%04,d", 1234) == "1,234"); assert(format( "%05,d", 1234) == "1,234"); assert(format( "%06,d", 1234) == "01,234"); assert(format( "%07,d", 1234) == "001,234"); assert(format( "%08,d", 1234) == "0,001,234"); assert(format( "%09,d", 1234) == "0,001,234"); assert(format("%010,d", 1234) == "00,001,234"); assert(format("%011,d", 1234) == "000,001,234"); assert(format("%012,d", 1234) == "0,000,001,234"); assert(format("%013,d", 1234) == "0,000,001,234"); assert(format("%014,d", 1234) == "00,000,001,234"); assert(format("%015,d", 1234) == "000,000,001,234"); assert(format("%016,d", 1234) == "0,000,000,001,234"); assert(format("%017,d", 1234) == "0,000,000,001,234"); assert(format( "%03,d", -1234) == "-1,234"); assert(format( "%04,d", -1234) == "-1,234"); assert(format( "%05,d", -1234) == "-1,234"); assert(format( "%06,d", -1234) == "-1,234"); assert(format( "%07,d", -1234) == "-01,234"); assert(format( "%08,d", -1234) == "-001,234"); assert(format( "%09,d", -1234) == "-0,001,234"); assert(format("%010,d", -1234) == "-0,001,234"); assert(format("%011,d", -1234) == "-00,001,234"); assert(format("%012,d", -1234) == "-000,001,234"); assert(format("%013,d", -1234) == "-0,000,001,234"); assert(format("%014,d", -1234) == "-0,000,001,234"); assert(format("%015,d", -1234) == "-00,000,001,234"); assert(format("%016,d", -1234) == "-000,000,001,234"); assert(format("%017,d", -1234) == "-0,000,000,001,234");} @safe pure unittest{ string t1 = format("[%6s] [%-6s]", 123, 123); assert(t1 == "[ 123] [123 ]"); string t2 = format("[%6s] [%-6s]", -123, -123); assert(t2 == "[ -123] [-123 ]");} @safe pure unittest{ formatTest(byte.min, "-128"); formatTest(short.min, "-32768"); formatTest(int.min, "-2147483648"); formatTest(long.min, "-9223372036854775808");} // https://issues.dlang.org/show_bug.cgi?id=21777@safe pure unittest{ assert(format!"%20.5,d"(cast(short) 120) == " 00,120"); assert(format!"%20.5,o"(cast(short) 120) == " 00,170"); assert(format!"%20.5,x"(cast(short) 120) == " 00,078"); assert(format!"%20.5,2d"(cast(short) 120) == " 0,01,20"); assert(format!"%20.5,2o"(cast(short) 120) == " 0,01,70"); assert(format!"%20.5,4d"(cast(short) 120) == " 0,0120"); assert(format!"%20.5,4o"(cast(short) 120) == " 0,0170"); assert(format!"%20.5,4x"(cast(short) 120) == " 0,0078"); assert(format!"%20.5,2x"(3000) == " 0,0b,b8"); assert(format!"%20.5,4d"(3000) == " 0,3000"); assert(format!"%20.5,4o"(3000) == " 0,5670"); assert(format!"%20.5,4x"(3000) == " 0,0bb8"); assert(format!"%20.5,d"(-400) == " -00,400"); assert(format!"%20.30d"(-400) == "-000000000000000000000000000400"); assert(format!"%20.5,4d"(0) == " 0,0000"); assert(format!"%0#.8,2s"(12345) == "00,01,23,45"); assert(format!"%0#.9,3x"(55) == "0x000,000,037");} // https://issues.dlang.org/show_bug.cgi?id=21814@safe pure unittest{ assert(format("%,0d",1000) == "1000");} // https://issues.dlang.org/show_bug.cgi?id=21817@safe pure unittest{ assert(format!"%u"(-5) == "4294967291");} // https://issues.dlang.org/show_bug.cgi?id=21820@safe pure unittest{ assert(format!"%#.0o"(0) == "0");Lines 1–500 of 3994. Load more
// Written in the D programming language. /* Copyright: Copyright The D Language Foundation 2000-2013. License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). Authors: $(HTTP walterbright.com, Walter Bright), $(HTTP erdani.com, Andrei Alexandrescu), and Kenji Hara Source: $(PHOBOSSRC std/format/internal/write.d) */ module std.format.internal.write; import std.format.spec : FormatSpec; import std.range.primitives : isInputRange; import std.traits; version (StdUnittest) { import std.exception : assertCTFEable; import std.format : format; } package(std.format): /* `bool`s are formatted as `"true"` or `"false"` with `%s` and as `1` or `0` with integral-specific format specs. */ void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f) if (is(BooleanTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { BooleanTypeOf!T val = obj; if (f.spec == 's') writeAligned(w, val ? "true" : "false", f); else formatValueImpl(w, cast(byte) val, f); } @safe pure unittest { assertCTFEable!( { formatTest(false, "false"); formatTest(true, "true"); }); } @safe unittest { struct S1 { bool val; alias val this; } struct S2 { bool val; alias val this; string toString() const { return "S"; } } formatTest(S1(false), "false"); formatTest(S1(true), "true"); formatTest(S2(false), "S"); formatTest(S2(true), "S"); } @safe pure unittest { string t1 = format("[%6s] [%6s] [%-6s]", true, false, true); assert(t1 == "[ true] [ false] [true ]"); string t2 = format("[%3s] [%-2s]", true, false); assert(t2 == "[true] [false]"); } // https://issues.dlang.org/show_bug.cgi?id=20534 @safe pure unittest { assert(format("%r",false) == "\0"); } @safe pure unittest { assert(format("%07s",true) == " true"); } @safe pure unittest { assert(format("%=8s",true) == " true "); assert(format("%=9s",false) == " false "); assert(format("%=9s",true) == " true "); assert(format("%-=9s",true) == " true "); assert(format("%=10s",false) == " false "); assert(format("%-=10s",false) == " false "); } /* `null` literal is formatted as `"null"` */ void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f) if (is(immutable T == immutable typeof(null)) && !is(T == enum) && !hasToString!(T, Char)) { import std.format : enforceFmt; const spec = f.spec; enforceFmt(spec == 's', "null literal cannot match %" ~ spec); writeAligned(w, "null", f); } @safe pure unittest { import std.exception : collectExceptionMsg; import std.format : FormatException; import std.range.primitives : back; assert(collectExceptionMsg!FormatException(format("%p", null)).back == 'p'); assertCTFEable!( { formatTest(null, "null"); }); } @safe pure unittest { string t = format("[%6s] [%-6s]", null, null); assert(t == "[ null] [null ]"); } /* Integrals are formatted like $(REF printf, core, stdc, stdio). */ void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f) if (is(IntegralTypeOf!T) && !is(T == enum) && !hasToString!(T, Char)) { alias U = IntegralTypeOf!T; U val = obj; // Extracting alias this may be impure/system/may-throw if (f.spec == 'r') { // raw write, skip all else and write the thing auto raw = (ref val) @trusted { return (cast(const char*) &val)[0 .. val.sizeof]; }(val); import std.range.primitives : put; if (needToSwapEndianess(f)) foreach_reverse (c; raw) put(w, c); else foreach (c; raw) put(w, c); return; } static if (isSigned!U) { const negative = val < 0 && f.spec != 'x' && f.spec != 'X' && f.spec != 'b' && f.spec != 'o' && f.spec != 'u'; ulong arg = negative ? -cast(ulong) val : val; } else { const negative = false; ulong arg = val; } arg &= Unsigned!U.max; formatValueImplUlong!(Writer, Char)(w, arg, negative, f); } // Helper function for `formatValueImpl` that avoids template bloat private void formatValueImplUlong(Writer, Char)(auto ref Writer w, ulong arg, in bool negative, scope const ref FormatSpec!Char f) { immutable uint base = baseOfSpec(f.spec); const bool zero = arg == 0; char[64] digits = void; size_t pos = digits.length - 1; do { /* `cast(char)` is needed because value range propagation (VRP) cannot * analyze `base` because it’s computed in a separate function * (`baseOfSpec`). */ digits[pos--] = cast(char) ('0' + arg % base); if (base > 10 && digits[pos + 1] > '9') digits[pos + 1] += ((f.spec == 'x' || f.spec == 'a') ? 'a' : 'A') - '0' - 10; arg /= base; } while (arg > 0); char[3] prefix = void; size_t left = 2; size_t right = 2; // add sign if (f.spec != 'x' && f.spec != 'X' && f.spec != 'b' && f.spec != 'o' && f.spec != 'u') { if (negative) prefix[right++] = '-'; else if (f.flPlus) prefix[right++] = '+'; else if (f.flSpace) prefix[right++] = ' '; } // not a floating point like spec if (f.spec == 'x' || f.spec == 'X' || f.spec == 'b' || f.spec == 'o' || f.spec == 'u' || f.spec == 'd' || f.spec == 's') { if (f.flHash && (base == 16) && !zero) { prefix[--left] = f.spec; prefix[--left] = '0'; } if (f.flHash && (base == 8) && !zero && (digits.length - (pos + 1) >= f.precision || f.precision == f.UNSPECIFIED)) prefix[--left] = '0'; writeAligned(w, prefix[left .. right], digits[pos + 1 .. $], "", f, true); return; } FormatSpec!Char fs = f; if (f.precision == f.UNSPECIFIED) fs.precision = cast(typeof(fs.precision)) (digits.length - pos - 2); // %f like output if (f.spec == 'f' || f.spec == 'F' || ((f.spec == 'g' || f.spec == 'G') && (fs.precision >= digits.length - pos - 2))) { if (f.precision == f.UNSPECIFIED) fs.precision = 0; writeAligned(w, prefix[left .. right], digits[pos + 1 .. $], ".", "", fs, (f.spec == 'g' || f.spec == 'G') ? PrecisionType.allDigits : PrecisionType.fractionalDigits); return; } import std.algorithm.searching : all; // at least one digit for %g if ((f.spec == 'g' || f.spec == 'G') && fs.precision == 0) fs.precision = 1; // rounding size_t digit_end = pos + fs.precision + ((f.spec == 'g' || f.spec == 'G') ? 1 : 2); if (digit_end <= digits.length) { RoundingClass rt = RoundingClass.ZERO; if (digit_end < digits.length) { auto tie = (f.spec == 'a' || f.spec == 'A') ? '8' : '5'; if (digits[digit_end] >= tie) { rt = RoundingClass.UPPER; if (digits[digit_end] == tie && digits[digit_end + 1 .. $].all!(a => a == '0')) rt = RoundingClass.FIVE; } else { rt = RoundingClass.LOWER; if (digits[digit_end .. $].all!(a => a == '0')) rt = RoundingClass.ZERO; } } if (round(digits, pos + 1, digit_end, rt, negative, f.spec == 'a' ? 'f' : (f.spec == 'A' ? 'F' : '9'))) { pos--; digit_end--; } } // convert to scientific notation char[1] int_digit = void; int_digit[0] = digits[pos + 1]; digits[pos + 1] = '.'; char[4] suffix = void; if (f.spec == 'e' || f.spec == 'E' || f.spec == 'g' || f.spec == 'G') { suffix[0] = (f.spec == 'e' || f.spec == 'g') ? 'e' : 'E'; suffix[1] = '+'; suffix[2] = cast(char) ('0' + (digits.length - pos - 2) / 10); suffix[3] = cast(char) ('0' + (digits.length - pos - 2) % 10); } else { if (right == 3) prefix[0] = prefix[2]; prefix[1] = '0'; prefix[2] = f.spec == 'a' ? 'x' : 'X'; left = right == 3 ? 0 : 1; right = 3; suffix[0] = f.spec == 'a' ? 'p' : 'P'; suffix[1] = '+'; suffix[2] = cast(char) ('0' + ((digits.length - pos - 2) * 4) / 10); suffix[3] = cast(char) ('0' + ((digits.length - pos - 2) * 4) % 10); } import std.algorithm.comparison : min; // remove trailing zeros if ((f.spec == 'g' || f.spec == 'G') && !f.flHash) { digit_end = min(digit_end, digits.length); while (digit_end > pos + 1 && (digits[digit_end - 1] == '0' || digits[digit_end - 1] == '.')) digit_end--; } writeAligned(w, prefix[left .. right], int_digit[0 .. $], digits[pos + 1 .. min(digit_end, $)], suffix[0 .. $], fs, (f.spec == 'g' || f.spec == 'G') ? PrecisionType.allDigits : PrecisionType.fractionalDigits); } private uint baseOfSpec(in char spec) @safe pure { typeof(return) base = spec == 'x' || spec == 'X' || spec == 'a' || spec == 'A' ? 16 : spec == 'o' ? 8 : spec == 'b' ? 2 : spec == 's' || spec == 'd' || spec == 'u' || spec == 'e' || spec == 'E' || spec == 'f' || spec == 'F' || spec == 'g' || spec == 'G' ? 10 : 0; import std.format : enforceFmt; enforceFmt(base > 0, "incompatible format character for integral argument: %" ~ spec); return base; } @safe pure unittest { assertCTFEable!( { formatTest(byte.min, "-128"); formatTest(byte.max, "127"); formatTest(short.min, "-32768"); formatTest(short.max, "32767"); formatTest(int.min, "-2147483648"); formatTest(int.max, "2147483647"); formatTest(long.min, "-9223372036854775808"); formatTest(long.max, "9223372036854775807"); formatTest(ubyte.min, "0"); formatTest(ubyte.max, "255"); formatTest(ushort.min, "0"); formatTest(ushort.max, "65535"); formatTest(uint.min, "0"); formatTest(uint.max, "4294967295"); formatTest(ulong.min, "0"); formatTest(ulong.max, "18446744073709551615"); }); } // https://issues.dlang.org/show_bug.cgi?id=18838 @safe pure unittest { assert("%12,d".format(0) == " 0"); } @safe pure unittest { import std.exception : collectExceptionMsg; import std.format : FormatException; import std.range.primitives : back; assert(collectExceptionMsg!FormatException(format("%c", 5)).back == 'c'); assertCTFEable!( { formatTest(9, "9"); formatTest(10, "10"); }); } @safe unittest { struct S1 { long val; alias val this; } struct S2 { long val; alias val this; string toString() const { return "S"; } } formatTest(S1(10), "10"); formatTest(S2(10), "S"); } // https://issues.dlang.org/show_bug.cgi?id=20064 @safe unittest { assert(format( "%03,d", 1234) == "1,234"); assert(format( "%04,d", 1234) == "1,234"); assert(format( "%05,d", 1234) == "1,234"); assert(format( "%06,d", 1234) == "01,234"); assert(format( "%07,d", 1234) == "001,234"); assert(format( "%08,d", 1234) == "0,001,234"); assert(format( "%09,d", 1234) == "0,001,234"); assert(format("%010,d", 1234) == "00,001,234"); assert(format("%011,d", 1234) == "000,001,234"); assert(format("%012,d", 1234) == "0,000,001,234"); assert(format("%013,d", 1234) == "0,000,001,234"); assert(format("%014,d", 1234) == "00,000,001,234"); assert(format("%015,d", 1234) == "000,000,001,234"); assert(format("%016,d", 1234) == "0,000,000,001,234"); assert(format("%017,d", 1234) == "0,000,000,001,234"); assert(format( "%03,d", -1234) == "-1,234"); assert(format( "%04,d", -1234) == "-1,234"); assert(format( "%05,d", -1234) == "-1,234"); assert(format( "%06,d", -1234) == "-1,234"); assert(format( "%07,d", -1234) == "-01,234"); assert(format( "%08,d", -1234) == "-001,234"); assert(format( "%09,d", -1234) == "-0,001,234"); assert(format("%010,d", -1234) == "-0,001,234"); assert(format("%011,d", -1234) == "-00,001,234"); assert(format("%012,d", -1234) == "-000,001,234"); assert(format("%013,d", -1234) == "-0,000,001,234"); assert(format("%014,d", -1234) == "-0,000,001,234"); assert(format("%015,d", -1234) == "-00,000,001,234"); assert(format("%016,d", -1234) == "-000,000,001,234"); assert(format("%017,d", -1234) == "-0,000,000,001,234"); } @safe pure unittest { string t1 = format("[%6s] [%-6s]", 123, 123); assert(t1 == "[ 123] [123 ]"); string t2 = format("[%6s] [%-6s]", -123, -123); assert(t2 == "[ -123] [-123 ]"); } @safe pure unittest { formatTest(byte.min, "-128"); formatTest(short.min, "-32768"); formatTest(int.min, "-2147483648"); formatTest(long.min, "-9223372036854775808"); } // https://issues.dlang.org/show_bug.cgi?id=21777 @safe pure unittest { assert(format!"%20.5,d"(cast(short) 120) == " 00,120"); assert(format!"%20.5,o"(cast(short) 120) == " 00,170"); assert(format!"%20.5,x"(cast(short) 120) == " 00,078"); assert(format!"%20.5,2d"(cast(short) 120) == " 0,01,20"); assert(format!"%20.5,2o"(cast(short) 120) == " 0,01,70"); assert(format!"%20.5,4d"(cast(short) 120) == " 0,0120"); assert(format!"%20.5,4o"(cast(short) 120) == " 0,0170"); assert(format!"%20.5,4x"(cast(short) 120) == " 0,0078"); assert(format!"%20.5,2x"(3000) == " 0,0b,b8"); assert(format!"%20.5,4d"(3000) == " 0,3000"); assert(format!"%20.5,4o"(3000) == " 0,5670"); assert(format!"%20.5,4x"(3000) == " 0,0bb8"); assert(format!"%20.5,d"(-400) == " -00,400"); assert(format!"%20.30d"(-400) == "-000000000000000000000000000400"); assert(format!"%20.5,4d"(0) == " 0,0000"); assert(format!"%0#.8,2s"(12345) == "00,01,23,45"); assert(format!"%0#.9,3x"(55) == "0x000,000,037"); } // https://issues.dlang.org/show_bug.cgi?id=21814 @safe pure unittest { assert(format("%,0d",1000) == "1000"); } // https://issues.dlang.org/show_bug.cgi?id=21817 @safe pure unittest { assert(format!"%u"(-5) == "4294967291"); } // https://issues.dlang.org/show_bug.cgi?id=21820 @safe pure unittest { assert(format!"%#.0o"(0) == "0");