Merge pull request #939 from 9rnsr/replace_format

Replacement std.string.format and sformat implementations in November 2012
This commit is contained in:
Andrei Alexandrescu 2012-12-08 19:41:35 -08:00
commit d6100b404f
3 changed files with 150 additions and 189 deletions

View file

@ -33660,7 +33660,7 @@ unittest
this.value = value; this.value = value;
} }
string toString() string toString() const
{ {
return to!string(value); return to!string(value);
} }
@ -33963,7 +33963,7 @@ unittest
return this; return this;
} }
string toString() string toString() const
{ {
return to!string(value); return to!string(value);
} }
@ -33987,7 +33987,7 @@ unittest
return IntWrapper_BadAssign(mixin("old " ~ op ~ " rhs.value")); return IntWrapper_BadAssign(mixin("old " ~ op ~ " rhs.value"));
} }
string toString() string toString() const
{ {
return to!string(value); return to!string(value);
} }
@ -34009,7 +34009,7 @@ unittest
return IntWrapper_BadReturn(rhs.value); return IntWrapper_BadReturn(rhs.value);
} }
string toString() string toString() const
{ {
return to!string(value); return to!string(value);
} }

View file

@ -5454,20 +5454,20 @@ unittest
debug(format) printf("std.format.format.unittest\n"); debug(format) printf("std.format.format.unittest\n");
s = std.string.format("hello world! %s %s ", true, 57, 1_000_000_000, 'x', " foo"); s = std.string.format("hello world! %s %s %s%s%s", true, 57, 1_000_000_000, 'x', " foo");
assert(s == "hello world! true 57 1000000000x foo"); assert(s == "hello world! true 57 1000000000x foo");
s = std.string.format(1.67, " %A ", -1.28, float.nan); s = std.string.format("%s %A %s", 1.67, -1.28, float.nan);
/* The host C library is used to format floats. /* The host C library is used to format floats.
* C99 doesn't specify what the hex digit before the decimal point * C99 doesn't specify what the hex digit before the decimal point
* is for %A. * is for %A.
*/ */
version (linux) //version (linux)
assert(s == "1.67 -0XA.3D70A3D70A3D8P-3 nan"); // assert(s == "1.67 -0XA.3D70A3D70A3D8P-3 nan");
else version (OSX) //else version (OSX)
assert(s == "1.67 -0XA.3D70A3D70A3D8P-3 nan", s); // assert(s == "1.67 -0XA.3D70A3D70A3D8P-3 nan", s);
else //else
assert(s == "1.67 -0X1.47AE147AE147BP+0 nan"); assert(s == "1.67 -0X1.47AE147AE147BP+0 nan", s);
s = std.string.format("%x %X", 0x1234AF, 0xAFAFAFAF); s = std.string.format("%x %X", 0x1234AF, 0xAFAFAFAF);
assert(s == "1234af AFAFAFAF"); assert(s == "1234af AFAFAFAF");
@ -5478,19 +5478,19 @@ unittest
s = std.string.format("%d %s", 0x1234AF, 0xAFAFAFAF); s = std.string.format("%d %s", 0x1234AF, 0xAFAFAFAF);
assert(s == "1193135 2947526575"); assert(s == "1193135 2947526575");
version(X86_64) //version(X86_64)
{ //{
pragma(msg, "several format tests disabled on x86_64 due to bug 5625"); // pragma(msg, "several format tests disabled on x86_64 due to bug 5625");
} //}
else //else
{ //{
s = std.string.format("%s", 1.2 + 3.4i); s = std.string.format("%s", 1.2 + 3.4i);
assert(s == "1.2+3.4i"); assert(s == "1.2+3.4i", s);
s = std.string.format("%x %X", 1.32, 6.78f); //s = std.string.format("%x %X", 1.32, 6.78f);
assert(s == "3ff51eb851eb851f 40D8F5C3"); //assert(s == "3ff51eb851eb851f 40D8F5C3");
} //}
s = std.string.format("%#06.*f",2,12.345); s = std.string.format("%#06.*f",2,12.345);
assert(s == "012.35"); assert(s == "012.35");
@ -5558,63 +5558,57 @@ unittest
arrbyte[0] = 100; arrbyte[0] = 100;
arrbyte[1] = -99; arrbyte[1] = -99;
arrbyte[3] = 0; arrbyte[3] = 0;
r = std.string.format(arrbyte); r = std.string.format("%s", arrbyte);
assert(r == "[100,-99,0,0]"); assert(r == "[100, -99, 0, 0]");
ubyte[] arrubyte = new ubyte[4]; ubyte[] arrubyte = new ubyte[4];
arrubyte[0] = 100; arrubyte[0] = 100;
arrubyte[1] = 200; arrubyte[1] = 200;
arrubyte[3] = 0; arrubyte[3] = 0;
r = std.string.format(arrubyte); r = std.string.format("%s", arrubyte);
assert(r == "[100,200,0,0]"); assert(r == "[100, 200, 0, 0]");
short[] arrshort = new short[4]; short[] arrshort = new short[4];
arrshort[0] = 100; arrshort[0] = 100;
arrshort[1] = -999; arrshort[1] = -999;
arrshort[3] = 0; arrshort[3] = 0;
r = std.string.format(arrshort); r = std.string.format("%s", arrshort);
assert(r == "[100,-999,0,0]"); assert(r == "[100, -999, 0, 0]");
r = std.string.format("%s",arrshort);
assert(r == "[100,-999,0,0]");
ushort[] arrushort = new ushort[4]; ushort[] arrushort = new ushort[4];
arrushort[0] = 100; arrushort[0] = 100;
arrushort[1] = 20_000; arrushort[1] = 20_000;
arrushort[3] = 0; arrushort[3] = 0;
r = std.string.format(arrushort); r = std.string.format("%s", arrushort);
assert(r == "[100,20000,0,0]"); assert(r == "[100, 20000, 0, 0]");
int[] arrint = new int[4]; int[] arrint = new int[4];
arrint[0] = 100; arrint[0] = 100;
arrint[1] = -999; arrint[1] = -999;
arrint[3] = 0; arrint[3] = 0;
r = std.string.format(arrint); r = std.string.format("%s", arrint);
assert(r == "[100,-999,0,0]"); assert(r == "[100, -999, 0, 0]");
r = std.string.format("%s",arrint);
assert(r == "[100,-999,0,0]");
long[] arrlong = new long[4]; long[] arrlong = new long[4];
arrlong[0] = 100; arrlong[0] = 100;
arrlong[1] = -999; arrlong[1] = -999;
arrlong[3] = 0; arrlong[3] = 0;
r = std.string.format(arrlong); r = std.string.format("%s", arrlong);
assert(r == "[100,-999,0,0]"); assert(r == "[100, -999, 0, 0]");
r = std.string.format("%s",arrlong);
assert(r == "[100,-999,0,0]");
ulong[] arrulong = new ulong[4]; ulong[] arrulong = new ulong[4];
arrulong[0] = 100; arrulong[0] = 100;
arrulong[1] = 999; arrulong[1] = 999;
arrulong[3] = 0; arrulong[3] = 0;
r = std.string.format(arrulong); r = std.string.format("%s", arrulong);
assert(r == "[100,999,0,0]"); assert(r == "[100, 999, 0, 0]");
string[] arr2 = new string[4]; string[] arr2 = new string[4];
arr2[0] = "hello"; arr2[0] = "hello";
arr2[1] = "world"; arr2[1] = "world";
arr2[3] = "foo"; arr2[3] = "foo";
r = std.string.format(arr2); r = std.string.format("%s", arr2);
assert(r == "[hello,world,,foo]"); assert(r == `["hello", "world", "", "foo"]`);
r = std.string.format("%.8d", 7); r = std.string.format("%.8d", 7);
assert(r == "00000007"); assert(r == "00000007");
@ -5643,7 +5637,7 @@ unittest
assert(r == "ghi"); assert(r == "ghi");
void* p = cast(void*)0xDEADBEEF; void* p = cast(void*)0xDEADBEEF;
r = std.string.format(p); r = std.string.format("%s", p);
assert(r == "DEADBEEF"); assert(r == "DEADBEEF");
r = std.string.format("%#x", 0xabcd); r = std.string.format("%#x", 0xabcd);
@ -5716,21 +5710,21 @@ unittest
assert(r == "F"); assert(r == "F");
Object c = null; Object c = null;
r = std.string.format(c); r = std.string.format("%s", c);
assert(r == "null"); assert(r == "null");
enum TestEnum enum TestEnum
{ {
Value1, Value2 Value1, Value2
} }
r = std.string.format("%s", TestEnum.Value2); r = std.string.format("%s", TestEnum.Value2);
assert(r == "1"); assert(r == "Value2");
immutable(char[5])[int] aa = ([3:"hello", 4:"betty"]); immutable(char[5])[int] aa = ([3:"hello", 4:"betty"]);
r = std.string.format("%s", aa.values); r = std.string.format("%s", aa.values);
assert(r == "[[h,e,l,l,o],[b,e,t,t,y]]"); assert(r == `["hello", "betty"]`);
r = std.string.format("%s", aa); r = std.string.format("%s", aa);
assert(r == "[3:[h,e,l,l,o],4:[b,e,t,t,y]]"); assert(r == `[3:"hello", 4:"betty"]`);
static const dchar[] ds = ['a','b']; static const dchar[] ds = ['a','b'];
for (int j = 0; j < ds.length; ++j) for (int j = 0; j < ds.length; ++j)
@ -5742,11 +5736,11 @@ unittest
assert(r == " 98"); assert(r == " 98");
} }
r = std.string.format(">%14d<, ", 15, [1,2,3]); r = std.string.format(">%14d<, %s", 15, [1,2,3]);
assert(r == "> 15<, [1,2,3]"); assert(r == "> 15<, [1, 2, 3]");
assert(std.string.format("%8s", "bar") == " bar"); assert(std.string.format("%8s", "bar") == " bar");
assert(std.string.format("%8s", "b\u00e9ll\u00f4") == " b\u00e9ll\u00f4"); assert(std.string.format("%8s", "b\u00e9ll\u00f4") == " b\u00e9ll\u00f4");
} }
unittest unittest

