diff options
author | Dimitri van Heesch <doxygen@gmail.com> | 2021-03-28 11:58:30 (GMT) |
---|---|---|
committer | Dimitri van Heesch <doxygen@gmail.com> | 2021-03-28 12:25:48 (GMT) |
commit | c48639744a6fa118b9851b307107994ba93ce4c8 (patch) | |
tree | 8917c567f8f00560fba4554ade2b7e79bbe3ff45 /src/textstream.h | |
parent | cef71dc4fcfca9e3580214c39f20dc538ed6b2d9 (diff) | |
download | Doxygen-c48639744a6fa118b9851b307107994ba93ce4c8.zip Doxygen-c48639744a6fa118b9851b307107994ba93ce4c8.tar.gz Doxygen-c48639744a6fa118b9851b307107994ba93ce4c8.tar.bz2 |
Refactoring: Add TextStream buffer to improve output writing performance
- direct use of std::stringstream and std::ostream gave a 30%
drop in performance.
Diffstat (limited to 'src/textstream.h')
-rw-r--r-- | src/textstream.h | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/src/textstream.h b/src/textstream.h new file mode 100644 index 0000000..37525ef --- /dev/null +++ b/src/textstream.h @@ -0,0 +1,232 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2021 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ + +#ifndef TEXTSTREAM_H +#define TEXTSTREAM_H + +#include <string> +#include <iostream> +#include <sstream> +#include <cstdint> +#include <cstdio> +#include <fstream> + +#include "qcstring.h" + +/** @brief Text streaming class that buffers data. + * + * Simpler version of std::ostringstream that has much better + * performance. + */ +class TextStream final +{ + static const int INITIAL_CAPACITY = 4096; + public: + /** Creates an empty stream object. + */ + TextStream() + { + m_buffer.reserve(INITIAL_CAPACITY); + } + /** Create a text stream object for writing to a std::ostream. + * @note data is buffered until flush() is called or the object is destroyed. + */ + TextStream(std::ostream *s) : m_s(s) + { + m_buffer.reserve(INITIAL_CAPACITY); + } + /** Create a text stream, initializing the buffer with string \a s + */ + TextStream(const std::string &s) : m_buffer(s) + { + m_buffer.reserve(s.length()+INITIAL_CAPACITY); + } + + /** Writes any data that is buffered to the attached std::ostream */ + ~TextStream() { flush(); } + + /** Sets or changes the std::ostream to write to. + * @note Any data already buffered will be flushed. + */ + void setStream(std::ostream *s) + { + flush(); + m_s = s; + } + + /** Returns the attached std::ostream object. + * @see setStream() + */ + std::ostream *stream() const + { + return m_s; + } + + /** Adds a character to the stream */ + TextStream &operator<<( char c) + { + m_buffer+=c; + return static_cast<TextStream&>(*this); + } + + /** Adds a C-style string to the stream */ + TextStream &operator<<( const char *s) + { + if (s) m_buffer+=s; + return static_cast<TextStream&>(*this); + } + + /** Adds a QCString to the stream */ + TextStream &operator<<( const QCString &s ) + { + m_buffer+=s.str(); + return static_cast<TextStream&>(*this); + } + + /** Adds a std::string to the stream */ + TextStream &operator<<( const std::string &s ) + { + m_buffer+=s; + return static_cast<TextStream&>(*this); + } + + /** Adds a signed short integer to the stream */ + TextStream &operator<<( signed short i) + { + output_int32(i,i<0); + return static_cast<TextStream&>(*this); + } + + /** Adds a unsigned short integer to the stream */ + TextStream &operator<<( unsigned short i) + { + output_int32(i,false); + return static_cast<TextStream&>(*this); + } + + /** Adds a signed integer to the stream */ + TextStream &operator<<( signed int i) + { + output_int32(i,i<0); + return static_cast<TextStream&>(*this); + } + + /** Adds a unsigned integer to the stream */ + TextStream &operator<<( unsigned int i) + { + output_int32(i,false); + return static_cast<TextStream&>(*this); + } + + /** Adds a float to the stream */ + TextStream &operator<<( float f) + { + output_double((double)f); + return static_cast<TextStream&>(*this); + } + + /** Adds a double to the stream */ + TextStream &operator<<( double d) + { + output_double(d); + return static_cast<TextStream&>(*this); + } + + /** Adds a array of character to the stream + * @param buf the character buffer + * @param len the number of characters in the buffer to write + */ + void write(const char *buf,size_t len) + { + m_buffer.append(buf,len); + } + + /** Flushes the buffer. If a std::ostream is attached, the buffer's + * contents will be written to the stream. + */ + void flush() + { + if (m_s) + { + m_s->write(m_buffer.c_str(),m_buffer.length()); + } + m_buffer.clear(); + } + + /** Clears any buffered data */ + void clear() + { + m_buffer.clear(); + } + + /** Return the contents of the buffer as a std::string object */ + std::string str() const + { + return m_buffer; + } + + /** Sets the buffer's contents to string \a s. + * Any data already in the buffer will be flushed. + */ + void str(const std::string &s) + { + flush(); + m_buffer=s; + } + + /** Sets the buffer's contents to string \a s + * Any data already in the buffer will be flushed. + */ + void str(const char *s) + { + flush(); + if (s) m_buffer=s; + } + + /** Returns true iff the buffer is empty */ + bool empty() const + { + return m_buffer.empty(); + } + + private: + /** Writes a string representation of an integer to the buffer + * @param n the absolute value of the integer + * @param neg indicates if the integer is negative + */ + void output_int32( uint32_t n, bool neg ) + { + char buf[20]; + char *p = &buf[19]; + *p = '\0'; + if ( neg ) + { + n = (uint32_t)(-(int32_t)n); + } + do { *--p = ((int32_t)(n%10)) + '0'; n /= 10; } while ( n ); + if ( neg ) *--p = '-'; + m_buffer+=p; + } + void output_double( double d) + { + char buf[64]; + snprintf(buf,64,"%f",d); + m_buffer+=buf; + } + std::string m_buffer; + std::ostream *m_s = nullptr; +}; + +#endif |