From d6bf6d2708d510fa6d0d7f11d43d351e165fd5b6 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 12 Dec 2012 09:14:00 -0800 Subject: [PATCH] Workaround a bug in Visual C++. --- format.h | 148 ++++++++++++++++++++++++++----------------------- format_test.cc | 17 +++--- 2 files changed, 87 insertions(+), 78 deletions(-) diff --git a/format.h b/format.h index d3281582..a91cb27e 100644 --- a/format.h +++ b/format.h @@ -37,6 +37,8 @@ namespace format { +namespace internal { + // A simple array for POD types with the first SIZE elements stored in // the object itself. It supports a subset of std::vector's operations. template @@ -111,6 +113,9 @@ void Array::append(const T *begin, const T *end) { size_ += num_elements; } +class ArgInserter; +} + class FormatError : public std::runtime_error { public: explicit FormatError(const std::string &message) @@ -134,7 +139,7 @@ class FormatError : public std::runtime_error { class Formatter { private: enum { INLINE_BUFFER_SIZE = 500 }; - Array buffer_; // Output buffer. + internal::Array buffer_; // Output buffer. enum Type { // Numeric types should go first. @@ -236,73 +241,11 @@ class Formatter { }; enum { NUM_INLINE_ARGS = 10 }; - Array args_; // Format arguments. + internal::Array args_; // Format arguments. const char *format_; // Format string. - template - friend class ActiveFormatter; - - // This is a transient object that normally exists only as a temporary - // returned by one of the formatting functions. It stores a reference - // to a formatter and provides operator<< that feeds arguments to the - // formatter. - class ArgInserter { - private: - mutable Formatter *formatter_; - - friend class Formatter; - - protected: - explicit ArgInserter(Formatter *f = 0) : formatter_(f) {} - - ArgInserter(ArgInserter& other) - : formatter_(other.formatter_) { - other.formatter_ = 0; - } - - ArgInserter& operator=(const ArgInserter& other) { - formatter_ = other.formatter_; - other.formatter_ = 0; - return *this; - } - - const Formatter *Format() const { - Formatter *f = formatter_; - if (f) { - formatter_ = 0; - f->Format(); - } - return f; - } - - Formatter *formatter() const { return formatter_; } - - void ResetFormatter() { formatter_ = 0; } - - public: - ~ArgInserter() { - if (formatter_) - formatter_->Format(); - } - - // Feeds an argument to a formatter. - ArgInserter &operator<<(const Formatter::Arg &arg) { - arg.formatter = formatter_; - formatter_->Add(arg); - return *this; - } - - // Performs formatting and returns a C string with the output. - friend const char *c_str(const ArgInserter &af) { - return af.Format()->c_str(); - } - - // Performs formatting and returns a std::string with the output. - friend std::string str(const ArgInserter &af) { - return af.Format()->str(); - } - }; + friend class internal::ArgInserter; void Add(const Arg &arg) { args_.push_back(&arg); @@ -342,7 +285,7 @@ class Formatter { // Formats a string appending the output to the internal buffer. // Arguments are accepted through the returned ArgInserter object // using inserter operator<<. - ArgInserter operator()(const char *format); + internal::ArgInserter operator()(const char *format); std::size_t size() const { return buffer_.size(); } @@ -352,6 +295,71 @@ class Formatter { std::string str() const { return std::string(&buffer_[0], buffer_.size()); } }; +namespace internal { + +// This is a transient object that normally exists only as a temporary +// returned by one of the formatting functions. It stores a reference +// to a formatter and provides operator<< that feeds arguments to the +// formatter. +class ArgInserter { + private: + mutable Formatter *formatter_; + + friend class format::Formatter; + + protected: + explicit ArgInserter(Formatter *f = 0) : formatter_(f) {} + + ArgInserter(ArgInserter& other) + : formatter_(other.formatter_) { + other.formatter_ = 0; + } + + ArgInserter& operator=(const ArgInserter& other) { + formatter_ = other.formatter_; + other.formatter_ = 0; + return *this; + } + + const Formatter *Format() const { + Formatter *f = formatter_; + if (f) { + formatter_ = 0; + f->Format(); + } + return f; + } + + Formatter *formatter() const { return formatter_; } + const char *format() const { return formatter_->format_; } + + void ResetFormatter() { formatter_ = 0; } + + public: + ~ArgInserter() { + if (formatter_) + formatter_->Format(); + } + + // Feeds an argument to a formatter. + ArgInserter &operator<<(const Formatter::Arg &arg) { + arg.formatter = formatter_; + formatter_->Add(arg); + return *this; + } + + // Performs formatting and returns a C string with the output. + friend const char *c_str(const ArgInserter &af) { + return af.Format()->c_str(); + } + + // Performs formatting and returns a std::string with the output. + friend std::string str(const ArgInserter &af) { + return af.Format()->str(); + } +}; +} + template void Formatter::FormatCustomArg(const void *arg, int width) { const T &value = *static_cast(arg); @@ -364,8 +372,8 @@ void Formatter::FormatCustomArg(const void *arg, int width) { std::fill_n(out + str.size(), width - str.size(), ' '); } -inline Formatter::ArgInserter Formatter::operator()(const char *format) { - ArgInserter formatter(this); +inline internal::ArgInserter Formatter::operator()(const char *format) { + internal::ArgInserter formatter(this); format_ = format; args_.clear(); return formatter; @@ -375,7 +383,7 @@ inline Formatter::ArgInserter Formatter::operator()(const char *format) { // This is a transient object that normally exists only as a temporary // returned by one of the formatting functions. template -class ActiveFormatter : public Formatter::ArgInserter { +class ActiveFormatter : public internal::ArgInserter { private: Formatter formatter_; Action action_; @@ -400,8 +408,8 @@ class ActiveFormatter : public Formatter::ArgInserter { // are provided. ActiveFormatter(ActiveFormatter &other) : ArgInserter(0), action_(other.action_) { + ArgInserter::operator=(formatter_(other.format())); other.ResetFormatter(); - ArgInserter::operator=(formatter_(other.formatter_.format_)); } ~ActiveFormatter() { diff --git a/format_test.cc b/format_test.cc index b33b8c23..67a01c76 100644 --- a/format_test.cc +++ b/format_test.cc @@ -35,6 +35,7 @@ using std::size_t; using std::sprintf; +using fmt::internal::Array; using fmt::Formatter; using fmt::Format; using fmt::FormatError; @@ -90,23 +91,23 @@ class TestString { }; TEST(ArrayTest, Ctor) { - fmt::Array array; + Array array; EXPECT_EQ(0u, array.size()); EXPECT_EQ(123u, array.capacity()); } TEST(ArrayTest, Access) { - fmt::Array array; + Array array; array[0] = 11; EXPECT_EQ(11, array[0]); array[3] = 42; EXPECT_EQ(42, *(&array[0] + 3)); - const fmt::Array &carray = array; + const Array &carray = array; EXPECT_EQ(42, carray[3]); } TEST(ArrayTest, Resize) { - fmt::Array array; + Array array; array[10] = 42; EXPECT_EQ(42, array[10]); array.resize(20); @@ -120,7 +121,7 @@ TEST(ArrayTest, Resize) { } TEST(ArrayTest, Grow) { - fmt::Array array; + Array array; array.resize(10); for (int i = 0; i < 10; ++i) array[i] = i * i; @@ -132,7 +133,7 @@ TEST(ArrayTest, Grow) { } TEST(ArrayTest, Clear) { - fmt::Array array; + Array array; array.resize(20); array.clear(); EXPECT_EQ(0u, array.size()); @@ -140,7 +141,7 @@ TEST(ArrayTest, Clear) { } TEST(ArrayTest, PushBack) { - fmt::Array array; + Array array; array.push_back(11); EXPECT_EQ(11, array[0]); EXPECT_EQ(1u, array.size()); @@ -152,7 +153,7 @@ TEST(ArrayTest, PushBack) { } TEST(ArrayTest, Append) { - fmt::Array array; + Array array; const char *test = "test"; array.append(test, test + 5); EXPECT_STREQ("test", &array[0]);