Replace format and sformat implementations

This commit is contained in:
k-hara 2012-11-14 14:14:16 +09:00
parent f93fe17b83
commit d76c46f40b

View file

@ -2494,83 +2494,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));
} }
@ -2579,103 +2551,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)
@ -2714,11 +2680,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)
*/ */