From 5343eab4c8dbf7ca33369937bb27940505376f00 Mon Sep 17 00:00:00 2001 From: Michael Kasperovich Date: Tue, 17 Nov 2015 20:06:11 +0300 Subject: [PATCH 1/7] fmt::format inefficiency #92 --- format.h | 50 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/format.h b/format.h index 1d3dffbeb88b..7e6c88f7ad37 100644 --- a/format.h +++ b/format.h @@ -38,6 +38,7 @@ #include #include #include +#include #ifndef FMT_USE_IOSTREAMS # define FMT_USE_IOSTREAMS 1 @@ -478,6 +479,11 @@ class Buffer { T &operator[](std::size_t index) { return ptr_[index]; } const T &operator[](std::size_t index) const { return ptr_[index]; } + + + template > + friend class basic_formatbuf; + }; template @@ -2027,6 +2033,11 @@ class BasicWriter { */ std::size_t size() const { return buffer_.size(); } + /** + Returns underlying buffer. + */ + Buffer& buffer() const { return buffer_; } + /** Returns a pointer to the output buffer content. No terminating null character is appended. @@ -2628,16 +2639,39 @@ class BasicArrayWriter : public BasicWriter { typedef BasicArrayWriter ArrayWriter; typedef BasicArrayWriter WArrayWriter; +template > +class basic_formatbuf : public std::basic_streambuf { + + typedef typename std::basic_streambuf::int_type int_type; + + Buffer& buffer_; + +public: + basic_formatbuf(BasicFormatter &formatter) : buffer_(formatter.writer().buffer()) { + setp(buffer_.ptr_, buffer_.ptr_ + buffer_.size_, buffer_.ptr_ + buffer_.capacity_); + } + + virtual int_type overflow(int_type _Meta = Traits::eof()) { + buffer_.grow(buffer_.capacity_ * 2); + setp(buffer_.ptr_, buffer_.ptr_ + buffer_.size_, buffer_.ptr_ + buffer_.capacity_); + + return traits_type::to_int_type(*pptr()); + } + + int_type flush() { + buffer_.size_ = pptr() - pbase(); + return traits_type::to_int_type(*pptr()); + } +}; + // Formats a value. template -void format(BasicFormatter &f, const Char *&format_str, const T &value) { - std::basic_ostringstream os; - os << value; - std::basic_string str = os.str(); - internal::Arg arg = internal::MakeValue(str); - arg.type = static_cast( - internal::MakeValue::type(str)); - format_str = f.format(format_str, arg); +void format(BasicFormatter &formatter, const Char *&format_str, const T &value) { + + basic_formatbuf format_buf(formatter); + std::basic_ostream output(&format_buf); + output << value; + format_buf.flush(); } // Reports a system error without throwing an exception. From ad77903832cdb19ee5041f38deafbf3fdc96dcd4 Mon Sep 17 00:00:00 2001 From: Michael Kasperovich Date: Wed, 18 Nov 2015 21:30:53 +0300 Subject: [PATCH 2/7] a) Fix format check tests b) Disable friendship for basic_formatbuf --- format.h | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/format.h b/format.h index 7e6c88f7ad37..ce4e6f0cda95 100644 --- a/format.h +++ b/format.h @@ -479,11 +479,6 @@ class Buffer { T &operator[](std::size_t index) { return ptr_[index]; } const T &operator[](std::size_t index) const { return ptr_[index]; } - - - template > - friend class basic_formatbuf; - }; template @@ -2647,31 +2642,39 @@ class basic_formatbuf : public std::basic_streambuf { Buffer& buffer_; public: - basic_formatbuf(BasicFormatter &formatter) : buffer_(formatter.writer().buffer()) { - setp(buffer_.ptr_, buffer_.ptr_ + buffer_.size_, buffer_.ptr_ + buffer_.capacity_); - } + basic_formatbuf(Buffer& buffer) : buffer_(buffer) { + + Elem* start = &buffer_[0]; + setp(start, start + buffer_.size(), start + buffer_.capacity()); + } virtual int_type overflow(int_type _Meta = Traits::eof()) { - buffer_.grow(buffer_.capacity_ * 2); - setp(buffer_.ptr_, buffer_.ptr_ + buffer_.size_, buffer_.ptr_ + buffer_.capacity_); + buffer_.reserve(buffer_.capacity() * 2); + Elem* start = &buffer_[0]; + setp(start, start + buffer_.size(), start + buffer_.capacity()); return traits_type::to_int_type(*pptr()); } - int_type flush() { - buffer_.size_ = pptr() - pbase(); - return traits_type::to_int_type(*pptr()); + size_t size() { + return pptr() - pbase(); } }; // Formats a value. template -void format(BasicFormatter &formatter, const Char *&format_str, const T &value) { +void format(BasicFormatter &f, const Char *&format_str, const T &value) { + internal::MemoryBuffer buffer; - basic_formatbuf format_buf(formatter); + basic_formatbuf format_buf(buffer); std::basic_ostream output(&format_buf); output << value; - format_buf.flush(); + + BasicStringRef str(format_buf.size() > 0 ? &buffer[0] : 0, format_buf.size()); + internal::Arg arg = internal::MakeValue(str); + arg.type = static_cast( + internal::MakeValue::type(str)); + format_str = f.format(format_str, arg); } // Reports a system error without throwing an exception. From 914853716b347d8ba8d835d5bdff9c25ade228c1 Mon Sep 17 00:00:00 2001 From: Michael Kasperovich Date: Wed, 18 Nov 2015 22:02:45 +0300 Subject: [PATCH 3/7] Fix gcc errors. --- format.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/format.h b/format.h index ce4e6f0cda95..dab9f8df4d62 100644 --- a/format.h +++ b/format.h @@ -2638,6 +2638,7 @@ template > class basic_formatbuf : public std::basic_streambuf { typedef typename std::basic_streambuf::int_type int_type; + typedef typename std::basic_streambuf::traits_type traits_type; Buffer& buffer_; @@ -2648,7 +2649,7 @@ class basic_formatbuf : public std::basic_streambuf { setp(start, start + buffer_.size(), start + buffer_.capacity()); } - virtual int_type overflow(int_type _Meta = Traits::eof()) { + virtual int_type overflow(int_type) { buffer_.reserve(buffer_.capacity() * 2); Elem* start = &buffer_[0]; setp(start, start + buffer_.size(), start + buffer_.capacity()); @@ -2657,7 +2658,7 @@ class basic_formatbuf : public std::basic_streambuf { } size_t size() { - return pptr() - pbase(); + return this->pptr() - this->pbase(); } }; From 9ffdec9622c827c8d82b4372c1b55aba70e51684 Mon Sep 17 00:00:00 2001 From: Michael Kasperovich Date: Thu, 19 Nov 2015 22:23:42 +0300 Subject: [PATCH 4/7] Fixed overflow implementation. --- format.h | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/format.h b/format.h index dab9f8df4d62..8c8288859986 100644 --- a/format.h +++ b/format.h @@ -2640,25 +2640,37 @@ class basic_formatbuf : public std::basic_streambuf { typedef typename std::basic_streambuf::int_type int_type; typedef typename std::basic_streambuf::traits_type traits_type; + using std::basic_streambuf::setp; + using std::basic_streambuf::pptr; + using std::basic_streambuf::pbase; + Buffer& buffer_; + Elem* start_; public: - basic_formatbuf(Buffer& buffer) : buffer_(buffer) { + basic_formatbuf(Buffer& buffer) : buffer_(buffer), start_(&buffer[0]) { - Elem* start = &buffer_[0]; - setp(start, start + buffer_.size(), start + buffer_.capacity()); + setp(start_, start_ + buffer_.capacity()); } - virtual int_type overflow(int_type) { - buffer_.reserve(buffer_.capacity() * 2); - Elem* start = &buffer_[0]; - setp(start, start + buffer_.size(), start + buffer_.capacity()); + virtual int_type overflow(int_type _Meta = traits_type::eof()) { + + if (!traits_type::eq_int_type(_Meta, traits_type::eof())) { + + size_t size = pptr() - start_; + buffer_.resize(size); + buffer_.reserve(size * 2); + + start_ = &buffer_[0]; + start_[size] = traits_type::to_char_type(_Meta); + setp(start_+ size + 1, start_ + size * 2); + } - return traits_type::to_int_type(*pptr()); + return _Meta; } size_t size() { - return this->pptr() - this->pbase(); + return pptr() - start_; } }; From cadb63e7de7908f0243d3ff66baea2d3f7dc7b63 Mon Sep 17 00:00:00 2001 From: Michael Kasperovich Date: Mon, 23 Nov 2015 17:57:04 +0300 Subject: [PATCH 5/7] Custom formatbuf implementation. Four commits squashed into one. --- format.h | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/format.h b/format.h index 1d3dffbeb88b..8c8288859986 100644 --- a/format.h +++ b/format.h @@ -38,6 +38,7 @@ #include #include #include +#include #ifndef FMT_USE_IOSTREAMS # define FMT_USE_IOSTREAMS 1 @@ -2027,6 +2028,11 @@ class BasicWriter { */ std::size_t size() const { return buffer_.size(); } + /** + Returns underlying buffer. + */ + Buffer& buffer() const { return buffer_; } + /** Returns a pointer to the output buffer content. No terminating null character is appended. @@ -2628,12 +2634,56 @@ class BasicArrayWriter : public BasicWriter { typedef BasicArrayWriter ArrayWriter; typedef BasicArrayWriter WArrayWriter; +template > +class basic_formatbuf : public std::basic_streambuf { + + typedef typename std::basic_streambuf::int_type int_type; + typedef typename std::basic_streambuf::traits_type traits_type; + + using std::basic_streambuf::setp; + using std::basic_streambuf::pptr; + using std::basic_streambuf::pbase; + + Buffer& buffer_; + Elem* start_; + +public: + basic_formatbuf(Buffer& buffer) : buffer_(buffer), start_(&buffer[0]) { + + setp(start_, start_ + buffer_.capacity()); + } + + virtual int_type overflow(int_type _Meta = traits_type::eof()) { + + if (!traits_type::eq_int_type(_Meta, traits_type::eof())) { + + size_t size = pptr() - start_; + buffer_.resize(size); + buffer_.reserve(size * 2); + + start_ = &buffer_[0]; + start_[size] = traits_type::to_char_type(_Meta); + setp(start_+ size + 1, start_ + size * 2); + } + + return _Meta; + } + + size_t size() { + return pptr() - start_; + } +}; + // Formats a value. template void format(BasicFormatter &f, const Char *&format_str, const T &value) { - std::basic_ostringstream os; - os << value; - std::basic_string str = os.str(); + internal::MemoryBuffer buffer; + + basic_formatbuf format_buf(buffer); + std::basic_ostream output(&format_buf); + output << value; + + BasicStringRef str(format_buf.size() > 0 ? &buffer[0] : 0, format_buf.size()); internal::Arg arg = internal::MakeValue(str); arg.type = static_cast( internal::MakeValue::type(str)); From 662544605e7001adf1abd4ca27787d63ef2343c8 Mon Sep 17 00:00:00 2001 From: Michael Kasperovich Date: Tue, 24 Nov 2015 18:47:04 +0300 Subject: [PATCH 6/7] Squash last 2 commits. --- format.h | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/format.h b/format.h index 1d3dffbeb88b..8c8288859986 100644 --- a/format.h +++ b/format.h @@ -38,6 +38,7 @@ #include #include #include +#include #ifndef FMT_USE_IOSTREAMS # define FMT_USE_IOSTREAMS 1 @@ -2027,6 +2028,11 @@ class BasicWriter { */ std::size_t size() const { return buffer_.size(); } + /** + Returns underlying buffer. + */ + Buffer& buffer() const { return buffer_; } + /** Returns a pointer to the output buffer content. No terminating null character is appended. @@ -2628,12 +2634,56 @@ class BasicArrayWriter : public BasicWriter { typedef BasicArrayWriter ArrayWriter; typedef BasicArrayWriter WArrayWriter; +template > +class basic_formatbuf : public std::basic_streambuf { + + typedef typename std::basic_streambuf::int_type int_type; + typedef typename std::basic_streambuf::traits_type traits_type; + + using std::basic_streambuf::setp; + using std::basic_streambuf::pptr; + using std::basic_streambuf::pbase; + + Buffer& buffer_; + Elem* start_; + +public: + basic_formatbuf(Buffer& buffer) : buffer_(buffer), start_(&buffer[0]) { + + setp(start_, start_ + buffer_.capacity()); + } + + virtual int_type overflow(int_type _Meta = traits_type::eof()) { + + if (!traits_type::eq_int_type(_Meta, traits_type::eof())) { + + size_t size = pptr() - start_; + buffer_.resize(size); + buffer_.reserve(size * 2); + + start_ = &buffer_[0]; + start_[size] = traits_type::to_char_type(_Meta); + setp(start_+ size + 1, start_ + size * 2); + } + + return _Meta; + } + + size_t size() { + return pptr() - start_; + } +}; + // Formats a value. template void format(BasicFormatter &f, const Char *&format_str, const T &value) { - std::basic_ostringstream os; - os << value; - std::basic_string str = os.str(); + internal::MemoryBuffer buffer; + + basic_formatbuf format_buf(buffer); + std::basic_ostream output(&format_buf); + output << value; + + BasicStringRef str(format_buf.size() > 0 ? &buffer[0] : 0, format_buf.size()); internal::Arg arg = internal::MakeValue(str); arg.type = static_cast( internal::MakeValue::type(str)); From 7b6117344bc27d51ffc37442fa99a21055e96dbd Mon Sep 17 00:00:00 2001 From: Michael Kasperovich Date: Tue, 24 Nov 2015 19:24:47 +0300 Subject: [PATCH 7/7] Remove unnecessary stuff. --- format.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/format.h b/format.h index 8c8288859986..91f16e7f38ce 100644 --- a/format.h +++ b/format.h @@ -2028,11 +2028,6 @@ class BasicWriter { */ std::size_t size() const { return buffer_.size(); } - /** - Returns underlying buffer. - */ - Buffer& buffer() const { return buffer_; } - /** Returns a pointer to the output buffer content. No terminating null character is appended.