View file

@ -1179,7 +1179,7 @@ deprecated S capwords(S)(S s) if (isSomeString!S)
return cast(S)retval.data; return cast(S)retval.data;
} }
unittest deprecated unittest
{ {
debug(string) printf("string.capwords.unittest\n"); debug(string) printf("string.capwords.unittest\n");
@ -2482,7 +2482,7 @@ unittest
//Explicitly undocumented. Do not use. To be removed in March 2013. //Explicitly undocumented. Do not use. To be removed in March 2013.
deprecated("Please use std.string.makeTrans instead.") alias makeTrans maketrans; deprecated("Please use std.string.makeTrans instead.") alias makeTrans maketrans;
unittest deprecated unittest
{ {
debug(string) printf("string.translate.unittest\n"); debug(string) printf("string.translate.unittest\n");
@ -2501,83 +2501,55 @@ unittest
} }
// @@@BUG@@@ workaround for bugzilla 2479
private string bug2479format(TypeInfo[] arguments, va_list argptr)
{
char[] s;
void putc(dchar c)
{
std.utf.encode(s, c);
}
std.format.doFormat(&putc, arguments, argptr);
return assumeUnique(s);
}
// @@@BUG@@@ workaround for bugzilla 2479
private char[] bug2479sformat(char[] s, TypeInfo[] arguments, va_list argptr)
{
size_t i;
void putc(dchar c)
{
if(std.ascii.isASCII(c))
{
if (i >= s.length)
onRangeError("std.string.sformat", 0);
s[i] = cast(char)c;
++i;
}
else
{ char[4] buf;
auto b = std.utf.toUTF8(buf, c);
if (i + b.length > s.length)
onRangeError("std.string.sformat", 0);
s[i..i+b.length] = b[];
i += b.length;
}
}
std.format.doFormat(&putc, arguments, argptr);
return s[0 .. i];
}
/***************************************************** /*****************************************************
* Format arguments into a string. * Format arguments into a string.
* *
* $(RED format's current implementation is scheduled for replacement in * $(RED format's current implementation has been replaced with $(LREF xformat)'s
* November 2012. It will then be replaced with $(LREF xformat)'s implementation. * implementation. in November 2012.
* This will be seamless for most code, but it will make it so that the * This is seamless for most code, but it makes it so that the only
* only argument that can be a format string is the first one, so any * argument that can be a format string is the first one, so any
* code which uses multiple format strings will break. Please change * code which used multiple format strings has broken. Please change
* your calls to format accordingly. * your calls to format accordingly.
* *
* e.g.: * e.g.:
---- ----
format("key = %s", key, ", value = %s", value) format("key = %s", key, ", value = %s", value)
---- ----
* will need to be rewritten as: * needs to be rewritten as:
---- ----
format("key = %s, value = %s", key, value) format("key = %s, value = %s", key, value)
---- ----
* ) * )
*/ */
string format(Char, Args...)(in Char[] fmt, Args args)
string format(...)
{ {
/+ // @@@BUG@@@ Fails due to regression bug 2479. auto w = appender!string();
char[] s; auto n = formattedWrite(w, fmt, args);
version (all)
void putc(dchar c)
{ {
std.utf.encode(s, c); // In the future, this check will be removed to increase consistency
// with formattedWrite
enforce(n == args.length, new FormatException(
text("Orphan format arguments: args[", n, "..", args.length, "]")));
} }
return w.data;
}
std.format.doFormat(&putc, _arguments, _argptr); unittest
return assumeUnique(s); {
+/ debug(string) printf("std.string.format.unittest\n");
return bug2479format(_arguments, _argptr);
// assert(format(null) == "");
assert(format("foo") == "foo");
assert(format("foo%%") == "foo%");
assert(format("foo%s", 'C') == "fooC");
assert(format("%s foo", "bar") == "bar foo");
assert(format("%s foo %s", "bar", "abc") == "bar foo abc");
assert(format("foo %d", -123) == "foo -123");
assert(format("foo %d", 123) == "foo 123");
assertThrown!FormatError(format("foo %s"));
assertThrown!FormatError(format("foo %s", 123, 456));
} }
@ -2586,103 +2558,97 @@ string format(...)
* enough to hold the result. Throws RangeError if it is not. * enough to hold the result. Throws RangeError if it is not.
* Returns: s * Returns: s
* *
* $(RED sformat's current implementation is scheduled for replacement in * $(RED sformat's current implementation has been replaced with $(LREF xsformat)'s
* November 2012. It will then be replaced with $(LREF xsformat)'s implementation. * implementation. in November 2012.
* This will be seamless for most code, but it will make it so that the * This is seamless for most code, but it makes it so that the only
* only argument that can be a format string is the first one, so any * argument that can be a format string is the first one, so any
* code which uses multiple format strings will break. Please change * code which used multiple format strings has broken. Please change
* your calls to sformat accordingly. * your calls to sformat accordingly.
* *
* e.g.: * e.g.:
---- ----
sformat(buf, "key = %s", key, ", value = %s", value) sformat(buf, "key = %s", key, ", value = %s", value)
---- ----
* will need to be rewritten as: * needs to be rewritten as:
---- ----
sformat(buf, "key = %s, value = %s", key, value) sformat(buf, "key = %s, value = %s", key, value)
---- ----
* ) * )
*/ */
char[] sformat(char[] s, ...) char[] sformat(Char, Args...)(char[] buf, in Char[] fmt, Args args)
{ {
/+ // @@@BUG@@@ Fails due to regression bug 2479. size_t i;
size_t i; struct Sink
void putc(dchar c)
{ {
if(std.ascii.isASCII(c)) void put(dchar c)
{ {
if (i >= s.length) char[4] enc;
onRangeError("std.string.sformat", 0); auto n = encode(enc, c);
s[i] = cast(char)c;
++i;
}
else
{ char[4] buf;
auto b = std.utf.toUTF8(buf, c);
if (i + b.length > s.length)
onRangeError("std.string.sformat", 0);
s[i..i+b.length] = b[];
i += b.length;
}
}
std.format.doFormat(&putc, _arguments, _argptr); if (buf.length < i + n)
return s[0 .. i]; onRangeError("std.string.sformat", 0);
+/
return bug2479sformat(s, _arguments, _argptr); buf[i .. i + n] = enc[0 .. n];
i += n;
}
void put(const(char)[] s)
{
if (buf.length < i + s.length)
onRangeError("std.string.sformat", 0);
buf[i .. i + s.length] = s[];
i += s.length;
}
void put(const(wchar)[] s)
{
for (; !s.empty; s.popFront())
put(s.front);
}
void put(const(dchar)[] s)
{
for (; !s.empty; s.popFront())
put(s.front);
}
}
auto n = formattedWrite(Sink(), fmt, args);
version (all)
{
// In the future, this check will be removed to increase consistency
// with formattedWrite
enforce(n == args.length, new FormatException(
text("Orphan format arguments: args[", n, "..", args.length, "]")));
}
return buf[0 .. i];
} }
unittest unittest
{ {
debug(string) printf("std.string.format.unittest\n"); debug(string) printf("std.string.sformat.unittest\n");
string r; char[10] buf;
int i;
/+
r = format(null);
i = cmp(r, "");
assert(i == 0);
+/
r = format("foo");
i = cmp(r, "foo");
assert(i == 0);
r = format("foo%%"); assert(sformat(buf[], "foo") == "foo");
i = cmp(r, "foo%"); assert(sformat(buf[], "foo%%") == "foo%");
assert(i == 0); assert(sformat(buf[], "foo%s", 'C') == "fooC");
assert(sformat(buf[], "%s foo", "bar") == "bar foo");
assertThrown!RangeError(sformat(buf[], "%s foo %s", "bar", "abc"));
assert(sformat(buf[], "foo %d", -123) == "foo -123");
assert(sformat(buf[], "foo %d", 123) == "foo 123");
r = format("foo%s", 'C'); assertThrown!FormatError(sformat(buf[], "foo %s"));
i = cmp(r, "fooC"); assertThrown!FormatError(sformat(buf[], "foo %s", 123, 456));
assert(i == 0);
r = format("%s foo", "bar"); assert(sformat(buf[], "%s %s %s", "c"c, "w"w, "d"d) == "c w d");
i = cmp(r, "bar foo");
assert(i == 0);
r = format("%s foo %s", "bar", "abc");
i = cmp(r, "bar foo abc");
assert(i == 0);
r = format("foo %d", -123);
i = cmp(r, "foo -123");
assert(i == 0);
r = format("foo %d", 123);
i = cmp(r, "foo 123");
assert(i == 0);
} }
/***************************************************** /*****************************************************
* Format arguments into a string. * Format arguments into a string.
* *
* xformat is a version of $(LREF format) whose behavior matches that of * $(LREF format) has been changed to use this implementation in November 2012.
* $(XREF stdio, writef). $(LREF format) will be changed to use this * Then xformat has been scheduled for deprecation at the same time.
* implementation in November 2012. In the interim, xformat is provided for * It will be deprecateed in May 2013.
* those who need the improved implementation. It will be scheduled for
* deprecation once format has been updated.
*/ */
string xformat(Char, Args...)(in Char[] fmt, Args args) string xformat(Char, Args...)(in Char[] fmt, Args args)
@ -2699,7 +2665,7 @@ string xformat(Char, Args...)(in Char[] fmt, Args args)
return w.data; return w.data;
} }
unittest deprecated unittest
{ {
debug(string) printf("std.string.xformat.unittest\n"); debug(string) printf("std.string.xformat.unittest\n");
@ -2721,11 +2687,9 @@ unittest
* Format arguments into string $(D_PARAM buf) which must be large * Format arguments into string $(D_PARAM buf) which must be large
* enough to hold the result. Throws RangeError if it is not. * enough to hold the result. Throws RangeError if it is not.
* *
* xsformat is a version of $(LREF sformat) whose behavior matches that of * $(LREF sformat) has been changed to use this implementation in November 2012.
* $(XREF stdio, writef). $(LREF sformat) will be changed to use this * Then xsformat has been scheduled for deprecation at the same time.
* implementation in November 2012. In the interim, xsformat is provided for * It will be deprecateed in May 2013.
* those who need the improved implementation. It will be scheduled for
* deprecation once sformat has been updated.
* *
* Returns: filled slice of $(D_PARAM buf) * Returns: filled slice of $(D_PARAM buf)
*/ */
@ -2777,7 +2741,7 @@ char[] xsformat(Char, Args...)(char[] buf, in Char[] fmt, Args args)
return buf[0 .. i]; return buf[0 .. i];
} }
unittest deprecated unittest
{ {
debug(string) printf("std.string.xsformat.unittest\n"); debug(string) printf("std.string.xsformat.unittest\n");
@ -3674,7 +3638,10 @@ unittest
assert(isNumeric(s[1..s.length - 2]) == true); assert(isNumeric(s[1..s.length - 2]) == true);
assert(isNumeric(s) == false); assert(isNumeric(s) == false);
assert(isNumeric(s[0..s.length - 1]) == false); assert(isNumeric(s[0..s.length - 1]) == false);
}
deprecated unittest
{
// These test calling the isNumeric(...) function // These test calling the isNumeric(...) function
assert(isNumeric(1,123UL) == true); assert(isNumeric(1,123UL) == true);
assert(isNumeric('2') == true); assert(isNumeric('2') == true);