diff --git a/example/example.cpp b/example/example.cpp index 11afa9a3..5bc71740 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -33,7 +33,7 @@ int main(int argc, char* argv[]) auto start = system_clock::now(); for (unsigned int i = 1; i <= howmany; ++i) - my_logger.info("Hello logger: msg #") << i << " дан жд йтбег??"; + my_logger.info("Hello logger: msg #") << i; //as->shutdown(std::chrono::milliseconds(15000)); auto delta = system_clock::now() - start; diff --git a/include/c11log/details/fast_oss.h b/include/c11log/details/fast_oss.h new file mode 100644 index 00000000..30a59fcb --- /dev/null +++ b/include/c11log/details/fast_oss.h @@ -0,0 +1,105 @@ +#pragma once + +// Faster than ostringstream--returns its string by ref +#include +#include "stack_buf.h" + +namespace c11log +{ +namespace details +{ + + +class stack_devicebuf :public std::streambuf +{ +public: + using Base = std::streambuf; + stack_devicebuf() = default; + ~stack_devicebuf() = default; + stack_devicebuf& operator=(const stack_devicebuf&) = delete; + + stack_devicebuf(const stack_devicebuf& other) :std::basic_streambuf(), _stackbuf(other._stackbuf) + {} + + stack_devicebuf(stack_devicebuf&& other) :std::basic_streambuf(), _stackbuf(std::move(other._stackbuf)) + { + other.clear(); + } + + bufpair_t buf() const + { + return _stackbuf.get(); + } + + std::size_t size() const + { + return _stackbuf.size(); + } + + void clear() + { + _stackbuf.clear(); + } + +protected: + // copy the give buffer into the accumulated fast buffer + std::streamsize xsputn(const char_type* s, std::streamsize count) override + { + _stackbuf.append(s, static_cast(count)); + return count; + } + + int_type overflow(int_type ch) override + { + if (traits_type::not_eof(ch)) + { + char c = traits_type::to_char_type(ch); + xsputn(&c, 1); + } + return ch; + } +private: + stack_buf<256> _stackbuf; +}; + +class fast_oss :public std::ostream +{ +public: + fast_oss() :std::ostream(&_dev) {} + ~fast_oss() = default; + + fast_oss& operator=(const fast_oss& other) = delete; + fast_oss& operator=(const fast_oss&& other) = delete; + + fast_oss(const fast_oss& other) :std::basic_ios(), std::ostream(&_dev), _dev(other._dev) + {} + + fast_oss(fast_oss&& other) :std::basic_ios(), std::ostream(&_dev), _dev(std::move(other._dev)) + { + other.clear(); + } + + + std::string str() + { + auto buf = _dev.buf(); + return std::string(buf.first, buf.second); + } + + + + std::size_t size() const + { + return _dev.size(); + } + + void clear() + { + _dev.clear(); + } + +private: + stack_devicebuf _dev; +}; +} +} \ No newline at end of file diff --git a/include/c11log/details/line_logger.h b/include/c11log/details/line_logger.h index 0faa5fab..aae3f1b3 100644 --- a/include/c11log/details/line_logger.h +++ b/include/c11log/details/line_logger.h @@ -3,6 +3,8 @@ #include #include "../common_types.h" #include "../logger.h" +#include "fast_oss.h" + // line_logger class. @@ -21,8 +23,7 @@ public: _callback_logger(callback_logger), _log_msg(msg_level), _oss(), - _enabled(enabled), - _empty(true) + _enabled(enabled) { if(enabled) { @@ -39,19 +40,16 @@ public: line_logger(line_logger&& other) : _callback_logger(other._callback_logger), _log_msg(std::move(other._log_msg)), - _oss(std::move(other._oss.str())), - _enabled(other._enabled), - _empty(other._empty) + _oss(std::move(other._oss)), + _enabled(other._enabled) { other.disable(); } - - + //Log the log message using the callback logger ~line_logger() { - //only if enabled and not empty - if (_enabled && !_empty) + if (_enabled) { _log_msg.raw = _oss.str(); _callback_logger->_log_it(_log_msg); @@ -64,7 +62,6 @@ public: if (_enabled) { _oss << what; - _empty = false; } } @@ -85,10 +82,8 @@ public: private: logger* _callback_logger; log_msg _log_msg; - //details::stack_oss _oss; - std::ostringstream _oss; + details::fast_oss _oss; bool _enabled; - bool _empty; }; } //Namespace details } // Namespace c11log diff --git a/include/c11log/details/stack_buf.h b/include/c11log/details/stack_buf.h new file mode 100644 index 00000000..d96d10c9 --- /dev/null +++ b/include/c11log/details/stack_buf.h @@ -0,0 +1,111 @@ +#pragma once + +#include +#include +#include +#include + +// Fast memory storage +// stores its contents on the stack when possible, in vector otherwise +// NOTE: User should be remember that returned buffer might be on the stack!! +namespace c11log +{ +namespace details +{ + +using bufpair_t = std::pair; + +template +class stack_buf +{ +public: + stack_buf() :_v(), _stack_array(), _stack_size(0) {} + ~stack_buf() {}; + + stack_buf& operator=(const stack_buf& other) = delete; + + stack_buf(const bufpair_t& buf_to_copy) :stack_buf() + { + append(buf_to_copy); + } + + stack_buf(const stack_buf& other) + { + _stack_size = other._stack_size; + if (!other._v.empty()) + _v = other._v; + else if (_stack_size) + std::copy(other._stack_array.begin(), other._stack_array.begin() + _stack_size, _stack_array.begin()); + } + + stack_buf(stack_buf&& other) + { + _stack_size = other._stack_size; + if (!other._v.empty()) + _v = std::move(other._v); + else if (_stack_size) + std::copy(other._stack_array.begin(), other._stack_array.begin() + _stack_size, _stack_array.begin()); + other.clear(); + } + + void append(const char* buf, std::size_t buf_size) + { + //If we are aleady using _v, forget about the stack + if (!_v.empty()) + { + _v.insert(_v.end(), buf, buf + buf_size); + } + //Try use the stack + else + { + if (_stack_size + buf_size <= STACK_SIZE) + { + std::memcpy(&_stack_array[_stack_size], buf, buf_size); + _stack_size += buf_size; + } + //Not enough stack space. Copy all to _v + else + { + _v.reserve(_stack_size + buf_size); + if (_stack_size) + _v.insert(_v.end(), _stack_array.begin(), _stack_array.begin() + _stack_size); + _v.insert(_v.end(), buf, buf + buf_size); + } + } + } + + void append(const bufpair_t &buf) + { + append(buf.first, buf.second); + } + + void clear() + { + _stack_size = 0; + _v.clear(); + } + + bufpair_t get() const + { + if (!_v.empty()) + return bufpair_t(_v.data(), _v.size()); + else + return bufpair_t(_stack_array.data(), _stack_size); + } + + std::size_t size() const + { + if (!_v.empty()) + return _v.size(); + else + return _stack_size; + } + +private: + std::vector _v; + std::array _stack_array; + std::size_t _stack_size; +}; + +} +} //namespace c11log { namespace details { \ No newline at end of file diff --git a/include/c11log/formatter.h b/include/c11log/formatter.h index 6f436a31..9879e4d0 100644 --- a/include/c11log/formatter.h +++ b/include/c11log/formatter.h @@ -11,6 +11,7 @@ #include "common_types.h" #include "details/os.h" #include "details/log_msg.h" +#include "details/fast_oss.h" namespace c11log @@ -31,8 +32,7 @@ public: // Format: [2013-12-29 01:04:42.900] [logger_name:Info] Message body void format(const std::string& logger_name, details::log_msg& msg) override { - std::ostringstream oss; - //Format datetime like this:[2014 - 03 - 14 17:15 : 22] + details::fast_oss oss; _format_time(msg.time, oss); if(!logger_name.empty()) oss << " [" << logger_name << ':' << c11log::level::to_str(msg.level) << "] ";