From 8412ad6aeb7a3805baa136f04cedc55c5c2b8e35 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 27 Dec 2012 06:56:55 -0800 Subject: [PATCH] Implement automatic argument indexing. --- doc/conf.py | 4 ++-- format.cc | 31 +++++++++++++++++++++++-------- format.h | 3 ++- format_test.cc | 22 +++++++++++++++++----- 4 files changed, 44 insertions(+), 16 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 6dde2bfc..93a6b17d 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -48,9 +48,9 @@ copyright = u'1990-2012, Python Software Foundation' # built documents. # # The short X.Y version. -version = '0.1' +version = '0.2' # The full version, including alpha/beta/rc tags. -release = '0.1' +release = '0.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/format.cc b/format.cc index a6affaae..52dbe79c 100644 --- a/format.cc +++ b/format.cc @@ -171,8 +171,8 @@ void Formatter::ReportError(const char *s, StringRef message) const { // content area. char *FillPadding(char *buffer, unsigned total_size, std::size_t content_size, char fill) { - unsigned padding = total_size - content_size; - unsigned left_padding = padding / 2; + std::size_t padding = total_size - content_size; + std::size_t left_padding = padding / 2; std::fill_n(buffer, left_padding, fill); buffer += left_padding; char *content = buffer; @@ -415,12 +415,26 @@ unsigned Formatter::ParseUInt(const char *&s) const { return value; } -const Formatter::Arg &Formatter::ParseArgIndex(const char *&s) const { - if (*s < '0' || *s > '9') - ReportError(s, "missing argument index in format string"); - unsigned arg_index = ParseUInt(s); - if (arg_index >= args_.size()) - ReportError(s, "argument index is out of range in format"); +const Formatter::Arg &Formatter::ParseArgIndex(const char *&s) { + unsigned arg_index = 0; + if (*s < '0' || *s > '9') { + if (*s != '}' && *s != ':') + ReportError(s, "invalid argument index in format string"); + if (next_arg_index_ < 0) { + ReportError(s, + "cannot switch from manual to automatic argument indexing"); + } + arg_index = next_arg_index_++; + } else { + if (next_arg_index_ > 0) { + ReportError(s, + "cannot switch from automatic to manual argument indexing"); + } + next_arg_index_ = -1; + arg_index = ParseUInt(s); + if (arg_index >= args_.size()) + ReportError(s, "argument index is out of range in format"); + } return *args_[arg_index]; } @@ -439,6 +453,7 @@ void Formatter::CheckSign(const char *&s, const Arg &arg) { void Formatter::DoFormat() { const char *start = format_; format_ = 0; + next_arg_index_ = 0; const char *s = start; while (*s) { char c = *s++; diff --git a/format.h b/format.h index 8e3b7711..f7b82567 100644 --- a/format.h +++ b/format.h @@ -301,6 +301,7 @@ class Formatter : public BasicFormatter { const char *format_; // Format string. int num_open_braces_; + int next_arg_index_; friend class internal::ArgInserter; friend class ArgFormatter; @@ -330,7 +331,7 @@ class Formatter : public BasicFormatter { unsigned ParseUInt(const char *&s) const; // Parses argument index and returns an argument with this index. - const Arg &ParseArgIndex(const char *&s) const; + const Arg &ParseArgIndex(const char *&s); void CheckSign(const char *&s, const Arg &arg); diff --git a/format_test.cc b/format_test.cc index 6660169f..4ab1e642 100644 --- a/format_test.cc +++ b/format_test.cc @@ -235,8 +235,8 @@ TEST(FormatterTest, ArgsInDifferentPositions) { TEST(FormatterTest, ArgErrors) { EXPECT_THROW_MSG(Format("{"), FormatError, "unmatched '{' in format"); - EXPECT_THROW_MSG(Format("{}"), FormatError, - "missing argument index in format string"); + EXPECT_THROW_MSG(Format("{x}"), FormatError, + "invalid argument index in format string"); EXPECT_THROW_MSG(Format("{0"), FormatError, "unmatched '{' in format"); EXPECT_THROW_MSG(Format("{0}"), FormatError, "argument index is out of range in format"); @@ -257,6 +257,19 @@ TEST(FormatterTest, ArgErrors) { EXPECT_THROW_MSG(Format(format), FormatError, "number is too big in format"); } +TEST(FormatterTest, AutoArgIndex) { + EXPECT_EQ("abc", str(Format("{}{}{}") << 'a' << 'b' << 'c')); + EXPECT_THROW_MSG(Format("{0}{}") << 'a' << 'b', + FormatError, "cannot switch from manual to automatic argument indexing"); + EXPECT_THROW_MSG(Format("{}{0}") << 'a' << 'b', + FormatError, "cannot switch from automatic to manual argument indexing"); + EXPECT_EQ("1.2", str(Format("{:.{}}") << 1.2345 << 2)); + EXPECT_THROW_MSG(Format("{0}:.{}") << 1.2345 << 2, + FormatError, "cannot switch from manual to automatic argument indexing"); + EXPECT_THROW_MSG(Format("{:.{0}}") << 1.2345 << 2, + FormatError, "cannot switch from automatic to manual argument indexing"); +} + TEST(FormatterTest, EmptySpecs) { EXPECT_EQ("42", str(Format("{0:}") << 42)); } @@ -426,7 +439,6 @@ TEST(FormatterTest, SpaceSign) { } TEST(FormatterTest, HashFlag) { - // TODO EXPECT_EQ("42", str(Format("{0:#}") << 42)); EXPECT_EQ("-42", str(Format("{0:#}") << -42)); EXPECT_EQ("0x42", str(Format("{0:#x}") << 0x42)); @@ -589,8 +601,8 @@ TEST(FormatterTest, RuntimePrecision) { FormatError, "unmatched '{' in format"); EXPECT_THROW_MSG(Format("{0:.{}") << 0, FormatError, "unmatched '{' in format"); - EXPECT_THROW_MSG(Format("{0:.{}}") << 0, - FormatError, "missing argument index in format string"); + EXPECT_THROW_MSG(Format("{0:.{x}}") << 0, + FormatError, "invalid argument index in format string"); EXPECT_THROW_MSG(Format("{0:.{1}") << 0 << 0, FormatError, "unmatched '{' in format"); EXPECT_THROW_MSG(Format("{0:.{1}}") << 0,