[Format] add variable width support (#1743)

* add variable width test cases

* add variable width support

* update the documentation for variable width
This commit is contained in:
was4444 2017-07-24 18:21:35 +08:00 committed by Aleksandar Fabijanic
parent fd1d113acb
commit 303e398803
3 changed files with 119 additions and 11 deletions

View File

@ -82,11 +82,11 @@ std::string Foundation_API format(const std::string& fmt, const Any& value);
/// * h argument is short (d, i), unsigned short (o, u, x, X) or float (e, E, f, g, G)
/// * ? argument is any signed or unsigned int, short, long, or 64-bit integer (d, i, o, x, X)
///
/// The width argument is a nonnegative decimal integer controlling the minimum number of characters printed.
/// The width argument is a nonnegative decimal integer or '*' with an additional nonnegative integer value preceding the value to be formated, controlling the minimum number of characters printed.
/// If the number of characters in the output value is less than the specified width, blanks or
/// leading zeros are added, according to the specified flags (-, +, 0).
///
/// Precision is a nonnegative decimal integer, preceded by a period (.), which specifies the number of characters
/// Precision is a nonnegative decimal integer or '*' with an additional nonnegative integer value preceding the value to be formated, preceded by a period (.), which specifies the number of characters
/// to be printed, the number of decimal places, or the number of significant digits.
///
/// Throws an InvalidArgumentException if an argument index is out of range.

View File

@ -46,28 +46,44 @@ namespace
}
void parseWidth(std::ostream& str, std::string::const_iterator& itFmt, const std::string::const_iterator& endFmt)
void parseWidth(std::ostream& str, std::string::const_iterator& itFmt, const std::string::const_iterator& endFmt, std::vector<Any>::const_iterator& itVal)
{
int width = 0;
while (itFmt != endFmt && Ascii::isDigit(*itFmt))
if (itFmt != endFmt && *itFmt == '*')
{
width = 10*width + *itFmt - '0';
++itFmt;
width = AnyCast<int>(*itVal++);
}
if (width != 0) str.width(width);
else
{
while (itFmt != endFmt && Ascii::isDigit(*itFmt))
{
width = 10*width + *itFmt - '0';
++itFmt;
}
}
if (width > 0) str.width(width);
}
void parsePrec(std::ostream& str, std::string::const_iterator& itFmt, const std::string::const_iterator& endFmt)
void parsePrec(std::ostream& str, std::string::const_iterator& itFmt, const std::string::const_iterator& endFmt, std::vector<Any>::const_iterator& itVal)
{
if (itFmt != endFmt && *itFmt == '.')
{
++itFmt;
int prec = 0;
while (itFmt != endFmt && Ascii::isDigit(*itFmt))
if (itFmt != endFmt && *itFmt == '*')
{
prec = 10*prec + *itFmt - '0';
++itFmt;
prec = AnyCast<int>(*itVal++);
}
else
{
while (itFmt != endFmt && Ascii::isDigit(*itFmt))
{
prec = 10*prec + *itFmt - '0';
++itFmt;
}
}
if (prec >= 0) str.precision(prec);
}
@ -155,8 +171,8 @@ namespace
try
{
parseFlags(str, itFmt, endFmt);
parseWidth(str, itFmt, endFmt);
parsePrec(str, itFmt, endFmt);
parseWidth(str, itFmt, endFmt, itVal);
parsePrec(str, itFmt, endFmt, itVal);
char mod = parseMod(itFmt, endFmt);
if (itFmt != endFmt)
{

View File

@ -44,6 +44,11 @@ void FormatTest::testChar()
s = format("%-2c", c);
assert(s == "a ");
s = format("%*c", 2, c);
assert(s == " a");
s = format("%-*c", 2, c);
assert(s == "a ");
s = format("%c", std::string("foo"));
assert(s == "[ERRFMT]");
}
@ -59,6 +64,11 @@ void FormatTest::testInt()
s = format("%04d", i);
assert (s == "0042");
s = format("%*d", 4, i);
assert (s == " 42");
s = format("%0*d", 4, i);
assert (s == "0042");
short h = 42;
s = format("%hd", h);
assert (s == "42");
@ -67,6 +77,11 @@ void FormatTest::testInt()
s = format("%04hd", h);
assert (s == "0042");
s = format("%*hd", 4, h);
assert (s == " 42");
s = format("%0*hd", 4, h);
assert (s == "0042");
unsigned short hu = 42;
s = format("%hu", hu);
assert (s == "42");
@ -74,6 +89,11 @@ void FormatTest::testInt()
assert (s == " 42");
s = format("%04hu", hu);
assert (s == "0042");
s = format("%*hu", 4, hu);
assert (s == " 42");
s = format("%0*hu", 4, hu);
assert (s == "0042");
unsigned x = 0x42;
s = format("%x", x);
@ -83,6 +103,11 @@ void FormatTest::testInt()
s = format("%04x", x);
assert (s == "0042");
s = format("%*x", 4, x);
assert (s == " 42");
s = format("%0*x", 4, x);
assert (s == "0042");
unsigned o = 042;
s = format("%o", o);
assert (s == "42");
@ -91,6 +116,11 @@ void FormatTest::testInt()
s = format("%04o", o);
assert (s == "0042");
s = format("%*o", 4, o);
assert (s == " 42");
s = format("%0*o", 4, o);
assert (s == "0042");
unsigned u = 42;
s = format("%u", u);
assert (s == "42");
@ -98,6 +128,11 @@ void FormatTest::testInt()
assert (s == " 42");
s = format("%04u", u);
assert (s == "0042");
s = format("%*u", 4, u);
assert (s == " 42");
s = format("%0*u", 4, u);
assert (s == "0042");
long l = 42;
s = format("%ld", l);
@ -107,6 +142,11 @@ void FormatTest::testInt()
s = format("%04ld", l);
assert (s == "0042");
s = format("%*ld", 4, l);
assert (s == " 42");
s = format("%0*ld", 4, l);
assert (s == "0042");
unsigned long ul = 42;
s = format("%lu", ul);
assert (s == "42");
@ -114,6 +154,11 @@ void FormatTest::testInt()
assert (s == " 42");
s = format("%04lu", ul);
assert (s == "0042");
s = format("%*lu", 4, ul);
assert (s == " 42");
s = format("%0*lu", 4, ul);
assert (s == "0042");
unsigned long xl = 0x42;
s = format("%lx", xl);
@ -122,6 +167,11 @@ void FormatTest::testInt()
assert (s == " 42");
s = format("%04lx", xl);
assert (s == "0042");
s = format("%*lx", 4, xl);
assert (s == " 42");
s = format("%0*lx", 4, xl);
assert (s == "0042");
Int64 i64 = 42;
s = format("%Ld", i64);
@ -130,6 +180,11 @@ void FormatTest::testInt()
assert (s == " 42");
s = format("%04Ld", i64);
assert (s == "0042");
s = format("%*Ld", 4, i64);
assert (s == " 42");
s = format("%0*Ld", 4, i64);
assert (s == "0042");
UInt64 ui64 = 42;
s = format("%Lu", ui64);
@ -138,6 +193,11 @@ void FormatTest::testInt()
assert (s == " 42");
s = format("%04Lu", ui64);
assert (s == "0042");
s = format("%*Lu", 4, ui64);
assert (s == " 42");
s = format("%0*Lu", 4, ui64);
assert (s == "0042");
x = 0xaa;
s = format("%x", x);
@ -154,6 +214,10 @@ void FormatTest::testInt()
assert (s == "-42");
s = format("%+04d", i);
assert (s == "-042");
s = format("%+0*d", 4, i);
assert (s == "-042");
s = format("%d", i);
assert (s == "-42");
@ -266,10 +330,18 @@ void FormatTest::testFloatFix()
s = format("%10f", d);
assert (s.find(" 1.50") != std::string::npos);
s = format("%*f", 10, d);
assert (s.find(" 1.50") != std::string::npos);
s = format("%6.2f", d);
assert (s == " 1.50");
s = format("%-6.2f", d);
assert (s == "1.50 ");
s = format("%*.*f", 6, 2, d);
assert (s == " 1.50");
s = format("%-*.*f", 6,2, d);
assert (s == "1.50 ");
float f = 1.5;
s = format("%hf", f);
@ -277,6 +349,9 @@ void FormatTest::testFloatFix()
s = format("%.0f", 1.0);
assert (s == "1");
s = format("%.*f", 0, 1.0);
assert (s == "1");
}
@ -291,12 +366,23 @@ void FormatTest::testFloatSci()
assert (s.find(" 1.50") != std::string::npos);
assert (s.find("0e+0") != std::string::npos);
s = format("%*e", 20, d);
assert (s.find(" 1.50") != std::string::npos);
assert (s.find("0e+0") != std::string::npos);
s = format("%10.2e", d);
assert (s == " 1.50e+000" || s == " 1.50e+00");
s = format("%-10.2e", d);
assert (s == "1.50e+000 " || s == "1.50e+00 ");
s = format("%-10.2E", d);
assert (s == "1.50E+000 " || s == "1.50E+00 ");
s = format("%*.*e", 10, 2, d);
assert (s == " 1.50e+000" || s == " 1.50e+00");
s = format("%-*.*e", 10, 2, d);
assert (s == "1.50e+000 " || s == "1.50e+00 ");
s = format("%-*.*E", 10, 2, d);
assert (s == "1.50E+000 " || s == "1.50E+00 ");
}
@ -312,6 +398,12 @@ void FormatTest::testString()
s = format("%-5s", foo);
assert (s == "foo ");
s = format("%*s", 5, foo);
assert (s == " foo");
s = format("%-*s", 5, foo);
assert (s == "foo ");
s = format("%s%%a", foo);
assert (s == "foo%a");