From 5d399e61d6eb03ffbc636cfd0dfd279551199f1f Mon Sep 17 00:00:00 2001 From: gabi Date: Sat, 29 Nov 2014 09:49:23 +0200 Subject: [PATCH 001/120] Added cppformat files --- include/spdlog/details/format.cc | 1166 ++++++++++++++ include/spdlog/details/format.h | 2589 ++++++++++++++++++++++++++++++ 2 files changed, 3755 insertions(+) create mode 100644 include/spdlog/details/format.cc create mode 100644 include/spdlog/details/format.h diff --git a/include/spdlog/details/format.cc b/include/spdlog/details/format.cc new file mode 100644 index 00000000..3559d185 --- /dev/null +++ b/include/spdlog/details/format.cc @@ -0,0 +1,1166 @@ +/* +Formatting library for C++ + +Copyright (c) 2012 - 2014, Victor Zverovich +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +// Disable useless MSVC warnings. +#undef _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_WARNINGS +#undef _SCL_SECURE_NO_WARNINGS +#define _SCL_SECURE_NO_WARNINGS + +#include "format.h" + +#include + +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# ifdef __MINGW32__ +# include +# endif +# include +# undef ERROR +#endif + +using fmt::LongLong; +using fmt::ULongLong; +using fmt::internal::Arg; + +// Check if exceptions are disabled. +#if __GNUC__ && !__EXCEPTIONS +# define FMT_EXCEPTIONS 0 +#endif +#if _MSC_VER && !_HAS_EXCEPTIONS +# define FMT_EXCEPTIONS 0 +#endif +#ifndef FMT_EXCEPTIONS +# define FMT_EXCEPTIONS 1 +#endif + +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + +#ifndef FMT_THROW +# if FMT_EXCEPTIONS +# define FMT_THROW(x) throw x +# else +# define FMT_THROW(x) assert(false) +# endif +#endif + +#ifdef FMT_HEADER_ONLY +# define FMT_FUNC inline +#else +# define FMT_FUNC +#endif + +#if _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant +#endif + +namespace { + +#ifndef _MSC_VER +# define FMT_SNPRINTF snprintf +#else // _MSC_VER +inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { + va_list args; + va_start(args, format); + int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); + va_end(args); + return result; +} +# define FMT_SNPRINTF fmt_snprintf +#endif // _MSC_VER + +// Checks if a value fits in int - used to avoid warnings about comparing +// signed and unsigned integers. +template +struct IntChecker { + template + static bool fits_in_int(T value) { + unsigned max = INT_MAX; + return value <= max; + } +}; + +template <> +struct IntChecker { + template + static bool fits_in_int(T value) { + return value >= INT_MIN && value <= INT_MAX; + } +}; + +const char RESET_COLOR[] = "\x1b[0m"; + +typedef void(*FormatFunc)(fmt::Writer &, int, fmt::StringRef); + +// Portable thread-safe version of strerror. +// Sets buffer to point to a string describing the error code. +// This can be either a pointer to a string stored in buffer, +// or a pointer to some static immutable string. +// Returns one of the following values: +// 0 - success +// ERANGE - buffer is not large enough to store the error message +// other - failure +// Buffer should be at least of size 1. +int safe_strerror( + int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) { + assert(buffer != 0 && buffer_size != 0); + int result = 0; +#ifdef _GNU_SOURCE + char *message = strerror_r(error_code, buffer, buffer_size); + // If the buffer is full then the message is probably truncated. + if (message == buffer && strlen(buffer) == buffer_size - 1) + result = ERANGE; + buffer = message; +#elif __MINGW32__ + errno = 0; + (void)buffer_size; + buffer = strerror(error_code); + result = errno; +#elif _WIN32 + result = strerror_s(buffer, buffer_size, error_code); + // If the buffer is full then the message is probably truncated. + if (result == 0 && std::strlen(buffer) == buffer_size - 1) + result = ERANGE; +#else + result = strerror_r(error_code, buffer, buffer_size); + if (result == -1) + result = errno; // glibc versions before 2.13 return result in errno. +#endif + return result; +} + +void format_error_code(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT(true) { + // Report error code making sure that the output fits into + // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential + // bad_alloc. + out.clear(); + static const char SEP[] = ": "; + static const char ERROR[] = "error "; + fmt::internal::IntTraits::MainType ec_value = error_code; + // Subtract 2 to account for terminating null characters in SEP and ERROR. + std::size_t error_code_size = + sizeof(SEP) + sizeof(ERROR) + fmt::internal::count_digits(ec_value) - 2; + if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size) + out << message << SEP; + out << ERROR << error_code; + assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE); +} + +void report_error(FormatFunc func, + int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { + fmt::MemoryWriter full_message; + func(full_message, error_code, message); + // Use Writer::data instead of Writer::c_str to avoid potential memory + // allocation. + std::fwrite(full_message.data(), full_message.size(), 1, stderr); + std::fputc('\n', stderr); +} + +// IsZeroInt::visit(arg) returns true iff arg is a zero integer. +class IsZeroInt : public fmt::internal::ArgVisitor { +public: + template + bool visit_any_int(T value) { + return value == 0; + } +}; + +// Parses an unsigned integer advancing s to the end of the parsed input. +// This function assumes that the first character of s is a digit. +template +int parse_nonnegative_int(const Char *&s) { + assert('0' <= *s && *s <= '9'); + unsigned value = 0; + do { + unsigned new_value = value * 10 + (*s++ - '0'); + // Check if value wrapped around. + if (new_value < value) { + value = UINT_MAX; + break; + } + value = new_value; + } while ('0' <= *s && *s <= '9'); + if (value > INT_MAX) + FMT_THROW(fmt::FormatError("number is too big")); + return value; +} + +inline void require_numeric_argument(const Arg &arg, char spec) { + if (arg.type > Arg::LAST_NUMERIC_TYPE) { + std::string message = + fmt::format("format specifier '{}' requires numeric argument", spec); + FMT_THROW(fmt::FormatError(message)); + } +} + +template +void check_sign(const Char *&s, const Arg &arg) { + char sign = static_cast(*s); + require_numeric_argument(arg, sign); + if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { + FMT_THROW(fmt::FormatError(fmt::format( + "format specifier '{}' requires signed argument", sign))); + } + ++s; +} + +// Checks if an argument is a valid printf width specifier and sets +// left alignment if it is negative. +class WidthHandler : public fmt::internal::ArgVisitor { +private: + fmt::FormatSpec &spec_; + +public: + explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {} + + unsigned visit_unhandled_arg() { + FMT_THROW(fmt::FormatError("width is not integer")); + return 0; + } + + template + unsigned visit_any_int(T value) { + typedef typename fmt::internal::IntTraits::MainType UnsignedType; + UnsignedType width = value; + if (fmt::internal::is_negative(value)) { + spec_.align_ = fmt::ALIGN_LEFT; + width = 0 - width; + } + if (width > INT_MAX) + FMT_THROW(fmt::FormatError("number is too big")); + return static_cast(width); + } +}; + +class PrecisionHandler : + public fmt::internal::ArgVisitor { +public: + unsigned visit_unhandled_arg() { + FMT_THROW(fmt::FormatError("precision is not integer")); + return 0; + } + + template + int visit_any_int(T value) { + if (!IntChecker::is_signed>::fits_in_int(value)) + FMT_THROW(fmt::FormatError("number is too big")); + return static_cast(value); + } +}; + +// Converts an integer argument to an integral type T for printf. +template +class ArgConverter : public fmt::internal::ArgVisitor, void> { +private: + fmt::internal::Arg &arg_; + wchar_t type_; + +public: + ArgConverter(fmt::internal::Arg &arg, wchar_t type) + : arg_(arg), type_(type) {} + + template + void visit_any_int(U value) { + bool is_signed = type_ == 'd' || type_ == 'i'; + using fmt::internal::Arg; + if (sizeof(T) <= sizeof(int)) { + // Extra casts are used to silence warnings. + if (is_signed) { + arg_.type = Arg::INT; + arg_.int_value = static_cast(static_cast(value)); + } + else { + arg_.type = Arg::UINT; + arg_.uint_value = static_cast( + static_cast::Type>(value)); + } + } + else { + if (is_signed) { + arg_.type = Arg::LONG_LONG; + arg_.long_long_value = + static_cast::Type>(value); + } + else { + arg_.type = Arg::ULONG_LONG; + arg_.ulong_long_value = + static_cast::Type>(value); + } + } + } +}; + +// Converts an integer argument to char for printf. +class CharConverter : public fmt::internal::ArgVisitor { +private: + fmt::internal::Arg &arg_; + +public: + explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {} + + template + void visit_any_int(T value) { + arg_.type = Arg::CHAR; + arg_.int_value = static_cast(value); + } +}; + +// This function template is used to prevent compile errors when handling +// incompatible string arguments, e.g. handling a wide string in a narrow +// string formatter. +template +Arg::StringValue ignore_incompatible_str(Arg::StringValue); + +template <> +inline Arg::StringValue ignore_incompatible_str( + Arg::StringValue) { + return Arg::StringValue(); +} + +template <> +inline Arg::StringValue ignore_incompatible_str( + Arg::StringValue s) { + return s; +} +} // namespace + +FMT_FUNC void fmt::SystemError::init( + int error_code, StringRef format_str, ArgList args) { + error_code_ = error_code; + MemoryWriter w; + internal::format_system_error(w, error_code, format(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + +template +int fmt::internal::CharTraits::format_float( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, T value) { + if (width == 0) { + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, value) : + FMT_SNPRINTF(buffer, size, format, precision, value); + } + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, width, value) : + FMT_SNPRINTF(buffer, size, format, width, precision, value); +} + +template +int fmt::internal::CharTraits::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, T value) { + if (width == 0) { + return precision < 0 ? + swprintf(buffer, size, format, value) : + swprintf(buffer, size, format, precision, value); + } + return precision < 0 ? + swprintf(buffer, size, format, width, value) : + swprintf(buffer, size, format, width, precision, value); +} + +const char fmt::internal::DIGITS[] = + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"; + +#define FMT_POWERS_OF_10(factor) \ + factor * 10, \ + factor * 100, \ + factor * 1000, \ + factor * 10000, \ + factor * 100000, \ + factor * 1000000, \ + factor * 10000000, \ + factor * 100000000, \ + factor * 1000000000 + +const uint32_t fmt::internal::POWERS_OF_10_32[] = { 0, FMT_POWERS_OF_10(1) }; +const uint64_t fmt::internal::POWERS_OF_10_64[] = { + 0, + FMT_POWERS_OF_10(1), + FMT_POWERS_OF_10(ULongLong(1000000000)), + // Multiply several constants instead of using a single long long constant + // to avoid warnings about C++98 not supporting long long. + ULongLong(1000000000) * ULongLong(1000000000) * 10 +}; + +FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) { + if (std::isprint(static_cast(code))) { + FMT_THROW(fmt::FormatError( + fmt::format("unknown format code '{}' for {}", code, type))); + } + FMT_THROW(fmt::FormatError( + fmt::format("unknown format code '\\x{:02x}' for {}", + static_cast(code), type))); +} + +#ifdef _WIN32 + +fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { + int length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0); + static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16"; + if (length == 0) + FMT_THROW(WindowsError(GetLastError(), ERROR)); + buffer_.resize(length); + length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length); + if (length == 0) + FMT_THROW(WindowsError(GetLastError(), ERROR)); +} + +fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { + if (int error_code = convert(s)) { + FMT_THROW(WindowsError(error_code, + "cannot convert string from UTF-16 to UTF-8")); + } +} + +int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { + int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0); + if (length == 0) + return GetLastError(); + buffer_.resize(length); + length = WideCharToMultiByte( + CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0); + if (length == 0) + return GetLastError(); + return 0; +} + +void fmt::WindowsError::init( + int error_code, StringRef format_str, ArgList args) { + error_code_ = error_code; + MemoryWriter w; + internal::format_windows_error(w, error_code, format(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + +#endif + +FMT_FUNC void fmt::internal::format_system_error( + fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT(true) { + FMT_TRY { + MemoryBuffer buffer; + buffer.resize(INLINE_BUFFER_SIZE); + for (;;) { + char *system_message = &buffer[0]; + int result = safe_strerror(error_code, system_message, buffer.size()); + if (result == 0) { + out << message << ": " << system_message; + return; + } + if (result != ERANGE) + break; // Can't get error message, report error code instead. + buffer.resize(buffer.size() * 2); + } + } FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +#ifdef _WIN32 +void fmt::internal::format_windows_error( + fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT(true) { + class String { + private: + LPWSTR str_; + + public: + String() : str_() {} + ~String() { + LocalFree(str_); + } + LPWSTR *ptr() { + return &str_; + } + LPCWSTR c_str() const { + return str_; + } + }; + FMT_TRY { + String system_message; + if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, + error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(system_message.ptr()), 0, 0)) { + UTF16ToUTF8 utf8_message; + if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) { + out << message << ": " << utf8_message; + return; + } + } + } FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} +#endif + +// An argument formatter. +template +class fmt::internal::ArgFormatter : + public fmt::internal::ArgVisitor, void> { +private: + fmt::BasicFormatter &formatter_; + fmt::BasicWriter &writer_; + fmt::FormatSpec &spec_; + const Char *format_; + +public: + ArgFormatter( + fmt::BasicFormatter &f, fmt::FormatSpec &s, const Char *fmt) + : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {} + + template + void visit_any_int(T value) { + writer_.write_int(value, spec_); + } + + template + void visit_any_double(T value) { + writer_.write_double(value, spec_); + } + + void visit_char(int value) { + if (spec_.type_ && spec_.type_ != 'c') { + spec_.flags_ |= CHAR_FLAG; + writer_.write_int(value, spec_); + return; + } + if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) + FMT_THROW(FormatError("invalid format specifier for char")); + typedef typename fmt::BasicWriter::CharPtr CharPtr; + CharPtr out = CharPtr(); + if (spec_.width_ > 1) { + Char fill = static_cast(spec_.fill()); + out = writer_.grow_buffer(spec_.width_); + if (spec_.align_ == fmt::ALIGN_RIGHT) { + std::fill_n(out, spec_.width_ - 1, fill); + out += spec_.width_ - 1; + } + else if (spec_.align_ == fmt::ALIGN_CENTER) { + out = writer_.fill_padding(out, spec_.width_, 1, fill); + } + else { + std::fill_n(out + 1, spec_.width_ - 1, fill); + } + } + else { + out = writer_.grow_buffer(1); + } + *out = static_cast(value); + } + + void visit_string(Arg::StringValue value) { + writer_.write_str(value, spec_); + } + void visit_wstring(Arg::StringValue value) { + writer_.write_str(ignore_incompatible_str(value), spec_); + } + + void visit_pointer(const void *value) { + if (spec_.type_ && spec_.type_ != 'p') + fmt::internal::report_unknown_type(spec_.type_, "pointer"); + spec_.flags_ = fmt::HASH_FLAG; + spec_.type_ = 'x'; + writer_.write_int(reinterpret_cast(value), spec_); + } + + void visit_custom(Arg::CustomValue c) { + c.format(&formatter_, c.value, &format_); + } +}; + +template +template +void fmt::BasicWriter::write_str( + const Arg::StringValue &str, const FormatSpec &spec) { + // Check if StrChar is convertible to Char. + internal::CharTraits::convert(StrChar()); + if (spec.type_ && spec.type_ != 's') + internal::report_unknown_type(spec.type_, "string"); + const StrChar *s = str.value; + std::size_t size = str.size; + if (size == 0) { + if (!s) + FMT_THROW(FormatError("string pointer is null")); + if (*s) + size = std::char_traits::length(s); + } + write_str(s, size, spec); +} + +template +inline Arg fmt::BasicFormatter::parse_arg_index(const Char *&s) { + const char *error = 0; + Arg arg = *s < '0' || *s > '9' ? + next_arg(error) : get_arg(parse_nonnegative_int(s), error); + if (error) { + FMT_THROW(FormatError( + *s != '}' && *s != ':' ? "invalid format string" : error)); + } + return arg; +} + +FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( + unsigned arg_index, const char *&error) { + Arg arg = args_[arg_index]; + if (arg.type == Arg::NONE) + error = "argument index out of range"; + return arg; +} + +inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) { + if (next_arg_index_ >= 0) + return do_get_arg(next_arg_index_++, error); + error = "cannot switch from manual to automatic argument indexing"; + return Arg(); +} + +inline Arg fmt::internal::FormatterBase::get_arg( + unsigned arg_index, const char *&error) { + if (next_arg_index_ <= 0) { + next_arg_index_ = -1; + return do_get_arg(arg_index, error); + } + error = "cannot switch from automatic to manual argument indexing"; + return Arg(); +} + +template +void fmt::internal::PrintfFormatter::parse_flags( + FormatSpec &spec, const Char *&s) { + for (;;) { + switch (*s++) { + case '-': + spec.align_ = ALIGN_LEFT; + break; + case '+': + spec.flags_ |= SIGN_FLAG | PLUS_FLAG; + break; + case '0': + spec.fill_ = '0'; + break; + case ' ': + spec.flags_ |= SIGN_FLAG; + break; + case '#': + spec.flags_ |= HASH_FLAG; + break; + default: + --s; + return; + } + } +} + +template +Arg fmt::internal::PrintfFormatter::get_arg( + const Char *s, unsigned arg_index) { + const char *error = 0; + Arg arg = arg_index == UINT_MAX ? + next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); + if (error) + FMT_THROW(FormatError(!*s ? "invalid format string" : error)); + return arg; +} + +template +unsigned fmt::internal::PrintfFormatter::parse_header( + const Char *&s, FormatSpec &spec) { + unsigned arg_index = UINT_MAX; + Char c = *s; + if (c >= '0' && c <= '9') { + // Parse an argument index (if followed by '$') or a width possibly + // preceded with '0' flag(s). + unsigned value = parse_nonnegative_int(s); + if (*s == '$') { // value is an argument index + ++s; + arg_index = value; + } + else { + if (c == '0') + spec.fill_ = '0'; + if (value != 0) { + // Nonzero value means that we parsed width and don't need to + // parse it or flags again, so return now. + spec.width_ = value; + return arg_index; + } + } + } + parse_flags(spec, s); + // Parse width. + if (*s >= '0' && *s <= '9') { + spec.width_ = parse_nonnegative_int(s); + } + else if (*s == '*') { + ++s; + spec.width_ = WidthHandler(spec).visit(get_arg(s)); + } + return arg_index; +} + +template +void fmt::internal::PrintfFormatter::format( + BasicWriter &writer, BasicStringRef format, + const ArgList &args) { + const Char *start = format.c_str(); + set_args(args); + const Char *s = start; + while (*s) { + Char c = *s++; + if (c != '%') continue; + if (*s == c) { + write(writer, start, s); + start = ++s; + continue; + } + write(writer, start, s - 1); + + FormatSpec spec; + spec.align_ = ALIGN_RIGHT; + + // Parse argument index, flags and width. + unsigned arg_index = parse_header(s, spec); + + // Parse precision. + if (*s == '.') { + ++s; + if ('0' <= *s && *s <= '9') { + spec.precision_ = parse_nonnegative_int(s); + } + else if (*s == '*') { + ++s; + spec.precision_ = PrecisionHandler().visit(get_arg(s)); + } + } + + Arg arg = get_arg(s, arg_index); + if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg)) + spec.flags_ &= ~HASH_FLAG; + if (spec.fill_ == '0') { + if (arg.type <= Arg::LAST_NUMERIC_TYPE) + spec.align_ = ALIGN_NUMERIC; + else + spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. + } + + // Parse length and convert the argument to the required type. + switch (*s++) { + case 'h': + if (*s == 'h') + ArgConverter(arg, *++s).visit(arg); + else + ArgConverter(arg, *s).visit(arg); + break; + case 'l': + if (*s == 'l') + ArgConverter(arg, *++s).visit(arg); + else + ArgConverter(arg, *s).visit(arg); + break; + case 'j': + ArgConverter(arg, *s).visit(arg); + break; + case 'z': + ArgConverter(arg, *s).visit(arg); + break; + case 't': + ArgConverter(arg, *s).visit(arg); + break; + case 'L': + // printf produces garbage when 'L' is omitted for long double, no + // need to do the same. + break; + default: + --s; + ArgConverter(arg, *s).visit(arg); + } + + // Parse type. + if (!*s) + FMT_THROW(FormatError("invalid format string")); + spec.type_ = static_cast(*s++); + if (arg.type <= Arg::LAST_INTEGER_TYPE) { + // Normalize type. + switch (spec.type_) { + case 'i': + case 'u': + spec.type_ = 'd'; + break; + case 'c': + // TODO: handle wchar_t + CharConverter(arg).visit(arg); + break; + } + } + + start = s; + + // Format argument. + switch (arg.type) { + case Arg::INT: + writer.write_int(arg.int_value, spec); + break; + case Arg::UINT: + writer.write_int(arg.uint_value, spec); + break; + case Arg::LONG_LONG: + writer.write_int(arg.long_long_value, spec); + break; + case Arg::ULONG_LONG: + writer.write_int(arg.ulong_long_value, spec); + break; + case Arg::CHAR: { + if (spec.type_ && spec.type_ != 'c') + writer.write_int(arg.int_value, spec); + typedef typename BasicWriter::CharPtr CharPtr; + CharPtr out = CharPtr(); + if (spec.width_ > 1) { + Char fill = ' '; + out = writer.grow_buffer(spec.width_); + if (spec.align_ != ALIGN_LEFT) { + std::fill_n(out, spec.width_ - 1, fill); + out += spec.width_ - 1; + } + else { + std::fill_n(out + 1, spec.width_ - 1, fill); + } + } + else { + out = writer.grow_buffer(1); + } + *out = static_cast(arg.int_value); + break; + } + case Arg::DOUBLE: + writer.write_double(arg.double_value, spec); + break; + case Arg::LONG_DOUBLE: + writer.write_double(arg.long_double_value, spec); + break; + case Arg::CSTRING: + arg.string.size = 0; + writer.write_str(arg.string, spec); + break; + case Arg::STRING: + writer.write_str(arg.string, spec); + break; + case Arg::WSTRING: + writer.write_str(ignore_incompatible_str(arg.wstring), spec); + break; + case Arg::POINTER: + if (spec.type_ && spec.type_ != 'p') + internal::report_unknown_type(spec.type_, "pointer"); + spec.flags_ = HASH_FLAG; + spec.type_ = 'x'; + writer.write_int(reinterpret_cast(arg.pointer), spec); + break; + case Arg::CUSTOM: { + if (spec.type_) + internal::report_unknown_type(spec.type_, "object"); + const void *s = "s"; + arg.custom.format(&writer, arg.custom.value, &s); + break; + } + default: + assert(false); + break; + } + } + write(writer, start, s); +} + +template +const Char *fmt::BasicFormatter::format( + const Char *&format_str, const Arg &arg) { + const Char *s = format_str; + FormatSpec spec; + if (*s == ':') { + if (arg.type == Arg::CUSTOM) { + arg.custom.format(this, arg.custom.value, &s); + return s; + } + ++s; + // Parse fill and alignment. + if (Char c = *s) { + const Char *p = s + 1; + spec.align_ = ALIGN_DEFAULT; + do { + switch (*p) { + case '<': + spec.align_ = ALIGN_LEFT; + break; + case '>': + spec.align_ = ALIGN_RIGHT; + break; + case '=': + spec.align_ = ALIGN_NUMERIC; + break; + case '^': + spec.align_ = ALIGN_CENTER; + break; + } + if (spec.align_ != ALIGN_DEFAULT) { + if (p != s) { + if (c == '}') break; + if (c == '{') + FMT_THROW(FormatError("invalid fill character '{'")); + s += 2; + spec.fill_ = c; + } + else ++s; + if (spec.align_ == ALIGN_NUMERIC) + require_numeric_argument(arg, '='); + break; + } + } while (--p >= s); + } + + // Parse sign. + switch (*s) { + case '+': + check_sign(s, arg); + spec.flags_ |= SIGN_FLAG | PLUS_FLAG; + break; + case '-': + check_sign(s, arg); + spec.flags_ |= MINUS_FLAG; + break; + case ' ': + check_sign(s, arg); + spec.flags_ |= SIGN_FLAG; + break; + } + + if (*s == '#') { + require_numeric_argument(arg, '#'); + spec.flags_ |= HASH_FLAG; + ++s; + } + + // Parse width and zero flag. + if ('0' <= *s && *s <= '9') { + if (*s == '0') { + require_numeric_argument(arg, '0'); + spec.align_ = ALIGN_NUMERIC; + spec.fill_ = '0'; + } + // Zero may be parsed again as a part of the width, but it is simpler + // and more efficient than checking if the next char is a digit. + spec.width_ = parse_nonnegative_int(s); + } + + // Parse precision. + if (*s == '.') { + ++s; + spec.precision_ = 0; + if ('0' <= *s && *s <= '9') { + spec.precision_ = parse_nonnegative_int(s); + } + else if (*s == '{') { + ++s; + const Arg &precision_arg = parse_arg_index(s); + if (*s++ != '}') + FMT_THROW(FormatError("invalid format string")); + ULongLong value = 0; + switch (precision_arg.type) { + case Arg::INT: + if (precision_arg.int_value < 0) + FMT_THROW(FormatError("negative precision")); + value = precision_arg.int_value; + break; + case Arg::UINT: + value = precision_arg.uint_value; + break; + case Arg::LONG_LONG: + if (precision_arg.long_long_value < 0) + FMT_THROW(FormatError("negative precision")); + value = precision_arg.long_long_value; + break; + case Arg::ULONG_LONG: + value = precision_arg.ulong_long_value; + break; + default: + FMT_THROW(FormatError("precision is not integer")); + } + if (value > INT_MAX) + FMT_THROW(FormatError("number is too big")); + spec.precision_ = static_cast(value); + } + else { + FMT_THROW(FormatError("missing precision specifier")); + } + if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) { + FMT_THROW(FormatError( + "precision specifier requires floating-point argument")); + } + } + + // Parse type. + if (*s != '}' && *s) + spec.type_ = static_cast(*s++); + } + + if (*s++ != '}') + FMT_THROW(FormatError("missing '}' in format string")); + start_ = s; + + // Format argument. + internal::ArgFormatter(*this, spec, s - 1).visit(arg); + return s; +} + +template +void fmt::BasicFormatter::format( + BasicStringRef format_str, const ArgList &args) { + const Char *s = start_ = format_str.c_str(); + set_args(args); + while (*s) { + Char c = *s++; + if (c != '{' && c != '}') continue; + if (*s == c) { + write(writer_, start_, s); + start_ = ++s; + continue; + } + if (c == '}') + FMT_THROW(FormatError("unmatched '}' in format string")); + write(writer_, start_, s - 1); + Arg arg = parse_arg_index(s); + s = format(s, arg); + } + write(writer_, start_, s); +} + +FMT_FUNC void fmt::report_system_error( + int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { + report_error(internal::format_system_error, error_code, message); +} + +#ifdef _WIN32 +void fmt::report_windows_error( + int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { + report_error(internal::format_windows_error, error_code, message); +} +#endif + +FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) { + MemoryWriter w; + w.write(format_str, args); + std::fwrite(w.data(), 1, w.size(), f); +} + +FMT_FUNC void fmt::print(StringRef format_str, ArgList args) { + print(stdout, format_str, args); +} + +FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) { + MemoryWriter w; + w.write(format_str, args); + os.write(w.data(), w.size()); +} + +FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) { + char escape[] = "\x1b[30m"; + escape[3] = '0' + static_cast(c); + std::fputs(escape, stdout); + print(format, args); + std::fputs(RESET_COLOR, stdout); +} + +FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) { + MemoryWriter w; + printf(w, format, args); + std::size_t size = w.size(); + return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast(size); +} + +// Explicit instantiations for char. + +template const char *fmt::BasicFormatter::format( + const char *&format_str, const fmt::internal::Arg &arg); + +template void fmt::BasicFormatter::format( + BasicStringRef format, const ArgList &args); + +template void fmt::internal::PrintfFormatter::format( + BasicWriter &writer, BasicStringRef format, const ArgList &args); + +template int fmt::internal::CharTraits::format_float( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, double value); + +template int fmt::internal::CharTraits::format_float( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, long double value); + +// Explicit instantiations for wchar_t. + +template const wchar_t *fmt::BasicFormatter::format( + const wchar_t *&format_str, const fmt::internal::Arg &arg); + +template void fmt::BasicFormatter::format( + BasicStringRef format, const ArgList &args); + +template void fmt::internal::PrintfFormatter::format( + BasicWriter &writer, BasicStringRef format, + const ArgList &args); + +template int fmt::internal::CharTraits::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, double value); + +template int fmt::internal::CharTraits::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, long double value); + +#if _MSC_VER +# pragma warning(pop) +#endif diff --git a/include/spdlog/details/format.h b/include/spdlog/details/format.h new file mode 100644 index 00000000..5e1644c2 --- /dev/null +++ b/include/spdlog/details/format.h @@ -0,0 +1,2589 @@ +/* +Formatting library for C++ + +Copyright (c) 2012 - 2014, Victor Zverovich +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FMT_FORMAT_H_ +#define FMT_FORMAT_H_ + +#include + +#include +#include +#include // for std::ptrdiff_t +#include +#include +#include +#include +#include +#include + +#if _SECURE_SCL +# include +#endif + +#ifdef __GNUC__ +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# define FMT_GCC_EXTENSION __extension__ +// Disable warning about "long long" which is sometimes reported even +// when using __extension__. +# if FMT_GCC_VERSION >= 406 +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wlong-long" +# endif +#else +# define FMT_GCC_EXTENSION +#endif + +#ifdef __GNUC_LIBSTD__ +# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) +#endif + +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif + +#ifdef __has_builtin +# define FMT_HAS_BUILTIN(x) __has_builtin(x) +#else +# define FMT_HAS_BUILTIN(x) 0 +#endif + +#ifndef FMT_USE_VARIADIC_TEMPLATES +// Variadic templates are available in GCC since version 4.4 +// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ +// since version 2013. +# define FMT_USE_VARIADIC_TEMPLATES \ + (FMT_HAS_FEATURE(cxx_variadic_templates) || \ + (FMT_GCC_VERSION >= 404 && __cplusplus >= 201103) || _MSC_VER >= 1800) +#endif + +#ifndef FMT_USE_RVALUE_REFERENCES +// Don't use rvalue references when compiling with clang and an old libstdc++ +// as the latter doesn't provide std::move. +# if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402 +# define FMT_USE_RVALUE_REFERENCES 0 +# else +# define FMT_USE_RVALUE_REFERENCES \ + (FMT_HAS_FEATURE(cxx_rvalue_references) || \ + (FMT_GCC_VERSION >= 403 && __cplusplus >= 201103) || _MSC_VER >= 1600) +# endif +#endif + +#if FMT_USE_RVALUE_REFERENCES +# include // for std::move +#endif + +// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). +#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && __cplusplus >= 201103) +# define FMT_NOEXCEPT(expr) noexcept(expr) +#else +# define FMT_NOEXCEPT(expr) +#endif + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +namespace fmt { + +// Fix the warning about long long on older versions of GCC +// that don't support the diagnostic pragma. +FMT_GCC_EXTENSION typedef long long LongLong; +FMT_GCC_EXTENSION typedef unsigned long long ULongLong; + +#if FMT_USE_RVALUE_REFERENCES +using std::move; +#endif + +template +class BasicWriter; + +typedef BasicWriter Writer; +typedef BasicWriter WWriter; + +template +class BasicFormatter; + +template +void format(BasicFormatter &f, const Char *&format_str, const T &value); + +/** +\rst +A string reference. It can be constructed from a C string or +``std::string``. + +You can use one of the following typedefs for common character types: + ++------------+-------------------------+ +| Type | Definition | ++============+=========================+ +| StringRef | BasicStringRef | ++------------+-------------------------+ +| WStringRef | BasicStringRef | ++------------+-------------------------+ + +This class is most useful as a parameter type to allow passing +different types of strings to a function, for example:: + +template +std::string format(StringRef format, const Args & ... args); + +format("{}", 42); +format(std::string("{}"), 42); +\endrst +*/ +template +class BasicStringRef { +private: + const Char *data_; + std::size_t size_; + +public: + /** + Constructs a string reference object from a C string and a size. + */ + BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} + + /** + Constructs a string reference object from a C string computing + the size with ``std::char_traits::length``. + */ + BasicStringRef(const Char *s) + : data_(s), size_(std::char_traits::length(s)) {} + + /** + Constructs a string reference from an `std::string` object. + */ + BasicStringRef(const std::basic_string &s) + : data_(s.c_str()), size_(s.size()) {} + + /** + Converts a string reference to an `std::string` object. + */ + operator std::basic_string() const { + return std::basic_string(data_, size()); + } + + /** + Returns the pointer to a C string. + */ + const Char *c_str() const { + return data_; + } + + /** + Returns the string size. + */ + std::size_t size() const { + return size_; + } + + friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { + return lhs.data_ == rhs.data_; + } + friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { + return lhs.data_ != rhs.data_; + } +}; + +typedef BasicStringRef StringRef; +typedef BasicStringRef WStringRef; + +/** +A formatting error such as invalid format string. +*/ +class FormatError : public std::runtime_error { +public: + explicit FormatError(StringRef message) + : std::runtime_error(message.c_str()) {} +}; + +namespace internal { + +// The number of characters to store in the MemoryBuffer object itself +// to avoid dynamic memory allocation. +enum { INLINE_BUFFER_SIZE = 500 }; + +#if _SECURE_SCL +// Use checked iterator to avoid warnings on MSVC. +template +inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { + return stdext::checked_array_iterator(ptr, size); +} +#else +template +inline T *make_ptr(T *ptr, std::size_t) { + return ptr; +} +#endif + +// A buffer for POD types. It supports a subset of std::vector's operations. +template +class Buffer { +private: + FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); + +protected: + T *ptr_; + std::size_t size_; + std::size_t capacity_; + + Buffer(T *ptr = 0, std::size_t capacity = 0) + : ptr_(ptr), size_(0), capacity_(capacity) {} + + virtual void grow(std::size_t size) = 0; + +public: + virtual ~Buffer() {} + + // Returns the size of this buffer. + std::size_t size() const { + return size_; + } + + // Returns the capacity of this buffer. + std::size_t capacity() const { + return capacity_; + } + + // Resizes the buffer. If T is a POD type new elements are not initialized. + void resize(std::size_t new_size) { + if (new_size > capacity_) + grow(new_size); + size_ = new_size; + } + + // Reserves space to store at least capacity elements. + void reserve(std::size_t capacity) { + if (capacity > capacity_) + grow(capacity); + } + + void clear() FMT_NOEXCEPT(true) { + size_ = 0; + } + + void push_back(const T &value) { + if (size_ == capacity_) + grow(size_ + 1); + ptr_[size_++] = value; + } + + // Appends data to the end of the buffer. + void append(const T *begin, const T *end); + + T &operator[](std::size_t index) { + return ptr_[index]; + } + const T &operator[](std::size_t index) const { + return ptr_[index]; + } +}; + +template +void Buffer::append(const T *begin, const T *end) { + std::ptrdiff_t num_elements = end - begin; + if (size_ + num_elements > capacity_) + grow(size_ + num_elements); + std::copy(begin, end, make_ptr(ptr_, capacity_) + size_); + size_ += num_elements; +} + +// A memory buffer for POD types with the first SIZE elements stored in +// the object itself. +template > +class MemoryBuffer : private Allocator, public Buffer { +private: + T data_[SIZE]; + + // Free memory allocated by the buffer. + void free() { + if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_); + } + +protected: + void grow(std::size_t size); + +public: + explicit MemoryBuffer(const Allocator &alloc = Allocator()) + : Allocator(alloc), Buffer(data_, SIZE) {} + ~MemoryBuffer() { + free(); + } + +#if FMT_USE_RVALUE_REFERENCES +private: + // Move data from other to this buffer. + void move(MemoryBuffer &other) { + Allocator &this_alloc = *this, &other_alloc = other; + this_alloc = std::move(other_alloc); + this->size_ = other.size_; + this->capacity_ = other.capacity_; + if (other.ptr_ == other.data_) { + this->ptr_ = data_; + std::copy(other.data_, + other.data_ + this->size_, make_ptr(data_, this->capacity_)); + } + else { + this->ptr_ = other.ptr_; + // Set pointer to the inline array so that delete is not called + // when freeing. + other.ptr_ = other.data_; + } + } + +public: + MemoryBuffer(MemoryBuffer &&other) { + move(other); + } + + MemoryBuffer &operator=(MemoryBuffer &&other) { + assert(this != &other); + free(); + move(other); + return *this; + } +#endif + + // Returns a copy of the allocator associated with this buffer. + Allocator get_allocator() const { + return *this; + } +}; + +template +void MemoryBuffer::grow(std::size_t size) { + std::size_t new_capacity = + (std::max)(size, this->capacity_ + this->capacity_ / 2); + T *new_ptr = this->allocate(new_capacity); + // The following code doesn't throw, so the raw pointer above doesn't leak. + std::copy(this->ptr_, + this->ptr_ + this->size_, make_ptr(new_ptr, new_capacity)); + std::size_t old_capacity = this->capacity_; + T *old_ptr = this->ptr_; + this->capacity_ = new_capacity; + this->ptr_ = new_ptr; + // deallocate may throw (at least in principle), but it doesn't matter since + // the buffer already uses the new storage and will deallocate it in case + // of exception. + if (old_ptr != data_) + this->deallocate(old_ptr, old_capacity); +} + +#ifndef _MSC_VER +// Portable version of signbit. +inline int getsign(double x) { + // When compiled in C++11 mode signbit is no longer a macro but a function + // defined in namespace std and the macro is undefined. +# ifdef signbit + return signbit(x); +# else + return std::signbit(x); +# endif +} + +// Portable version of isinf. +# ifdef isinf +inline int isinfinity(double x) { + return isinf(x); +} +inline int isinfinity(long double x) { + return isinf(x); +} +# else +inline int isinfinity(double x) { + return std::isinf(x); +} +inline int isinfinity(long double x) { + return std::isinf(x); +} +# endif +#else +inline int getsign(double value) { + if (value < 0) return 1; + if (value == value) return 0; + int dec = 0, sign = 0; + char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. + _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign); + return sign; +} +inline int isinfinity(double x) { + return !_finite(x); +} +#endif + +template +struct IsLongDouble { + enum { VALUE = 0 }; +}; + +template <> +struct IsLongDouble { + enum { VALUE = 1 }; +}; + +template +class BasicCharTraits { +public: +#if _SECURE_SCL + typedef stdext::checked_array_iterator CharPtr; +#else + typedef Char *CharPtr; +#endif +}; + +template +class CharTraits; + +template <> +class CharTraits : public BasicCharTraits { +private: + // Conversion from wchar_t to char is not allowed. + static char convert(wchar_t); + +public: + typedef const wchar_t *UnsupportedStrType; + + static char convert(char value) { + return value; + } + + // Formats a floating-point number. + template + static int format_float(char *buffer, std::size_t size, + const char *format, unsigned width, int precision, T value); +}; + +template <> +class CharTraits : public BasicCharTraits { +public: + typedef const char *UnsupportedStrType; + + static wchar_t convert(char value) { + return value; + } + static wchar_t convert(wchar_t value) { + return value; + } + + template + static int format_float(wchar_t *buffer, std::size_t size, + const wchar_t *format, unsigned width, int precision, T value); +}; + +// Checks if a number is negative - used to avoid warnings. +template +struct SignChecker { + template + static bool is_negative(T value) { + return value < 0; + } +}; + +template <> +struct SignChecker { + template + static bool is_negative(T) { + return false; + } +}; + +// Returns true if value is negative, false otherwise. +// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. +template +inline bool is_negative(T value) { + return SignChecker::is_signed>::is_negative(value); +} + +// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. +template +struct TypeSelector { + typedef uint32_t Type; +}; + +template <> +struct TypeSelector { + typedef uint64_t Type; +}; + +template +struct IntTraits { + // Smallest of uint32_t and uint64_t that is large enough to represent + // all values of T. + typedef typename + TypeSelector::digits <= 32>::Type MainType; +}; + +// MakeUnsigned::Type gives an unsigned type corresponding to integer type T. +template +struct MakeUnsigned { + typedef T Type; +}; + +#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ + template <> \ + struct MakeUnsigned { typedef U Type; } + +FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); +FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); +FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); +FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); +FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); +FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); + +void report_unknown_type(char code, const char *type); + +extern const uint32_t POWERS_OF_10_32[]; +extern const uint64_t POWERS_OF_10_64[]; + +#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) +// Returns the number of decimal digits in n. Leading zeros are not counted +// except for n == 0 in which case count_digits returns 1. +inline unsigned count_digits(uint64_t n) { + // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. + unsigned t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12; + return t - (n < POWERS_OF_10_64[t]) + 1; +} +# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) +// Optional version of count_digits for better performance on 32-bit platforms. +inline unsigned count_digits(uint32_t n) { + uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12; + return t - (n < POWERS_OF_10_32[t]) + 1; +} +# endif +#else +// Fallback version of count_digits used when __builtin_clz is not available. +inline unsigned count_digits(uint64_t n) { + unsigned count = 1; + for (;;) { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + if (n < 10000) return count + 3; + n /= 10000u; + count += 4; + } +} +#endif + +extern const char DIGITS[]; + +// Formats a decimal unsigned integer value writing into buffer. +template +inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { + --num_digits; + while (value >= 100) { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + unsigned index = (value % 100) * 2; + value /= 100; + buffer[num_digits] = DIGITS[index + 1]; + buffer[num_digits - 1] = DIGITS[index]; + num_digits -= 2; + } + if (value < 10) { + *buffer = static_cast('0' + value); + return; + } + unsigned index = static_cast(value * 2); + buffer[1] = DIGITS[index + 1]; + buffer[0] = DIGITS[index]; +} + +#ifdef _WIN32 +// A converter from UTF-8 to UTF-16. +// It is only provided for Windows since other systems support UTF-8 natively. +class UTF8ToUTF16 { +private: + MemoryBuffer buffer_; + +public: + explicit UTF8ToUTF16(StringRef s); + operator WStringRef() const { + return WStringRef(&buffer_[0], size()); + } + size_t size() const { + return buffer_.size() - 1; + } + const wchar_t *c_str() const { + return &buffer_[0]; + } + std::wstring str() const { + return std::wstring(&buffer_[0], size()); + } +}; + +// A converter from UTF-16 to UTF-8. +// It is only provided for Windows since other systems support UTF-8 natively. +class UTF16ToUTF8 { +private: + MemoryBuffer buffer_; + +public: + UTF16ToUTF8() {} + explicit UTF16ToUTF8(WStringRef s); + operator StringRef() const { + return StringRef(&buffer_[0], size()); + } + size_t size() const { + return buffer_.size() - 1; + } + const char *c_str() const { + return &buffer_[0]; + } + std::string str() const { + return std::string(&buffer_[0], size()); + } + + // Performs conversion returning a system error code instead of + // throwing exception on conversion error. This method may still throw + // in case of memory allocation error. + int convert(WStringRef s); +}; +#endif + +void format_system_error(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT(true); + +#ifdef _WIN32 +void format_windows_error(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT(true); +#endif + +// Computes max(Arg, 1) at compile time. It is used to avoid errors about +// allocating an array of 0 size. +template +struct NonZero { + enum { VALUE = Arg }; +}; + +template <> +struct NonZero<0> { + enum { VALUE = 1 }; +}; + +// The value of a formatting argument. It is a POD type to allow storage in +// internal::MemoryBuffer. +struct Value { + template + struct StringValue { + const Char *value; + std::size_t size; + }; + + typedef void(*FormatFunc)( + void *formatter, const void *arg, void *format_str_ptr); + + struct CustomValue { + const void *value; + FormatFunc format; + }; + + union { + int int_value; + unsigned uint_value; + LongLong long_long_value; + ULongLong ulong_long_value; + double double_value; + long double long_double_value; + const void *pointer; + StringValue string; + StringValue sstring; + StringValue ustring; + StringValue wstring; + CustomValue custom; + }; +}; + +struct Arg : Value { + enum Type { + NONE, + // Integer types should go first, + INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR, + // followed by floating-point types. + DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, + CSTRING, STRING, WSTRING, POINTER, CUSTOM + }; + Type type; +}; + +// Makes a Value object from any type. +template +class MakeValue : public Value { +private: + // The following two methods are private to disallow formatting of + // arbitrary pointers. If you want to output a pointer cast it to + // "void *" or "const void *". In particular, this forbids formatting + // of "[const] volatile char *" which is printed as bool by iostreams. + // Do not implement! + template + MakeValue(const T *value); + template + MakeValue(T *value); + + void set_string(StringRef str) { + string.value = str.c_str(); + string.size = str.size(); + } + + void set_string(WStringRef str) { + CharTraits::convert(wchar_t()); + wstring.value = str.c_str(); + wstring.size = str.size(); + } + + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom_arg( + void *formatter, const void *arg, void *format_str_ptr) { + format(*static_cast*>(formatter), + *static_cast(format_str_ptr), + *static_cast(arg)); + } + +public: + MakeValue() {} + +#define FMT_MAKE_VALUE(Type, field, TYPE) \ + MakeValue(Type value) { field = value; } \ + static uint64_t type(Type) { return Arg::TYPE; } + + FMT_MAKE_VALUE(bool, int_value, INT) + FMT_MAKE_VALUE(short, int_value, INT) + FMT_MAKE_VALUE(unsigned short, uint_value, UINT) + FMT_MAKE_VALUE(int, int_value, INT) + FMT_MAKE_VALUE(unsigned, uint_value, UINT) + + MakeValue(long value) { + // To minimize the number of types we need to deal with, long is + // translated either to int or to long long depending on its size. + if (sizeof(long) == sizeof(int)) + int_value = static_cast(value); + else + long_long_value = value; + } + static uint64_t type(long) { + return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; + } + + MakeValue(unsigned long value) { + if (sizeof(unsigned long) == sizeof(unsigned)) + uint_value = static_cast(value); + else + ulong_long_value = value; + } + static uint64_t type(unsigned long) { + return sizeof(unsigned long) == sizeof(unsigned) ? + Arg::UINT : Arg::ULONG_LONG; + } + + FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) + FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) + FMT_MAKE_VALUE(float, double_value, DOUBLE) + FMT_MAKE_VALUE(double, double_value, DOUBLE) + FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) + FMT_MAKE_VALUE(signed char, int_value, CHAR) + FMT_MAKE_VALUE(unsigned char, int_value, CHAR) + FMT_MAKE_VALUE(char, int_value, CHAR) + + MakeValue(wchar_t value) { + int_value = internal::CharTraits::convert(value); + } + static uint64_t type(wchar_t) { + return Arg::CHAR; + } + +#define FMT_MAKE_STR_VALUE(Type, TYPE) \ + MakeValue(Type value) { set_string(value); } \ + static uint64_t type(Type) { return Arg::TYPE; } + + FMT_MAKE_VALUE(char *, string.value, CSTRING) + FMT_MAKE_VALUE(const char *, string.value, CSTRING) + FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING) + FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) + FMT_MAKE_STR_VALUE(const std::string &, STRING) + FMT_MAKE_STR_VALUE(StringRef, STRING) + + FMT_MAKE_STR_VALUE(wchar_t *, WSTRING) + FMT_MAKE_STR_VALUE(const wchar_t *, WSTRING) + FMT_MAKE_STR_VALUE(const std::wstring &, WSTRING) + FMT_MAKE_STR_VALUE(WStringRef, WSTRING) + + FMT_MAKE_VALUE(void *, pointer, POINTER) + FMT_MAKE_VALUE(const void *, pointer, POINTER) + + template + MakeValue(const T &value) { + custom.value = &value; + custom.format = &format_custom_arg; + } + template + static uint64_t type(const T &) { + return Arg::CUSTOM; + } +}; + +#define FMT_DISPATCH(call) static_cast(this)->call + +// An argument visitor. +// To use ArgVisitor define a subclass that implements some or all of the +// visit methods with the same signatures as the methods in ArgVisitor, +// for example, visit_int(int). +// Specify the subclass name as the Impl template parameter. Then calling +// ArgVisitor::visit for some argument will dispatch to a visit method +// specific to the argument type. For example, if the argument type is +// double then visit_double(double) method of a subclass will be called. +// If the subclass doesn't contain a method with this signature, then +// a corresponding method of ArgVisitor will be called. +// +// Example: +// class MyArgVisitor : public ArgVisitor { +// public: +// void visit_int(int value) { print("{}", value); } +// void visit_double(double value) { print("{}", value ); } +// }; +// +// ArgVisitor uses the curiously recurring template pattern: +// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern +template +class ArgVisitor { +public: + Result visit_unhandled_arg() { + return Result(); + } + + Result visit_int(int value) { + return FMT_DISPATCH(visit_any_int(value)); + } + Result visit_long_long(LongLong value) { + return FMT_DISPATCH(visit_any_int(value)); + } + Result visit_uint(unsigned value) { + return FMT_DISPATCH(visit_any_int(value)); + } + Result visit_ulong_long(ULongLong value) { + return FMT_DISPATCH(visit_any_int(value)); + } + Result visit_char(int value) { + return FMT_DISPATCH(visit_any_int(value)); + } + template + Result visit_any_int(T) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + Result visit_double(double value) { + return FMT_DISPATCH(visit_any_double(value)); + } + Result visit_long_double(long double value) { + return FMT_DISPATCH(visit_any_double(value)); + } + template + Result visit_any_double(T) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + Result visit_string(Arg::StringValue) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + Result visit_wstring(Arg::StringValue) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + Result visit_pointer(const void *) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + Result visit_custom(Arg::CustomValue) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + Result visit(const Arg &arg) { + switch (arg.type) { + default: + assert(false); + // Fall through. + case Arg::INT: + return FMT_DISPATCH(visit_int(arg.int_value)); + case Arg::UINT: + return FMT_DISPATCH(visit_uint(arg.uint_value)); + case Arg::LONG_LONG: + return FMT_DISPATCH(visit_long_long(arg.long_long_value)); + case Arg::ULONG_LONG: + return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); + case Arg::DOUBLE: + return FMT_DISPATCH(visit_double(arg.double_value)); + case Arg::LONG_DOUBLE: + return FMT_DISPATCH(visit_long_double(arg.long_double_value)); + case Arg::CHAR: + return FMT_DISPATCH(visit_char(arg.int_value)); + case Arg::CSTRING: { + Value::StringValue str = arg.string; + str.size = 0; + return FMT_DISPATCH(visit_string(str)); + } + case Arg::STRING: + return FMT_DISPATCH(visit_string(arg.string)); + case Arg::WSTRING: + return FMT_DISPATCH(visit_wstring(arg.wstring)); + case Arg::POINTER: + return FMT_DISPATCH(visit_pointer(arg.pointer)); + case Arg::CUSTOM: + return FMT_DISPATCH(visit_custom(arg.custom)); + } + } +}; + +class RuntimeError : public std::runtime_error { +protected: + RuntimeError() : std::runtime_error("") {} +}; + +template +class ArgFormatter; +} // namespace internal + +/** +An argument list. +*/ +class ArgList { +private: + uint64_t types_; + const internal::Value *values_; + +public: + // Maximum number of arguments that can be passed in ArgList. + enum { MAX_ARGS = 16 }; + + ArgList() : types_(0) {} + ArgList(ULongLong types, const internal::Value *values) + : types_(types), values_(values) {} + + /** + Returns the argument at specified index. + */ + internal::Arg operator[](unsigned index) const { + using internal::Arg; + Arg arg; + if (index >= MAX_ARGS) { + arg.type = Arg::NONE; + return arg; + } + unsigned shift = index * 4; + uint64_t mask = 0xf; + Arg::Type type = + static_cast((types_ & (mask << shift)) >> shift); + arg.type = type; + if (type != Arg::NONE) { + internal::Value &value = arg; + value = values_[index]; + } + return arg; + } +}; + +struct FormatSpec; + +namespace internal { + +class FormatterBase { +private: + ArgList args_; + int next_arg_index_; + + // Returns the argument with specified index. + Arg do_get_arg(unsigned arg_index, const char *&error); + +protected: + void set_args(const ArgList &args) { + args_ = args; + next_arg_index_ = 0; + } + + // Returns the next argument. + Arg next_arg(const char *&error); + + // Checks if manual indexing is used and returns the argument with + // specified index. + Arg get_arg(unsigned arg_index, const char *&error); + + template + void write(BasicWriter &w, const Char *start, const Char *end) { + if (start != end) + w << BasicStringRef(start, end - start); + } +}; + +// A printf formatter. +template +class PrintfFormatter : private FormatterBase { +private: + void parse_flags(FormatSpec &spec, const Char *&s); + + // Returns the argument with specified index or, if arg_index is equal + // to the maximum unsigned value, the next argument. + Arg get_arg(const Char *s, + unsigned arg_index = (std::numeric_limits::max)()); + + // Parses argument index, flags and width and returns the argument index. + unsigned parse_header(const Char *&s, FormatSpec &spec); + +public: + void format(BasicWriter &writer, + BasicStringRef format, const ArgList &args); +}; +} // namespace internal + +// A formatter. +template +class BasicFormatter : private internal::FormatterBase { +private: + BasicWriter &writer_; + const Char *start_; + + // Parses argument index and returns corresponding argument. + internal::Arg parse_arg_index(const Char *&s); + +public: + explicit BasicFormatter(BasicWriter &w) : writer_(w) {} + + BasicWriter &writer() { + return writer_; + } + + void format(BasicStringRef format_str, const ArgList &args); + + const Char *format(const Char *&format_str, const internal::Arg &arg); +}; + +enum Alignment { + ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC +}; + +// Flags. +enum { + SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8, + CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. +}; + +// An empty format specifier. +struct EmptySpec {}; + +// A type specifier. +template +struct TypeSpec : EmptySpec { + Alignment align() const { + return ALIGN_DEFAULT; + } + unsigned width() const { + return 0; + } + int precision() const { + return -1; + } + bool flag(unsigned) const { + return false; + } + char type() const { + return TYPE; + } + char fill() const { + return ' '; + } +}; + +// A width specifier. +struct WidthSpec { + unsigned width_; + // Fill is always wchar_t and cast to char if necessary to avoid having + // two specialization of WidthSpec and its subclasses. + wchar_t fill_; + + WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} + + unsigned width() const { + return width_; + } + wchar_t fill() const { + return fill_; + } +}; + +// An alignment specifier. +struct AlignSpec : WidthSpec { + Alignment align_; + + AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) + : WidthSpec(width, fill), align_(align) {} + + Alignment align() const { + return align_; + } + + int precision() const { + return -1; + } +}; + +// An alignment and type specifier. +template +struct AlignTypeSpec : AlignSpec { + AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} + + bool flag(unsigned) const { + return false; + } + char type() const { + return TYPE; + } +}; + +// A full format specifier. +struct FormatSpec : AlignSpec { + unsigned flags_; + int precision_; + char type_; + + FormatSpec( + unsigned width = 0, char type = 0, wchar_t fill = ' ') + : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} + + bool flag(unsigned f) const { + return (flags_ & f) != 0; + } + int precision() const { + return precision_; + } + char type() const { + return type_; + } +}; + +// An integer format specifier. +template , typename Char = char> +class IntFormatSpec : public SpecT { +private: + T value_; + +public: + IntFormatSpec(T value, const SpecT &spec = SpecT()) + : SpecT(spec), value_(value) {} + + T value() const { + return value_; + } +}; + +// A string format specifier. +template +class StrFormatSpec : public AlignSpec { +private: + const T *str_; + +public: + StrFormatSpec(const T *str, unsigned width, wchar_t fill) + : AlignSpec(width, fill), str_(str) {} + + const T *str() const { + return str_; + } +}; + +/** +Returns an integer format specifier to format the value in base 2. +*/ +IntFormatSpec > bin(int value); + +/** +Returns an integer format specifier to format the value in base 8. +*/ +IntFormatSpec > oct(int value); + +/** +Returns an integer format specifier to format the value in base 16 using +lower-case letters for the digits above 9. +*/ +IntFormatSpec > hex(int value); + +/** +Returns an integer formatter format specifier to format in base 16 using +upper-case letters for the digits above 9. +*/ +IntFormatSpec > hexu(int value); + +/** +\rst +Returns an integer format specifier to pad the formatted argument with the +fill character to the specified width using the default (right) numeric +alignment. + +**Example**:: + +MemoryWriter out; +out << pad(hex(0xcafe), 8, '0'); +// out.str() == "0000cafe" + +\endrst +*/ +template +IntFormatSpec, Char> pad( + int value, unsigned width, Char fill = ' '); + +#define FMT_DEFINE_INT_FORMATTERS(TYPE) \ +inline IntFormatSpec > bin(TYPE value) { \ + return IntFormatSpec >(value, TypeSpec<'b'>()); \ + } \ + \ +inline IntFormatSpec > oct(TYPE value) { \ + return IntFormatSpec >(value, TypeSpec<'o'>()); \ + } \ + \ +inline IntFormatSpec > hex(TYPE value) { \ + return IntFormatSpec >(value, TypeSpec<'x'>()); \ + } \ + \ +inline IntFormatSpec > hexu(TYPE value) { \ + return IntFormatSpec >(value, TypeSpec<'X'>()); \ + } \ + \ +template \ +inline IntFormatSpec > pad( \ + IntFormatSpec > f, unsigned width) { \ + return IntFormatSpec >( \ + f.value(), AlignTypeSpec(width, ' ')); \ + } \ + \ +/* For compatibility with older compilers we provide two overloads for pad, */ \ +/* one that takes a fill character and one that doesn't. In the future this */ \ +/* can be replaced with one overload making the template argument Char */ \ +/* default to char (C++11). */ \ +template \ +inline IntFormatSpec, Char> pad( \ + IntFormatSpec, Char> f, \ + unsigned width, Char fill) { \ + return IntFormatSpec, Char>( \ + f.value(), AlignTypeSpec(width, fill)); \ + } \ + \ +inline IntFormatSpec > pad( \ + TYPE value, unsigned width) { \ + return IntFormatSpec >( \ + value, AlignTypeSpec<0>(width, ' ')); \ + } \ + \ +template \ +inline IntFormatSpec, Char> pad( \ + TYPE value, unsigned width, Char fill) { \ + return IntFormatSpec, Char>( \ + value, AlignTypeSpec<0>(width, fill)); \ + } + +FMT_DEFINE_INT_FORMATTERS(int) +FMT_DEFINE_INT_FORMATTERS(long) +FMT_DEFINE_INT_FORMATTERS(unsigned) +FMT_DEFINE_INT_FORMATTERS(unsigned long) +FMT_DEFINE_INT_FORMATTERS(LongLong) +FMT_DEFINE_INT_FORMATTERS(ULongLong) + +/** +\rst +Returns a string formatter that pads the formatted argument with the fill +character to the specified width using the default (left) string alignment. + +**Example**:: + +std::string s = str(MemoryWriter() << pad("abc", 8)); +// s == "abc " + +\endrst +*/ +template +inline StrFormatSpec pad( + const Char *str, unsigned width, Char fill = ' ') { + return StrFormatSpec(str, width, fill); +} + +inline StrFormatSpec pad( + const wchar_t *str, unsigned width, char fill = ' ') { + return StrFormatSpec(str, width, fill); +} + +// Generates a comma-separated list with results of applying f to +// numbers 0..n-1. +# define FMT_GEN(n, f) FMT_GEN##n(f) +# define FMT_GEN1(f) f(0) +# define FMT_GEN2(f) FMT_GEN1(f), f(1) +# define FMT_GEN3(f) FMT_GEN2(f), f(2) +# define FMT_GEN4(f) FMT_GEN3(f), f(3) +# define FMT_GEN5(f) FMT_GEN4(f), f(4) +# define FMT_GEN6(f) FMT_GEN5(f), f(5) +# define FMT_GEN7(f) FMT_GEN6(f), f(6) +# define FMT_GEN8(f) FMT_GEN7(f), f(7) +# define FMT_GEN9(f) FMT_GEN8(f), f(8) +# define FMT_GEN10(f) FMT_GEN9(f), f(9) +# define FMT_GEN11(f) FMT_GEN10(f), f(10) +# define FMT_GEN12(f) FMT_GEN11(f), f(11) +# define FMT_GEN13(f) FMT_GEN12(f), f(12) +# define FMT_GEN14(f) FMT_GEN13(f), f(13) +# define FMT_GEN15(f) FMT_GEN14(f), f(14) + +namespace internal { +inline uint64_t make_type() { + return 0; +} + +template +inline uint64_t make_type(const T &arg) { + return MakeValue::type(arg); +} + +#if FMT_USE_VARIADIC_TEMPLATES +template +inline uint64_t make_type(const Arg &first, const Args & ... tail) { + return make_type(first) | (make_type(tail...) << 4); +} +#else + +struct ArgType { + uint64_t type; + + ArgType() : type(0) {} + + template + ArgType(const T &arg) : type(make_type(arg)) {} +}; + +# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() + +inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { + return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | + (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | + (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | + (t12.type << 48) | (t13.type << 52) | (t14.type << 56); +} +#endif +} // namespace internal + +# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n +# define FMT_MAKE_ARG_TYPE(n) T##n +# define FMT_MAKE_ARG(n) const T##n &v##n +# define FMT_MAKE_REF_char(n) fmt::internal::MakeValue(v##n) +# define FMT_MAKE_REF_wchar_t(n) fmt::internal::MakeValue(v##n) + +#if FMT_USE_VARIADIC_TEMPLATES +// Defines a variadic function returning void. +# define FMT_VARIADIC_VOID(func, arg_type) \ + template \ + void func(arg_type arg1, const Args & ... args) { \ + const fmt::internal::Value values[ \ + fmt::internal::NonZero::VALUE] = { \ + fmt::internal::MakeValue(args)... \ + }; \ + func(arg1, ArgList(fmt::internal::make_type(args...), values)); \ + } + +// Defines a variadic constructor. +# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ + template \ + ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ + using fmt::internal::MakeValue; \ + const fmt::internal::Value values[ \ + fmt::internal::NonZero::VALUE] = { \ + MakeValue(args)... \ + }; \ + func(arg0, arg1, ArgList(fmt::internal::make_type(args...), values)); \ + } + +#else + +# define FMT_MAKE_REF(n) fmt::internal::MakeValue(v##n) +# define FMT_MAKE_REF2(n) v##n + +// Defines a wrapper for a function taking one argument of type arg_type +// and n additional arguments of arbitrary types. +# define FMT_WRAP1(func, arg_type, n) \ + template \ + inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ + func(arg1, fmt::ArgList( \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ + } + +// Emulates a variadic function returning void on a pre-C++11 compiler. +# define FMT_VARIADIC_VOID(func, arg_type) \ + FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \ + FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ + FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \ + FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \ + FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10) + +# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ + template \ + ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ + func(arg0, arg1, fmt::ArgList( \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ + } + +// Emulates a variadic constructor on a pre-C++11 compiler. +# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 10) +#endif + +// Generates a comma-separated list with results of applying f to pairs +// (argument, index). +#define FMT_FOR_EACH1(f, x0) f(x0, 0) +#define FMT_FOR_EACH2(f, x0, x1) \ + FMT_FOR_EACH1(f, x0), f(x1, 1) +#define FMT_FOR_EACH3(f, x0, x1, x2) \ + FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2) +#define FMT_FOR_EACH4(f, x0, x1, x2, x3) \ + FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3) +#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \ + FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4) +#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \ + FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5) +#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \ + FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6) +#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \ + FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7) +#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \ + FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8) +#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ + FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9) + +/** +An error returned by an operating system or a language runtime, +for example a file opening error. +*/ +class SystemError : public internal::RuntimeError { +private: + void init(int error_code, StringRef format_str, ArgList args); + +protected: + int error_code_; + + typedef char Char; // For FMT_VARIADIC_CTOR. + + SystemError() {} + +public: + /** + \rst + Constructs a :cpp:class:`fmt::SystemError` object with the description + of the form "**: **", where ** is the + formatted message and ** is the system message corresponding + to the error code. + *error_code* is a system error code as given by ``errno``. + \endrst + */ + SystemError(int error_code, StringRef message) { + init(error_code, message, ArgList()); + } + FMT_VARIADIC_CTOR(SystemError, init, int, StringRef) + + int error_code() const { + return error_code_; + } +}; + +/** +\rst +This template provides operations for formatting and writing data into +a character stream. The output is stored in a buffer provided by a subclass +such as :cpp:class:`fmt::BasicMemoryWriter`. + +You can use one of the following typedefs for common character types: + ++---------+----------------------+ +| Type | Definition | ++=========+======================+ +| Writer | BasicWriter | ++---------+----------------------+ +| WWriter | BasicWriter | ++---------+----------------------+ + +\endrst +*/ +template +class BasicWriter { +private: + // Output buffer. + internal::Buffer &buffer_; + + FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter); + + typedef typename internal::CharTraits::CharPtr CharPtr; + +#if _SECURE_SCL + // Returns pointer value. + static Char *get(CharPtr p) { + return p.base(); + } +#else + static Char *get(Char *p) { + return p; + } +#endif + + // Fills the padding around the content and returns the pointer to the + // content area. + static CharPtr fill_padding(CharPtr buffer, + unsigned total_size, std::size_t content_size, wchar_t fill); + + // Grows the buffer by n characters and returns a pointer to the newly + // allocated area. + CharPtr grow_buffer(std::size_t n) { + std::size_t size = buffer_.size(); + buffer_.resize(size + n); + return internal::make_ptr(&buffer_[size], n); + } + + // Prepare a buffer for integer formatting. + CharPtr prepare_int_buffer(unsigned num_digits, + const EmptySpec &, const char *prefix, unsigned prefix_size) { + unsigned size = prefix_size + num_digits; + CharPtr p = grow_buffer(size); + std::copy(prefix, prefix + prefix_size, p); + return p + size - 1; + } + + template + CharPtr prepare_int_buffer(unsigned num_digits, + const Spec &spec, const char *prefix, unsigned prefix_size); + + // Formats an integer. + template + void write_int(T value, Spec spec); + + // Formats a floating-point number (double or long double). + template + void write_double(T value, const FormatSpec &spec); + + // Writes a formatted string. + template + CharPtr write_str( + const StrChar *s, std::size_t size, const AlignSpec &spec); + + template + void write_str( + const internal::Arg::StringValue &str, const FormatSpec &spec); + + // This method is private to disallow writing a wide string to a + // char stream and vice versa. If you want to print a wide string + // as a pointer as std::ostream does, cast it to const void*. + // Do not implement! + void operator<<(typename internal::CharTraits::UnsupportedStrType); + + friend class internal::ArgFormatter; + friend class internal::PrintfFormatter; + +protected: + /** + Constructs a ``BasicWriter`` object. + */ + explicit BasicWriter(internal::Buffer &b) : buffer_(b) {} + +public: + /** + Destroys a ``BasicWriter`` object. + */ + virtual ~BasicWriter() {} + + /** + Returns the total number of characters written. + */ + std::size_t size() const { + return buffer_.size(); + } + + /** + Returns a pointer to the output buffer content. No terminating null + character is appended. + */ + const Char *data() const FMT_NOEXCEPT(true) { + return &buffer_[0]; + } + + /** + Returns a pointer to the output buffer content with terminating null + character appended. + */ + const Char *c_str() const { + std::size_t size = buffer_.size(); + buffer_.reserve(size + 1); + buffer_[size] = '\0'; + return &buffer_[0]; + } + + /** + Returns the content of the output buffer as an `std::string`. + */ + std::basic_string str() const { + return std::basic_string(&buffer_[0], buffer_.size()); + } + + /** + \rst + Writes formatted data. + + *args* is an argument list representing arbitrary arguments. + + **Example**:: + + MemoryWriter out; + out.write("Current point:\n"); + out.write("({:+f}, {:+f})", -3.14, 3.14); + + This will write the following output to the ``out`` object: + + .. code-block:: none + + Current point: + (-3.140000, +3.140000) + + The output can be accessed using :meth:`data`, :meth:`c_str` or :meth:`str` + methods. + + See also :ref:`syntax`. + \endrst + */ + void write(BasicStringRef format, ArgList args) { + BasicFormatter(*this).format(format, args); + } + FMT_VARIADIC_VOID(write, BasicStringRef) + + BasicWriter &operator<<(int value) { + return *this << IntFormatSpec(value); + } + BasicWriter &operator<<(unsigned value) { + return *this << IntFormatSpec(value); + } + BasicWriter &operator<<(long value) { + return *this << IntFormatSpec(value); + } + BasicWriter &operator<<(unsigned long value) { + return *this << IntFormatSpec(value); + } + BasicWriter &operator<<(LongLong value) { + return *this << IntFormatSpec(value); + } + + /** + Formats *value* and writes it to the stream. + */ + BasicWriter &operator<<(ULongLong value) { + return *this << IntFormatSpec(value); + } + + BasicWriter &operator<<(double value) { + write_double(value, FormatSpec()); + return *this; + } + + /** + Formats *value* using the general format for floating-point numbers + (``'g'``) and writes it to the stream. + */ + BasicWriter &operator<<(long double value) { + write_double(value, FormatSpec()); + return *this; + } + + /** + Writes a character to the stream. + */ + BasicWriter &operator<<(char value) { + buffer_.push_back(value); + return *this; + } + + BasicWriter &operator<<(wchar_t value) { + buffer_.push_back(internal::CharTraits::convert(value)); + return *this; + } + + /** + Writes *value* to the stream. + */ + BasicWriter &operator<<(fmt::BasicStringRef value) { + const Char *str = value.c_str(); + buffer_.append(str, str + value.size()); + return *this; + } + + template + BasicWriter &operator<<(IntFormatSpec spec) { + internal::CharTraits::convert(FillChar()); + write_int(spec.value(), spec); + return *this; + } + + template + BasicWriter &operator<<(const StrFormatSpec &spec) { + const StrChar *s = spec.str(); + // TODO: error if fill is not convertible to Char + write_str(s, std::char_traits::length(s), spec); + return *this; + } + + void clear() FMT_NOEXCEPT(true) { + buffer_.clear(); + } +}; + +template +template +typename BasicWriter::CharPtr BasicWriter::write_str( + const StrChar *s, std::size_t size, const AlignSpec &spec) { + CharPtr out = CharPtr(); + if (spec.width() > size) { + out = grow_buffer(spec.width()); + Char fill = static_cast(spec.fill()); + if (spec.align() == ALIGN_RIGHT) { + std::fill_n(out, spec.width() - size, fill); + out += spec.width() - size; + } + else if (spec.align() == ALIGN_CENTER) { + out = fill_padding(out, spec.width(), size, fill); + } + else { + std::fill_n(out + size, spec.width() - size, fill); + } + } + else { + out = grow_buffer(size); + } + std::copy(s, s + size, out); + return out; +} + +template +typename BasicWriter::CharPtr +BasicWriter::fill_padding( + CharPtr buffer, unsigned total_size, + std::size_t content_size, wchar_t fill) { + std::size_t padding = total_size - content_size; + std::size_t left_padding = padding / 2; + Char fill_char = static_cast(fill); + std::fill_n(buffer, left_padding, fill_char); + buffer += left_padding; + CharPtr content = buffer; + std::fill_n(buffer + content_size, padding - left_padding, fill_char); + return content; +} + +template +template +typename BasicWriter::CharPtr +BasicWriter::prepare_int_buffer( + unsigned num_digits, const Spec &spec, + const char *prefix, unsigned prefix_size) { + unsigned width = spec.width(); + Alignment align = spec.align(); + Char fill = static_cast(spec.fill()); + if (spec.precision() > static_cast(num_digits)) { + // Octal prefix '0' is counted as a digit, so ignore it if precision + // is specified. + if (prefix_size > 0 && prefix[prefix_size - 1] == '0') + --prefix_size; + unsigned number_size = prefix_size + spec.precision(); + AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); + if (number_size >= width) + return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); + buffer_.reserve(width); + unsigned fill_size = width - number_size; + if (align != ALIGN_LEFT) { + CharPtr p = grow_buffer(fill_size); + std::fill(p, p + fill_size, fill); + } + CharPtr result = prepare_int_buffer( + num_digits, subspec, prefix, prefix_size); + if (align == ALIGN_LEFT) { + CharPtr p = grow_buffer(fill_size); + std::fill(p, p + fill_size, fill); + } + return result; + } + unsigned size = prefix_size + num_digits; + if (width <= size) { + CharPtr p = grow_buffer(size); + std::copy(prefix, prefix + prefix_size, p); + return p + size - 1; + } + CharPtr p = grow_buffer(width); + CharPtr end = p + width; + if (align == ALIGN_LEFT) { + std::copy(prefix, prefix + prefix_size, p); + p += size; + std::fill(p, end, fill); + } + else if (align == ALIGN_CENTER) { + p = fill_padding(p, width, size, fill); + std::copy(prefix, prefix + prefix_size, p); + p += size; + } + else { + if (align == ALIGN_NUMERIC) { + if (prefix_size != 0) { + p = std::copy(prefix, prefix + prefix_size, p); + size -= prefix_size; + } + } + else { + std::copy(prefix, prefix + prefix_size, end - size); + } + std::fill(p, end - size, fill); + p = end; + } + return p - 1; +} + +template +template +void BasicWriter::write_int(T value, Spec spec) { + unsigned prefix_size = 0; + typedef typename internal::IntTraits::MainType UnsignedType; + UnsignedType abs_value = value; + char prefix[4] = ""; + if (internal::is_negative(value)) { + prefix[0] = '-'; + ++prefix_size; + abs_value = 0 - abs_value; + } + else if (spec.flag(SIGN_FLAG)) { + prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; + ++prefix_size; + } + switch (spec.type()) { + case 0: + case 'd': { + unsigned num_digits = internal::count_digits(abs_value); + CharPtr p = prepare_int_buffer( + num_digits, spec, prefix, prefix_size) + 1 - num_digits; + internal::format_decimal(get(p), abs_value, num_digits); + break; + } + case 'x': + case 'X': { + UnsignedType n = abs_value; + if (spec.flag(HASH_FLAG)) { + prefix[prefix_size++] = '0'; + prefix[prefix_size++] = spec.type(); + } + unsigned num_digits = 0; + do { + ++num_digits; + } while ((n >>= 4) != 0); + Char *p = get(prepare_int_buffer( + num_digits, spec, prefix, prefix_size)); + n = abs_value; + const char *digits = spec.type() == 'x' ? + "0123456789abcdef" : "0123456789ABCDEF"; + do { + *p-- = digits[n & 0xf]; + } while ((n >>= 4) != 0); + break; + } + case 'b': + case 'B': { + UnsignedType n = abs_value; + if (spec.flag(HASH_FLAG)) { + prefix[prefix_size++] = '0'; + prefix[prefix_size++] = spec.type(); + } + unsigned num_digits = 0; + do { + ++num_digits; + } while ((n >>= 1) != 0); + Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); + n = abs_value; + do { + *p-- = '0' + (n & 1); + } while ((n >>= 1) != 0); + break; + } + case 'o': { + UnsignedType n = abs_value; + if (spec.flag(HASH_FLAG)) + prefix[prefix_size++] = '0'; + unsigned num_digits = 0; + do { + ++num_digits; + } while ((n >>= 3) != 0); + Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); + n = abs_value; + do { + *p-- = '0' + (n & 7); + } while ((n >>= 3) != 0); + break; + } + default: + internal::report_unknown_type( + spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); + break; + } +} + +template +template +void BasicWriter::write_double( + T value, const FormatSpec &spec) { + // Check type. + char type = spec.type(); + bool upper = false; + switch (type) { + case 0: + type = 'g'; + break; + case 'e': + case 'f': + case 'g': + case 'a': + break; + case 'F': +#ifdef _MSC_VER + // MSVC's printf doesn't support 'F'. + type = 'f'; +#endif + // Fall through. + case 'E': + case 'G': + case 'A': + upper = true; + break; + default: + internal::report_unknown_type(type, "double"); + break; + } + + char sign = 0; + // Use getsign instead of value < 0 because the latter is always + // false for NaN. + if (internal::getsign(static_cast(value))) { + sign = '-'; + value = -value; + } + else if (spec.flag(SIGN_FLAG)) { + sign = spec.flag(PLUS_FLAG) ? '+' : ' '; + } + + if (value != value) { + // Format NaN ourselves because sprintf's output is not consistent + // across platforms. + std::size_t size = 4; + const char *nan = upper ? " NAN" : " nan"; + if (!sign) { + --size; + ++nan; + } + CharPtr out = write_str(nan, size, spec); + if (sign) + *out = sign; + return; + } + + if (internal::isinfinity(value)) { + // Format infinity ourselves because sprintf's output is not consistent + // across platforms. + std::size_t size = 4; + const char *inf = upper ? " INF" : " inf"; + if (!sign) { + --size; + ++inf; + } + CharPtr out = write_str(inf, size, spec); + if (sign) + *out = sign; + return; + } + + std::size_t offset = buffer_.size(); + unsigned width = spec.width(); + if (sign) { + buffer_.reserve(buffer_.size() + (std::max)(width, 1u)); + if (width > 0) + --width; + ++offset; + } + + // Build format string. + enum { MAX_FORMAT_SIZE = 10 }; // longest format: %#-*.*Lg + Char format[MAX_FORMAT_SIZE]; + Char *format_ptr = format; + *format_ptr++ = '%'; + unsigned width_for_sprintf = width; + if (spec.flag(HASH_FLAG)) + *format_ptr++ = '#'; + if (spec.align() == ALIGN_CENTER) { + width_for_sprintf = 0; + } + else { + if (spec.align() == ALIGN_LEFT) + *format_ptr++ = '-'; + if (width != 0) + *format_ptr++ = '*'; + } + if (spec.precision() >= 0) { + *format_ptr++ = '.'; + *format_ptr++ = '*'; + } + if (internal::IsLongDouble::VALUE) + *format_ptr++ = 'L'; + *format_ptr++ = type; + *format_ptr = '\0'; + + // Format using snprintf. + Char fill = static_cast(spec.fill()); + for (;;) { + std::size_t size = buffer_.capacity() - offset; +#if _MSC_VER + // MSVC's vsnprintf_s doesn't work with zero size, so reserve + // space for at least one extra character to make the size non-zero. + // Note that the buffer's capacity will increase by more than 1. + if (size == 0) { + buffer_.reserve(offset + 1); + size = buffer_.capacity() - offset; + } +#endif + Char *start = &buffer_[offset]; + int n = internal::CharTraits::format_float( + start, size, format, width_for_sprintf, spec.precision(), value); + if (n >= 0 && offset + n < buffer_.capacity()) { + if (sign) { + if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || + *start != ' ') { + *(start - 1) = sign; + sign = 0; + } + else { + *(start - 1) = fill; + } + ++n; + } + if (spec.align() == ALIGN_CENTER && + spec.width() > static_cast(n)) { + unsigned width = spec.width(); + CharPtr p = grow_buffer(width); + std::copy(p, p + n, p + (width - n) / 2); + fill_padding(p, spec.width(), n, fill); + return; + } + if (spec.fill() != ' ' || sign) { + while (*start == ' ') + *start++ = fill; + if (sign) + *(start - 1) = sign; + } + grow_buffer(n); + return; + } + // If n is negative we ask to increase the capacity by at least 1, + // but as std::vector, the buffer grows exponentially. + buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1); + } +} + +/** +\rst +This template provides operations for formatting and writing data into +a character stream. The output is stored in a memory buffer that grows +dynamically. + +You can use one of the following typedefs for common character types +and the standard allocator: + ++---------------+-----------------------------------------------+ +| Type | Definition | ++===============+===============================================+ +| MemoryWriter | BasicWriter> | ++---------------+-----------------------------------------------+ +| WMemoryWriter | BasicWriter> | ++---------------+-----------------------------------------------+ + +**Example**:: + +MemoryWriter out; +out << "The answer is " << 42 << "\n"; +out.write("({:+f}, {:+f})", -3.14, 3.14); + +This will write the following output to the ``out`` object: + +.. code-block:: none + +The answer is 42 +(-3.140000, +3.140000) + +The output can be converted to an ``std::string`` with ``out.str()`` or +accessed as a C string with ``out.c_str()``. +\endrst +*/ +template > +class BasicMemoryWriter : public BasicWriter { +private: + internal::MemoryBuffer buffer_; + +public: + explicit BasicMemoryWriter(const Allocator& alloc = Allocator()) + : BasicWriter(buffer_), buffer_(alloc) {} + +#if FMT_USE_RVALUE_REFERENCES + /** + Constructs a ``BasicMemoryWriter`` object moving the content of the other + object to it. + */ + BasicMemoryWriter(BasicMemoryWriter &&other) + : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) { + } + + /** + Moves the content of the other ``BasicMemoryWriter`` object to this one. + */ + BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { + buffer_ = std::move(other.buffer_); + return *this; + } +#endif +}; + +typedef BasicMemoryWriter MemoryWriter; +typedef BasicMemoryWriter WMemoryWriter; + +// Formats a value. +template +void format(BasicFormatter &f, const Char *&format_str, const T &value) { + std::basic_ostringstream os; + os << value; + internal::Arg arg; + internal::Value &arg_value = arg; + std::basic_string str = os.str(); + arg_value = internal::MakeValue(str); + arg.type = internal::Arg::STRING; + format_str = f.format(format_str, arg); +} + +// Reports a system error without throwing an exception. +// Can be used to report errors from destructors. +void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT(true); + +#ifdef _WIN32 + +/** +A Windows error. +*/ +class WindowsError : public SystemError { +private: + void init(int error_code, StringRef format_str, ArgList args); + +public: + /** + \rst + Constructs a :cpp:class:`fmt::WindowsError` object with the description + of the form "**: **", where ** is the + formatted message and ** is the system message corresponding + to the error code. + *error_code* is a Windows error code as given by ``GetLastError``. + \endrst + */ + WindowsError(int error_code, StringRef message) { + init(error_code, message, ArgList()); + } + FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef) +}; + +// Reports a Windows error without throwing an exception. +// Can be used to report errors from destructors. +void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT(true); + +#endif + +enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; + +/** +Formats a string and prints it to stdout using ANSI escape sequences +to specify color (experimental). +Example: +PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23; +*/ +void print_colored(Color c, StringRef format, ArgList args); + +/** +\rst +Formats arguments and returns the result as a string. + +**Example**:: + +std::string message = format("The answer is {}", 42); +\endrst +*/ +inline std::string format(StringRef format_str, ArgList args) { + MemoryWriter w; + w.write(format_str, args); + return w.str(); +} + +inline std::wstring format(WStringRef format_str, ArgList args) { + WMemoryWriter w; + w.write(format_str, args); + return w.str(); +} + +/** +\rst +Prints formatted data to the file *f*. + +**Example**:: + +print(stderr, "Don't {}!", "panic"); +\endrst +*/ +void print(std::FILE *f, StringRef format_str, ArgList args); + +/** +\rst +Prints formatted data to ``stdout``. + +**Example**:: + +print("Elapsed time: {0:.2f} seconds", 1.23); +\endrst +*/ +void print(StringRef format_str, ArgList args); + +/** +\rst +Prints formatted data to the stream *os*. + +**Example**:: + +print(cerr, "Don't {}!", "panic"); +\endrst +*/ +void print(std::ostream &os, StringRef format_str, ArgList args); + +template +void printf(BasicWriter &w, BasicStringRef format, ArgList args) { + internal::PrintfFormatter().format(w, format, args); +} + +/** +\rst +Formats arguments and returns the result as a string. + +**Example**:: + +std::string message = fmt::sprintf("The answer is %d", 42); +\endrst +*/ +inline std::string sprintf(StringRef format, ArgList args) { + MemoryWriter w; + printf(w, format, args); + return w.str(); +} + +/** +\rst +Prints formatted data to the file *f*. + +**Example**:: + +fmt::fprintf(stderr, "Don't %s!", "panic"); +\endrst +*/ +int fprintf(std::FILE *f, StringRef format, ArgList args); + +/** +\rst +Prints formatted data to ``stdout``. + +**Example**:: + +fmt::printf("Elapsed time: %.2f seconds", 1.23); +\endrst +*/ +inline int printf(StringRef format, ArgList args) { + return fprintf(stdout, format, args); +} + +/** +Fast integer formatter. +*/ +class FormatInt { +private: + // Buffer should be large enough to hold all digits (digits10 + 1), + // a sign and a null character. + enum { BUFFER_SIZE = std::numeric_limits::digits10 + 3 }; + mutable char buffer_[BUFFER_SIZE]; + char *str_; + + // Formats value in reverse and returns the number of digits. + char *format_decimal(ULongLong value) { + char *buffer_end = buffer_ + BUFFER_SIZE - 1; + while (value >= 100) { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + unsigned index = (value % 100) * 2; + value /= 100; + *--buffer_end = internal::DIGITS[index + 1]; + *--buffer_end = internal::DIGITS[index]; + } + if (value < 10) { + *--buffer_end = static_cast('0' + value); + return buffer_end; + } + unsigned index = static_cast(value * 2); + *--buffer_end = internal::DIGITS[index + 1]; + *--buffer_end = internal::DIGITS[index]; + return buffer_end; + } + + void FormatSigned(LongLong value) { + ULongLong abs_value = static_cast(value); + bool negative = value < 0; + if (negative) + abs_value = 0 - abs_value; + str_ = format_decimal(abs_value); + if (negative) + *--str_ = '-'; + } + +public: + explicit FormatInt(int value) { + FormatSigned(value); + } + explicit FormatInt(long value) { + FormatSigned(value); + } + explicit FormatInt(LongLong value) { + FormatSigned(value); + } + explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} + explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} + explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {} + + /** + Returns the number of characters written to the output buffer. + */ + std::size_t size() const { + return buffer_ - str_ + BUFFER_SIZE - 1; + } + + /** + Returns a pointer to the output buffer content. No terminating null + character is appended. + */ + const char *data() const { + return str_; + } + + /** + Returns a pointer to the output buffer content with terminating null + character appended. + */ + const char *c_str() const { + buffer_[BUFFER_SIZE - 1] = '\0'; + return str_; + } + + /** + Returns the content of the output buffer as an `std::string`. + */ + std::string str() const { + return std::string(str_, size()); + } +}; + +// Formats a decimal integer value writing into buffer and returns +// a pointer to the end of the formatted string. This function doesn't +// write a terminating null character. +template +inline void format_decimal(char *&buffer, T value) { + typename internal::IntTraits::MainType abs_value = value; + if (internal::is_negative(value)) { + *buffer++ = '-'; + abs_value = 0 - abs_value; + } + if (abs_value < 100) { + if (abs_value < 10) { + *buffer++ = static_cast('0' + abs_value); + return; + } + unsigned index = static_cast(abs_value * 2); + *buffer++ = internal::DIGITS[index]; + *buffer++ = internal::DIGITS[index + 1]; + return; + } + unsigned num_digits = internal::count_digits(abs_value); + internal::format_decimal(buffer, abs_value, num_digits); + buffer += num_digits; +} +} + +#if FMT_GCC_VERSION +// Use the system_header pragma to suppress warnings about variadic macros +// because suppressing -Wvariadic-macros with the diagnostic pragma doesn't +// work. It is used at the end because we want to suppress as little warnings +// as possible. +# pragma GCC system_header +#endif + +// This is used to work around VC++ bugs in handling variadic macros. +#define FMT_EXPAND(args) args + +// Returns the number of arguments. +// Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s. +#define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N()) +#define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__)) +#define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N +#define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + +#define FMT_CONCAT(a, b) a##b +#define FMT_FOR_EACH_(N, f, ...) \ + FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) +#define FMT_FOR_EACH(f, ...) \ + FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__)) + +#define FMT_ADD_ARG_NAME(type, index) type arg##index +#define FMT_GET_ARG_NAME(type, index) arg##index + +#if FMT_USE_VARIADIC_TEMPLATES +# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ + template \ + ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ + const Args & ... args) { \ + using fmt::internal::Value; \ + const Value values[fmt::internal::NonZero::VALUE] = { \ + fmt::internal::MakeValue(args)... \ + }; \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ + fmt::internal::make_type(args...), values)); \ + } +#else +// Defines a wrapper for a function taking __VA_ARGS__ arguments +// and n additional arguments of arbitrary types. +# define FMT_WRAP(Char, ReturnType, func, call, n, ...) \ + template \ + inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ + FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ + } + +# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ + inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ + } \ + FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 11, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 12, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 13, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 14, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, call, 15, __VA_ARGS__) +#endif // FMT_USE_VARIADIC_TEMPLATES + +/** +\rst +Defines a variadic function with the specified return type, function name +and argument types passed as variable arguments to this macro. + +**Example**:: + +void print_error(const char *file, int line, const char *format, +fmt::ArgList args) { +fmt::print("{}: {}: ", file, line); +fmt::print(format, args); +} +FMT_VARIADIC(void, print_error, const char *, int, const char *) + +``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that +don't implement variadic templates. You don't have to use this macro if +you don't need legacy compiler support and can use variadic templates +directly:: + +template +void print_error(const char *file, int line, const char *format, +const Args & ... args) { +fmt::print("{}: {}: ", file, line); +fmt::print(format, args...); +} +\endrst +*/ +#define FMT_VARIADIC(ReturnType, func, ...) \ + FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__) + +#define FMT_VARIADIC_W(ReturnType, func, ...) \ + FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) + +namespace fmt { +FMT_VARIADIC(std::string, format, StringRef) +FMT_VARIADIC_W(std::wstring, format, WStringRef) +FMT_VARIADIC(void, print, StringRef) +FMT_VARIADIC(void, print, std::FILE *, StringRef) +FMT_VARIADIC(void, print, std::ostream &, StringRef) +FMT_VARIADIC(void, print_colored, Color, StringRef) +FMT_VARIADIC(std::string, sprintf, StringRef) +FMT_VARIADIC(int, printf, StringRef) +FMT_VARIADIC(int, fprintf, std::FILE *, StringRef) +} + +// Restore warnings. +#if FMT_GCC_VERSION >= 406 +# pragma GCC diagnostic pop +#endif + +#define FMT_HEADER_ONLY +# include "format.cc" +#undef FMT_HEADER_ONLY + +#endif // FMT_FORMAT_H_ From 8974d2ded9dd17d81eb9be6d708f2b929c0e092c Mon Sep 17 00:00:00 2001 From: gabi Date: Sat, 29 Nov 2014 12:25:37 +0200 Subject: [PATCH 002/120] Using cppformat for all formatting needs instead of fast_oss --- include/spdlog/details/fast_oss.h | 189 ------------------ include/spdlog/details/file_helper.h | 11 +- include/spdlog/details/line_logger.h | 1 - include/spdlog/details/log_msg.h | 23 ++- .../spdlog/details/pattern_formatter_impl.h | 124 +++++------- include/spdlog/details/stack_buf.h | 134 ------------- 6 files changed, 69 insertions(+), 413 deletions(-) delete mode 100644 include/spdlog/details/fast_oss.h delete mode 100644 include/spdlog/details/stack_buf.h diff --git a/include/spdlog/details/fast_oss.h b/include/spdlog/details/fast_oss.h deleted file mode 100644 index 447c1783..00000000 --- a/include/spdlog/details/fast_oss.h +++ /dev/null @@ -1,189 +0,0 @@ -/*************************************************************************/ -/* spdlog - an extremely fast and easy to use c++11 logging library. */ -/* Copyright (c) 2014 Gabi Melman. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#pragma once - -// A faster-than-ostringstream class -// uses stack_buf as the underlying buffer (upto 256 bytes before using the heap) - -#include -#include -#include "fast_istostr.h" -#include "stack_buf.h" -#include - -namespace spdlog -{ -namespace details -{ - -class stack_devicebuf :public std::streambuf -{ -public: - static const unsigned short stack_size = 256; - using stackbuf_t = stack_buf; - - stack_devicebuf() = default; - ~stack_devicebuf() = default; - - 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(); - } - - stack_devicebuf& operator=(stack_devicebuf other) - { - std::swap(_stackbuf, other._stackbuf); - return *this; - } - - const stackbuf_t& buf() const - { - return _stackbuf; - } - 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: - stackbuf_t _stackbuf; -}; - - -class fast_oss :public std::ostream -{ -public: - fast_oss() :std::ostream(&_dev) {} - ~fast_oss() = default; - - 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(); - } - - - fast_oss& operator=(fast_oss other) - { - swap(*this, other); - return *this; - } - - void swap(fast_oss& first, fast_oss& second) // nothrow - { - using std::swap; - swap(first._dev, second._dev); - } - - std::string str() const - { - auto& buffer = _dev.buf(); - const char*data = buffer.data(); - return std::string(data, data+buffer.size()); - } - - const stack_devicebuf::stackbuf_t& buf() const - { - return _dev.buf(); - } - - - std::size_t size() const - { - return _dev.size(); - } - - void clear() - { - _dev.clear(); - } - - // - // The following were added because they significantly boost to perfromance - // - void putc(char c) - { - _dev.sputc(c); - } - - // put int and pad with zeroes if smalled than min_width - void put_int(int n, size_t padding) - { - std::string s; - details::fast_itostr(n, s, padding); - _dev.sputn(s.data(), s.size()); - } - - void put_data(const char* p, std::size_t data_size) - { - _dev.sputn(p, data_size); - } - - void put_str(const std::string& s) - { - _dev.sputn(s.data(), s.size()); - } - - void put_fast_oss(const fast_oss& oss) - { - auto& buffer = oss.buf(); - _dev.sputn(buffer.data(), buffer.size()); - } - - -private: - stack_devicebuf _dev; -}; -} -} diff --git a/include/spdlog/details/file_helper.h b/include/spdlog/details/file_helper.h index db2c9da2..7932a45b 100644 --- a/include/spdlog/details/file_helper.h +++ b/include/spdlog/details/file_helper.h @@ -52,7 +52,7 @@ public: explicit file_helper(bool auto_flush): _fd(nullptr), _auto_flush(auto_flush) - {}; + {}; file_helper(const file_helper&) = delete; file_helper& operator=(const file_helper&) = delete; @@ -99,14 +99,15 @@ public: void write(const log_msg& msg) { - auto& buf = msg.formatted.buf(); - size_t size = buf.size(); - if(std::fwrite(buf.data(), sizeof(char), size, _fd) != size) + + size_t size = msg.formatted.size(); + auto data = msg.formatted.data(); + if(std::fwrite(data, sizeof(char), size, _fd) != size) throw spdlog_ex("Failed writing to file " + _filename); if(_auto_flush) std::fflush(_fd); - + } const std::string& filename() const diff --git a/include/spdlog/details/line_logger.h b/include/spdlog/details/line_logger.h index c16a81ad..d3919b67 100644 --- a/include/spdlog/details/line_logger.h +++ b/include/spdlog/details/line_logger.h @@ -26,7 +26,6 @@ #include "../common.h" #include "../logger.h" -#include "fast_oss.h" // Line logger class - aggregates operator<< calls to fast ostream diff --git a/include/spdlog/details/log_msg.h b/include/spdlog/details/log_msg.h index 19abcfda..b9038cda 100644 --- a/include/spdlog/details/log_msg.h +++ b/include/spdlog/details/log_msg.h @@ -25,7 +25,7 @@ #pragma once #include "../common.h" -#include "./fast_oss.h" +#include "./format.h" namespace spdlog { @@ -42,13 +42,18 @@ struct log_msg raw(), formatted() {} - log_msg(const log_msg& other): + + log_msg(const log_msg& other) : logger_name(other.logger_name), level(other.level), time(other.time), - tm_time(other.tm_time), - raw(other.raw), - formatted(other.formatted) {} + tm_time(other.tm_time) + + { + //fmt::MemoryWriter does not allow copy ctor} + raw.write(other.raw.data(), other.raw.size()); + formatted.write(other.formatted.data(), other.formatted.size()); + } log_msg(log_msg&& other) : logger_name(std::move(other.logger_name)), @@ -56,7 +61,9 @@ struct log_msg time(std::move(other.time)), tm_time(other.tm_time), raw(std::move(other.raw)), - formatted(std::move(other.formatted)) {} + formatted(std::move(other.formatted)) + { + } log_msg& operator=(log_msg&& other) { @@ -84,8 +91,8 @@ struct log_msg level::level_enum level; log_clock::time_point time; std::tm tm_time; - fast_oss raw; - fast_oss formatted; + fmt::MemoryWriter raw; + fmt::MemoryWriter formatted; }; } } diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index aaf4b137..1febb30d 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -32,7 +32,6 @@ #include "../formatter.h" #include "./log_msg.h" -#include "./fast_oss.h" #include "./os.h" namespace spdlog @@ -89,7 +88,7 @@ class a_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_str(days[msg.tm_time.tm_wday]); + msg.formatted << days[msg.tm_time.tm_wday]; } }; @@ -99,7 +98,7 @@ class A_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_str(full_days[msg.tm_time.tm_wday]); + msg.formatted << full_days[msg.tm_time.tm_wday]; } }; @@ -109,7 +108,7 @@ class b_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_str(months[msg.tm_time.tm_mon]); + msg.formatted<< months[msg.tm_time.tm_mon]; } }; @@ -119,7 +118,7 @@ class B_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_str(full_months[msg.tm_time.tm_mon]); + msg.formatted << full_months[msg.tm_time.tm_mon]; } }; @@ -128,17 +127,14 @@ class c_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_str(days[msg.tm_time.tm_wday]); - msg.formatted.putc(' '); - msg.formatted.put_str(months[msg.tm_time.tm_mon]); - msg.formatted.putc(' '); - msg.formatted.put_int(msg.tm_time.tm_mday, 2); - msg.formatted.putc(' '); - msg.formatted.put_int(msg.tm_time.tm_hour, 2); - msg.formatted.putc(':'); - msg.formatted.put_int(msg.tm_time.tm_min, 2); - msg.formatted.putc(':'); - msg.formatted.put_int(msg.tm_time.tm_sec, 2); + msg.formatted.write("{} {} {:02d} {:02d}:{:02d}:{:02d} {:04d}", + days[msg.tm_time.tm_wday], + months[msg.tm_time.tm_mon], + msg.tm_time.tm_mday, + msg.tm_time.tm_hour, + msg.tm_time.tm_min, + msg.tm_time.tm_sec, + msg.tm_time.tm_year + 1900); } }; @@ -148,7 +144,7 @@ class C_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_int(msg.tm_time.tm_year % 100, 2); + msg.formatted.write("{02:d}", msg.tm_time.tm_year % 100); } }; @@ -159,11 +155,7 @@ class D_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_int(msg.tm_time.tm_mon + 1, 2); - msg.formatted.putc('/'); - msg.formatted.put_int(msg.tm_time.tm_mday, 2); - msg.formatted.putc('/'); - msg.formatted.put_int(msg.tm_time.tm_year % 100, 2); + msg.formatted.write("{:02d}/{:02d}/{:02d}", msg.tm_time.tm_mon + 1, msg.tm_time.tm_mday, msg.tm_time.tm_year % 100); } }; @@ -173,7 +165,7 @@ class Y_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_int(msg.tm_time.tm_year + 1900, 4); + msg.formatted.write("{:04d}", msg.tm_time.tm_year + 1900); } }; @@ -182,7 +174,7 @@ class m_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_int(msg.tm_time.tm_mon + 1, 2); + msg.formatted.write("{:02d}", msg.tm_time.tm_mon + 1); } }; @@ -191,7 +183,7 @@ class d_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_int(msg.tm_time.tm_mday, 2); + msg.formatted.write("{:02d}", msg.tm_time.tm_mday); } }; @@ -200,7 +192,7 @@ class H_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_int(msg.tm_time.tm_hour, 2); + msg.formatted.write("{:02d}", msg.tm_time.tm_hour); } }; @@ -209,7 +201,7 @@ class I_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_int(to12h(msg.tm_time), 2); + msg.formatted.write("{:02d}", to12h(msg.tm_time)); } }; @@ -218,7 +210,7 @@ class M_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_int(msg.tm_time.tm_min, 2); + msg.formatted.write("{:02d}", msg.tm_time.tm_min); } }; @@ -227,7 +219,7 @@ class S_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_int(msg.tm_time.tm_sec, 2); + //msg.formatted.put_int(msg.tm_time.tm_sec, 2); } }; @@ -238,7 +230,7 @@ class e_formatter :public flag_formatter { auto duration = msg.time.time_since_epoch(); auto millis = std::chrono::duration_cast(duration).count() % 1000; - msg.formatted.put_int(static_cast(millis), 3); + msg.formatted.write("{03:d}", static_cast(millis)); } }; @@ -247,7 +239,7 @@ class p_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_data(ampm(msg.tm_time), 2); + msg.formatted << ampm(msg.tm_time); } }; @@ -257,13 +249,7 @@ class r_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_int(to12h(msg.tm_time), 2); - msg.formatted.putc(':'); - msg.formatted.put_int(msg.tm_time.tm_min, 2); - msg.formatted.putc(':'); - msg.formatted.put_int(msg.tm_time.tm_sec, 2); - msg.formatted.putc(' '); - msg.formatted.put_data(ampm(msg.tm_time), 2); + msg.formatted.write("{:02d}:{:02d}:{:02d} {}", to12h(msg.tm_time), msg.tm_time.tm_min, msg.tm_time.tm_sec, ampm(msg.tm_time)); } }; @@ -272,9 +258,7 @@ class R_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_int(msg.tm_time.tm_hour, 2); - msg.formatted.putc(':'); - msg.formatted.put_int(msg.tm_time.tm_min, 2); + msg.formatted.write("{:02d}:{:02d}", msg.tm_time.tm_hour, msg.tm_time.tm_min); } }; @@ -284,14 +268,11 @@ class T_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_int(msg.tm_time.tm_hour, 2); - msg.formatted.putc(':'); - msg.formatted.put_int(msg.tm_time.tm_min, 2); - msg.formatted.putc(':'); - msg.formatted.put_int(msg.tm_time.tm_sec, 2); + msg.formatted.write("{:02d}:{:02d}:{:02d}", msg.tm_time.tm_hour, msg.tm_time.tm_min, msg.tm_time.tm_sec); } }; + // ISO 8601 offset from UTC in timezone (HH:MM) class z_formatter :public flag_formatter { @@ -311,7 +292,7 @@ public: _value = get_value(msg); _last_update = msg.time; } - msg.formatted.put_str(_value); + msg.formatted << _value; } private: log_clock::time_point _last_update; @@ -323,23 +304,21 @@ private: int total_minutes = os::utc_minutes_offset(msg.tm_time); int h = total_minutes / 60; int m = total_minutes % 60; - fast_oss oss; - oss.putc(h < 0 ? '-' : '+'); - oss.put_int(h, 2); - oss.putc(':'); - oss.put_int(m, 2); - return oss.str(); + fmt::MemoryWriter w; + w.write("{} {:02d}:{:02d}", h >= 0 ? '+' : '-', h, m); + return w.str(); } }; + //Thread id class t_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted << std::this_thread::get_id(); + msg.formatted << std::this_thread::get_id().hash(); } }; @@ -348,7 +327,7 @@ class v_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.put_fast_oss(msg.raw); + msg.formatted.write(msg.raw.data(), msg.raw.size()); } }; @@ -359,7 +338,7 @@ public: {} void format(details::log_msg& msg) override { - msg.formatted.putc(_ch); + msg.formatted << _ch; } private: char _ch; @@ -378,7 +357,7 @@ public: } void format(details::log_msg& msg) override { - msg.formatted.put_str(_str); + msg.formatted << _str; } private: std::string _str; @@ -390,27 +369,20 @@ class full_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.putc('['); - msg.formatted.put_int(msg.tm_time.tm_year+1900, 4); - msg.formatted.putc('-'); - msg.formatted.put_int(msg.tm_time.tm_mon+ 1, 2); - msg.formatted.putc('-'); - msg.formatted.put_int(msg.tm_time.tm_mday, 2); - msg.formatted.putc(' '); - msg.formatted.put_int(msg.tm_time.tm_hour, 2); - msg.formatted.putc(':'); - msg.formatted.put_int(msg.tm_time.tm_min, 2); - msg.formatted.putc(':'); - msg.formatted.put_int(msg.tm_time.tm_sec, 2); - //millis - msg.formatted.putc('.'); auto duration = msg.time.time_since_epoch(); auto millis = std::chrono::duration_cast(duration).count() % 1000; - msg.formatted.put_int(static_cast(millis), 3); - msg.formatted.putc(']'); - msg.formatted << " [" << msg.logger_name << "] [" << level::to_str(msg.level) << "] "; - msg.formatted.put_fast_oss(msg.raw); + msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] ", + msg.tm_time.tm_year + 1900, + msg.tm_time.tm_mon + 1, + msg.tm_time.tm_mday, + msg.tm_time.tm_hour, + msg.tm_time.tm_min, + msg.tm_time.tm_sec, + static_cast(millis), + msg.logger_name, + level::to_str(msg.level)); + msg.formatted.write(msg.raw.str()); } }; @@ -457,7 +429,7 @@ inline void spdlog::pattern_formatter::handle_flag(char flag) { switch (flag) { - // logger name + // logger name case 'n': _formatters.push_back(std::unique_ptr(new details::name_formatter())); break; diff --git a/include/spdlog/details/stack_buf.h b/include/spdlog/details/stack_buf.h deleted file mode 100644 index 7b120967..00000000 --- a/include/spdlog/details/stack_buf.h +++ /dev/null @@ -1,134 +0,0 @@ -/*************************************************************************/ -/* spdlog - an extremely fast and easy to use c++11 logging library. */ -/* Copyright (c) 2014 Gabi Melman. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#pragma once - -#include -#include -#include -#include - -namespace spdlog -{ -namespace details -{ - -// Fast memory storage on the stack when possible or in std::vector -template -class stack_buf -{ -public: - static const unsigned short stack_size = STACK_SIZE; - stack_buf() :_v(), _stack_size(0) {} - ~stack_buf() = default; - stack_buf(const stack_buf& other) :stack_buf(other, delegate_copy_or_move {}) - {} - - stack_buf(stack_buf&& other) :stack_buf(other, delegate_copy_or_move {}) - { - other.clear(); - } - template - stack_buf& operator=(T1&& other) - { - _stack_size = other._stack_size; - if (other.vector_used()) - _v = std::forward(other)._v; - else - std::copy_n(other._stack_array.begin(), other._stack_size, _stack_array.begin()); - return *this; - } - - void append(const char* buf, std::size_t buf_size) - { - //If we are aleady using _v, forget about the stack - if (vector_used()) - { - _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); - _v.insert(_v.end(), _stack_array.begin(), _stack_array.begin() + _stack_size); - _v.insert(_v.end(), buf, buf + buf_size); - } - } - } - - - void clear() - { - _stack_size = 0; - _v.clear(); - } - - const char* data() const - { - if (vector_used()) - return _v.data(); - else - return _stack_array.data(); - } - - std::size_t size() const - { - if (vector_used()) - return _v.size(); - else - return _stack_size; - } - -private: - struct delegate_copy_or_move {}; - template - stack_buf(T1&& other, delegate_copy_or_move) - { - _stack_size = other._stack_size; - if (other.vector_used()) - _v = std::forward(other)._v; - else - std::copy_n(other._stack_array.begin(), other._stack_size, _stack_array.begin()); - } - - inline bool vector_used() const - { - return !(_v.empty()); - } - - std::vector _v; - std::array _stack_array; - std::size_t _stack_size; -}; - -} -} //namespace spdlog { namespace details { From 2c0acf66f954436ddd62689f1003833cea9a9c62 Mon Sep 17 00:00:00 2001 From: gabi Date: Sat, 29 Nov 2014 17:10:17 +0200 Subject: [PATCH 003/120] use cppformat in sinks --- include/spdlog/sinks/file_sinks.h | 19 ++++++++----------- include/spdlog/sinks/ostream_sink.h | 3 +-- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/include/spdlog/sinks/file_sinks.h b/include/spdlog/sinks/file_sinks.h index 25325b1b..26d5d0e1 100644 --- a/include/spdlog/sinks/file_sinks.h +++ b/include/spdlog/sinks/file_sinks.h @@ -28,8 +28,7 @@ #include "base_sink.h" #include "../details/null_mutex.h" #include "../details/file_helper.h" -#include "../details/fast_oss.h" - +#include "../details/format.h" namespace spdlog @@ -100,12 +99,12 @@ protected: private: static std::string calc_filename(const std::string& filename, std::size_t index, const std::string& extension) { - details::fast_oss oss; + fmt::MemoryWriter w; if (index) - oss << filename << "." << index << "." << extension; + w.write("{}.{}.{}", filename, index, extension); else - oss << filename << "." << extension; - return oss.str(); + w.write("{}.{}", filename, extension); + return w.str(); } @@ -197,11 +196,9 @@ private: static std::string calc_filename(const std::string& basename, const std::string& extension) { std::tm tm = spdlog::details::os::localtime(); - details::fast_oss oss; - oss << basename << '.'; - oss << tm.tm_year + 1900 << '-' << std::setw(2) << std::setfill('0') << tm.tm_mon + 1 << '-' << tm.tm_mday; - oss << '.' << extension; - return oss.str(); + fmt::MemoryWriter w; + w.write("{}.{:04d}-{:02d}-{:02d}.{}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, extension); + return w.str(); } std::string _base_filename; diff --git a/include/spdlog/sinks/ostream_sink.h b/include/spdlog/sinks/ostream_sink.h index 5f33743b..b62e4b7e 100644 --- a/include/spdlog/sinks/ostream_sink.h +++ b/include/spdlog/sinks/ostream_sink.h @@ -47,8 +47,7 @@ public: protected: virtual void _sink_it(const details::log_msg& msg) override { - auto& buf = msg.formatted.buf(); - _ostream.write(buf.data(), buf.size()); + _ostream.write(msg.formatted.data(), msg.formatted.size()); } std::ostream& _ostream; }; From 068a7cfac6f17be1ac51aab74bb2dbf018c67c6d Mon Sep 17 00:00:00 2001 From: gabi Date: Sat, 29 Nov 2014 17:11:25 +0200 Subject: [PATCH 004/120] Start of work on lockfreee async queue --- include/spdlog/details/mpcs_q.h | 168 ++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 include/spdlog/details/mpcs_q.h diff --git a/include/spdlog/details/mpcs_q.h b/include/spdlog/details/mpcs_q.h new file mode 100644 index 00000000..acc62a75 --- /dev/null +++ b/include/spdlog/details/mpcs_q.h @@ -0,0 +1,168 @@ +#pragma once +/*************************************************************************/ +/* +Modified version of Intrusive MPSC node-based queue + +Original code from +http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue +licensed by Dmitry Vyukov under the terms below: + +Simplified BSD license + +Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list +of conditions and the following disclaimer in the documentation and/or other materials +provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those of the authors and +should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov. + +/*************************************************************************/ +/* The code in its current form adds the license below: */ +/*************************************************************************/ +/* spdlog - an extremely fast and easy to use c++11 logging library. */ +/* Copyright (c) 2014 Gabi Melman. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + + +#include +namespace spdlog { +namespace details { +template +class mpsc_q +{ + +public: + mpsc_q(size_t size) :_stub(T()), _head(&_stub), _tail(&_stub) + { + _stub.next = nullptr; + } + + ~mpsc_q() + { + reset(); + } + + void reset() + { + T dummy_val; + while (pop(dummy_val)); + } + + bool push(const T& value) + { + mpscq_node_t* new_node = new mpscq_node_t(value); + push_node(new_node); + return true; + } + + bool pop(T& value) + { + mpscq_node_t* node = pop_node(); + if (node != nullptr) + { + value = node->value; + delete(node); + return true; + } + else + { + return false; + } + } + +private: + struct mpscq_node_t + { + std::atomic next; + T value; + + explicit mpscq_node_t(const T& value) :next(nullptr), value(value) + { + } + }; + + mpscq_node_t _stub; + std::atomic _head; + mpscq_node_t* _tail; + + + + void push_node(mpscq_node_t* n) + { + n->next = nullptr; + mpscq_node_t* prev = _head.exchange(n); + prev->next = n; + } + + mpscq_node_t* pop_node() + { + mpscq_node_t* tail = _tail; + mpscq_node_t* next = tail->next; + if (tail == &_stub) + { + if (nullptr == next) + return nullptr; + _tail = next; + tail = next; + next = next->next; + } + if (next) + { + _tail = next; + return tail; + } + mpscq_node_t* head = _head; + if (tail != head) + return 0; + + push_node(&_stub); + next = tail->next; + if (next) + { + _tail = next; + return tail; + } + return nullptr; + } + + + +}; +} +} \ No newline at end of file From 77d9eaa59f60b92e7dbeb0ea084a23fb393d3ced Mon Sep 17 00:00:00 2001 From: gabime Date: Sat, 29 Nov 2014 19:33:54 +0200 Subject: [PATCH 005/120] fixes in pattern formatter --- include/spdlog/details/pattern_formatter_impl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index 1febb30d..69640a7b 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -219,7 +219,7 @@ class S_formatter :public flag_formatter { void format(details::log_msg& msg) override { - //msg.formatted.put_int(msg.tm_time.tm_sec, 2); + msg.formatted.write("{:02d}", msg.tm_time.tm_sec); } }; @@ -230,7 +230,7 @@ class e_formatter :public flag_formatter { auto duration = msg.time.time_since_epoch(); auto millis = std::chrono::duration_cast(duration).count() % 1000; - msg.formatted.write("{03:d}", static_cast(millis)); + msg.formatted.write("{:03d}", static_cast(millis)); } }; @@ -318,7 +318,7 @@ class t_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted << std::this_thread::get_id().hash(); + msg.formatted << std::hash()(std::this_thread::get_id()); } }; From 0629c519101ed4d638451ed6e6f85f59aa906018 Mon Sep 17 00:00:00 2001 From: gabime Date: Sat, 29 Nov 2014 19:58:32 +0200 Subject: [PATCH 006/120] Makefile - removed WShadow warning --- example/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/Makefile b/example/Makefile index b576fa7b..63e3d025 100644 --- a/example/Makefile +++ b/example/Makefile @@ -1,5 +1,5 @@ CXX = g++ -CXXFLAGS = -march=native -Wall -Wextra -Wshadow -pedantic -std=c++11 -pthread -Wl,--no-as-needed -I../include +CXXFLAGS = -march=native -Wall -Wextra -pedantic -std=c++11 -pthread -Wl,--no-as-needed -I../include CXX_RELEASE_FLAGS = -O3 -flto CXX_DEBUG_FLAGS= -g From 8d253244448e8dc3cf25bdbad8c2e43fa2ab6369 Mon Sep 17 00:00:00 2001 From: gabime Date: Sat, 29 Nov 2014 20:01:01 +0200 Subject: [PATCH 007/120] continue with cppformatter integration --- bench/Makefile | 2 +- bench/spdlog-bench-mt.cpp | 2 +- example/bench.cpp | 4 ++-- example/example.cpp | 9 ++------- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/bench/Makefile b/bench/Makefile index 8bbdbd70..30781eea 100644 --- a/bench/Makefile +++ b/bench/Makefile @@ -1,5 +1,5 @@ CXX = g++ -CXXFLAGS = -g -march=native -Wall -Wextra -Wshadow -pedantic -std=c++11 -pthread -Wl,--no-as-needed -I../include +CXXFLAGS = -g -march=native -Wall -Wextra -pedantic -std=c++11 -pthread -Wl,--no-as-needed -I../include CXX_RELEASE_FLAGS = -O3 -flto diff --git a/bench/spdlog-bench-mt.cpp b/bench/spdlog-bench-mt.cpp index 93a3cca0..c70b779f 100644 --- a/bench/spdlog-bench-mt.cpp +++ b/bench/spdlog-bench-mt.cpp @@ -18,7 +18,7 @@ int main(int argc, char* argv[]) namespace spd = spdlog; ///Create a file rotating logger with 5mb size max and 5 rotated files - auto logger = spd::rotating_logger_mt("file_logger", "logs/spd-sample", 10 *1024 * 1024 , 5); + auto logger = spd::rotating_logger_mt("file_logger", "logs/spd-sample", 10 *1024 * 1024 , 5, false); logger->set_pattern("[%Y-%b-%d %T.%e]: %v"); diff --git a/example/bench.cpp b/example/bench.cpp index 87cf4946..31787af7 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -52,7 +52,7 @@ int main(int argc, char* argv[]) int howmany = 1000000; int threads = 10; - bool auto_flush = true; + bool auto_flush = false; int file_size = 30 * 1024 * 1024; int rotating_files = 5; @@ -79,7 +79,7 @@ int main(int argc, char* argv[]) cout << "*******************************************************************************\n"; auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", file_size, rotating_files, auto_flush); - bench_mt(howmany, rotating_mt, threads); + bench_mt(howmany, rotating_mt, threads); auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt", auto_flush); diff --git a/example/example.cpp b/example/example.cpp index 889d96bc..927578fe 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -45,16 +45,12 @@ int main(int, char* []) auto console = spd::stdout_logger_mt("console"); console->info("Welcome to spdlog!") ; console->info("An info message example", "...", 1, 2, 3.5); - console->info() << "Streams are supported too " << std::setw(5) << std::setfill('0') << 1; + console->info() << "Streams are supported too " << 1; //Create a file rotating logger with 5mb size max and 3 rotated files auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3); file_logger->info("Log file message number", 1); - for (int i = 0; i < 100; ++i) - { - file_logger->info(i, "in hex is", "0x") << std::hex << std::uppercase << i; - } spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***"); file_logger->info("This is another message with custom format"); @@ -67,10 +63,9 @@ int main(int, char* []) // Asynchronous logging is easy.. // Just call spdlog::set_async_mode(max_q_size) and all created loggers from now on will be asynchronous.. // - size_t max_q_size = 100000; spdlog::set_async_mode(max_q_size); - auto async_file= spd::daily_logger_st("async_file_logger", "async_" + filename); + auto async_file= spd::daily_logger_st("async_file_logger", "logs/async_log.txt"); async_file->info() << "This is async log.." << "Should be very fast!"; // From 2485dae1cca05bb2cb36b60b2bc7204de51f174b Mon Sep 17 00:00:00 2001 From: gabime Date: Sat, 29 Nov 2014 20:01:45 +0200 Subject: [PATCH 008/120] example fix --- example/bench.cpp | 6 +++--- example/example.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/example/bench.cpp b/example/bench.cpp index 87cf4946..b1e908af 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -52,7 +52,7 @@ int main(int argc, char* argv[]) int howmany = 1000000; int threads = 10; - bool auto_flush = true; + bool auto_flush = false; int file_size = 30 * 1024 * 1024; int rotating_files = 5; @@ -78,8 +78,8 @@ int main(int argc, char* argv[]) cout << threads << " threads sharing same logger, " << format(howmany) << " iterations, auto_flush=" << auto_flush << endl; cout << "*******************************************************************************\n"; - auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", file_size, rotating_files, auto_flush); - bench_mt(howmany, rotating_mt, threads); + auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", file_size, rotating_files, auto_flush); + bench_mt(howmany, rotating_mt, threads); auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt", auto_flush); diff --git a/example/example.cpp b/example/example.cpp index 889d96bc..fbd5fc3f 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -70,7 +70,7 @@ int main(int, char* []) size_t max_q_size = 100000; spdlog::set_async_mode(max_q_size); - auto async_file= spd::daily_logger_st("async_file_logger", "async_" + filename); + auto async_file= spd::daily_logger_st("async_file_logger", "logs/async_log.txt"); async_file->info() << "This is async log.." << "Should be very fast!"; // From 73b31e4d109c9377d116a46de7492c26dc2f3986 Mon Sep 17 00:00:00 2001 From: gabime Date: Sat, 29 Nov 2014 20:02:14 +0200 Subject: [PATCH 009/120] astyle --- bench/g2log-bench-mt.cpp | 2 +- bench/g2log-bench.cpp | 6 +- bench/spdlog-bench-async.cpp | 4 +- bench/spdlog-bench-mt-async.cpp | 4 +- example/bench.cpp | 14 +- include/spdlog/details/format.h | 817 ++++++++++++------ include/spdlog/details/mpcs_q.h | 6 +- .../spdlog/details/pattern_formatter_impl.h | 2 +- 8 files changed, 564 insertions(+), 291 deletions(-) diff --git a/bench/g2log-bench-mt.cpp b/bench/g2log-bench-mt.cpp index 60660ecf..9e32c3f4 100644 --- a/bench/g2log-bench-mt.cpp +++ b/bench/g2log-bench-mt.cpp @@ -19,7 +19,7 @@ int main(int argc, char* argv[]) g2LogWorker g2log(argv[0], "logs"); g2::initializeLogging(&g2log); - + std::atomic msg_counter {0}; vector threads; diff --git a/bench/g2log-bench.cpp b/bench/g2log-bench.cpp index d06131b8..f716940a 100644 --- a/bench/g2log-bench.cpp +++ b/bench/g2log-bench.cpp @@ -5,10 +5,10 @@ int main(int, char* argv[]) { int howmany = 1000000; - - g2LogWorker g2log(argv[0], "logs"); + + g2LogWorker g2log(argv[0], "logs"); g2::initializeLogging(&g2log); - + for(int i = 0 ; i < howmany; ++i) LOG(INFO) << "g2log message # " << i << ": This is some text for your pleasure"; diff --git a/bench/spdlog-bench-async.cpp b/bench/spdlog-bench-async.cpp index 9054cb6e..9ec78472 100644 --- a/bench/spdlog-bench-async.cpp +++ b/bench/spdlog-bench-async.cpp @@ -6,13 +6,13 @@ int main(int, char* []) { int howmany = 1000000; namespace spd = spdlog; - spd::set_async_mode(2500, std::chrono::seconds(0)); + spd::set_async_mode(2500, std::chrono::seconds(0)); ///Create a file rotating logger with 5mb size max and 3 rotated files auto logger = spd::rotating_logger_mt("file_logger", "logs/spd-sample", 10 *1024 * 1024 , 5); logger->set_pattern("[%Y-%b-%d %T.%e]: %v"); for(int i = 0 ; i < howmany; ++i) logger->info() << "spdlog message #" << i << ": This is some text for your pleasure"; - spd::stop(); + spd::stop(); return 0; } diff --git a/bench/spdlog-bench-mt-async.cpp b/bench/spdlog-bench-mt-async.cpp index 17c72a8c..58027020 100644 --- a/bench/spdlog-bench-mt-async.cpp +++ b/bench/spdlog-bench-mt-async.cpp @@ -17,7 +17,7 @@ int main(int argc, char* argv[]) int howmany = 1000000; namespace spd = spdlog; - spd::set_async_mode(2500, std::chrono::seconds(0)); + spd::set_async_mode(2500, std::chrono::seconds(0)); ///Create a file rotating logger with 5mb size max and 3 rotated files auto logger = spd::rotating_logger_mt("file_logger", "logs/spd-sample", 10 *1024 * 1024 , 5); @@ -45,6 +45,6 @@ int main(int argc, char* argv[]) t.join(); }; - spd::stop(); + spd::stop(); return 0; } diff --git a/example/bench.cpp b/example/bench.cpp index 31787af7..70d2ef9d 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -52,7 +52,7 @@ int main(int argc, char* argv[]) int howmany = 1000000; int threads = 10; - bool auto_flush = false; + bool auto_flush = false; int file_size = 30 * 1024 * 1024; int rotating_files = 5; @@ -79,22 +79,22 @@ int main(int argc, char* argv[]) cout << "*******************************************************************************\n"; auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", file_size, rotating_files, auto_flush); - bench_mt(howmany, rotating_mt, threads); + bench_mt(howmany, rotating_mt, threads); auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt", auto_flush); bench_mt(howmany, daily_mt, threads); bench(howmany, spdlog::create("null_mt")); - + cout << "\n*******************************************************************************\n"; cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " iterations, auto_flush=" << auto_flush << endl; - cout << "*******************************************************************************\n"; + cout << "*******************************************************************************\n"; + - spdlog::set_async_mode(2500); auto daily_st_async = spdlog::daily_logger_st("daily_async", "logs/daily_async", auto_flush); - bench_mt(howmany, daily_st_async, threads); - + bench_mt(howmany, daily_st_async, threads); + spdlog::stop(); } diff --git a/include/spdlog/details/format.h b/include/spdlog/details/format.h index 5e1644c2..208efe54 100644 --- a/include/spdlog/details/format.h +++ b/include/spdlog/details/format.h @@ -112,7 +112,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. TypeName(const TypeName&); \ void operator=(const TypeName&) -namespace fmt { +namespace fmt +{ // Fix the warning about long long on older versions of GCC // that don't support the diagnostic pragma. @@ -161,7 +162,8 @@ format(std::string("{}"), 42); \endrst */ template -class BasicStringRef { +class BasicStringRef +{ private: const Char *data_; std::size_t size_; @@ -188,28 +190,33 @@ public: /** Converts a string reference to an `std::string` object. */ - operator std::basic_string() const { + operator std::basic_string() const + { return std::basic_string(data_, size()); } /** Returns the pointer to a C string. */ - const Char *c_str() const { + const Char *c_str() const + { return data_; } /** Returns the string size. */ - std::size_t size() const { + std::size_t size() const + { return size_; } - friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { + friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) + { return lhs.data_ == rhs.data_; } - friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { + friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) + { return lhs.data_ != rhs.data_; } }; @@ -220,13 +227,15 @@ typedef BasicStringRef WStringRef; /** A formatting error such as invalid format string. */ -class FormatError : public std::runtime_error { +class FormatError : public std::runtime_error +{ public: explicit FormatError(StringRef message) : std::runtime_error(message.c_str()) {} }; -namespace internal { +namespace internal +{ // The number of characters to store in the MemoryBuffer object itself // to avoid dynamic memory allocation. @@ -235,19 +244,22 @@ enum { INLINE_BUFFER_SIZE = 500 }; #if _SECURE_SCL // Use checked iterator to avoid warnings on MSVC. template -inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { +inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) +{ return stdext::checked_array_iterator(ptr, size); } #else template -inline T *make_ptr(T *ptr, std::size_t) { +inline T *make_ptr(T *ptr, std::size_t) +{ return ptr; } #endif // A buffer for POD types. It supports a subset of std::vector's operations. template -class Buffer { +class Buffer +{ private: FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); @@ -265,33 +277,39 @@ public: virtual ~Buffer() {} // Returns the size of this buffer. - std::size_t size() const { + std::size_t size() const + { return size_; } // Returns the capacity of this buffer. - std::size_t capacity() const { + std::size_t capacity() const + { return capacity_; } // Resizes the buffer. If T is a POD type new elements are not initialized. - void resize(std::size_t new_size) { + void resize(std::size_t new_size) + { if (new_size > capacity_) grow(new_size); size_ = new_size; } // Reserves space to store at least capacity elements. - void reserve(std::size_t capacity) { + void reserve(std::size_t capacity) + { if (capacity > capacity_) grow(capacity); } - void clear() FMT_NOEXCEPT(true) { + void clear() FMT_NOEXCEPT(true) + { size_ = 0; } - void push_back(const T &value) { + void push_back(const T &value) + { if (size_ == capacity_) grow(size_ + 1); ptr_[size_++] = value; @@ -300,16 +318,19 @@ public: // Appends data to the end of the buffer. void append(const T *begin, const T *end); - T &operator[](std::size_t index) { + T &operator[](std::size_t index) + { return ptr_[index]; } - const T &operator[](std::size_t index) const { + const T &operator[](std::size_t index) const + { return ptr_[index]; } }; template -void Buffer::append(const T *begin, const T *end) { +void Buffer::append(const T *begin, const T *end) +{ std::ptrdiff_t num_elements = end - begin; if (size_ + num_elements > capacity_) grow(size_ + num_elements); @@ -320,12 +341,14 @@ void Buffer::append(const T *begin, const T *end) { // A memory buffer for POD types with the first SIZE elements stored in // the object itself. template > -class MemoryBuffer : private Allocator, public Buffer { +class MemoryBuffer : private Allocator, public Buffer +{ private: T data_[SIZE]; // Free memory allocated by the buffer. - void free() { + void free() + { if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_); } @@ -335,24 +358,28 @@ protected: public: explicit MemoryBuffer(const Allocator &alloc = Allocator()) : Allocator(alloc), Buffer(data_, SIZE) {} - ~MemoryBuffer() { + ~MemoryBuffer() + { free(); } #if FMT_USE_RVALUE_REFERENCES private: // Move data from other to this buffer. - void move(MemoryBuffer &other) { + void move(MemoryBuffer &other) + { Allocator &this_alloc = *this, &other_alloc = other; this_alloc = std::move(other_alloc); this->size_ = other.size_; this->capacity_ = other.capacity_; - if (other.ptr_ == other.data_) { + if (other.ptr_ == other.data_) + { this->ptr_ = data_; std::copy(other.data_, other.data_ + this->size_, make_ptr(data_, this->capacity_)); } - else { + else + { this->ptr_ = other.ptr_; // Set pointer to the inline array so that delete is not called // when freeing. @@ -361,11 +388,13 @@ private: } public: - MemoryBuffer(MemoryBuffer &&other) { + MemoryBuffer(MemoryBuffer &&other) + { move(other); } - MemoryBuffer &operator=(MemoryBuffer &&other) { + MemoryBuffer &operator=(MemoryBuffer &&other) + { assert(this != &other); free(); move(other); @@ -374,13 +403,15 @@ public: #endif // Returns a copy of the allocator associated with this buffer. - Allocator get_allocator() const { + Allocator get_allocator() const + { return *this; } }; template -void MemoryBuffer::grow(std::size_t size) { +void MemoryBuffer::grow(std::size_t size) +{ std::size_t new_capacity = (std::max)(size, this->capacity_ + this->capacity_ / 2); T *new_ptr = this->allocate(new_capacity); @@ -400,7 +431,8 @@ void MemoryBuffer::grow(std::size_t size) { #ifndef _MSC_VER // Portable version of signbit. -inline int getsign(double x) { +inline int getsign(double x) +{ // When compiled in C++11 mode signbit is no longer a macro but a function // defined in namespace std and the macro is undefined. # ifdef signbit @@ -412,22 +444,27 @@ inline int getsign(double x) { // Portable version of isinf. # ifdef isinf -inline int isinfinity(double x) { +inline int isinfinity(double x) +{ return isinf(x); } -inline int isinfinity(long double x) { +inline int isinfinity(long double x) +{ return isinf(x); } # else -inline int isinfinity(double x) { +inline int isinfinity(double x) +{ return std::isinf(x); } -inline int isinfinity(long double x) { +inline int isinfinity(long double x) +{ return std::isinf(x); } # endif #else -inline int getsign(double value) { +inline int getsign(double value) +{ if (value < 0) return 1; if (value == value) return 0; int dec = 0, sign = 0; @@ -435,23 +472,27 @@ inline int getsign(double value) { _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign); return sign; } -inline int isinfinity(double x) { +inline int isinfinity(double x) +{ return !_finite(x); } #endif template -struct IsLongDouble { +struct IsLongDouble +{ enum { VALUE = 0 }; }; template <> -struct IsLongDouble { +struct IsLongDouble +{ enum { VALUE = 1 }; }; template -class BasicCharTraits { +class BasicCharTraits +{ public: #if _SECURE_SCL typedef stdext::checked_array_iterator CharPtr; @@ -464,7 +505,8 @@ template class CharTraits; template <> -class CharTraits : public BasicCharTraits { +class CharTraits : public BasicCharTraits +{ private: // Conversion from wchar_t to char is not allowed. static char convert(wchar_t); @@ -472,7 +514,8 @@ private: public: typedef const wchar_t *UnsupportedStrType; - static char convert(char value) { + static char convert(char value) + { return value; } @@ -483,14 +526,17 @@ public: }; template <> -class CharTraits : public BasicCharTraits { +class CharTraits : public BasicCharTraits +{ public: typedef const char *UnsupportedStrType; - static wchar_t convert(char value) { + static wchar_t convert(char value) + { return value; } - static wchar_t convert(wchar_t value) { + static wchar_t convert(wchar_t value) + { return value; } @@ -501,17 +547,21 @@ public: // Checks if a number is negative - used to avoid warnings. template -struct SignChecker { +struct SignChecker +{ template - static bool is_negative(T value) { + static bool is_negative(T value) + { return value < 0; } }; template <> -struct SignChecker { +struct SignChecker +{ template - static bool is_negative(T) { + static bool is_negative(T) + { return false; } }; @@ -519,23 +569,27 @@ struct SignChecker { // Returns true if value is negative, false otherwise. // Same as (value < 0) but doesn't produce warnings if T is an unsigned type. template -inline bool is_negative(T value) { +inline bool is_negative(T value) +{ return SignChecker::is_signed>::is_negative(value); } // Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. template -struct TypeSelector { +struct TypeSelector +{ typedef uint32_t Type; }; template <> -struct TypeSelector { +struct TypeSelector +{ typedef uint64_t Type; }; template -struct IntTraits { +struct IntTraits +{ // Smallest of uint32_t and uint64_t that is large enough to represent // all values of T. typedef typename @@ -544,7 +598,8 @@ struct IntTraits { // MakeUnsigned::Type gives an unsigned type corresponding to integer type T. template -struct MakeUnsigned { +struct MakeUnsigned +{ typedef T Type; }; @@ -567,7 +622,8 @@ extern const uint64_t POWERS_OF_10_64[]; #if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) // Returns the number of decimal digits in n. Leading zeros are not counted // except for n == 0 in which case count_digits returns 1. -inline unsigned count_digits(uint64_t n) { +inline unsigned count_digits(uint64_t n) +{ // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. unsigned t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12; @@ -575,16 +631,19 @@ inline unsigned count_digits(uint64_t n) { } # if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) // Optional version of count_digits for better performance on 32-bit platforms. -inline unsigned count_digits(uint32_t n) { +inline unsigned count_digits(uint32_t n) +{ uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12; return t - (n < POWERS_OF_10_32[t]) + 1; } # endif #else // Fallback version of count_digits used when __builtin_clz is not available. -inline unsigned count_digits(uint64_t n) { +inline unsigned count_digits(uint64_t n) +{ unsigned count = 1; - for (;;) { + for (;;) + { // Integer division is slow so do it for a group of four digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. @@ -602,9 +661,11 @@ extern const char DIGITS[]; // Formats a decimal unsigned integer value writing into buffer. template -inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { +inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) +{ --num_digits; - while (value >= 100) { + while (value >= 100) + { // Integer division is slow so do it for a group of two digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. @@ -614,7 +675,8 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { buffer[num_digits - 1] = DIGITS[index]; num_digits -= 2; } - if (value < 10) { + if (value < 10) + { *buffer = static_cast('0' + value); return; } @@ -626,45 +688,55 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { #ifdef _WIN32 // A converter from UTF-8 to UTF-16. // It is only provided for Windows since other systems support UTF-8 natively. -class UTF8ToUTF16 { +class UTF8ToUTF16 +{ private: MemoryBuffer buffer_; public: explicit UTF8ToUTF16(StringRef s); - operator WStringRef() const { + operator WStringRef() const + { return WStringRef(&buffer_[0], size()); } - size_t size() const { + size_t size() const + { return buffer_.size() - 1; } - const wchar_t *c_str() const { + const wchar_t *c_str() const + { return &buffer_[0]; } - std::wstring str() const { + std::wstring str() const + { return std::wstring(&buffer_[0], size()); } }; // A converter from UTF-16 to UTF-8. // It is only provided for Windows since other systems support UTF-8 natively. -class UTF16ToUTF8 { +class UTF16ToUTF8 +{ private: MemoryBuffer buffer_; public: UTF16ToUTF8() {} explicit UTF16ToUTF8(WStringRef s); - operator StringRef() const { + operator StringRef() const + { return StringRef(&buffer_[0], size()); } - size_t size() const { + size_t size() const + { return buffer_.size() - 1; } - const char *c_str() const { + const char *c_str() const + { return &buffer_[0]; } - std::string str() const { + std::string str() const + { return std::string(&buffer_[0], size()); } @@ -686,20 +758,24 @@ void format_windows_error(fmt::Writer &out, int error_code, // Computes max(Arg, 1) at compile time. It is used to avoid errors about // allocating an array of 0 size. template -struct NonZero { +struct NonZero +{ enum { VALUE = Arg }; }; template <> -struct NonZero<0> { +struct NonZero<0> +{ enum { VALUE = 1 }; }; // The value of a formatting argument. It is a POD type to allow storage in // internal::MemoryBuffer. -struct Value { +struct Value +{ template - struct StringValue { + struct StringValue + { const Char *value; std::size_t size; }; @@ -707,12 +783,14 @@ struct Value { typedef void(*FormatFunc)( void *formatter, const void *arg, void *format_str_ptr); - struct CustomValue { + struct CustomValue + { const void *value; FormatFunc format; }; - union { + union + { int int_value; unsigned uint_value; LongLong long_long_value; @@ -728,8 +806,10 @@ struct Value { }; }; -struct Arg : Value { - enum Type { +struct Arg : Value +{ + enum Type + { NONE, // Integer types should go first, INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR, @@ -742,7 +822,8 @@ struct Arg : Value { // Makes a Value object from any type. template -class MakeValue : public Value { +class MakeValue : public Value +{ private: // The following two methods are private to disallow formatting of // arbitrary pointers. If you want to output a pointer cast it to @@ -754,12 +835,14 @@ private: template MakeValue(T *value); - void set_string(StringRef str) { + void set_string(StringRef str) + { string.value = str.c_str(); string.size = str.size(); } - void set_string(WStringRef str) { + void set_string(WStringRef str) + { CharTraits::convert(wchar_t()); wstring.value = str.c_str(); wstring.size = str.size(); @@ -768,7 +851,8 @@ private: // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( - void *formatter, const void *arg, void *format_str_ptr) { + void *formatter, const void *arg, void *format_str_ptr) + { format(*static_cast*>(formatter), *static_cast(format_str_ptr), *static_cast(arg)); @@ -787,7 +871,8 @@ public: FMT_MAKE_VALUE(int, int_value, INT) FMT_MAKE_VALUE(unsigned, uint_value, UINT) - MakeValue(long value) { + MakeValue(long value) + { // To minimize the number of types we need to deal with, long is // translated either to int or to long long depending on its size. if (sizeof(long) == sizeof(int)) @@ -795,17 +880,20 @@ public: else long_long_value = value; } - static uint64_t type(long) { + static uint64_t type(long) + { return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; } - MakeValue(unsigned long value) { + MakeValue(unsigned long value) + { if (sizeof(unsigned long) == sizeof(unsigned)) uint_value = static_cast(value); else ulong_long_value = value; } - static uint64_t type(unsigned long) { + static uint64_t type(unsigned long) + { return sizeof(unsigned long) == sizeof(unsigned) ? Arg::UINT : Arg::ULONG_LONG; } @@ -819,10 +907,12 @@ public: FMT_MAKE_VALUE(unsigned char, int_value, CHAR) FMT_MAKE_VALUE(char, int_value, CHAR) - MakeValue(wchar_t value) { + MakeValue(wchar_t value) + { int_value = internal::CharTraits::convert(value); } - static uint64_t type(wchar_t) { + static uint64_t type(wchar_t) + { return Arg::CHAR; } @@ -846,12 +936,14 @@ public: FMT_MAKE_VALUE(const void *, pointer, POINTER) template - MakeValue(const T &value) { + MakeValue(const T &value) + { custom.value = &value; custom.format = &format_custom_arg; } template - static uint64_t type(const T &) { + static uint64_t type(const T &) + { return Arg::CUSTOM; } }; @@ -879,61 +971,78 @@ public: // ArgVisitor uses the curiously recurring template pattern: // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern template -class ArgVisitor { +class ArgVisitor +{ public: - Result visit_unhandled_arg() { + Result visit_unhandled_arg() + { return Result(); } - Result visit_int(int value) { + Result visit_int(int value) + { return FMT_DISPATCH(visit_any_int(value)); } - Result visit_long_long(LongLong value) { + Result visit_long_long(LongLong value) + { return FMT_DISPATCH(visit_any_int(value)); } - Result visit_uint(unsigned value) { + Result visit_uint(unsigned value) + { return FMT_DISPATCH(visit_any_int(value)); } - Result visit_ulong_long(ULongLong value) { + Result visit_ulong_long(ULongLong value) + { return FMT_DISPATCH(visit_any_int(value)); } - Result visit_char(int value) { + Result visit_char(int value) + { return FMT_DISPATCH(visit_any_int(value)); } template - Result visit_any_int(T) { + Result visit_any_int(T) + { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_double(double value) { + Result visit_double(double value) + { return FMT_DISPATCH(visit_any_double(value)); } - Result visit_long_double(long double value) { + Result visit_long_double(long double value) + { return FMT_DISPATCH(visit_any_double(value)); } template - Result visit_any_double(T) { + Result visit_any_double(T) + { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_string(Arg::StringValue) { + Result visit_string(Arg::StringValue) + { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_wstring(Arg::StringValue) { + Result visit_wstring(Arg::StringValue) + { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_pointer(const void *) { + Result visit_pointer(const void *) + { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_custom(Arg::CustomValue) { + Result visit_custom(Arg::CustomValue) + { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit(const Arg &arg) { - switch (arg.type) { + Result visit(const Arg &arg) + { + switch (arg.type) + { default: assert(false); - // Fall through. + // Fall through. case Arg::INT: return FMT_DISPATCH(visit_int(arg.int_value)); case Arg::UINT: @@ -948,7 +1057,8 @@ public: return FMT_DISPATCH(visit_long_double(arg.long_double_value)); case Arg::CHAR: return FMT_DISPATCH(visit_char(arg.int_value)); - case Arg::CSTRING: { + case Arg::CSTRING: + { Value::StringValue str = arg.string; str.size = 0; return FMT_DISPATCH(visit_string(str)); @@ -965,7 +1075,8 @@ public: } }; -class RuntimeError : public std::runtime_error { +class RuntimeError : public std::runtime_error +{ protected: RuntimeError() : std::runtime_error("") {} }; @@ -977,7 +1088,8 @@ class ArgFormatter; /** An argument list. */ -class ArgList { +class ArgList +{ private: uint64_t types_; const internal::Value *values_; @@ -993,10 +1105,12 @@ public: /** Returns the argument at specified index. */ - internal::Arg operator[](unsigned index) const { + internal::Arg operator[](unsigned index) const + { using internal::Arg; Arg arg; - if (index >= MAX_ARGS) { + if (index >= MAX_ARGS) + { arg.type = Arg::NONE; return arg; } @@ -1005,7 +1119,8 @@ public: Arg::Type type = static_cast((types_ & (mask << shift)) >> shift); arg.type = type; - if (type != Arg::NONE) { + if (type != Arg::NONE) + { internal::Value &value = arg; value = values_[index]; } @@ -1015,9 +1130,11 @@ public: struct FormatSpec; -namespace internal { +namespace internal +{ -class FormatterBase { +class FormatterBase +{ private: ArgList args_; int next_arg_index_; @@ -1026,7 +1143,8 @@ private: Arg do_get_arg(unsigned arg_index, const char *&error); protected: - void set_args(const ArgList &args) { + void set_args(const ArgList &args) + { args_ = args; next_arg_index_ = 0; } @@ -1039,7 +1157,8 @@ protected: Arg get_arg(unsigned arg_index, const char *&error); template - void write(BasicWriter &w, const Char *start, const Char *end) { + void write(BasicWriter &w, const Char *start, const Char *end) + { if (start != end) w << BasicStringRef(start, end - start); } @@ -1047,7 +1166,8 @@ protected: // A printf formatter. template -class PrintfFormatter : private FormatterBase { +class PrintfFormatter : private FormatterBase +{ private: void parse_flags(FormatSpec &spec, const Char *&s); @@ -1067,7 +1187,8 @@ public: // A formatter. template -class BasicFormatter : private internal::FormatterBase { +class BasicFormatter : private internal::FormatterBase +{ private: BasicWriter &writer_; const Char *start_; @@ -1078,7 +1199,8 @@ private: public: explicit BasicFormatter(BasicWriter &w) : writer_(w) {} - BasicWriter &writer() { + BasicWriter &writer() + { return writer_; } @@ -1087,12 +1209,14 @@ public: const Char *format(const Char *&format_str, const internal::Arg &arg); }; -enum Alignment { +enum Alignment +{ ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC }; // Flags. -enum { +enum +{ SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8, CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. }; @@ -1102,29 +1226,37 @@ struct EmptySpec {}; // A type specifier. template -struct TypeSpec : EmptySpec { - Alignment align() const { +struct TypeSpec : EmptySpec +{ + Alignment align() const + { return ALIGN_DEFAULT; } - unsigned width() const { + unsigned width() const + { return 0; } - int precision() const { + int precision() const + { return -1; } - bool flag(unsigned) const { + bool flag(unsigned) const + { return false; } - char type() const { + char type() const + { return TYPE; } - char fill() const { + char fill() const + { return ' '; } }; // A width specifier. -struct WidthSpec { +struct WidthSpec +{ unsigned width_; // Fill is always wchar_t and cast to char if necessary to avoid having // two specialization of WidthSpec and its subclasses. @@ -1132,45 +1264,54 @@ struct WidthSpec { WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} - unsigned width() const { + unsigned width() const + { return width_; } - wchar_t fill() const { + wchar_t fill() const + { return fill_; } }; // An alignment specifier. -struct AlignSpec : WidthSpec { +struct AlignSpec : WidthSpec +{ Alignment align_; AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) : WidthSpec(width, fill), align_(align) {} - Alignment align() const { + Alignment align() const + { return align_; } - int precision() const { + int precision() const + { return -1; } }; // An alignment and type specifier. template -struct AlignTypeSpec : AlignSpec { +struct AlignTypeSpec : AlignSpec +{ AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} - bool flag(unsigned) const { + bool flag(unsigned) const + { return false; } - char type() const { + char type() const + { return TYPE; } }; // A full format specifier. -struct FormatSpec : AlignSpec { +struct FormatSpec : AlignSpec +{ unsigned flags_; int precision_; char type_; @@ -1179,20 +1320,24 @@ struct FormatSpec : AlignSpec { unsigned width = 0, char type = 0, wchar_t fill = ' ') : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} - bool flag(unsigned f) const { + bool flag(unsigned f) const + { return (flags_ & f) != 0; } - int precision() const { + int precision() const + { return precision_; } - char type() const { + char type() const + { return type_; } }; // An integer format specifier. template , typename Char = char> -class IntFormatSpec : public SpecT { +class IntFormatSpec : public SpecT +{ private: T value_; @@ -1200,14 +1345,16 @@ public: IntFormatSpec(T value, const SpecT &spec = SpecT()) : SpecT(spec), value_(value) {} - T value() const { + T value() const + { return value_; } }; // A string format specifier. template -class StrFormatSpec : public AlignSpec { +class StrFormatSpec : public AlignSpec +{ private: const T *str_; @@ -1215,7 +1362,8 @@ public: StrFormatSpec(const T *str, unsigned width, wchar_t fill) : AlignSpec(width, fill), str_(str) {} - const T *str() const { + const T *str() const + { return str_; } }; @@ -1330,12 +1478,14 @@ std::string s = str(MemoryWriter() << pad("abc", 8)); */ template inline StrFormatSpec pad( - const Char *str, unsigned width, Char fill = ' ') { + const Char *str, unsigned width, Char fill = ' ') +{ return StrFormatSpec(str, width, fill); } inline StrFormatSpec pad( - const wchar_t *str, unsigned width, char fill = ' ') { + const wchar_t *str, unsigned width, char fill = ' ') +{ return StrFormatSpec(str, width, fill); } @@ -1358,24 +1508,29 @@ inline StrFormatSpec pad( # define FMT_GEN14(f) FMT_GEN13(f), f(13) # define FMT_GEN15(f) FMT_GEN14(f), f(14) -namespace internal { -inline uint64_t make_type() { +namespace internal +{ +inline uint64_t make_type() +{ return 0; } template -inline uint64_t make_type(const T &arg) { +inline uint64_t make_type(const T &arg) +{ return MakeValue::type(arg); } #if FMT_USE_VARIADIC_TEMPLATES template -inline uint64_t make_type(const Arg &first, const Args & ... tail) { +inline uint64_t make_type(const Arg &first, const Args & ... tail) +{ return make_type(first) | (make_type(tail...) << 4); } #else -struct ArgType { +struct ArgType +{ uint64_t type; ArgType() : type(0) {} @@ -1386,7 +1541,8 @@ struct ArgType { # define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() -inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { +inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) +{ return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | @@ -1496,7 +1652,8 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { An error returned by an operating system or a language runtime, for example a file opening error. */ -class SystemError : public internal::RuntimeError { +class SystemError : public internal::RuntimeError +{ private: void init(int error_code, StringRef format_str, ArgList args); @@ -1517,12 +1674,14 @@ public: *error_code* is a system error code as given by ``errno``. \endrst */ - SystemError(int error_code, StringRef message) { + SystemError(int error_code, StringRef message) + { init(error_code, message, ArgList()); } FMT_VARIADIC_CTOR(SystemError, init, int, StringRef) - int error_code() const { + int error_code() const + { return error_code_; } }; @@ -1546,7 +1705,8 @@ You can use one of the following typedefs for common character types: \endrst */ template -class BasicWriter { +class BasicWriter +{ private: // Output buffer. internal::Buffer &buffer_; @@ -1557,11 +1717,13 @@ private: #if _SECURE_SCL // Returns pointer value. - static Char *get(CharPtr p) { + static Char *get(CharPtr p) + { return p.base(); } #else - static Char *get(Char *p) { + static Char *get(Char *p) + { return p; } #endif @@ -1573,7 +1735,8 @@ private: // Grows the buffer by n characters and returns a pointer to the newly // allocated area. - CharPtr grow_buffer(std::size_t n) { + CharPtr grow_buffer(std::size_t n) + { std::size_t size = buffer_.size(); buffer_.resize(size + n); return internal::make_ptr(&buffer_[size], n); @@ -1581,7 +1744,8 @@ private: // Prepare a buffer for integer formatting. CharPtr prepare_int_buffer(unsigned num_digits, - const EmptySpec &, const char *prefix, unsigned prefix_size) { + const EmptySpec &, const char *prefix, unsigned prefix_size) + { unsigned size = prefix_size + num_digits; CharPtr p = grow_buffer(size); std::copy(prefix, prefix + prefix_size, p); @@ -1633,7 +1797,8 @@ public: /** Returns the total number of characters written. */ - std::size_t size() const { + std::size_t size() const + { return buffer_.size(); } @@ -1641,7 +1806,8 @@ public: Returns a pointer to the output buffer content. No terminating null character is appended. */ - const Char *data() const FMT_NOEXCEPT(true) { + const Char *data() const FMT_NOEXCEPT(true) + { return &buffer_[0]; } @@ -1649,7 +1815,8 @@ public: Returns a pointer to the output buffer content with terminating null character appended. */ - const Char *c_str() const { + const Char *c_str() const + { std::size_t size = buffer_.size(); buffer_.reserve(size + 1); buffer_[size] = '\0'; @@ -1659,7 +1826,8 @@ public: /** Returns the content of the output buffer as an `std::string`. */ - std::basic_string str() const { + std::basic_string str() const + { return std::basic_string(&buffer_[0], buffer_.size()); } @@ -1688,35 +1856,43 @@ public: See also :ref:`syntax`. \endrst */ - void write(BasicStringRef format, ArgList args) { + void write(BasicStringRef format, ArgList args) + { BasicFormatter(*this).format(format, args); } FMT_VARIADIC_VOID(write, BasicStringRef) - BasicWriter &operator<<(int value) { + BasicWriter &operator<<(int value) + { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(unsigned value) { + BasicWriter &operator<<(unsigned value) + { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(long value) { + BasicWriter &operator<<(long value) + { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(unsigned long value) { + BasicWriter &operator<<(unsigned long value) + { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(LongLong value) { + BasicWriter &operator<<(LongLong value) + { return *this << IntFormatSpec(value); } /** Formats *value* and writes it to the stream. */ - BasicWriter &operator<<(ULongLong value) { + BasicWriter &operator<<(ULongLong value) + { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(double value) { + BasicWriter &operator<<(double value) + { write_double(value, FormatSpec()); return *this; } @@ -1725,7 +1901,8 @@ public: Formats *value* using the general format for floating-point numbers (``'g'``) and writes it to the stream. */ - BasicWriter &operator<<(long double value) { + BasicWriter &operator<<(long double value) + { write_double(value, FormatSpec()); return *this; } @@ -1733,12 +1910,14 @@ public: /** Writes a character to the stream. */ - BasicWriter &operator<<(char value) { + BasicWriter &operator<<(char value) + { buffer_.push_back(value); return *this; } - BasicWriter &operator<<(wchar_t value) { + BasicWriter &operator<<(wchar_t value) + { buffer_.push_back(internal::CharTraits::convert(value)); return *this; } @@ -1746,28 +1925,32 @@ public: /** Writes *value* to the stream. */ - BasicWriter &operator<<(fmt::BasicStringRef value) { + BasicWriter &operator<<(fmt::BasicStringRef value) + { const Char *str = value.c_str(); buffer_.append(str, str + value.size()); return *this; } template - BasicWriter &operator<<(IntFormatSpec spec) { + BasicWriter &operator<<(IntFormatSpec spec) + { internal::CharTraits::convert(FillChar()); write_int(spec.value(), spec); return *this; } template - BasicWriter &operator<<(const StrFormatSpec &spec) { + BasicWriter &operator<<(const StrFormatSpec &spec) + { const StrChar *s = spec.str(); // TODO: error if fill is not convertible to Char write_str(s, std::char_traits::length(s), spec); return *this; } - void clear() FMT_NOEXCEPT(true) { + void clear() FMT_NOEXCEPT(true) + { buffer_.clear(); } }; @@ -1775,23 +1958,29 @@ public: template template typename BasicWriter::CharPtr BasicWriter::write_str( - const StrChar *s, std::size_t size, const AlignSpec &spec) { + const StrChar *s, std::size_t size, const AlignSpec &spec) +{ CharPtr out = CharPtr(); - if (spec.width() > size) { + if (spec.width() > size) + { out = grow_buffer(spec.width()); Char fill = static_cast(spec.fill()); - if (spec.align() == ALIGN_RIGHT) { + if (spec.align() == ALIGN_RIGHT) + { std::fill_n(out, spec.width() - size, fill); out += spec.width() - size; } - else if (spec.align() == ALIGN_CENTER) { + else if (spec.align() == ALIGN_CENTER) + { out = fill_padding(out, spec.width(), size, fill); } - else { + else + { std::fill_n(out + size, spec.width() - size, fill); } } - else { + else + { out = grow_buffer(size); } std::copy(s, s + size, out); @@ -1802,7 +1991,8 @@ template typename BasicWriter::CharPtr BasicWriter::fill_padding( CharPtr buffer, unsigned total_size, - std::size_t content_size, wchar_t fill) { + std::size_t content_size, wchar_t fill) +{ std::size_t padding = total_size - content_size; std::size_t left_padding = padding / 2; Char fill_char = static_cast(fill); @@ -1818,11 +2008,13 @@ template typename BasicWriter::CharPtr BasicWriter::prepare_int_buffer( unsigned num_digits, const Spec &spec, - const char *prefix, unsigned prefix_size) { + const char *prefix, unsigned prefix_size) +{ unsigned width = spec.width(); Alignment align = spec.align(); Char fill = static_cast(spec.fill()); - if (spec.precision() > static_cast(num_digits)) { + if (spec.precision() > static_cast(num_digits)) + { // Octal prefix '0' is counted as a digit, so ignore it if precision // is specified. if (prefix_size > 0 && prefix[prefix_size - 1] == '0') @@ -1833,44 +2025,53 @@ BasicWriter::prepare_int_buffer( return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); buffer_.reserve(width); unsigned fill_size = width - number_size; - if (align != ALIGN_LEFT) { + if (align != ALIGN_LEFT) + { CharPtr p = grow_buffer(fill_size); std::fill(p, p + fill_size, fill); } CharPtr result = prepare_int_buffer( num_digits, subspec, prefix, prefix_size); - if (align == ALIGN_LEFT) { + if (align == ALIGN_LEFT) + { CharPtr p = grow_buffer(fill_size); std::fill(p, p + fill_size, fill); } return result; } unsigned size = prefix_size + num_digits; - if (width <= size) { + if (width <= size) + { CharPtr p = grow_buffer(size); std::copy(prefix, prefix + prefix_size, p); return p + size - 1; } CharPtr p = grow_buffer(width); CharPtr end = p + width; - if (align == ALIGN_LEFT) { + if (align == ALIGN_LEFT) + { std::copy(prefix, prefix + prefix_size, p); p += size; std::fill(p, end, fill); } - else if (align == ALIGN_CENTER) { + else if (align == ALIGN_CENTER) + { p = fill_padding(p, width, size, fill); std::copy(prefix, prefix + prefix_size, p); p += size; } - else { - if (align == ALIGN_NUMERIC) { - if (prefix_size != 0) { + else + { + if (align == ALIGN_NUMERIC) + { + if (prefix_size != 0) + { p = std::copy(prefix, prefix + prefix_size, p); size -= prefix_size; } } - else { + else + { std::copy(prefix, prefix + prefix_size, end - size); } std::fill(p, end - size, fill); @@ -1881,23 +2082,28 @@ BasicWriter::prepare_int_buffer( template template -void BasicWriter::write_int(T value, Spec spec) { +void BasicWriter::write_int(T value, Spec spec) +{ unsigned prefix_size = 0; typedef typename internal::IntTraits::MainType UnsignedType; UnsignedType abs_value = value; char prefix[4] = ""; - if (internal::is_negative(value)) { + if (internal::is_negative(value)) + { prefix[0] = '-'; ++prefix_size; abs_value = 0 - abs_value; } - else if (spec.flag(SIGN_FLAG)) { + else if (spec.flag(SIGN_FLAG)) + { prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; ++prefix_size; } - switch (spec.type()) { + switch (spec.type()) + { case 0: - case 'd': { + case 'd': + { unsigned num_digits = internal::count_digits(abs_value); CharPtr p = prepare_int_buffer( num_digits, spec, prefix, prefix_size) + 1 - num_digits; @@ -1905,57 +2111,74 @@ void BasicWriter::write_int(T value, Spec spec) { break; } case 'x': - case 'X': { + case 'X': + { UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { + if (spec.flag(HASH_FLAG)) + { prefix[prefix_size++] = '0'; prefix[prefix_size++] = spec.type(); } unsigned num_digits = 0; - do { + do + { ++num_digits; - } while ((n >>= 4) != 0); + } + while ((n >>= 4) != 0); Char *p = get(prepare_int_buffer( num_digits, spec, prefix, prefix_size)); n = abs_value; const char *digits = spec.type() == 'x' ? "0123456789abcdef" : "0123456789ABCDEF"; - do { + do + { *p-- = digits[n & 0xf]; - } while ((n >>= 4) != 0); + } + while ((n >>= 4) != 0); break; } case 'b': - case 'B': { + case 'B': + { UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { + if (spec.flag(HASH_FLAG)) + { prefix[prefix_size++] = '0'; prefix[prefix_size++] = spec.type(); } unsigned num_digits = 0; - do { + do + { ++num_digits; - } while ((n >>= 1) != 0); + } + while ((n >>= 1) != 0); Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); n = abs_value; - do { + do + { *p-- = '0' + (n & 1); - } while ((n >>= 1) != 0); + } + while ((n >>= 1) != 0); break; } - case 'o': { + case 'o': + { UnsignedType n = abs_value; if (spec.flag(HASH_FLAG)) prefix[prefix_size++] = '0'; unsigned num_digits = 0; - do { + do + { ++num_digits; - } while ((n >>= 3) != 0); + } + while ((n >>= 3) != 0); Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); n = abs_value; - do { + do + { *p-- = '0' + (n & 7); - } while ((n >>= 3) != 0); + } + while ((n >>= 3) != 0); break; } default: @@ -1968,11 +2191,13 @@ void BasicWriter::write_int(T value, Spec spec) { template template void BasicWriter::write_double( - T value, const FormatSpec &spec) { + T value, const FormatSpec &spec) +{ // Check type. char type = spec.type(); bool upper = false; - switch (type) { + switch (type) + { case 0: type = 'g'; break; @@ -1986,7 +2211,7 @@ void BasicWriter::write_double( // MSVC's printf doesn't support 'F'. type = 'f'; #endif - // Fall through. + // Fall through. case 'E': case 'G': case 'A': @@ -2000,20 +2225,24 @@ void BasicWriter::write_double( char sign = 0; // Use getsign instead of value < 0 because the latter is always // false for NaN. - if (internal::getsign(static_cast(value))) { + if (internal::getsign(static_cast(value))) + { sign = '-'; value = -value; } - else if (spec.flag(SIGN_FLAG)) { + else if (spec.flag(SIGN_FLAG)) + { sign = spec.flag(PLUS_FLAG) ? '+' : ' '; } - if (value != value) { + if (value != value) + { // Format NaN ourselves because sprintf's output is not consistent // across platforms. std::size_t size = 4; const char *nan = upper ? " NAN" : " nan"; - if (!sign) { + if (!sign) + { --size; ++nan; } @@ -2023,12 +2252,14 @@ void BasicWriter::write_double( return; } - if (internal::isinfinity(value)) { + if (internal::isinfinity(value)) + { // Format infinity ourselves because sprintf's output is not consistent // across platforms. std::size_t size = 4; const char *inf = upper ? " INF" : " inf"; - if (!sign) { + if (!sign) + { --size; ++inf; } @@ -2040,7 +2271,8 @@ void BasicWriter::write_double( std::size_t offset = buffer_.size(); unsigned width = spec.width(); - if (sign) { + if (sign) + { buffer_.reserve(buffer_.size() + (std::max)(width, 1u)); if (width > 0) --width; @@ -2055,16 +2287,19 @@ void BasicWriter::write_double( unsigned width_for_sprintf = width; if (spec.flag(HASH_FLAG)) *format_ptr++ = '#'; - if (spec.align() == ALIGN_CENTER) { + if (spec.align() == ALIGN_CENTER) + { width_for_sprintf = 0; } - else { + else + { if (spec.align() == ALIGN_LEFT) *format_ptr++ = '-'; if (width != 0) *format_ptr++ = '*'; } - if (spec.precision() >= 0) { + if (spec.precision() >= 0) + { *format_ptr++ = '.'; *format_ptr++ = '*'; } @@ -2075,13 +2310,15 @@ void BasicWriter::write_double( // Format using snprintf. Char fill = static_cast(spec.fill()); - for (;;) { + for (;;) + { std::size_t size = buffer_.capacity() - offset; #if _MSC_VER // MSVC's vsnprintf_s doesn't work with zero size, so reserve // space for at least one extra character to make the size non-zero. // Note that the buffer's capacity will increase by more than 1. - if (size == 0) { + if (size == 0) + { buffer_.reserve(offset + 1); size = buffer_.capacity() - offset; } @@ -2089,27 +2326,33 @@ void BasicWriter::write_double( Char *start = &buffer_[offset]; int n = internal::CharTraits::format_float( start, size, format, width_for_sprintf, spec.precision(), value); - if (n >= 0 && offset + n < buffer_.capacity()) { - if (sign) { + if (n >= 0 && offset + n < buffer_.capacity()) + { + if (sign) + { if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || - *start != ' ') { + *start != ' ') + { *(start - 1) = sign; sign = 0; } - else { + else + { *(start - 1) = fill; } ++n; } if (spec.align() == ALIGN_CENTER && - spec.width() > static_cast(n)) { + spec.width() > static_cast(n)) + { unsigned width = spec.width(); CharPtr p = grow_buffer(width); std::copy(p, p + n, p + (width - n) / 2); fill_padding(p, spec.width(), n, fill); return; } - if (spec.fill() != ' ' || sign) { + if (spec.fill() != ' ' || sign) + { while (*start == ' ') *start++ = fill; if (sign) @@ -2159,7 +2402,8 @@ accessed as a C string with ``out.c_str()``. \endrst */ template > -class BasicMemoryWriter : public BasicWriter { +class BasicMemoryWriter : public BasicWriter +{ private: internal::MemoryBuffer buffer_; @@ -2173,13 +2417,15 @@ public: object to it. */ BasicMemoryWriter(BasicMemoryWriter &&other) - : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) { + : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) + { } /** Moves the content of the other ``BasicMemoryWriter`` object to this one. */ - BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { + BasicMemoryWriter &operator=(BasicMemoryWriter &&other) + { buffer_ = std::move(other.buffer_); return *this; } @@ -2191,7 +2437,8 @@ typedef BasicMemoryWriter WMemoryWriter; // Formats a value. template -void format(BasicFormatter &f, const Char *&format_str, const T &value) { +void format(BasicFormatter &f, const Char *&format_str, const T &value) +{ std::basic_ostringstream os; os << value; internal::Arg arg; @@ -2211,7 +2458,8 @@ void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT(true); /** A Windows error. */ -class WindowsError : public SystemError { +class WindowsError : public SystemError +{ private: void init(int error_code, StringRef format_str, ArgList args); @@ -2225,7 +2473,8 @@ public: *error_code* is a Windows error code as given by ``GetLastError``. \endrst */ - WindowsError(int error_code, StringRef message) { + WindowsError(int error_code, StringRef message) + { init(error_code, message, ArgList()); } FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef) @@ -2256,13 +2505,15 @@ Formats arguments and returns the result as a string. std::string message = format("The answer is {}", 42); \endrst */ -inline std::string format(StringRef format_str, ArgList args) { +inline std::string format(StringRef format_str, ArgList args) +{ MemoryWriter w; w.write(format_str, args); return w.str(); } -inline std::wstring format(WStringRef format_str, ArgList args) { +inline std::wstring format(WStringRef format_str, ArgList args) +{ WMemoryWriter w; w.write(format_str, args); return w.str(); @@ -2302,7 +2553,8 @@ print(cerr, "Don't {}!", "panic"); void print(std::ostream &os, StringRef format_str, ArgList args); template -void printf(BasicWriter &w, BasicStringRef format, ArgList args) { +void printf(BasicWriter &w, BasicStringRef format, ArgList args) +{ internal::PrintfFormatter().format(w, format, args); } @@ -2315,7 +2567,8 @@ Formats arguments and returns the result as a string. std::string message = fmt::sprintf("The answer is %d", 42); \endrst */ -inline std::string sprintf(StringRef format, ArgList args) { +inline std::string sprintf(StringRef format, ArgList args) +{ MemoryWriter w; printf(w, format, args); return w.str(); @@ -2341,14 +2594,16 @@ Prints formatted data to ``stdout``. fmt::printf("Elapsed time: %.2f seconds", 1.23); \endrst */ -inline int printf(StringRef format, ArgList args) { +inline int printf(StringRef format, ArgList args) +{ return fprintf(stdout, format, args); } /** Fast integer formatter. */ -class FormatInt { +class FormatInt +{ private: // Buffer should be large enough to hold all digits (digits10 + 1), // a sign and a null character. @@ -2357,9 +2612,11 @@ private: char *str_; // Formats value in reverse and returns the number of digits. - char *format_decimal(ULongLong value) { + char *format_decimal(ULongLong value) + { char *buffer_end = buffer_ + BUFFER_SIZE - 1; - while (value >= 100) { + while (value >= 100) + { // Integer division is slow so do it for a group of two digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. @@ -2368,7 +2625,8 @@ private: *--buffer_end = internal::DIGITS[index + 1]; *--buffer_end = internal::DIGITS[index]; } - if (value < 10) { + if (value < 10) + { *--buffer_end = static_cast('0' + value); return buffer_end; } @@ -2378,7 +2636,8 @@ private: return buffer_end; } - void FormatSigned(LongLong value) { + void FormatSigned(LongLong value) + { ULongLong abs_value = static_cast(value); bool negative = value < 0; if (negative) @@ -2389,13 +2648,16 @@ private: } public: - explicit FormatInt(int value) { + explicit FormatInt(int value) + { FormatSigned(value); } - explicit FormatInt(long value) { + explicit FormatInt(long value) + { FormatSigned(value); } - explicit FormatInt(LongLong value) { + explicit FormatInt(LongLong value) + { FormatSigned(value); } explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} @@ -2405,7 +2667,8 @@ public: /** Returns the number of characters written to the output buffer. */ - std::size_t size() const { + std::size_t size() const + { return buffer_ - str_ + BUFFER_SIZE - 1; } @@ -2413,7 +2676,8 @@ public: Returns a pointer to the output buffer content. No terminating null character is appended. */ - const char *data() const { + const char *data() const + { return str_; } @@ -2421,7 +2685,8 @@ public: Returns a pointer to the output buffer content with terminating null character appended. */ - const char *c_str() const { + const char *c_str() const + { buffer_[BUFFER_SIZE - 1] = '\0'; return str_; } @@ -2429,7 +2694,8 @@ public: /** Returns the content of the output buffer as an `std::string`. */ - std::string str() const { + std::string str() const + { return std::string(str_, size()); } }; @@ -2438,14 +2704,18 @@ public: // a pointer to the end of the formatted string. This function doesn't // write a terminating null character. template -inline void format_decimal(char *&buffer, T value) { +inline void format_decimal(char *&buffer, T value) +{ typename internal::IntTraits::MainType abs_value = value; - if (internal::is_negative(value)) { + if (internal::is_negative(value)) + { *buffer++ = '-'; abs_value = 0 - abs_value; } - if (abs_value < 100) { - if (abs_value < 10) { + if (abs_value < 100) + { + if (abs_value < 10) + { *buffer++ = static_cast('0' + abs_value); return; } @@ -2565,7 +2835,8 @@ fmt::print(format, args...); #define FMT_VARIADIC_W(ReturnType, func, ...) \ FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) -namespace fmt { +namespace fmt +{ FMT_VARIADIC(std::string, format, StringRef) FMT_VARIADIC_W(std::wstring, format, WStringRef) FMT_VARIADIC(void, print, StringRef) diff --git a/include/spdlog/details/mpcs_q.h b/include/spdlog/details/mpcs_q.h index acc62a75..058d6ee4 100644 --- a/include/spdlog/details/mpcs_q.h +++ b/include/spdlog/details/mpcs_q.h @@ -61,8 +61,10 @@ should not be interpreted as representing official policies, either expressed or #include -namespace spdlog { -namespace details { +namespace spdlog +{ +namespace details +{ template class mpsc_q { diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index 69640a7b..aa0c4e8d 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -429,7 +429,7 @@ inline void spdlog::pattern_formatter::handle_flag(char flag) { switch (flag) { - // logger name + // logger name case 'n': _formatters.push_back(std::unique_ptr(new details::name_formatter())); break; From eaa61ed44836828e168c01b1fb5ad22e645e4c1f Mon Sep 17 00:00:00 2001 From: gabime Date: Sat, 29 Nov 2014 20:03:12 +0200 Subject: [PATCH 010/120] type --- bench/spdlog-bench-mt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/spdlog-bench-mt.cpp b/bench/spdlog-bench-mt.cpp index c70b779f..778c7745 100644 --- a/bench/spdlog-bench-mt.cpp +++ b/bench/spdlog-bench-mt.cpp @@ -17,7 +17,7 @@ int main(int argc, char* argv[]) int howmany = 1000000; namespace spd = spdlog; - ///Create a file rotating logger with 5mb size max and 5 rotated files + ///Create a file rotating logger with 10mb size max and 5 rotated files auto logger = spd::rotating_logger_mt("file_logger", "logs/spd-sample", 10 *1024 * 1024 , 5, false); logger->set_pattern("[%Y-%b-%d %T.%e]: %v"); From 45628c8ec3379cf05aca44705ddad0acf68b8911 Mon Sep 17 00:00:00 2001 From: gabi Date: Mon, 1 Dec 2014 00:59:25 +0200 Subject: [PATCH 011/120] logger main interface now is in the form logger.info(fmt, args) --- include/spdlog/details/format.cc | 14 +- include/spdlog/details/format.h | 859 +++++++++------------------ include/spdlog/details/line_logger.h | 7 + include/spdlog/details/logger_impl.h | 61 +- include/spdlog/logger.h | 30 +- 5 files changed, 347 insertions(+), 624 deletions(-) diff --git a/include/spdlog/details/format.cc b/include/spdlog/details/format.cc index 3559d185..06b8c846 100644 --- a/include/spdlog/details/format.cc +++ b/include/spdlog/details/format.cc @@ -400,7 +400,8 @@ int fmt::internal::CharTraits::format_float( swprintf(buffer, size, format, width, precision, value); } -const char fmt::internal::DIGITS[] = +template +const char fmt::internal::BasicData::DIGITS[] = "0001020304050607080910111213141516171819" "2021222324252627282930313233343536373839" "4041424344454647484950515253545556575859" @@ -418,8 +419,13 @@ const char fmt::internal::DIGITS[] = factor * 100000000, \ factor * 1000000000 -const uint32_t fmt::internal::POWERS_OF_10_32[] = { 0, FMT_POWERS_OF_10(1) }; -const uint64_t fmt::internal::POWERS_OF_10_64[] = { +template +const uint32_t fmt::internal::BasicData::POWERS_OF_10_32[] = { + 0, FMT_POWERS_OF_10(1) +}; + +template +const uint64_t fmt::internal::BasicData::POWERS_OF_10_64[] = { 0, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(ULongLong(1000000000)), @@ -1163,4 +1169,4 @@ template int fmt::internal::CharTraits::format_float( #if _MSC_VER # pragma warning(pop) -#endif +#endif \ No newline at end of file diff --git a/include/spdlog/details/format.h b/include/spdlog/details/format.h index 208efe54..26f74e8c 100644 --- a/include/spdlog/details/format.h +++ b/include/spdlog/details/format.h @@ -112,8 +112,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. TypeName(const TypeName&); \ void operator=(const TypeName&) -namespace fmt -{ +namespace fmt { // Fix the warning about long long on older versions of GCC // that don't support the diagnostic pragma. @@ -162,8 +161,7 @@ format(std::string("{}"), 42); \endrst */ template -class BasicStringRef -{ +class BasicStringRef { private: const Char *data_; std::size_t size_; @@ -190,33 +188,28 @@ public: /** Converts a string reference to an `std::string` object. */ - operator std::basic_string() const - { + operator std::basic_string() const { return std::basic_string(data_, size()); } /** Returns the pointer to a C string. */ - const Char *c_str() const - { + const Char *c_str() const { return data_; } /** Returns the string size. */ - std::size_t size() const - { + std::size_t size() const { return size_; } - friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) - { + friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { return lhs.data_ == rhs.data_; } - friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) - { + friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { return lhs.data_ != rhs.data_; } }; @@ -227,15 +220,13 @@ typedef BasicStringRef WStringRef; /** A formatting error such as invalid format string. */ -class FormatError : public std::runtime_error -{ +class FormatError : public std::runtime_error { public: explicit FormatError(StringRef message) : std::runtime_error(message.c_str()) {} }; -namespace internal -{ +namespace internal { // The number of characters to store in the MemoryBuffer object itself // to avoid dynamic memory allocation. @@ -244,22 +235,19 @@ enum { INLINE_BUFFER_SIZE = 500 }; #if _SECURE_SCL // Use checked iterator to avoid warnings on MSVC. template -inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) -{ +inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { return stdext::checked_array_iterator(ptr, size); } #else template -inline T *make_ptr(T *ptr, std::size_t) -{ +inline T *make_ptr(T *ptr, std::size_t) { return ptr; } #endif // A buffer for POD types. It supports a subset of std::vector's operations. template -class Buffer -{ +class Buffer { private: FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); @@ -277,39 +265,33 @@ public: virtual ~Buffer() {} // Returns the size of this buffer. - std::size_t size() const - { + std::size_t size() const { return size_; } // Returns the capacity of this buffer. - std::size_t capacity() const - { + std::size_t capacity() const { return capacity_; } // Resizes the buffer. If T is a POD type new elements are not initialized. - void resize(std::size_t new_size) - { + void resize(std::size_t new_size) { if (new_size > capacity_) grow(new_size); size_ = new_size; } // Reserves space to store at least capacity elements. - void reserve(std::size_t capacity) - { + void reserve(std::size_t capacity) { if (capacity > capacity_) grow(capacity); } - void clear() FMT_NOEXCEPT(true) - { + void clear() FMT_NOEXCEPT(true) { size_ = 0; } - void push_back(const T &value) - { + void push_back(const T &value) { if (size_ == capacity_) grow(size_ + 1); ptr_[size_++] = value; @@ -318,19 +300,16 @@ public: // Appends data to the end of the buffer. void append(const T *begin, const T *end); - T &operator[](std::size_t index) - { + T &operator[](std::size_t index) { return ptr_[index]; } - const T &operator[](std::size_t index) const - { + const T &operator[](std::size_t index) const { return ptr_[index]; } }; template -void Buffer::append(const T *begin, const T *end) -{ +void Buffer::append(const T *begin, const T *end) { std::ptrdiff_t num_elements = end - begin; if (size_ + num_elements > capacity_) grow(size_ + num_elements); @@ -341,14 +320,12 @@ void Buffer::append(const T *begin, const T *end) // A memory buffer for POD types with the first SIZE elements stored in // the object itself. template > -class MemoryBuffer : private Allocator, public Buffer -{ +class MemoryBuffer : private Allocator, public Buffer { private: T data_[SIZE]; // Free memory allocated by the buffer. - void free() - { + void free() { if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_); } @@ -358,28 +335,24 @@ protected: public: explicit MemoryBuffer(const Allocator &alloc = Allocator()) : Allocator(alloc), Buffer(data_, SIZE) {} - ~MemoryBuffer() - { + ~MemoryBuffer() { free(); } #if FMT_USE_RVALUE_REFERENCES private: // Move data from other to this buffer. - void move(MemoryBuffer &other) - { + void move(MemoryBuffer &other) { Allocator &this_alloc = *this, &other_alloc = other; this_alloc = std::move(other_alloc); this->size_ = other.size_; this->capacity_ = other.capacity_; - if (other.ptr_ == other.data_) - { + if (other.ptr_ == other.data_) { this->ptr_ = data_; std::copy(other.data_, other.data_ + this->size_, make_ptr(data_, this->capacity_)); } - else - { + else { this->ptr_ = other.ptr_; // Set pointer to the inline array so that delete is not called // when freeing. @@ -388,13 +361,11 @@ private: } public: - MemoryBuffer(MemoryBuffer &&other) - { + MemoryBuffer(MemoryBuffer &&other) { move(other); } - MemoryBuffer &operator=(MemoryBuffer &&other) - { + MemoryBuffer &operator=(MemoryBuffer &&other) { assert(this != &other); free(); move(other); @@ -403,15 +374,13 @@ public: #endif // Returns a copy of the allocator associated with this buffer. - Allocator get_allocator() const - { + Allocator get_allocator() const { return *this; } }; template -void MemoryBuffer::grow(std::size_t size) -{ +void MemoryBuffer::grow(std::size_t size) { std::size_t new_capacity = (std::max)(size, this->capacity_ + this->capacity_ / 2); T *new_ptr = this->allocate(new_capacity); @@ -431,8 +400,7 @@ void MemoryBuffer::grow(std::size_t size) #ifndef _MSC_VER // Portable version of signbit. -inline int getsign(double x) -{ +inline int getsign(double x) { // When compiled in C++11 mode signbit is no longer a macro but a function // defined in namespace std and the macro is undefined. # ifdef signbit @@ -444,27 +412,22 @@ inline int getsign(double x) // Portable version of isinf. # ifdef isinf -inline int isinfinity(double x) -{ +inline int isinfinity(double x) { return isinf(x); } -inline int isinfinity(long double x) -{ +inline int isinfinity(long double x) { return isinf(x); } # else -inline int isinfinity(double x) -{ +inline int isinfinity(double x) { return std::isinf(x); } -inline int isinfinity(long double x) -{ +inline int isinfinity(long double x) { return std::isinf(x); } # endif #else -inline int getsign(double value) -{ +inline int getsign(double value) { if (value < 0) return 1; if (value == value) return 0; int dec = 0, sign = 0; @@ -472,27 +435,23 @@ inline int getsign(double value) _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign); return sign; } -inline int isinfinity(double x) -{ +inline int isinfinity(double x) { return !_finite(x); } #endif template -struct IsLongDouble -{ +struct IsLongDouble { enum { VALUE = 0 }; }; template <> -struct IsLongDouble -{ +struct IsLongDouble { enum { VALUE = 1 }; }; template -class BasicCharTraits -{ +class BasicCharTraits { public: #if _SECURE_SCL typedef stdext::checked_array_iterator CharPtr; @@ -505,8 +464,7 @@ template class CharTraits; template <> -class CharTraits : public BasicCharTraits -{ +class CharTraits : public BasicCharTraits { private: // Conversion from wchar_t to char is not allowed. static char convert(wchar_t); @@ -514,8 +472,7 @@ private: public: typedef const wchar_t *UnsupportedStrType; - static char convert(char value) - { + static char convert(char value) { return value; } @@ -526,17 +483,14 @@ public: }; template <> -class CharTraits : public BasicCharTraits -{ +class CharTraits : public BasicCharTraits { public: typedef const char *UnsupportedStrType; - static wchar_t convert(char value) - { + static wchar_t convert(char value) { return value; } - static wchar_t convert(wchar_t value) - { + static wchar_t convert(wchar_t value) { return value; } @@ -547,21 +501,17 @@ public: // Checks if a number is negative - used to avoid warnings. template -struct SignChecker -{ +struct SignChecker { template - static bool is_negative(T value) - { + static bool is_negative(T value) { return value < 0; } }; template <> -struct SignChecker -{ +struct SignChecker { template - static bool is_negative(T) - { + static bool is_negative(T) { return false; } }; @@ -569,27 +519,23 @@ struct SignChecker // Returns true if value is negative, false otherwise. // Same as (value < 0) but doesn't produce warnings if T is an unsigned type. template -inline bool is_negative(T value) -{ +inline bool is_negative(T value) { return SignChecker::is_signed>::is_negative(value); } // Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. template -struct TypeSelector -{ +struct TypeSelector { typedef uint32_t Type; }; template <> -struct TypeSelector -{ +struct TypeSelector { typedef uint64_t Type; }; template -struct IntTraits -{ +struct IntTraits { // Smallest of uint32_t and uint64_t that is large enough to represent // all values of T. typedef typename @@ -598,8 +544,7 @@ struct IntTraits // MakeUnsigned::Type gives an unsigned type corresponding to integer type T. template -struct MakeUnsigned -{ +struct MakeUnsigned { typedef T Type; }; @@ -616,34 +561,38 @@ FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); void report_unknown_type(char code, const char *type); -extern const uint32_t POWERS_OF_10_32[]; -extern const uint64_t POWERS_OF_10_64[]; +// Static data is placed in this class template to allow header-only +// configuration. +template +struct BasicData { + static const uint32_t POWERS_OF_10_32[]; + static const uint64_t POWERS_OF_10_64[]; + static const char DIGITS[]; +}; + +typedef BasicData<> Data; #if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) // Returns the number of decimal digits in n. Leading zeros are not counted // except for n == 0 in which case count_digits returns 1. -inline unsigned count_digits(uint64_t n) -{ +inline unsigned count_digits(uint64_t n) { // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. unsigned t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12; - return t - (n < POWERS_OF_10_64[t]) + 1; + return t - (n < Data::POWERS_OF_10_64[t]) + 1; } # if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) // Optional version of count_digits for better performance on 32-bit platforms. -inline unsigned count_digits(uint32_t n) -{ +inline unsigned count_digits(uint32_t n) { uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12; - return t - (n < POWERS_OF_10_32[t]) + 1; + return t - (n < Data::POWERS_OF_10_32[t]) + 1; } # endif #else // Fallback version of count_digits used when __builtin_clz is not available. -inline unsigned count_digits(uint64_t n) -{ +inline unsigned count_digits(uint64_t n) { unsigned count = 1; - for (;;) - { + for (;;) { // Integer division is slow so do it for a group of four digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. @@ -657,86 +606,71 @@ inline unsigned count_digits(uint64_t n) } #endif -extern const char DIGITS[]; - // Formats a decimal unsigned integer value writing into buffer. template -inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) -{ +inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { --num_digits; - while (value >= 100) - { + while (value >= 100) { // Integer division is slow so do it for a group of two digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. unsigned index = (value % 100) * 2; value /= 100; - buffer[num_digits] = DIGITS[index + 1]; - buffer[num_digits - 1] = DIGITS[index]; + buffer[num_digits] = Data::DIGITS[index + 1]; + buffer[num_digits - 1] = Data::DIGITS[index]; num_digits -= 2; } - if (value < 10) - { + if (value < 10) { *buffer = static_cast('0' + value); return; } unsigned index = static_cast(value * 2); - buffer[1] = DIGITS[index + 1]; - buffer[0] = DIGITS[index]; + buffer[1] = Data::DIGITS[index + 1]; + buffer[0] = Data::DIGITS[index]; } #ifdef _WIN32 // A converter from UTF-8 to UTF-16. // It is only provided for Windows since other systems support UTF-8 natively. -class UTF8ToUTF16 -{ +class UTF8ToUTF16 { private: MemoryBuffer buffer_; public: explicit UTF8ToUTF16(StringRef s); - operator WStringRef() const - { + operator WStringRef() const { return WStringRef(&buffer_[0], size()); } - size_t size() const - { + size_t size() const { return buffer_.size() - 1; } - const wchar_t *c_str() const - { + const wchar_t *c_str() const { return &buffer_[0]; } - std::wstring str() const - { + std::wstring str() const { return std::wstring(&buffer_[0], size()); } }; // A converter from UTF-16 to UTF-8. // It is only provided for Windows since other systems support UTF-8 natively. -class UTF16ToUTF8 -{ +class UTF16ToUTF8 { private: MemoryBuffer buffer_; public: UTF16ToUTF8() {} explicit UTF16ToUTF8(WStringRef s); - operator StringRef() const - { + operator StringRef() const { return StringRef(&buffer_[0], size()); } - size_t size() const - { + size_t size() const { return buffer_.size() - 1; } - const char *c_str() const - { + const char *c_str() const { return &buffer_[0]; } - std::string str() const - { + std::string str() const { return std::string(&buffer_[0], size()); } @@ -758,24 +692,20 @@ void format_windows_error(fmt::Writer &out, int error_code, // Computes max(Arg, 1) at compile time. It is used to avoid errors about // allocating an array of 0 size. template -struct NonZero -{ +struct NonZero { enum { VALUE = Arg }; }; template <> -struct NonZero<0> -{ +struct NonZero<0> { enum { VALUE = 1 }; }; // The value of a formatting argument. It is a POD type to allow storage in // internal::MemoryBuffer. -struct Value -{ +struct Value { template - struct StringValue - { + struct StringValue { const Char *value; std::size_t size; }; @@ -783,14 +713,12 @@ struct Value typedef void(*FormatFunc)( void *formatter, const void *arg, void *format_str_ptr); - struct CustomValue - { + struct CustomValue { const void *value; FormatFunc format; }; - union - { + union { int int_value; unsigned uint_value; LongLong long_long_value; @@ -806,10 +734,8 @@ struct Value }; }; -struct Arg : Value -{ - enum Type - { +struct Arg : Value { + enum Type { NONE, // Integer types should go first, INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR, @@ -822,8 +748,7 @@ struct Arg : Value // Makes a Value object from any type. template -class MakeValue : public Value -{ +class MakeValue : public Value { private: // The following two methods are private to disallow formatting of // arbitrary pointers. If you want to output a pointer cast it to @@ -835,14 +760,12 @@ private: template MakeValue(T *value); - void set_string(StringRef str) - { + void set_string(StringRef str) { string.value = str.c_str(); string.size = str.size(); } - void set_string(WStringRef str) - { + void set_string(WStringRef str) { CharTraits::convert(wchar_t()); wstring.value = str.c_str(); wstring.size = str.size(); @@ -851,8 +774,7 @@ private: // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( - void *formatter, const void *arg, void *format_str_ptr) - { + void *formatter, const void *arg, void *format_str_ptr) { format(*static_cast*>(formatter), *static_cast(format_str_ptr), *static_cast(arg)); @@ -871,8 +793,7 @@ public: FMT_MAKE_VALUE(int, int_value, INT) FMT_MAKE_VALUE(unsigned, uint_value, UINT) - MakeValue(long value) - { + MakeValue(long value) { // To minimize the number of types we need to deal with, long is // translated either to int or to long long depending on its size. if (sizeof(long) == sizeof(int)) @@ -880,20 +801,17 @@ public: else long_long_value = value; } - static uint64_t type(long) - { + static uint64_t type(long) { return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; } - MakeValue(unsigned long value) - { + MakeValue(unsigned long value) { if (sizeof(unsigned long) == sizeof(unsigned)) uint_value = static_cast(value); else ulong_long_value = value; } - static uint64_t type(unsigned long) - { + static uint64_t type(unsigned long) { return sizeof(unsigned long) == sizeof(unsigned) ? Arg::UINT : Arg::ULONG_LONG; } @@ -907,12 +825,10 @@ public: FMT_MAKE_VALUE(unsigned char, int_value, CHAR) FMT_MAKE_VALUE(char, int_value, CHAR) - MakeValue(wchar_t value) - { + MakeValue(wchar_t value) { int_value = internal::CharTraits::convert(value); } - static uint64_t type(wchar_t) - { + static uint64_t type(wchar_t) { return Arg::CHAR; } @@ -936,14 +852,12 @@ public: FMT_MAKE_VALUE(const void *, pointer, POINTER) template - MakeValue(const T &value) - { + MakeValue(const T &value) { custom.value = &value; custom.format = &format_custom_arg; } template - static uint64_t type(const T &) - { + static uint64_t type(const T &) { return Arg::CUSTOM; } }; @@ -971,78 +885,61 @@ public: // ArgVisitor uses the curiously recurring template pattern: // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern template -class ArgVisitor -{ +class ArgVisitor { public: - Result visit_unhandled_arg() - { + Result visit_unhandled_arg() { return Result(); } - Result visit_int(int value) - { + Result visit_int(int value) { return FMT_DISPATCH(visit_any_int(value)); } - Result visit_long_long(LongLong value) - { + Result visit_long_long(LongLong value) { return FMT_DISPATCH(visit_any_int(value)); } - Result visit_uint(unsigned value) - { + Result visit_uint(unsigned value) { return FMT_DISPATCH(visit_any_int(value)); } - Result visit_ulong_long(ULongLong value) - { + Result visit_ulong_long(ULongLong value) { return FMT_DISPATCH(visit_any_int(value)); } - Result visit_char(int value) - { + Result visit_char(int value) { return FMT_DISPATCH(visit_any_int(value)); } template - Result visit_any_int(T) - { + Result visit_any_int(T) { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_double(double value) - { + Result visit_double(double value) { return FMT_DISPATCH(visit_any_double(value)); } - Result visit_long_double(long double value) - { + Result visit_long_double(long double value) { return FMT_DISPATCH(visit_any_double(value)); } template - Result visit_any_double(T) - { + Result visit_any_double(T) { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_string(Arg::StringValue) - { + Result visit_string(Arg::StringValue) { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_wstring(Arg::StringValue) - { + Result visit_wstring(Arg::StringValue) { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_pointer(const void *) - { + Result visit_pointer(const void *) { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_custom(Arg::CustomValue) - { + Result visit_custom(Arg::CustomValue) { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit(const Arg &arg) - { - switch (arg.type) - { + Result visit(const Arg &arg) { + switch (arg.type) { default: assert(false); - // Fall through. + // Fall through. case Arg::INT: return FMT_DISPATCH(visit_int(arg.int_value)); case Arg::UINT: @@ -1057,8 +954,7 @@ public: return FMT_DISPATCH(visit_long_double(arg.long_double_value)); case Arg::CHAR: return FMT_DISPATCH(visit_char(arg.int_value)); - case Arg::CSTRING: - { + case Arg::CSTRING: { Value::StringValue str = arg.string; str.size = 0; return FMT_DISPATCH(visit_string(str)); @@ -1075,8 +971,7 @@ public: } }; -class RuntimeError : public std::runtime_error -{ +class RuntimeError : public std::runtime_error { protected: RuntimeError() : std::runtime_error("") {} }; @@ -1088,8 +983,7 @@ class ArgFormatter; /** An argument list. */ -class ArgList -{ +class ArgList { private: uint64_t types_; const internal::Value *values_; @@ -1105,12 +999,10 @@ public: /** Returns the argument at specified index. */ - internal::Arg operator[](unsigned index) const - { + internal::Arg operator[](unsigned index) const { using internal::Arg; Arg arg; - if (index >= MAX_ARGS) - { + if (index >= MAX_ARGS) { arg.type = Arg::NONE; return arg; } @@ -1119,8 +1011,7 @@ public: Arg::Type type = static_cast((types_ & (mask << shift)) >> shift); arg.type = type; - if (type != Arg::NONE) - { + if (type != Arg::NONE) { internal::Value &value = arg; value = values_[index]; } @@ -1130,11 +1021,9 @@ public: struct FormatSpec; -namespace internal -{ +namespace internal { -class FormatterBase -{ +class FormatterBase { private: ArgList args_; int next_arg_index_; @@ -1143,8 +1032,7 @@ private: Arg do_get_arg(unsigned arg_index, const char *&error); protected: - void set_args(const ArgList &args) - { + void set_args(const ArgList &args) { args_ = args; next_arg_index_ = 0; } @@ -1157,8 +1045,7 @@ protected: Arg get_arg(unsigned arg_index, const char *&error); template - void write(BasicWriter &w, const Char *start, const Char *end) - { + void write(BasicWriter &w, const Char *start, const Char *end) { if (start != end) w << BasicStringRef(start, end - start); } @@ -1166,8 +1053,7 @@ protected: // A printf formatter. template -class PrintfFormatter : private FormatterBase -{ +class PrintfFormatter : private FormatterBase { private: void parse_flags(FormatSpec &spec, const Char *&s); @@ -1187,8 +1073,7 @@ public: // A formatter. template -class BasicFormatter : private internal::FormatterBase -{ +class BasicFormatter : private internal::FormatterBase { private: BasicWriter &writer_; const Char *start_; @@ -1199,8 +1084,7 @@ private: public: explicit BasicFormatter(BasicWriter &w) : writer_(w) {} - BasicWriter &writer() - { + BasicWriter &writer() { return writer_; } @@ -1209,14 +1093,12 @@ public: const Char *format(const Char *&format_str, const internal::Arg &arg); }; -enum Alignment -{ +enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC }; // Flags. -enum -{ +enum { SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8, CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. }; @@ -1226,37 +1108,29 @@ struct EmptySpec {}; // A type specifier. template -struct TypeSpec : EmptySpec -{ - Alignment align() const - { +struct TypeSpec : EmptySpec { + Alignment align() const { return ALIGN_DEFAULT; } - unsigned width() const - { + unsigned width() const { return 0; } - int precision() const - { + int precision() const { return -1; } - bool flag(unsigned) const - { + bool flag(unsigned) const { return false; } - char type() const - { + char type() const { return TYPE; } - char fill() const - { + char fill() const { return ' '; } }; // A width specifier. -struct WidthSpec -{ +struct WidthSpec { unsigned width_; // Fill is always wchar_t and cast to char if necessary to avoid having // two specialization of WidthSpec and its subclasses. @@ -1264,54 +1138,45 @@ struct WidthSpec WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} - unsigned width() const - { + unsigned width() const { return width_; } - wchar_t fill() const - { + wchar_t fill() const { return fill_; } }; // An alignment specifier. -struct AlignSpec : WidthSpec -{ +struct AlignSpec : WidthSpec { Alignment align_; AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) : WidthSpec(width, fill), align_(align) {} - Alignment align() const - { + Alignment align() const { return align_; } - int precision() const - { + int precision() const { return -1; } }; // An alignment and type specifier. template -struct AlignTypeSpec : AlignSpec -{ +struct AlignTypeSpec : AlignSpec { AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} - bool flag(unsigned) const - { + bool flag(unsigned) const { return false; } - char type() const - { + char type() const { return TYPE; } }; // A full format specifier. -struct FormatSpec : AlignSpec -{ +struct FormatSpec : AlignSpec { unsigned flags_; int precision_; char type_; @@ -1320,24 +1185,20 @@ struct FormatSpec : AlignSpec unsigned width = 0, char type = 0, wchar_t fill = ' ') : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} - bool flag(unsigned f) const - { + bool flag(unsigned f) const { return (flags_ & f) != 0; } - int precision() const - { + int precision() const { return precision_; } - char type() const - { + char type() const { return type_; } }; // An integer format specifier. template , typename Char = char> -class IntFormatSpec : public SpecT -{ +class IntFormatSpec : public SpecT { private: T value_; @@ -1345,16 +1206,14 @@ public: IntFormatSpec(T value, const SpecT &spec = SpecT()) : SpecT(spec), value_(value) {} - T value() const - { + T value() const { return value_; } }; // A string format specifier. template -class StrFormatSpec : public AlignSpec -{ +class StrFormatSpec : public AlignSpec { private: const T *str_; @@ -1362,8 +1221,7 @@ public: StrFormatSpec(const T *str, unsigned width, wchar_t fill) : AlignSpec(width, fill), str_(str) {} - const T *str() const - { + const T *str() const { return str_; } }; @@ -1478,14 +1336,12 @@ std::string s = str(MemoryWriter() << pad("abc", 8)); */ template inline StrFormatSpec pad( - const Char *str, unsigned width, Char fill = ' ') -{ + const Char *str, unsigned width, Char fill = ' ') { return StrFormatSpec(str, width, fill); } inline StrFormatSpec pad( - const wchar_t *str, unsigned width, char fill = ' ') -{ + const wchar_t *str, unsigned width, char fill = ' ') { return StrFormatSpec(str, width, fill); } @@ -1508,29 +1364,24 @@ inline StrFormatSpec pad( # define FMT_GEN14(f) FMT_GEN13(f), f(13) # define FMT_GEN15(f) FMT_GEN14(f), f(14) -namespace internal -{ -inline uint64_t make_type() -{ +namespace internal { +inline uint64_t make_type() { return 0; } template -inline uint64_t make_type(const T &arg) -{ +inline uint64_t make_type(const T &arg) { return MakeValue::type(arg); } #if FMT_USE_VARIADIC_TEMPLATES template -inline uint64_t make_type(const Arg &first, const Args & ... tail) -{ +inline uint64_t make_type(const Arg &first, const Args & ... tail) { return make_type(first) | (make_type(tail...) << 4); } #else -struct ArgType -{ +struct ArgType { uint64_t type; ArgType() : type(0) {} @@ -1541,8 +1392,7 @@ struct ArgType # define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() -inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) -{ +inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | @@ -1652,8 +1502,7 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) An error returned by an operating system or a language runtime, for example a file opening error. */ -class SystemError : public internal::RuntimeError -{ +class SystemError : public internal::RuntimeError { private: void init(int error_code, StringRef format_str, ArgList args); @@ -1674,14 +1523,12 @@ public: *error_code* is a system error code as given by ``errno``. \endrst */ - SystemError(int error_code, StringRef message) - { + SystemError(int error_code, StringRef message) { init(error_code, message, ArgList()); } FMT_VARIADIC_CTOR(SystemError, init, int, StringRef) - int error_code() const - { + int error_code() const { return error_code_; } }; @@ -1705,8 +1552,7 @@ You can use one of the following typedefs for common character types: \endrst */ template -class BasicWriter -{ +class BasicWriter { private: // Output buffer. internal::Buffer &buffer_; @@ -1717,13 +1563,11 @@ private: #if _SECURE_SCL // Returns pointer value. - static Char *get(CharPtr p) - { + static Char *get(CharPtr p) { return p.base(); } #else - static Char *get(Char *p) - { + static Char *get(Char *p) { return p; } #endif @@ -1735,8 +1579,7 @@ private: // Grows the buffer by n characters and returns a pointer to the newly // allocated area. - CharPtr grow_buffer(std::size_t n) - { + CharPtr grow_buffer(std::size_t n) { std::size_t size = buffer_.size(); buffer_.resize(size + n); return internal::make_ptr(&buffer_[size], n); @@ -1744,8 +1587,7 @@ private: // Prepare a buffer for integer formatting. CharPtr prepare_int_buffer(unsigned num_digits, - const EmptySpec &, const char *prefix, unsigned prefix_size) - { + const EmptySpec &, const char *prefix, unsigned prefix_size) { unsigned size = prefix_size + num_digits; CharPtr p = grow_buffer(size); std::copy(prefix, prefix + prefix_size, p); @@ -1797,8 +1639,7 @@ public: /** Returns the total number of characters written. */ - std::size_t size() const - { + std::size_t size() const { return buffer_.size(); } @@ -1806,8 +1647,7 @@ public: Returns a pointer to the output buffer content. No terminating null character is appended. */ - const Char *data() const FMT_NOEXCEPT(true) - { + const Char *data() const FMT_NOEXCEPT(true) { return &buffer_[0]; } @@ -1815,8 +1655,7 @@ public: Returns a pointer to the output buffer content with terminating null character appended. */ - const Char *c_str() const - { + const Char *c_str() const { std::size_t size = buffer_.size(); buffer_.reserve(size + 1); buffer_[size] = '\0'; @@ -1826,8 +1665,7 @@ public: /** Returns the content of the output buffer as an `std::string`. */ - std::basic_string str() const - { + std::basic_string str() const { return std::basic_string(&buffer_[0], buffer_.size()); } @@ -1856,43 +1694,35 @@ public: See also :ref:`syntax`. \endrst */ - void write(BasicStringRef format, ArgList args) - { + void write(BasicStringRef format, ArgList args) { BasicFormatter(*this).format(format, args); } FMT_VARIADIC_VOID(write, BasicStringRef) - BasicWriter &operator<<(int value) - { + BasicWriter &operator<<(int value) { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(unsigned value) - { + BasicWriter &operator<<(unsigned value) { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(long value) - { + BasicWriter &operator<<(long value) { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(unsigned long value) - { + BasicWriter &operator<<(unsigned long value) { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(LongLong value) - { + BasicWriter &operator<<(LongLong value) { return *this << IntFormatSpec(value); } /** Formats *value* and writes it to the stream. */ - BasicWriter &operator<<(ULongLong value) - { + BasicWriter &operator<<(ULongLong value) { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(double value) - { + BasicWriter &operator<<(double value) { write_double(value, FormatSpec()); return *this; } @@ -1901,8 +1731,7 @@ public: Formats *value* using the general format for floating-point numbers (``'g'``) and writes it to the stream. */ - BasicWriter &operator<<(long double value) - { + BasicWriter &operator<<(long double value) { write_double(value, FormatSpec()); return *this; } @@ -1910,14 +1739,12 @@ public: /** Writes a character to the stream. */ - BasicWriter &operator<<(char value) - { + BasicWriter &operator<<(char value) { buffer_.push_back(value); return *this; } - BasicWriter &operator<<(wchar_t value) - { + BasicWriter &operator<<(wchar_t value) { buffer_.push_back(internal::CharTraits::convert(value)); return *this; } @@ -1925,32 +1752,28 @@ public: /** Writes *value* to the stream. */ - BasicWriter &operator<<(fmt::BasicStringRef value) - { + BasicWriter &operator<<(fmt::BasicStringRef value) { const Char *str = value.c_str(); buffer_.append(str, str + value.size()); return *this; } template - BasicWriter &operator<<(IntFormatSpec spec) - { + BasicWriter &operator<<(IntFormatSpec spec) { internal::CharTraits::convert(FillChar()); write_int(spec.value(), spec); return *this; } template - BasicWriter &operator<<(const StrFormatSpec &spec) - { + BasicWriter &operator<<(const StrFormatSpec &spec) { const StrChar *s = spec.str(); // TODO: error if fill is not convertible to Char write_str(s, std::char_traits::length(s), spec); return *this; } - void clear() FMT_NOEXCEPT(true) - { + void clear() FMT_NOEXCEPT(true) { buffer_.clear(); } }; @@ -1958,29 +1781,23 @@ public: template template typename BasicWriter::CharPtr BasicWriter::write_str( - const StrChar *s, std::size_t size, const AlignSpec &spec) -{ + const StrChar *s, std::size_t size, const AlignSpec &spec) { CharPtr out = CharPtr(); - if (spec.width() > size) - { + if (spec.width() > size) { out = grow_buffer(spec.width()); Char fill = static_cast(spec.fill()); - if (spec.align() == ALIGN_RIGHT) - { + if (spec.align() == ALIGN_RIGHT) { std::fill_n(out, spec.width() - size, fill); out += spec.width() - size; } - else if (spec.align() == ALIGN_CENTER) - { + else if (spec.align() == ALIGN_CENTER) { out = fill_padding(out, spec.width(), size, fill); } - else - { + else { std::fill_n(out + size, spec.width() - size, fill); } } - else - { + else { out = grow_buffer(size); } std::copy(s, s + size, out); @@ -1991,8 +1808,7 @@ template typename BasicWriter::CharPtr BasicWriter::fill_padding( CharPtr buffer, unsigned total_size, - std::size_t content_size, wchar_t fill) -{ + std::size_t content_size, wchar_t fill) { std::size_t padding = total_size - content_size; std::size_t left_padding = padding / 2; Char fill_char = static_cast(fill); @@ -2008,13 +1824,11 @@ template typename BasicWriter::CharPtr BasicWriter::prepare_int_buffer( unsigned num_digits, const Spec &spec, - const char *prefix, unsigned prefix_size) -{ + const char *prefix, unsigned prefix_size) { unsigned width = spec.width(); Alignment align = spec.align(); Char fill = static_cast(spec.fill()); - if (spec.precision() > static_cast(num_digits)) - { + if (spec.precision() > static_cast(num_digits)) { // Octal prefix '0' is counted as a digit, so ignore it if precision // is specified. if (prefix_size > 0 && prefix[prefix_size - 1] == '0') @@ -2025,53 +1839,44 @@ BasicWriter::prepare_int_buffer( return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); buffer_.reserve(width); unsigned fill_size = width - number_size; - if (align != ALIGN_LEFT) - { + if (align != ALIGN_LEFT) { CharPtr p = grow_buffer(fill_size); std::fill(p, p + fill_size, fill); } CharPtr result = prepare_int_buffer( num_digits, subspec, prefix, prefix_size); - if (align == ALIGN_LEFT) - { + if (align == ALIGN_LEFT) { CharPtr p = grow_buffer(fill_size); std::fill(p, p + fill_size, fill); } return result; } unsigned size = prefix_size + num_digits; - if (width <= size) - { + if (width <= size) { CharPtr p = grow_buffer(size); std::copy(prefix, prefix + prefix_size, p); return p + size - 1; } CharPtr p = grow_buffer(width); CharPtr end = p + width; - if (align == ALIGN_LEFT) - { + if (align == ALIGN_LEFT) { std::copy(prefix, prefix + prefix_size, p); p += size; std::fill(p, end, fill); } - else if (align == ALIGN_CENTER) - { + else if (align == ALIGN_CENTER) { p = fill_padding(p, width, size, fill); std::copy(prefix, prefix + prefix_size, p); p += size; } - else - { - if (align == ALIGN_NUMERIC) - { - if (prefix_size != 0) - { + else { + if (align == ALIGN_NUMERIC) { + if (prefix_size != 0) { p = std::copy(prefix, prefix + prefix_size, p); size -= prefix_size; } } - else - { + else { std::copy(prefix, prefix + prefix_size, end - size); } std::fill(p, end - size, fill); @@ -2082,28 +1887,23 @@ BasicWriter::prepare_int_buffer( template template -void BasicWriter::write_int(T value, Spec spec) -{ +void BasicWriter::write_int(T value, Spec spec) { unsigned prefix_size = 0; typedef typename internal::IntTraits::MainType UnsignedType; UnsignedType abs_value = value; char prefix[4] = ""; - if (internal::is_negative(value)) - { + if (internal::is_negative(value)) { prefix[0] = '-'; ++prefix_size; abs_value = 0 - abs_value; } - else if (spec.flag(SIGN_FLAG)) - { + else if (spec.flag(SIGN_FLAG)) { prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; ++prefix_size; } - switch (spec.type()) - { + switch (spec.type()) { case 0: - case 'd': - { + case 'd': { unsigned num_digits = internal::count_digits(abs_value); CharPtr p = prepare_int_buffer( num_digits, spec, prefix, prefix_size) + 1 - num_digits; @@ -2111,74 +1911,57 @@ void BasicWriter::write_int(T value, Spec spec) break; } case 'x': - case 'X': - { + case 'X': { UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) - { + if (spec.flag(HASH_FLAG)) { prefix[prefix_size++] = '0'; prefix[prefix_size++] = spec.type(); } unsigned num_digits = 0; - do - { + do { ++num_digits; - } - while ((n >>= 4) != 0); + } while ((n >>= 4) != 0); Char *p = get(prepare_int_buffer( num_digits, spec, prefix, prefix_size)); n = abs_value; const char *digits = spec.type() == 'x' ? "0123456789abcdef" : "0123456789ABCDEF"; - do - { + do { *p-- = digits[n & 0xf]; - } - while ((n >>= 4) != 0); + } while ((n >>= 4) != 0); break; } case 'b': - case 'B': - { + case 'B': { UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) - { + if (spec.flag(HASH_FLAG)) { prefix[prefix_size++] = '0'; prefix[prefix_size++] = spec.type(); } unsigned num_digits = 0; - do - { + do { ++num_digits; - } - while ((n >>= 1) != 0); + } while ((n >>= 1) != 0); Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); n = abs_value; - do - { + do { *p-- = '0' + (n & 1); - } - while ((n >>= 1) != 0); + } while ((n >>= 1) != 0); break; } - case 'o': - { + case 'o': { UnsignedType n = abs_value; if (spec.flag(HASH_FLAG)) prefix[prefix_size++] = '0'; unsigned num_digits = 0; - do - { + do { ++num_digits; - } - while ((n >>= 3) != 0); + } while ((n >>= 3) != 0); Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); n = abs_value; - do - { + do { *p-- = '0' + (n & 7); - } - while ((n >>= 3) != 0); + } while ((n >>= 3) != 0); break; } default: @@ -2191,13 +1974,11 @@ void BasicWriter::write_int(T value, Spec spec) template template void BasicWriter::write_double( - T value, const FormatSpec &spec) -{ + T value, const FormatSpec &spec) { // Check type. char type = spec.type(); bool upper = false; - switch (type) - { + switch (type) { case 0: type = 'g'; break; @@ -2211,7 +1992,7 @@ void BasicWriter::write_double( // MSVC's printf doesn't support 'F'. type = 'f'; #endif - // Fall through. + // Fall through. case 'E': case 'G': case 'A': @@ -2225,24 +2006,20 @@ void BasicWriter::write_double( char sign = 0; // Use getsign instead of value < 0 because the latter is always // false for NaN. - if (internal::getsign(static_cast(value))) - { + if (internal::getsign(static_cast(value))) { sign = '-'; value = -value; } - else if (spec.flag(SIGN_FLAG)) - { + else if (spec.flag(SIGN_FLAG)) { sign = spec.flag(PLUS_FLAG) ? '+' : ' '; } - if (value != value) - { + if (value != value) { // Format NaN ourselves because sprintf's output is not consistent // across platforms. std::size_t size = 4; const char *nan = upper ? " NAN" : " nan"; - if (!sign) - { + if (!sign) { --size; ++nan; } @@ -2252,14 +2029,12 @@ void BasicWriter::write_double( return; } - if (internal::isinfinity(value)) - { + if (internal::isinfinity(value)) { // Format infinity ourselves because sprintf's output is not consistent // across platforms. std::size_t size = 4; const char *inf = upper ? " INF" : " inf"; - if (!sign) - { + if (!sign) { --size; ++inf; } @@ -2271,8 +2046,7 @@ void BasicWriter::write_double( std::size_t offset = buffer_.size(); unsigned width = spec.width(); - if (sign) - { + if (sign) { buffer_.reserve(buffer_.size() + (std::max)(width, 1u)); if (width > 0) --width; @@ -2287,19 +2061,16 @@ void BasicWriter::write_double( unsigned width_for_sprintf = width; if (spec.flag(HASH_FLAG)) *format_ptr++ = '#'; - if (spec.align() == ALIGN_CENTER) - { + if (spec.align() == ALIGN_CENTER) { width_for_sprintf = 0; } - else - { + else { if (spec.align() == ALIGN_LEFT) *format_ptr++ = '-'; if (width != 0) *format_ptr++ = '*'; } - if (spec.precision() >= 0) - { + if (spec.precision() >= 0) { *format_ptr++ = '.'; *format_ptr++ = '*'; } @@ -2310,15 +2081,13 @@ void BasicWriter::write_double( // Format using snprintf. Char fill = static_cast(spec.fill()); - for (;;) - { + for (;;) { std::size_t size = buffer_.capacity() - offset; #if _MSC_VER // MSVC's vsnprintf_s doesn't work with zero size, so reserve // space for at least one extra character to make the size non-zero. // Note that the buffer's capacity will increase by more than 1. - if (size == 0) - { + if (size == 0) { buffer_.reserve(offset + 1); size = buffer_.capacity() - offset; } @@ -2326,33 +2095,27 @@ void BasicWriter::write_double( Char *start = &buffer_[offset]; int n = internal::CharTraits::format_float( start, size, format, width_for_sprintf, spec.precision(), value); - if (n >= 0 && offset + n < buffer_.capacity()) - { - if (sign) - { + if (n >= 0 && offset + n < buffer_.capacity()) { + if (sign) { if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || - *start != ' ') - { + *start != ' ') { *(start - 1) = sign; sign = 0; } - else - { + else { *(start - 1) = fill; } ++n; } if (spec.align() == ALIGN_CENTER && - spec.width() > static_cast(n)) - { + spec.width() > static_cast(n)) { unsigned width = spec.width(); CharPtr p = grow_buffer(width); std::copy(p, p + n, p + (width - n) / 2); fill_padding(p, spec.width(), n, fill); return; } - if (spec.fill() != ' ' || sign) - { + if (spec.fill() != ' ' || sign) { while (*start == ' ') *start++ = fill; if (sign) @@ -2402,8 +2165,7 @@ accessed as a C string with ``out.c_str()``. \endrst */ template > -class BasicMemoryWriter : public BasicWriter -{ +class BasicMemoryWriter : public BasicWriter { private: internal::MemoryBuffer buffer_; @@ -2417,15 +2179,13 @@ public: object to it. */ BasicMemoryWriter(BasicMemoryWriter &&other) - : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) - { + : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) { } /** Moves the content of the other ``BasicMemoryWriter`` object to this one. */ - BasicMemoryWriter &operator=(BasicMemoryWriter &&other) - { + BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { buffer_ = std::move(other.buffer_); return *this; } @@ -2437,8 +2197,7 @@ typedef BasicMemoryWriter WMemoryWriter; // Formats a value. template -void format(BasicFormatter &f, const Char *&format_str, const T &value) -{ +void format(BasicFormatter &f, const Char *&format_str, const T &value) { std::basic_ostringstream os; os << value; internal::Arg arg; @@ -2458,8 +2217,7 @@ void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT(true); /** A Windows error. */ -class WindowsError : public SystemError -{ +class WindowsError : public SystemError { private: void init(int error_code, StringRef format_str, ArgList args); @@ -2473,8 +2231,7 @@ public: *error_code* is a Windows error code as given by ``GetLastError``. \endrst */ - WindowsError(int error_code, StringRef message) - { + WindowsError(int error_code, StringRef message) { init(error_code, message, ArgList()); } FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef) @@ -2505,15 +2262,13 @@ Formats arguments and returns the result as a string. std::string message = format("The answer is {}", 42); \endrst */ -inline std::string format(StringRef format_str, ArgList args) -{ +inline std::string format(StringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); return w.str(); } -inline std::wstring format(WStringRef format_str, ArgList args) -{ +inline std::wstring format(WStringRef format_str, ArgList args) { WMemoryWriter w; w.write(format_str, args); return w.str(); @@ -2553,8 +2308,7 @@ print(cerr, "Don't {}!", "panic"); void print(std::ostream &os, StringRef format_str, ArgList args); template -void printf(BasicWriter &w, BasicStringRef format, ArgList args) -{ +void printf(BasicWriter &w, BasicStringRef format, ArgList args) { internal::PrintfFormatter().format(w, format, args); } @@ -2567,8 +2321,7 @@ Formats arguments and returns the result as a string. std::string message = fmt::sprintf("The answer is %d", 42); \endrst */ -inline std::string sprintf(StringRef format, ArgList args) -{ +inline std::string sprintf(StringRef format, ArgList args) { MemoryWriter w; printf(w, format, args); return w.str(); @@ -2594,16 +2347,14 @@ Prints formatted data to ``stdout``. fmt::printf("Elapsed time: %.2f seconds", 1.23); \endrst */ -inline int printf(StringRef format, ArgList args) -{ +inline int printf(StringRef format, ArgList args) { return fprintf(stdout, format, args); } /** Fast integer formatter. */ -class FormatInt -{ +class FormatInt { private: // Buffer should be large enough to hold all digits (digits10 + 1), // a sign and a null character. @@ -2612,32 +2363,28 @@ private: char *str_; // Formats value in reverse and returns the number of digits. - char *format_decimal(ULongLong value) - { + char *format_decimal(ULongLong value) { char *buffer_end = buffer_ + BUFFER_SIZE - 1; - while (value >= 100) - { + while (value >= 100) { // Integer division is slow so do it for a group of two digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. unsigned index = (value % 100) * 2; value /= 100; - *--buffer_end = internal::DIGITS[index + 1]; - *--buffer_end = internal::DIGITS[index]; + *--buffer_end = internal::Data::DIGITS[index + 1]; + *--buffer_end = internal::Data::DIGITS[index]; } - if (value < 10) - { + if (value < 10) { *--buffer_end = static_cast('0' + value); return buffer_end; } unsigned index = static_cast(value * 2); - *--buffer_end = internal::DIGITS[index + 1]; - *--buffer_end = internal::DIGITS[index]; + *--buffer_end = internal::Data::DIGITS[index + 1]; + *--buffer_end = internal::Data::DIGITS[index]; return buffer_end; } - void FormatSigned(LongLong value) - { + void FormatSigned(LongLong value) { ULongLong abs_value = static_cast(value); bool negative = value < 0; if (negative) @@ -2648,16 +2395,13 @@ private: } public: - explicit FormatInt(int value) - { + explicit FormatInt(int value) { FormatSigned(value); } - explicit FormatInt(long value) - { + explicit FormatInt(long value) { FormatSigned(value); } - explicit FormatInt(LongLong value) - { + explicit FormatInt(LongLong value) { FormatSigned(value); } explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} @@ -2667,8 +2411,7 @@ public: /** Returns the number of characters written to the output buffer. */ - std::size_t size() const - { + std::size_t size() const { return buffer_ - str_ + BUFFER_SIZE - 1; } @@ -2676,8 +2419,7 @@ public: Returns a pointer to the output buffer content. No terminating null character is appended. */ - const char *data() const - { + const char *data() const { return str_; } @@ -2685,8 +2427,7 @@ public: Returns a pointer to the output buffer content with terminating null character appended. */ - const char *c_str() const - { + const char *c_str() const { buffer_[BUFFER_SIZE - 1] = '\0'; return str_; } @@ -2694,8 +2435,7 @@ public: /** Returns the content of the output buffer as an `std::string`. */ - std::string str() const - { + std::string str() const { return std::string(str_, size()); } }; @@ -2704,24 +2444,20 @@ public: // a pointer to the end of the formatted string. This function doesn't // write a terminating null character. template -inline void format_decimal(char *&buffer, T value) -{ +inline void format_decimal(char *&buffer, T value) { typename internal::IntTraits::MainType abs_value = value; - if (internal::is_negative(value)) - { + if (internal::is_negative(value)) { *buffer++ = '-'; abs_value = 0 - abs_value; } - if (abs_value < 100) - { - if (abs_value < 10) - { + if (abs_value < 100) { + if (abs_value < 10) { *buffer++ = static_cast('0' + abs_value); return; } unsigned index = static_cast(abs_value * 2); - *buffer++ = internal::DIGITS[index]; - *buffer++ = internal::DIGITS[index + 1]; + *buffer++ = internal::Data::DIGITS[index]; + *buffer++ = internal::Data::DIGITS[index + 1]; return; } unsigned num_digits = internal::count_digits(abs_value); @@ -2835,8 +2571,7 @@ fmt::print(format, args...); #define FMT_VARIADIC_W(ReturnType, func, ...) \ FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) -namespace fmt -{ +namespace fmt { FMT_VARIADIC(std::string, format, StringRef) FMT_VARIADIC_W(std::wstring, format, WStringRef) FMT_VARIADIC(void, print, StringRef) @@ -2855,6 +2590,6 @@ FMT_VARIADIC(int, fprintf, std::FILE *, StringRef) #define FMT_HEADER_ONLY # include "format.cc" -#undef FMT_HEADER_ONLY -#endif // FMT_FORMAT_H_ + +#endif // FMT_FORMAT_H_ \ No newline at end of file diff --git a/include/spdlog/details/line_logger.h b/include/spdlog/details/line_logger.h index d3919b67..65251e50 100644 --- a/include/spdlog/details/line_logger.h +++ b/include/spdlog/details/line_logger.h @@ -79,6 +79,12 @@ public: } } + template + void write(const std::string& fmt, const Args&... args) + { + _log_msg.raw.write(fmt, args...); + } + template line_logger& operator<<(const T& what) { @@ -86,6 +92,7 @@ public: return *this; } + void disable() { _enabled = false; diff --git a/include/spdlog/details/logger_impl.h b/include/spdlog/details/logger_impl.h index ccf1886e..d11c8164 100644 --- a/include/spdlog/details/logger_impl.h +++ b/include/spdlog/details/logger_impl.h @@ -66,73 +66,73 @@ inline void spdlog::logger::set_pattern(const std::string& pattern) template -inline spdlog::details::line_logger spdlog::logger::log(level::level_enum lvl, const Args&... args) +inline spdlog::details::line_logger spdlog::logger::log(level::level_enum lvl, const std::string& fmt, const Args&... args) { bool msg_enabled = should_log(lvl); details::line_logger l(this, lvl, msg_enabled); if (msg_enabled) - _variadic_log(l, args...); + l.write(fmt, args...); return l; } template -inline spdlog::details::line_logger spdlog::logger::log(const Args&... args) +inline spdlog::details::line_logger spdlog::logger::log(const std::string& fmt, const Args&... args) { - return log(level::ALWAYS, args...); + return log(level::ALWAYS, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::trace(const Args&... args) +inline spdlog::details::line_logger spdlog::logger::trace(const std::string& fmt, const Args&... args) { - return log(level::TRACE, args...); + return log(level::TRACE, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::debug(const Args&... args) +inline spdlog::details::line_logger spdlog::logger::debug(const std::string& fmt, const Args&... args) { - return log(level::DEBUG, args...); + return log(level::DEBUG, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::info(const Args&... args) +inline spdlog::details::line_logger spdlog::logger::info(const std::string& fmt, const Args&... args) { - return log(level::INFO, args...); + return log(level::INFO, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::notice(const Args&... args) +inline spdlog::details::line_logger spdlog::logger::notice(const std::string& fmt, const Args&... args) { - return log(level::NOTICE, args...); + return log(level::NOTICE, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::warn(const Args&... args) +inline spdlog::details::line_logger spdlog::logger::warn(const std::string& fmt, const Args&... args) { - return log(level::WARN, args...); + return log(level::WARN, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::error(const Args&... args) +inline spdlog::details::line_logger spdlog::logger::error(const std::string& fmt, const Args&... args) { - return log(level::ERR, args...); + return log(level::ERR, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::critical(const Args&... args) +inline spdlog::details::line_logger spdlog::logger::critical(const std::string& fmt, const Args&... args) { - return log(level::CRITICAL, args...); + return log(level::CRITICAL, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::alert(const Args&... args) +inline spdlog::details::line_logger spdlog::logger::alert(const std::string& fmt, const Args&... args) { - return log(level::ALERT, args...); + return log(level::ALERT, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::emerg(const Args&... args) +inline spdlog::details::line_logger spdlog::logger::emerg(const std::string& fmt, const Args&... args) { - return log(level::EMERG, args...); + return log(level::EMERG, fmt, args...); } inline const std::string& spdlog::logger::name() const @@ -182,24 +182,7 @@ inline void spdlog::logger::_stop() set_level(level::OFF); } -/* private functions */ -inline void spdlog::logger::_variadic_log(spdlog::details::line_logger&) {} - -template -inline void spdlog::logger::_variadic_log(spdlog::details::line_logger& l, const Last& last) -{ - l.write(last); -} -template -inline void spdlog::logger::_variadic_log(spdlog::details::line_logger& l, const First& first, const Rest&... rest) -{ - l.write(first); - l.write(' '); - _variadic_log(l, rest...); -} - - diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index d52f1665..fbe5086c 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -34,7 +34,6 @@ #include #include #include "sinks/base_sink.h" -#include "sinks/async_sink.h" #include "common.h" namespace spdlog @@ -66,17 +65,17 @@ public: //Stop logging void stop(); - template details::line_logger log(level::level_enum lvl, const Args&... args); - template details::line_logger log(const Args&... args); - template details::line_logger trace(const Args&... args); - template details::line_logger debug(const Args&... args); - template details::line_logger info(const Args&... args); - template details::line_logger notice(const Args&... args); - template details::line_logger warn(const Args&... args); - template details::line_logger error(const Args&... args); - template details::line_logger critical(const Args&... args); - template details::line_logger alert(const Args&... args); - template details::line_logger emerg(const Args&... args); + template details::line_logger log(level::level_enum lvl, const std::string& fmt, const Args&... args); + template details::line_logger log(const std::string& fmt, const Args&... args); + template details::line_logger trace(const std::string& fmt, const Args&... args); + template details::line_logger debug(const std::string& fmt, const Args&... args); + template details::line_logger info(const std::string& fmt, const Args&... args); + template details::line_logger notice(const std::string& fmt, const Args&... args); + template details::line_logger warn(const std::string& fmt, const Args&... args); + template details::line_logger error(const std::string& fmt, const Args&... args); + template details::line_logger critical(const std::string& fmt, const Args&... args); + template details::line_logger alert(const std::string& fmt, const Args&... args); + template details::line_logger emerg(const std::string& fmt, const Args&... args); void set_pattern(const std::string&); @@ -96,13 +95,6 @@ protected: formatter_ptr _formatter; std::atomic_int _level; -private: - void _variadic_log(details::line_logger& l); - template - inline void _variadic_log(spdlog::details::line_logger& l, const Last& last); - template - void _variadic_log(details::line_logger&l, const First& first, const Rest&... rest); - }; } From b5a5edacbe64b30a4414d10988fbf2b46f0abc81 Mon Sep 17 00:00:00 2001 From: xaqq Date: Mon, 1 Dec 2014 15:51:57 +0100 Subject: [PATCH 012/120] Add a drop() method to remove logger from the registry This commits allows the user to drop the registry reference to a logger, allowing deletion of logger at any time. --- include/spdlog/details/registry.h | 5 +++++ include/spdlog/details/spdlog_impl.h | 4 ++++ include/spdlog/spdlog.h | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h index 9cf14352..104ac18f 100644 --- a/include/spdlog/details/registry.h +++ b/include/spdlog/details/registry.h @@ -72,6 +72,11 @@ public: return new_logger; } + void drop(const std::string &logger_name) + { + std::lock_guard lock(_mutex); + _loggers.erase(logger_name); + } std::shared_ptr create(const std::string& logger_name, sinks_init_list sinks) { diff --git a/include/spdlog/details/spdlog_impl.h b/include/spdlog/details/spdlog_impl.h index 140b66a0..a3a76111 100644 --- a/include/spdlog/details/spdlog_impl.h +++ b/include/spdlog/details/spdlog_impl.h @@ -37,6 +37,10 @@ inline std::shared_ptr spdlog::get(const std::string& name) return details::registry::instance().get(name); } +inline void spdlog::drop(const std::string &name) +{ + details::registry::instance().drop(name); +} // Create multi/single threaded rotating file logger inline std::shared_ptr spdlog::rotating_logger_mt(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool auto_flush) diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h index c153b93f..6db7ca3d 100644 --- a/include/spdlog/spdlog.h +++ b/include/spdlog/spdlog.h @@ -42,6 +42,10 @@ namespace spdlog // logger.info() << "This is another message" << x << y << z; std::shared_ptr get(const std::string& name); +// +// Drop the reference to this logger. +// +void drop(const std::string &name); // // Set global formatting From c5afdbddcf97802892f638aa0b2d8c1c6aad9dbc Mon Sep 17 00:00:00 2001 From: gabi Date: Mon, 1 Dec 2014 18:25:42 +0200 Subject: [PATCH 013/120] Use fmt::pad for faster formatting of the default format pattern --- .../spdlog/details/pattern_formatter_impl.h | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index aa0c4e8d..786a6e69 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -371,18 +371,32 @@ class full_formatter :public flag_formatter { auto duration = msg.time.time_since_epoch(); auto millis = std::chrono::duration_cast(duration).count() % 1000; - msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] ", - msg.tm_time.tm_year + 1900, - msg.tm_time.tm_mon + 1, - msg.tm_time.tm_mday, - msg.tm_time.tm_hour, - msg.tm_time.tm_min, - msg.tm_time.tm_sec, - static_cast(millis), - msg.logger_name, - level::to_str(msg.level)); - msg.formatted.write(msg.raw.str()); + + /* Slower version(while still very fast - about 3.2 million lines/sec), + msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ", + msg.tm_time.tm_year + 1900, + msg.tm_time.tm_mon + 1, + msg.tm_time.tm_mday, + msg.tm_time.tm_hour, + msg.tm_time.tm_min, + msg.tm_time.tm_sec, + static_cast(millis), + msg.logger_name, + level::to_str(msg.level), + msg.raw.str());*/ + + // Faster (albeit uglier) way to format the line (5.6 million lines/sec) + msg.formatted << '[' << msg.tm_time.tm_year + 1900 << '-' + << fmt::pad(msg.tm_time.tm_mon + 1, 2, '0') << '-' + << fmt::pad(msg.tm_time.tm_mday, 2, '0') << ' ' + << fmt::pad(msg.tm_time.tm_hour, 2, '0') << ':' + << fmt::pad(msg.tm_time.tm_min, 2, '0') << ':' + << fmt::pad(msg.tm_time.tm_sec, 2, '0') << '.' + << fmt::pad(static_cast(millis), 3, '0') << "] "; + + msg.formatted << '[' << msg.logger_name << "] [" << level::to_str(msg.level) << "] "; + msg.formatted.write(msg.raw.data(), msg.raw.size()); } }; @@ -429,7 +443,7 @@ inline void spdlog::pattern_formatter::handle_flag(char flag) { switch (flag) { - // logger name + // logger name case 'n': _formatters.push_back(std::unique_ptr(new details::name_formatter())); break; From b0926326bb94bc83ae59b7c427f00e085a2bf2bd Mon Sep 17 00:00:00 2001 From: gabi Date: Mon, 1 Dec 2014 20:17:47 +0200 Subject: [PATCH 014/120] pattern_formatter_impl.h update --- .../spdlog/details/pattern_formatter_impl.h | 109 ++++++++++-------- 1 file changed, 63 insertions(+), 46 deletions(-) diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index 786a6e69..704f8931 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -30,6 +30,7 @@ #include #include + #include "../formatter.h" #include "./log_msg.h" #include "./os.h" @@ -122,19 +123,31 @@ class B_formatter :public flag_formatter } }; + +//write 2 ints seperated by sep with padding of 2 +static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, char sep) +{ + w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0'); + return w; +} + +//write 3 ints seperated by sep with padding of 2 +static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, int v3, char sep) +{ + w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0') << sep << fmt::pad(v3, 2, '0'); + return w; +} + + + + //Date and time representation (Thu Aug 23 15:35:46 2014) class c_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write("{} {} {:02d} {:02d}:{:02d}:{:02d} {:04d}", - days[msg.tm_time.tm_wday], - months[msg.tm_time.tm_mon], - msg.tm_time.tm_mday, - msg.tm_time.tm_hour, - msg.tm_time.tm_min, - msg.tm_time.tm_sec, - msg.tm_time.tm_year + 1900); + msg.formatted << days[msg.tm_time.tm_wday] << ' ' << months[msg.tm_time.tm_mon] << ' ' << msg.tm_time.tm_mday << ' '; + pad_n_join(msg.formatted, msg.tm_time.tm_hour, msg.tm_time.tm_min, msg.tm_time.tm_sec, ':') << ' ' << msg.tm_time.tm_year + 1900; } }; @@ -144,7 +157,7 @@ class C_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write("{02:d}", msg.tm_time.tm_year % 100); + msg.formatted << fmt::pad(msg.tm_time.tm_year % 100, 2, '0'); } }; @@ -155,7 +168,7 @@ class D_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write("{:02d}/{:02d}/{:02d}", msg.tm_time.tm_mon + 1, msg.tm_time.tm_mday, msg.tm_time.tm_year % 100); + pad_n_join(msg.formatted, msg.tm_time.tm_mon + 1, msg.tm_time.tm_mday, msg.tm_time.tm_year % 100, '/'); } }; @@ -165,7 +178,7 @@ class Y_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write("{:04d}", msg.tm_time.tm_year + 1900); + msg.formatted << msg.tm_time.tm_year + 1900; } }; @@ -174,7 +187,7 @@ class m_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write("{:02d}", msg.tm_time.tm_mon + 1); + msg.formatted << fmt::pad(msg.tm_time.tm_mon + 1, 2, '0'); } }; @@ -183,7 +196,7 @@ class d_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write("{:02d}", msg.tm_time.tm_mday); + msg.formatted << fmt::pad(msg.tm_time.tm_mday, 2, '0'); } }; @@ -192,7 +205,7 @@ class H_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write("{:02d}", msg.tm_time.tm_hour); + msg.formatted << fmt::pad(msg.tm_time.tm_hour, 2, '0'); } }; @@ -201,7 +214,7 @@ class I_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write("{:02d}", to12h(msg.tm_time)); + msg.formatted << fmt::pad(to12h(msg.tm_time), 2, '0'); } }; @@ -210,7 +223,7 @@ class M_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write("{:02d}", msg.tm_time.tm_min); + msg.formatted << fmt::pad(msg.tm_time.tm_min, 2, '0'); } }; @@ -219,7 +232,7 @@ class S_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write("{:02d}", msg.tm_time.tm_sec); + msg.formatted << fmt::pad(msg.tm_time.tm_sec, 2, '0'); } }; @@ -230,7 +243,7 @@ class e_formatter :public flag_formatter { auto duration = msg.time.time_since_epoch(); auto millis = std::chrono::duration_cast(duration).count() % 1000; - msg.formatted.write("{:03d}", static_cast(millis)); + msg.formatted << fmt::pad(static_cast(millis), 3, '0'); } }; @@ -249,7 +262,7 @@ class r_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write("{:02d}:{:02d}:{:02d} {}", to12h(msg.tm_time), msg.tm_time.tm_min, msg.tm_time.tm_sec, ampm(msg.tm_time)); + pad_n_join(msg.formatted, to12h(msg.tm_time), msg.tm_time.tm_min, msg.tm_time.tm_sec, ':') << ' ' << ampm(msg.tm_time); } }; @@ -258,8 +271,7 @@ class R_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write("{:02d}:{:02d}", msg.tm_time.tm_hour, msg.tm_time.tm_min); - + pad_n_join(msg.formatted, msg.tm_time.tm_hour, msg.tm_time.tm_min, ':'); } }; @@ -268,47 +280,53 @@ class T_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write("{:02d}:{:02d}:{:02d}", msg.tm_time.tm_hour, msg.tm_time.tm_min, msg.tm_time.tm_sec); + pad_n_join(msg.formatted, msg.tm_time.tm_hour, msg.tm_time.tm_min, msg.tm_time.tm_sec, ':'); } }; -// ISO 8601 offset from UTC in timezone (HH:MM) +// ISO 8601 offset from UTC in timezone (+-HH:MM) class z_formatter :public flag_formatter { public: - z_formatter() {} + const std::chrono::seconds cache_refresh = const std::chrono::seconds(5); + + z_formatter() :_last_update(std::chrono::seconds(0)) {} z_formatter(const z_formatter&) = delete; z_formatter& operator=(const z_formatter&) = delete; void format(log_msg& msg) override { - std::lock_guard l(_mutex); - using namespace std::chrono; - auto diff = msg.time - _last_update; - auto secs_diff = std::abs((duration_cast(diff)).count()); - if (secs_diff >= 2) - { - _value = get_value(msg); - _last_update = msg.time; - } - msg.formatted << _value; +#ifdef _WIN32 + int total_minutes = get_cached_offset(msg); +#else + // No need to chache under gcc, + // it is very fast (already stored in tm.tm_gmtoff) + int total_minutes = os::utc_minutes_offset(msg.tm_time); +#endif + + int h = total_minutes / 60; + int m = total_minutes % 60; + char sign = h >= 0 ? '+' : '-'; + msg.formatted << sign; + pad_n_join(msg.formatted, h, m, ':'); } private: log_clock::time_point _last_update; - std::string _value; + int _offset_minutes; std::mutex _mutex; - std::string get_value(const log_msg& msg) + int get_cached_offset(const log_msg& msg) { - int total_minutes = os::utc_minutes_offset(msg.tm_time); - int h = total_minutes / 60; - int m = total_minutes % 60; - fmt::MemoryWriter w; - w.write("{} {:02d}:{:02d}", h >= 0 ? '+' : '-', h, m); - return w.str(); + using namespace std::chrono; + std::lock_guard l(_mutex); + if (msg.time - _last_update >= cache_refresh) + { + _offset_minutes = os::utc_minutes_offset(msg.tm_time); + _last_update = msg.time; + } + return _offset_minutes; } - }; @@ -372,8 +390,7 @@ class full_formatter :public flag_formatter auto duration = msg.time.time_since_epoch(); auto millis = std::chrono::duration_cast(duration).count() % 1000; - - /* Slower version(while still very fast - about 3.2 million lines/sec), + /* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads), msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ", msg.tm_time.tm_year + 1900, msg.tm_time.tm_mon + 1, @@ -386,7 +403,7 @@ class full_formatter :public flag_formatter level::to_str(msg.level), msg.raw.str());*/ - // Faster (albeit uglier) way to format the line (5.6 million lines/sec) + // Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads) msg.formatted << '[' << msg.tm_time.tm_year + 1900 << '-' << fmt::pad(msg.tm_time.tm_mon + 1, 2, '0') << '-' << fmt::pad(msg.tm_time.tm_mday, 2, '0') << ' ' From a9dc2a970593a64dd6a370ce51eca37a7535800d Mon Sep 17 00:00:00 2001 From: gabi Date: Mon, 1 Dec 2014 22:02:21 +0200 Subject: [PATCH 015/120] typo --- include/spdlog/details/registry.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h index 104ac18f..ee6c7d95 100644 --- a/include/spdlog/details/registry.h +++ b/include/spdlog/details/registry.h @@ -72,7 +72,7 @@ public: return new_logger; } - void drop(const std::string &logger_name) + void drop(const std::string& logger_name) { std::lock_guard lock(_mutex); _loggers.erase(logger_name); From 58970bf1eaf5d065b2db0ebe248bc96c51a5b4ca Mon Sep 17 00:00:00 2001 From: gabi Date: Mon, 1 Dec 2014 22:25:31 +0200 Subject: [PATCH 016/120] Rethrow cppformat exceptions as spdlog_ex with description of the bad format string --- include/spdlog/details/logger_impl.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/spdlog/details/logger_impl.h b/include/spdlog/details/logger_impl.h index d11c8164..830136aa 100644 --- a/include/spdlog/details/logger_impl.h +++ b/include/spdlog/details/logger_impl.h @@ -71,7 +71,17 @@ inline spdlog::details::line_logger spdlog::logger::log(level::level_enum lvl, c bool msg_enabled = should_log(lvl); details::line_logger l(this, lvl, msg_enabled); if (msg_enabled) - l.write(fmt, args...); + { + try + { + l.write(fmt, args...); + } + catch(const fmt::FormatError& e) + { + throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what())); + } + + } return l; } From 26cf0b38ddf2bfc14ee55747efcfa588d5dcd705 Mon Sep 17 00:00:00 2001 From: gabi Date: Tue, 2 Dec 2014 00:14:38 +0200 Subject: [PATCH 017/120] support for API of the form logger.info() << .. --- include/spdlog/details/logger_impl.h | 95 ++++++++++++++++++++++++---- include/spdlog/logger.h | 18 +++++- 2 files changed, 98 insertions(+), 15 deletions(-) diff --git a/include/spdlog/details/logger_impl.h b/include/spdlog/details/logger_impl.h index 830136aa..62e8a6e5 100644 --- a/include/spdlog/details/logger_impl.h +++ b/include/spdlog/details/logger_impl.h @@ -63,10 +63,11 @@ inline void spdlog::logger::set_pattern(const std::string& pattern) _set_pattern(pattern); } - - +// +// cppformat API of the form logger.info("hello {} {}", "world", 1); +// template -inline spdlog::details::line_logger spdlog::logger::log(level::level_enum lvl, const std::string& fmt, const Args&... args) +inline spdlog::details::line_logger spdlog::logger::_log(level::level_enum lvl, const std::string& fmt, const Args&... args) { bool msg_enabled = should_log(lvl); details::line_logger l(this, lvl, msg_enabled); @@ -88,63 +89,131 @@ inline spdlog::details::line_logger spdlog::logger::log(level::level_enum lvl, c template inline spdlog::details::line_logger spdlog::logger::log(const std::string& fmt, const Args&... args) { - return log(level::ALWAYS, fmt, args...); + return _log(level::ALWAYS, fmt, args...); } template inline spdlog::details::line_logger spdlog::logger::trace(const std::string& fmt, const Args&... args) { - return log(level::TRACE, fmt, args...); + return _log(level::TRACE, fmt, args...); } template inline spdlog::details::line_logger spdlog::logger::debug(const std::string& fmt, const Args&... args) { - return log(level::DEBUG, fmt, args...); + return _log(level::DEBUG, fmt, args...); } template inline spdlog::details::line_logger spdlog::logger::info(const std::string& fmt, const Args&... args) { - return log(level::INFO, fmt, args...); + return _log(level::INFO, fmt, args...); } template inline spdlog::details::line_logger spdlog::logger::notice(const std::string& fmt, const Args&... args) { - return log(level::NOTICE, fmt, args...); + return _log(level::NOTICE, fmt, args...); } template inline spdlog::details::line_logger spdlog::logger::warn(const std::string& fmt, const Args&... args) { - return log(level::WARN, fmt, args...); + return _log(level::WARN, fmt, args...); } template inline spdlog::details::line_logger spdlog::logger::error(const std::string& fmt, const Args&... args) { - return log(level::ERR, fmt, args...); + return _log(level::ERR, fmt, args...); } template inline spdlog::details::line_logger spdlog::logger::critical(const std::string& fmt, const Args&... args) { - return log(level::CRITICAL, fmt, args...); + return _log(level::CRITICAL, fmt, args...); } template inline spdlog::details::line_logger spdlog::logger::alert(const std::string& fmt, const Args&... args) { - return log(level::ALERT, fmt, args...); + return _log(level::ALERT, fmt, args...); } template inline spdlog::details::line_logger spdlog::logger::emerg(const std::string& fmt, const Args&... args) { - return log(level::EMERG, fmt, args...); + return _log(level::EMERG, fmt, args...); } + +// +// //API to support logger.info() << ".." calls +// + + +inline spdlog::details::line_logger spdlog::logger::_log(level::level_enum lvl) +{ + bool msg_enabled = should_log(lvl); + details::line_logger l(this, lvl, msg_enabled); + return l; +} + +inline spdlog::details::line_logger spdlog::logger::log() +{ + return _log(level::ALWAYS); +} + +inline spdlog::details::line_logger spdlog::logger::trace() +{ + return _log(level::TRACE); +} + + +inline spdlog::details::line_logger spdlog::logger::debug() +{ + return _log(level::DEBUG); +} + +inline spdlog::details::line_logger spdlog::logger::info() +{ + return _log(level::INFO); +} + +inline spdlog::details::line_logger spdlog::logger::notice() +{ + return _log(level::NOTICE); +} + +inline spdlog::details::line_logger spdlog::logger::warn() +{ + return _log(level::WARN); +} + +inline spdlog::details::line_logger spdlog::logger::error() +{ + return _log(level::ERR); +} + +inline spdlog::details::line_logger spdlog::logger::critical() +{ + return _log(level::CRITICAL); +} + +inline spdlog::details::line_logger spdlog::logger::alert() +{ + return _log(level::ALERT); +} + +inline spdlog::details::line_logger spdlog::logger::emerg() +{ + return _log(level::EMERG); +} + + + +// + inline const std::string& spdlog::logger::name() const { return _name; diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index fbe5086c..cc7fb58b 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -65,7 +65,6 @@ public: //Stop logging void stop(); - template details::line_logger log(level::level_enum lvl, const std::string& fmt, const Args&... args); template details::line_logger log(const std::string& fmt, const Args&... args); template details::line_logger trace(const std::string& fmt, const Args&... args); template details::line_logger debug(const std::string& fmt, const Args&... args); @@ -77,16 +76,31 @@ public: template details::line_logger alert(const std::string& fmt, const Args&... args); template details::line_logger emerg(const std::string& fmt, const Args&... args); + //API to support logger.info() << ".." calls + + details::line_logger log(); + details::line_logger trace(); + details::line_logger debug(); + details::line_logger info(); + details::line_logger notice(); + details::line_logger warn(); + details::line_logger error(); + details::line_logger critical(); + details::line_logger alert(); + details::line_logger emerg(); + void set_pattern(const std::string&); void set_formatter(formatter_ptr); protected: - virtual void _log_msg(details::log_msg& msg); + virtual void _log_msg(details::log_msg&); virtual void _set_pattern(const std::string&); virtual void _set_formatter(formatter_ptr); virtual void _stop(); + details::line_logger _log(level::level_enum lvl); + template details::line_logger _log(level::level_enum lvl, const std::string& fmt, const Args&... args); friend details::line_logger; From 2278e9230fc20a78edeab91403a3a414793ab675 Mon Sep 17 00:00:00 2001 From: gabime Date: Tue, 2 Dec 2014 00:18:44 +0200 Subject: [PATCH 018/120] some fixes for gcc --- example/bench.cpp | 2 +- include/spdlog/details/pattern_formatter_impl.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/bench.cpp b/example/bench.cpp index 70d2ef9d..f7e51204 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -113,7 +113,7 @@ void bench(int howmany, std::shared_ptr log) auto start = system_clock::now(); for (auto i = 0; i < howmany; ++i) { - log->info("Hello logger: msg number ", i); + log->info("Hello logger: msg number {}", i); } diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index 704f8931..e7561608 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -289,7 +289,7 @@ class T_formatter :public flag_formatter class z_formatter :public flag_formatter { public: - const std::chrono::seconds cache_refresh = const std::chrono::seconds(5); + const std::chrono::seconds cache_refresh = std::chrono::seconds(5); z_formatter() :_last_update(std::chrono::seconds(0)) {} z_formatter(const z_formatter&) = delete; From f41d989bf07b5bc2f6a1c127eb07c5f77895e7f8 Mon Sep 17 00:00:00 2001 From: gabime Date: Tue, 2 Dec 2014 02:15:42 +0200 Subject: [PATCH 019/120] fix in move log_msg --- include/spdlog/details/log_msg.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/spdlog/details/log_msg.h b/include/spdlog/details/log_msg.h index b9038cda..30ff129b 100644 --- a/include/spdlog/details/log_msg.h +++ b/include/spdlog/details/log_msg.h @@ -48,9 +48,7 @@ struct log_msg level(other.level), time(other.time), tm_time(other.tm_time) - - { - //fmt::MemoryWriter does not allow copy ctor} + { raw.write(other.raw.data(), other.raw.size()); formatted.write(other.formatted.data(), other.formatted.size()); } @@ -63,6 +61,7 @@ struct log_msg raw(std::move(other.raw)), formatted(std::move(other.formatted)) { + other.clear(); } log_msg& operator=(log_msg&& other) @@ -76,6 +75,7 @@ struct log_msg tm_time = other.tm_time; raw = std::move(other.raw); formatted = std::move(other.formatted); + other.clear(); return *this; } @@ -83,6 +83,7 @@ struct log_msg void clear() { + level = level::OFF; raw.clear(); formatted.clear(); } From 7a9781a94cb1ab5878fa1a0e91e58f8c28d75134 Mon Sep 17 00:00:00 2001 From: gabime Date: Tue, 2 Dec 2014 02:16:09 +0200 Subject: [PATCH 020/120] throw spdlog_err on format errors --- include/spdlog/details/pattern_formatter_impl.h | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index e7561608..6a0c4ee9 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -460,7 +460,7 @@ inline void spdlog::pattern_formatter::handle_flag(char flag) { switch (flag) { - // logger name + // logger name case 'n': _formatters.push_back(std::unique_ptr(new details::name_formatter())); break; @@ -574,10 +574,17 @@ inline void spdlog::pattern_formatter::handle_flag(char flag) inline void spdlog::pattern_formatter::format(details::log_msg& msg) { - for (auto &f : _formatters) + try { - f->format(msg); + for (auto &f : _formatters) + { + f->format(msg); + } + //write eol + msg.formatted.write(details::os::eol(), details::os::eol_size()); + } + catch(const fmt::FormatError& e) + { + throw spdlog_ex(fmt::format("formatting error while processing format string: {}", e.what())); } - //write eol - msg.formatted.write(details::os::eol(), details::os::eol_size()); } From 0db417f9afbe42084d1404086f1b087a0658f47d Mon Sep 17 00:00:00 2001 From: gabime Date: Tue, 2 Dec 2014 02:16:56 +0200 Subject: [PATCH 021/120] merged drop() from master --- include/spdlog/details/registry.h | 5 +++++ include/spdlog/details/spdlog_impl.h | 4 ++++ include/spdlog/spdlog.h | 4 ++++ 3 files changed, 13 insertions(+) diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h index 9cf14352..ee6c7d95 100644 --- a/include/spdlog/details/registry.h +++ b/include/spdlog/details/registry.h @@ -72,6 +72,11 @@ public: return new_logger; } + void drop(const std::string& logger_name) + { + std::lock_guard lock(_mutex); + _loggers.erase(logger_name); + } std::shared_ptr create(const std::string& logger_name, sinks_init_list sinks) { diff --git a/include/spdlog/details/spdlog_impl.h b/include/spdlog/details/spdlog_impl.h index 140b66a0..a3a76111 100644 --- a/include/spdlog/details/spdlog_impl.h +++ b/include/spdlog/details/spdlog_impl.h @@ -37,6 +37,10 @@ inline std::shared_ptr spdlog::get(const std::string& name) return details::registry::instance().get(name); } +inline void spdlog::drop(const std::string &name) +{ + details::registry::instance().drop(name); +} // Create multi/single threaded rotating file logger inline std::shared_ptr spdlog::rotating_logger_mt(const std::string& logger_name, const std::string& filename, size_t max_file_size, size_t max_files, bool auto_flush) diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h index c153b93f..6db7ca3d 100644 --- a/include/spdlog/spdlog.h +++ b/include/spdlog/spdlog.h @@ -42,6 +42,10 @@ namespace spdlog // logger.info() << "This is another message" << x << y << z; std::shared_ptr get(const std::string& name); +// +// Drop the reference to this logger. +// +void drop(const std::string &name); // // Set global formatting From ed17c9a4a91617fd87256a858d4e926e220f0588 Mon Sep 17 00:00:00 2001 From: gabime Date: Tue, 2 Dec 2014 02:17:39 +0200 Subject: [PATCH 022/120] fixed async_sink to use move instead of unique_ptr --- include/spdlog/sinks/async_sink.h | 40 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/include/spdlog/sinks/async_sink.h b/include/spdlog/sinks/async_sink.h index fe87c10b..8cff37fa 100644 --- a/include/spdlog/sinks/async_sink.h +++ b/include/spdlog/sinks/async_sink.h @@ -41,6 +41,7 @@ #include "../details/blocking_queue.h" #include "../details/null_mutex.h" #include "../details/log_msg.h" +#include "../details/format.h" namespace spdlog @@ -52,7 +53,8 @@ namespace sinks class async_sink : public base_sink < details::null_mutex > //single worker thread so null_mutex { public: - using q_type = details::blocking_queue < std::unique_ptr > ; + + using q_type = details::blocking_queue < details::log_msg > ; explicit async_sink(const q_type::size_type max_queue_size); @@ -109,10 +111,10 @@ inline spdlog::sinks::async_sink::~async_sink() inline void spdlog::sinks::async_sink::_sink_it(const details::log_msg& msg) { _push_sentry(); - _q.push(std::unique_ptr(new details::log_msg(msg))); + _q.push(std::move(msg)); + } - inline void spdlog::sinks::async_sink::_thread_loop() { std::chrono::seconds pop_timeout { 1 }; @@ -124,22 +126,24 @@ inline void spdlog::sinks::async_sink::_thread_loop() { if (!_active) return; - _formatter->format(*msg); - for (auto &s : _sinks) + + try { - try - { - s->log(*msg); - } - catch (const std::exception& ex) - { - _last_backthread_ex = std::make_shared(ex.what()); - } - catch (...) - { - _last_backthread_ex = std::make_shared("Unknown exception"); - } + + _formatter->format(msg); + for (auto &s : _sinks) + s->log(msg); + } + catch (const std::exception& ex) + { + _last_backthread_ex = std::make_shared(ex.what()); + } + catch (...) + { + _last_backthread_ex = std::make_shared("Unknown exception"); + } + } } } @@ -178,7 +182,7 @@ inline void spdlog::sinks::async_sink::shutdown(const log_clock::duration& timeo _join(); } - +#include inline void spdlog::sinks::async_sink::_push_sentry() { if (_last_backthread_ex) From 5186aca67116cfb797188daa52884ef5e3776653 Mon Sep 17 00:00:00 2001 From: gabime Date: Tue, 2 Dec 2014 02:24:30 +0200 Subject: [PATCH 023/120] disabled formatcpp Wshadow warnings.. --- example/Makefile | 2 +- include/spdlog/details/format.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/example/Makefile b/example/Makefile index 63e3d025..4208786a 100644 --- a/example/Makefile +++ b/example/Makefile @@ -1,5 +1,5 @@ CXX = g++ -CXXFLAGS = -march=native -Wall -Wextra -pedantic -std=c++11 -pthread -Wl,--no-as-needed -I../include +CXXFLAGS = -march=native -Wall -Wshadow -Wextra -pedantic -std=c++11 -pthread -Wl,--no-as-needed -I../include CXX_RELEASE_FLAGS = -O3 -flto CXX_DEBUG_FLAGS= -g diff --git a/include/spdlog/details/format.h b/include/spdlog/details/format.h index 26f74e8c..baac9bec 100644 --- a/include/spdlog/details/format.h +++ b/include/spdlog/details/format.h @@ -51,6 +51,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // when using __extension__. # if FMT_GCC_VERSION >= 406 # pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wshadow" # pragma GCC diagnostic ignored "-Wlong-long" # endif #else @@ -2592,4 +2593,4 @@ FMT_VARIADIC(int, fprintf, std::FILE *, StringRef) # include "format.cc" -#endif // FMT_FORMAT_H_ \ No newline at end of file +#endif // FMT_FORMAT_H_ From 4462a3c4e3d449eae4628b2dce4306cec973cfca Mon Sep 17 00:00:00 2001 From: gabime Date: Tue, 2 Dec 2014 02:26:25 +0200 Subject: [PATCH 024/120] disabled formatcpp Wshadow warnings.. --- bench/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/Makefile b/bench/Makefile index 30781eea..4ffd5455 100644 --- a/bench/Makefile +++ b/bench/Makefile @@ -1,5 +1,5 @@ CXX = g++ -CXXFLAGS = -g -march=native -Wall -Wextra -pedantic -std=c++11 -pthread -Wl,--no-as-needed -I../include +CXXFLAGS = --march=native -Wall -Wshadow -Wextra -pedantic -std=c++11 -pthread -Wl,--no-as-needed -I../include CXX_RELEASE_FLAGS = -O3 -flto From b0a687c1486d4423e45315e45f1e95bb129ea313 Mon Sep 17 00:00:00 2001 From: gabime Date: Tue, 2 Dec 2014 02:27:11 +0200 Subject: [PATCH 025/120] astyle --- include/spdlog/details/format.h | 820 ++++++++++++++++++++---------- include/spdlog/details/log_msg.h | 8 +- include/spdlog/sinks/async_sink.h | 6 +- 3 files changed, 553 insertions(+), 281 deletions(-) diff --git a/include/spdlog/details/format.h b/include/spdlog/details/format.h index baac9bec..a9b51c21 100644 --- a/include/spdlog/details/format.h +++ b/include/spdlog/details/format.h @@ -113,7 +113,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. TypeName(const TypeName&); \ void operator=(const TypeName&) -namespace fmt { +namespace fmt +{ // Fix the warning about long long on older versions of GCC // that don't support the diagnostic pragma. @@ -162,7 +163,8 @@ format(std::string("{}"), 42); \endrst */ template -class BasicStringRef { +class BasicStringRef +{ private: const Char *data_; std::size_t size_; @@ -189,28 +191,33 @@ public: /** Converts a string reference to an `std::string` object. */ - operator std::basic_string() const { + operator std::basic_string() const + { return std::basic_string(data_, size()); } /** Returns the pointer to a C string. */ - const Char *c_str() const { + const Char *c_str() const + { return data_; } /** Returns the string size. */ - std::size_t size() const { + std::size_t size() const + { return size_; } - friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { + friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) + { return lhs.data_ == rhs.data_; } - friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { + friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) + { return lhs.data_ != rhs.data_; } }; @@ -221,13 +228,15 @@ typedef BasicStringRef WStringRef; /** A formatting error such as invalid format string. */ -class FormatError : public std::runtime_error { +class FormatError : public std::runtime_error +{ public: explicit FormatError(StringRef message) : std::runtime_error(message.c_str()) {} }; -namespace internal { +namespace internal +{ // The number of characters to store in the MemoryBuffer object itself // to avoid dynamic memory allocation. @@ -236,19 +245,22 @@ enum { INLINE_BUFFER_SIZE = 500 }; #if _SECURE_SCL // Use checked iterator to avoid warnings on MSVC. template -inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { +inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) +{ return stdext::checked_array_iterator(ptr, size); } #else template -inline T *make_ptr(T *ptr, std::size_t) { +inline T *make_ptr(T *ptr, std::size_t) +{ return ptr; } #endif // A buffer for POD types. It supports a subset of std::vector's operations. template -class Buffer { +class Buffer +{ private: FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); @@ -266,33 +278,39 @@ public: virtual ~Buffer() {} // Returns the size of this buffer. - std::size_t size() const { + std::size_t size() const + { return size_; } // Returns the capacity of this buffer. - std::size_t capacity() const { + std::size_t capacity() const + { return capacity_; } // Resizes the buffer. If T is a POD type new elements are not initialized. - void resize(std::size_t new_size) { + void resize(std::size_t new_size) + { if (new_size > capacity_) grow(new_size); size_ = new_size; } // Reserves space to store at least capacity elements. - void reserve(std::size_t capacity) { + void reserve(std::size_t capacity) + { if (capacity > capacity_) grow(capacity); } - void clear() FMT_NOEXCEPT(true) { + void clear() FMT_NOEXCEPT(true) + { size_ = 0; } - void push_back(const T &value) { + void push_back(const T &value) + { if (size_ == capacity_) grow(size_ + 1); ptr_[size_++] = value; @@ -301,16 +319,19 @@ public: // Appends data to the end of the buffer. void append(const T *begin, const T *end); - T &operator[](std::size_t index) { + T &operator[](std::size_t index) + { return ptr_[index]; } - const T &operator[](std::size_t index) const { + const T &operator[](std::size_t index) const + { return ptr_[index]; } }; template -void Buffer::append(const T *begin, const T *end) { +void Buffer::append(const T *begin, const T *end) +{ std::ptrdiff_t num_elements = end - begin; if (size_ + num_elements > capacity_) grow(size_ + num_elements); @@ -321,12 +342,14 @@ void Buffer::append(const T *begin, const T *end) { // A memory buffer for POD types with the first SIZE elements stored in // the object itself. template > -class MemoryBuffer : private Allocator, public Buffer { +class MemoryBuffer : private Allocator, public Buffer +{ private: T data_[SIZE]; // Free memory allocated by the buffer. - void free() { + void free() + { if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_); } @@ -336,24 +359,28 @@ protected: public: explicit MemoryBuffer(const Allocator &alloc = Allocator()) : Allocator(alloc), Buffer(data_, SIZE) {} - ~MemoryBuffer() { + ~MemoryBuffer() + { free(); } #if FMT_USE_RVALUE_REFERENCES private: // Move data from other to this buffer. - void move(MemoryBuffer &other) { + void move(MemoryBuffer &other) + { Allocator &this_alloc = *this, &other_alloc = other; this_alloc = std::move(other_alloc); this->size_ = other.size_; this->capacity_ = other.capacity_; - if (other.ptr_ == other.data_) { + if (other.ptr_ == other.data_) + { this->ptr_ = data_; std::copy(other.data_, other.data_ + this->size_, make_ptr(data_, this->capacity_)); } - else { + else + { this->ptr_ = other.ptr_; // Set pointer to the inline array so that delete is not called // when freeing. @@ -362,11 +389,13 @@ private: } public: - MemoryBuffer(MemoryBuffer &&other) { + MemoryBuffer(MemoryBuffer &&other) + { move(other); } - MemoryBuffer &operator=(MemoryBuffer &&other) { + MemoryBuffer &operator=(MemoryBuffer &&other) + { assert(this != &other); free(); move(other); @@ -375,13 +404,15 @@ public: #endif // Returns a copy of the allocator associated with this buffer. - Allocator get_allocator() const { + Allocator get_allocator() const + { return *this; } }; template -void MemoryBuffer::grow(std::size_t size) { +void MemoryBuffer::grow(std::size_t size) +{ std::size_t new_capacity = (std::max)(size, this->capacity_ + this->capacity_ / 2); T *new_ptr = this->allocate(new_capacity); @@ -401,7 +432,8 @@ void MemoryBuffer::grow(std::size_t size) { #ifndef _MSC_VER // Portable version of signbit. -inline int getsign(double x) { +inline int getsign(double x) +{ // When compiled in C++11 mode signbit is no longer a macro but a function // defined in namespace std and the macro is undefined. # ifdef signbit @@ -413,22 +445,27 @@ inline int getsign(double x) { // Portable version of isinf. # ifdef isinf -inline int isinfinity(double x) { +inline int isinfinity(double x) +{ return isinf(x); } -inline int isinfinity(long double x) { +inline int isinfinity(long double x) +{ return isinf(x); } # else -inline int isinfinity(double x) { +inline int isinfinity(double x) +{ return std::isinf(x); } -inline int isinfinity(long double x) { +inline int isinfinity(long double x) +{ return std::isinf(x); } # endif #else -inline int getsign(double value) { +inline int getsign(double value) +{ if (value < 0) return 1; if (value == value) return 0; int dec = 0, sign = 0; @@ -436,23 +473,27 @@ inline int getsign(double value) { _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign); return sign; } -inline int isinfinity(double x) { +inline int isinfinity(double x) +{ return !_finite(x); } #endif template -struct IsLongDouble { +struct IsLongDouble +{ enum { VALUE = 0 }; }; template <> -struct IsLongDouble { +struct IsLongDouble +{ enum { VALUE = 1 }; }; template -class BasicCharTraits { +class BasicCharTraits +{ public: #if _SECURE_SCL typedef stdext::checked_array_iterator CharPtr; @@ -465,7 +506,8 @@ template class CharTraits; template <> -class CharTraits : public BasicCharTraits { +class CharTraits : public BasicCharTraits +{ private: // Conversion from wchar_t to char is not allowed. static char convert(wchar_t); @@ -473,7 +515,8 @@ private: public: typedef const wchar_t *UnsupportedStrType; - static char convert(char value) { + static char convert(char value) + { return value; } @@ -484,14 +527,17 @@ public: }; template <> -class CharTraits : public BasicCharTraits { +class CharTraits : public BasicCharTraits +{ public: typedef const char *UnsupportedStrType; - static wchar_t convert(char value) { + static wchar_t convert(char value) + { return value; } - static wchar_t convert(wchar_t value) { + static wchar_t convert(wchar_t value) + { return value; } @@ -502,17 +548,21 @@ public: // Checks if a number is negative - used to avoid warnings. template -struct SignChecker { +struct SignChecker +{ template - static bool is_negative(T value) { + static bool is_negative(T value) + { return value < 0; } }; template <> -struct SignChecker { +struct SignChecker +{ template - static bool is_negative(T) { + static bool is_negative(T) + { return false; } }; @@ -520,23 +570,27 @@ struct SignChecker { // Returns true if value is negative, false otherwise. // Same as (value < 0) but doesn't produce warnings if T is an unsigned type. template -inline bool is_negative(T value) { +inline bool is_negative(T value) +{ return SignChecker::is_signed>::is_negative(value); } // Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. template -struct TypeSelector { +struct TypeSelector +{ typedef uint32_t Type; }; template <> -struct TypeSelector { +struct TypeSelector +{ typedef uint64_t Type; }; template -struct IntTraits { +struct IntTraits +{ // Smallest of uint32_t and uint64_t that is large enough to represent // all values of T. typedef typename @@ -545,7 +599,8 @@ struct IntTraits { // MakeUnsigned::Type gives an unsigned type corresponding to integer type T. template -struct MakeUnsigned { +struct MakeUnsigned +{ typedef T Type; }; @@ -565,7 +620,8 @@ void report_unknown_type(char code, const char *type); // Static data is placed in this class template to allow header-only // configuration. template -struct BasicData { +struct BasicData +{ static const uint32_t POWERS_OF_10_32[]; static const uint64_t POWERS_OF_10_64[]; static const char DIGITS[]; @@ -576,7 +632,8 @@ typedef BasicData<> Data; #if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) // Returns the number of decimal digits in n. Leading zeros are not counted // except for n == 0 in which case count_digits returns 1. -inline unsigned count_digits(uint64_t n) { +inline unsigned count_digits(uint64_t n) +{ // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. unsigned t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12; @@ -584,16 +641,19 @@ inline unsigned count_digits(uint64_t n) { } # if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) // Optional version of count_digits for better performance on 32-bit platforms. -inline unsigned count_digits(uint32_t n) { +inline unsigned count_digits(uint32_t n) +{ uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12; return t - (n < Data::POWERS_OF_10_32[t]) + 1; } # endif #else // Fallback version of count_digits used when __builtin_clz is not available. -inline unsigned count_digits(uint64_t n) { +inline unsigned count_digits(uint64_t n) +{ unsigned count = 1; - for (;;) { + for (;;) + { // Integer division is slow so do it for a group of four digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. @@ -609,9 +669,11 @@ inline unsigned count_digits(uint64_t n) { // Formats a decimal unsigned integer value writing into buffer. template -inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { +inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) +{ --num_digits; - while (value >= 100) { + while (value >= 100) + { // Integer division is slow so do it for a group of two digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. @@ -621,7 +683,8 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { buffer[num_digits - 1] = Data::DIGITS[index]; num_digits -= 2; } - if (value < 10) { + if (value < 10) + { *buffer = static_cast('0' + value); return; } @@ -633,45 +696,55 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { #ifdef _WIN32 // A converter from UTF-8 to UTF-16. // It is only provided for Windows since other systems support UTF-8 natively. -class UTF8ToUTF16 { +class UTF8ToUTF16 +{ private: MemoryBuffer buffer_; public: explicit UTF8ToUTF16(StringRef s); - operator WStringRef() const { + operator WStringRef() const + { return WStringRef(&buffer_[0], size()); } - size_t size() const { + size_t size() const + { return buffer_.size() - 1; } - const wchar_t *c_str() const { + const wchar_t *c_str() const + { return &buffer_[0]; } - std::wstring str() const { + std::wstring str() const + { return std::wstring(&buffer_[0], size()); } }; // A converter from UTF-16 to UTF-8. // It is only provided for Windows since other systems support UTF-8 natively. -class UTF16ToUTF8 { +class UTF16ToUTF8 +{ private: MemoryBuffer buffer_; public: UTF16ToUTF8() {} explicit UTF16ToUTF8(WStringRef s); - operator StringRef() const { + operator StringRef() const + { return StringRef(&buffer_[0], size()); } - size_t size() const { + size_t size() const + { return buffer_.size() - 1; } - const char *c_str() const { + const char *c_str() const + { return &buffer_[0]; } - std::string str() const { + std::string str() const + { return std::string(&buffer_[0], size()); } @@ -693,20 +766,24 @@ void format_windows_error(fmt::Writer &out, int error_code, // Computes max(Arg, 1) at compile time. It is used to avoid errors about // allocating an array of 0 size. template -struct NonZero { +struct NonZero +{ enum { VALUE = Arg }; }; template <> -struct NonZero<0> { +struct NonZero<0> +{ enum { VALUE = 1 }; }; // The value of a formatting argument. It is a POD type to allow storage in // internal::MemoryBuffer. -struct Value { +struct Value +{ template - struct StringValue { + struct StringValue + { const Char *value; std::size_t size; }; @@ -714,12 +791,14 @@ struct Value { typedef void(*FormatFunc)( void *formatter, const void *arg, void *format_str_ptr); - struct CustomValue { + struct CustomValue + { const void *value; FormatFunc format; }; - union { + union + { int int_value; unsigned uint_value; LongLong long_long_value; @@ -735,8 +814,10 @@ struct Value { }; }; -struct Arg : Value { - enum Type { +struct Arg : Value +{ + enum Type + { NONE, // Integer types should go first, INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR, @@ -749,7 +830,8 @@ struct Arg : Value { // Makes a Value object from any type. template -class MakeValue : public Value { +class MakeValue : public Value +{ private: // The following two methods are private to disallow formatting of // arbitrary pointers. If you want to output a pointer cast it to @@ -761,12 +843,14 @@ private: template MakeValue(T *value); - void set_string(StringRef str) { + void set_string(StringRef str) + { string.value = str.c_str(); string.size = str.size(); } - void set_string(WStringRef str) { + void set_string(WStringRef str) + { CharTraits::convert(wchar_t()); wstring.value = str.c_str(); wstring.size = str.size(); @@ -775,7 +859,8 @@ private: // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( - void *formatter, const void *arg, void *format_str_ptr) { + void *formatter, const void *arg, void *format_str_ptr) + { format(*static_cast*>(formatter), *static_cast(format_str_ptr), *static_cast(arg)); @@ -794,7 +879,8 @@ public: FMT_MAKE_VALUE(int, int_value, INT) FMT_MAKE_VALUE(unsigned, uint_value, UINT) - MakeValue(long value) { + MakeValue(long value) + { // To minimize the number of types we need to deal with, long is // translated either to int or to long long depending on its size. if (sizeof(long) == sizeof(int)) @@ -802,17 +888,20 @@ public: else long_long_value = value; } - static uint64_t type(long) { + static uint64_t type(long) + { return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; } - MakeValue(unsigned long value) { + MakeValue(unsigned long value) + { if (sizeof(unsigned long) == sizeof(unsigned)) uint_value = static_cast(value); else ulong_long_value = value; } - static uint64_t type(unsigned long) { + static uint64_t type(unsigned long) + { return sizeof(unsigned long) == sizeof(unsigned) ? Arg::UINT : Arg::ULONG_LONG; } @@ -826,10 +915,12 @@ public: FMT_MAKE_VALUE(unsigned char, int_value, CHAR) FMT_MAKE_VALUE(char, int_value, CHAR) - MakeValue(wchar_t value) { + MakeValue(wchar_t value) + { int_value = internal::CharTraits::convert(value); } - static uint64_t type(wchar_t) { + static uint64_t type(wchar_t) + { return Arg::CHAR; } @@ -853,12 +944,14 @@ public: FMT_MAKE_VALUE(const void *, pointer, POINTER) template - MakeValue(const T &value) { + MakeValue(const T &value) + { custom.value = &value; custom.format = &format_custom_arg; } template - static uint64_t type(const T &) { + static uint64_t type(const T &) + { return Arg::CUSTOM; } }; @@ -886,61 +979,78 @@ public: // ArgVisitor uses the curiously recurring template pattern: // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern template -class ArgVisitor { +class ArgVisitor +{ public: - Result visit_unhandled_arg() { + Result visit_unhandled_arg() + { return Result(); } - Result visit_int(int value) { + Result visit_int(int value) + { return FMT_DISPATCH(visit_any_int(value)); } - Result visit_long_long(LongLong value) { + Result visit_long_long(LongLong value) + { return FMT_DISPATCH(visit_any_int(value)); } - Result visit_uint(unsigned value) { + Result visit_uint(unsigned value) + { return FMT_DISPATCH(visit_any_int(value)); } - Result visit_ulong_long(ULongLong value) { + Result visit_ulong_long(ULongLong value) + { return FMT_DISPATCH(visit_any_int(value)); } - Result visit_char(int value) { + Result visit_char(int value) + { return FMT_DISPATCH(visit_any_int(value)); } template - Result visit_any_int(T) { + Result visit_any_int(T) + { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_double(double value) { + Result visit_double(double value) + { return FMT_DISPATCH(visit_any_double(value)); } - Result visit_long_double(long double value) { + Result visit_long_double(long double value) + { return FMT_DISPATCH(visit_any_double(value)); } template - Result visit_any_double(T) { + Result visit_any_double(T) + { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_string(Arg::StringValue) { + Result visit_string(Arg::StringValue) + { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_wstring(Arg::StringValue) { + Result visit_wstring(Arg::StringValue) + { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_pointer(const void *) { + Result visit_pointer(const void *) + { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit_custom(Arg::CustomValue) { + Result visit_custom(Arg::CustomValue) + { return FMT_DISPATCH(visit_unhandled_arg()); } - Result visit(const Arg &arg) { - switch (arg.type) { + Result visit(const Arg &arg) + { + switch (arg.type) + { default: assert(false); - // Fall through. + // Fall through. case Arg::INT: return FMT_DISPATCH(visit_int(arg.int_value)); case Arg::UINT: @@ -955,7 +1065,8 @@ public: return FMT_DISPATCH(visit_long_double(arg.long_double_value)); case Arg::CHAR: return FMT_DISPATCH(visit_char(arg.int_value)); - case Arg::CSTRING: { + case Arg::CSTRING: + { Value::StringValue str = arg.string; str.size = 0; return FMT_DISPATCH(visit_string(str)); @@ -972,7 +1083,8 @@ public: } }; -class RuntimeError : public std::runtime_error { +class RuntimeError : public std::runtime_error +{ protected: RuntimeError() : std::runtime_error("") {} }; @@ -984,7 +1096,8 @@ class ArgFormatter; /** An argument list. */ -class ArgList { +class ArgList +{ private: uint64_t types_; const internal::Value *values_; @@ -1000,10 +1113,12 @@ public: /** Returns the argument at specified index. */ - internal::Arg operator[](unsigned index) const { + internal::Arg operator[](unsigned index) const + { using internal::Arg; Arg arg; - if (index >= MAX_ARGS) { + if (index >= MAX_ARGS) + { arg.type = Arg::NONE; return arg; } @@ -1012,7 +1127,8 @@ public: Arg::Type type = static_cast((types_ & (mask << shift)) >> shift); arg.type = type; - if (type != Arg::NONE) { + if (type != Arg::NONE) + { internal::Value &value = arg; value = values_[index]; } @@ -1022,9 +1138,11 @@ public: struct FormatSpec; -namespace internal { +namespace internal +{ -class FormatterBase { +class FormatterBase +{ private: ArgList args_; int next_arg_index_; @@ -1033,7 +1151,8 @@ private: Arg do_get_arg(unsigned arg_index, const char *&error); protected: - void set_args(const ArgList &args) { + void set_args(const ArgList &args) + { args_ = args; next_arg_index_ = 0; } @@ -1046,7 +1165,8 @@ protected: Arg get_arg(unsigned arg_index, const char *&error); template - void write(BasicWriter &w, const Char *start, const Char *end) { + void write(BasicWriter &w, const Char *start, const Char *end) + { if (start != end) w << BasicStringRef(start, end - start); } @@ -1054,7 +1174,8 @@ protected: // A printf formatter. template -class PrintfFormatter : private FormatterBase { +class PrintfFormatter : private FormatterBase +{ private: void parse_flags(FormatSpec &spec, const Char *&s); @@ -1074,7 +1195,8 @@ public: // A formatter. template -class BasicFormatter : private internal::FormatterBase { +class BasicFormatter : private internal::FormatterBase +{ private: BasicWriter &writer_; const Char *start_; @@ -1085,7 +1207,8 @@ private: public: explicit BasicFormatter(BasicWriter &w) : writer_(w) {} - BasicWriter &writer() { + BasicWriter &writer() + { return writer_; } @@ -1094,12 +1217,14 @@ public: const Char *format(const Char *&format_str, const internal::Arg &arg); }; -enum Alignment { +enum Alignment +{ ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC }; // Flags. -enum { +enum +{ SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8, CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. }; @@ -1109,29 +1234,37 @@ struct EmptySpec {}; // A type specifier. template -struct TypeSpec : EmptySpec { - Alignment align() const { +struct TypeSpec : EmptySpec +{ + Alignment align() const + { return ALIGN_DEFAULT; } - unsigned width() const { + unsigned width() const + { return 0; } - int precision() const { + int precision() const + { return -1; } - bool flag(unsigned) const { + bool flag(unsigned) const + { return false; } - char type() const { + char type() const + { return TYPE; } - char fill() const { + char fill() const + { return ' '; } }; // A width specifier. -struct WidthSpec { +struct WidthSpec +{ unsigned width_; // Fill is always wchar_t and cast to char if necessary to avoid having // two specialization of WidthSpec and its subclasses. @@ -1139,45 +1272,54 @@ struct WidthSpec { WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} - unsigned width() const { + unsigned width() const + { return width_; } - wchar_t fill() const { + wchar_t fill() const + { return fill_; } }; // An alignment specifier. -struct AlignSpec : WidthSpec { +struct AlignSpec : WidthSpec +{ Alignment align_; AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) : WidthSpec(width, fill), align_(align) {} - Alignment align() const { + Alignment align() const + { return align_; } - int precision() const { + int precision() const + { return -1; } }; // An alignment and type specifier. template -struct AlignTypeSpec : AlignSpec { +struct AlignTypeSpec : AlignSpec +{ AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} - bool flag(unsigned) const { + bool flag(unsigned) const + { return false; } - char type() const { + char type() const + { return TYPE; } }; // A full format specifier. -struct FormatSpec : AlignSpec { +struct FormatSpec : AlignSpec +{ unsigned flags_; int precision_; char type_; @@ -1186,20 +1328,24 @@ struct FormatSpec : AlignSpec { unsigned width = 0, char type = 0, wchar_t fill = ' ') : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} - bool flag(unsigned f) const { + bool flag(unsigned f) const + { return (flags_ & f) != 0; } - int precision() const { + int precision() const + { return precision_; } - char type() const { + char type() const + { return type_; } }; // An integer format specifier. template , typename Char = char> -class IntFormatSpec : public SpecT { +class IntFormatSpec : public SpecT +{ private: T value_; @@ -1207,14 +1353,16 @@ public: IntFormatSpec(T value, const SpecT &spec = SpecT()) : SpecT(spec), value_(value) {} - T value() const { + T value() const + { return value_; } }; // A string format specifier. template -class StrFormatSpec : public AlignSpec { +class StrFormatSpec : public AlignSpec +{ private: const T *str_; @@ -1222,7 +1370,8 @@ public: StrFormatSpec(const T *str, unsigned width, wchar_t fill) : AlignSpec(width, fill), str_(str) {} - const T *str() const { + const T *str() const + { return str_; } }; @@ -1337,12 +1486,14 @@ std::string s = str(MemoryWriter() << pad("abc", 8)); */ template inline StrFormatSpec pad( - const Char *str, unsigned width, Char fill = ' ') { + const Char *str, unsigned width, Char fill = ' ') +{ return StrFormatSpec(str, width, fill); } inline StrFormatSpec pad( - const wchar_t *str, unsigned width, char fill = ' ') { + const wchar_t *str, unsigned width, char fill = ' ') +{ return StrFormatSpec(str, width, fill); } @@ -1365,24 +1516,29 @@ inline StrFormatSpec pad( # define FMT_GEN14(f) FMT_GEN13(f), f(13) # define FMT_GEN15(f) FMT_GEN14(f), f(14) -namespace internal { -inline uint64_t make_type() { +namespace internal +{ +inline uint64_t make_type() +{ return 0; } template -inline uint64_t make_type(const T &arg) { +inline uint64_t make_type(const T &arg) +{ return MakeValue::type(arg); } #if FMT_USE_VARIADIC_TEMPLATES template -inline uint64_t make_type(const Arg &first, const Args & ... tail) { +inline uint64_t make_type(const Arg &first, const Args & ... tail) +{ return make_type(first) | (make_type(tail...) << 4); } #else -struct ArgType { +struct ArgType +{ uint64_t type; ArgType() : type(0) {} @@ -1393,7 +1549,8 @@ struct ArgType { # define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() -inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { +inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) +{ return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | @@ -1503,7 +1660,8 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { An error returned by an operating system or a language runtime, for example a file opening error. */ -class SystemError : public internal::RuntimeError { +class SystemError : public internal::RuntimeError +{ private: void init(int error_code, StringRef format_str, ArgList args); @@ -1524,12 +1682,14 @@ public: *error_code* is a system error code as given by ``errno``. \endrst */ - SystemError(int error_code, StringRef message) { + SystemError(int error_code, StringRef message) + { init(error_code, message, ArgList()); } FMT_VARIADIC_CTOR(SystemError, init, int, StringRef) - int error_code() const { + int error_code() const + { return error_code_; } }; @@ -1553,7 +1713,8 @@ You can use one of the following typedefs for common character types: \endrst */ template -class BasicWriter { +class BasicWriter +{ private: // Output buffer. internal::Buffer &buffer_; @@ -1564,11 +1725,13 @@ private: #if _SECURE_SCL // Returns pointer value. - static Char *get(CharPtr p) { + static Char *get(CharPtr p) + { return p.base(); } #else - static Char *get(Char *p) { + static Char *get(Char *p) + { return p; } #endif @@ -1580,7 +1743,8 @@ private: // Grows the buffer by n characters and returns a pointer to the newly // allocated area. - CharPtr grow_buffer(std::size_t n) { + CharPtr grow_buffer(std::size_t n) + { std::size_t size = buffer_.size(); buffer_.resize(size + n); return internal::make_ptr(&buffer_[size], n); @@ -1588,7 +1752,8 @@ private: // Prepare a buffer for integer formatting. CharPtr prepare_int_buffer(unsigned num_digits, - const EmptySpec &, const char *prefix, unsigned prefix_size) { + const EmptySpec &, const char *prefix, unsigned prefix_size) + { unsigned size = prefix_size + num_digits; CharPtr p = grow_buffer(size); std::copy(prefix, prefix + prefix_size, p); @@ -1640,7 +1805,8 @@ public: /** Returns the total number of characters written. */ - std::size_t size() const { + std::size_t size() const + { return buffer_.size(); } @@ -1648,7 +1814,8 @@ public: Returns a pointer to the output buffer content. No terminating null character is appended. */ - const Char *data() const FMT_NOEXCEPT(true) { + const Char *data() const FMT_NOEXCEPT(true) + { return &buffer_[0]; } @@ -1656,7 +1823,8 @@ public: Returns a pointer to the output buffer content with terminating null character appended. */ - const Char *c_str() const { + const Char *c_str() const + { std::size_t size = buffer_.size(); buffer_.reserve(size + 1); buffer_[size] = '\0'; @@ -1666,7 +1834,8 @@ public: /** Returns the content of the output buffer as an `std::string`. */ - std::basic_string str() const { + std::basic_string str() const + { return std::basic_string(&buffer_[0], buffer_.size()); } @@ -1695,35 +1864,43 @@ public: See also :ref:`syntax`. \endrst */ - void write(BasicStringRef format, ArgList args) { + void write(BasicStringRef format, ArgList args) + { BasicFormatter(*this).format(format, args); } FMT_VARIADIC_VOID(write, BasicStringRef) - BasicWriter &operator<<(int value) { + BasicWriter &operator<<(int value) + { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(unsigned value) { + BasicWriter &operator<<(unsigned value) + { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(long value) { + BasicWriter &operator<<(long value) + { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(unsigned long value) { + BasicWriter &operator<<(unsigned long value) + { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(LongLong value) { + BasicWriter &operator<<(LongLong value) + { return *this << IntFormatSpec(value); } /** Formats *value* and writes it to the stream. */ - BasicWriter &operator<<(ULongLong value) { + BasicWriter &operator<<(ULongLong value) + { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(double value) { + BasicWriter &operator<<(double value) + { write_double(value, FormatSpec()); return *this; } @@ -1732,7 +1909,8 @@ public: Formats *value* using the general format for floating-point numbers (``'g'``) and writes it to the stream. */ - BasicWriter &operator<<(long double value) { + BasicWriter &operator<<(long double value) + { write_double(value, FormatSpec()); return *this; } @@ -1740,12 +1918,14 @@ public: /** Writes a character to the stream. */ - BasicWriter &operator<<(char value) { + BasicWriter &operator<<(char value) + { buffer_.push_back(value); return *this; } - BasicWriter &operator<<(wchar_t value) { + BasicWriter &operator<<(wchar_t value) + { buffer_.push_back(internal::CharTraits::convert(value)); return *this; } @@ -1753,28 +1933,32 @@ public: /** Writes *value* to the stream. */ - BasicWriter &operator<<(fmt::BasicStringRef value) { + BasicWriter &operator<<(fmt::BasicStringRef value) + { const Char *str = value.c_str(); buffer_.append(str, str + value.size()); return *this; } template - BasicWriter &operator<<(IntFormatSpec spec) { + BasicWriter &operator<<(IntFormatSpec spec) + { internal::CharTraits::convert(FillChar()); write_int(spec.value(), spec); return *this; } template - BasicWriter &operator<<(const StrFormatSpec &spec) { + BasicWriter &operator<<(const StrFormatSpec &spec) + { const StrChar *s = spec.str(); // TODO: error if fill is not convertible to Char write_str(s, std::char_traits::length(s), spec); return *this; } - void clear() FMT_NOEXCEPT(true) { + void clear() FMT_NOEXCEPT(true) + { buffer_.clear(); } }; @@ -1782,23 +1966,29 @@ public: template template typename BasicWriter::CharPtr BasicWriter::write_str( - const StrChar *s, std::size_t size, const AlignSpec &spec) { + const StrChar *s, std::size_t size, const AlignSpec &spec) +{ CharPtr out = CharPtr(); - if (spec.width() > size) { + if (spec.width() > size) + { out = grow_buffer(spec.width()); Char fill = static_cast(spec.fill()); - if (spec.align() == ALIGN_RIGHT) { + if (spec.align() == ALIGN_RIGHT) + { std::fill_n(out, spec.width() - size, fill); out += spec.width() - size; } - else if (spec.align() == ALIGN_CENTER) { + else if (spec.align() == ALIGN_CENTER) + { out = fill_padding(out, spec.width(), size, fill); } - else { + else + { std::fill_n(out + size, spec.width() - size, fill); } } - else { + else + { out = grow_buffer(size); } std::copy(s, s + size, out); @@ -1809,7 +1999,8 @@ template typename BasicWriter::CharPtr BasicWriter::fill_padding( CharPtr buffer, unsigned total_size, - std::size_t content_size, wchar_t fill) { + std::size_t content_size, wchar_t fill) +{ std::size_t padding = total_size - content_size; std::size_t left_padding = padding / 2; Char fill_char = static_cast(fill); @@ -1825,11 +2016,13 @@ template typename BasicWriter::CharPtr BasicWriter::prepare_int_buffer( unsigned num_digits, const Spec &spec, - const char *prefix, unsigned prefix_size) { + const char *prefix, unsigned prefix_size) +{ unsigned width = spec.width(); Alignment align = spec.align(); Char fill = static_cast(spec.fill()); - if (spec.precision() > static_cast(num_digits)) { + if (spec.precision() > static_cast(num_digits)) + { // Octal prefix '0' is counted as a digit, so ignore it if precision // is specified. if (prefix_size > 0 && prefix[prefix_size - 1] == '0') @@ -1840,44 +2033,53 @@ BasicWriter::prepare_int_buffer( return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); buffer_.reserve(width); unsigned fill_size = width - number_size; - if (align != ALIGN_LEFT) { + if (align != ALIGN_LEFT) + { CharPtr p = grow_buffer(fill_size); std::fill(p, p + fill_size, fill); } CharPtr result = prepare_int_buffer( num_digits, subspec, prefix, prefix_size); - if (align == ALIGN_LEFT) { + if (align == ALIGN_LEFT) + { CharPtr p = grow_buffer(fill_size); std::fill(p, p + fill_size, fill); } return result; } unsigned size = prefix_size + num_digits; - if (width <= size) { + if (width <= size) + { CharPtr p = grow_buffer(size); std::copy(prefix, prefix + prefix_size, p); return p + size - 1; } CharPtr p = grow_buffer(width); CharPtr end = p + width; - if (align == ALIGN_LEFT) { + if (align == ALIGN_LEFT) + { std::copy(prefix, prefix + prefix_size, p); p += size; std::fill(p, end, fill); } - else if (align == ALIGN_CENTER) { + else if (align == ALIGN_CENTER) + { p = fill_padding(p, width, size, fill); std::copy(prefix, prefix + prefix_size, p); p += size; } - else { - if (align == ALIGN_NUMERIC) { - if (prefix_size != 0) { + else + { + if (align == ALIGN_NUMERIC) + { + if (prefix_size != 0) + { p = std::copy(prefix, prefix + prefix_size, p); size -= prefix_size; } } - else { + else + { std::copy(prefix, prefix + prefix_size, end - size); } std::fill(p, end - size, fill); @@ -1888,23 +2090,28 @@ BasicWriter::prepare_int_buffer( template template -void BasicWriter::write_int(T value, Spec spec) { +void BasicWriter::write_int(T value, Spec spec) +{ unsigned prefix_size = 0; typedef typename internal::IntTraits::MainType UnsignedType; UnsignedType abs_value = value; char prefix[4] = ""; - if (internal::is_negative(value)) { + if (internal::is_negative(value)) + { prefix[0] = '-'; ++prefix_size; abs_value = 0 - abs_value; } - else if (spec.flag(SIGN_FLAG)) { + else if (spec.flag(SIGN_FLAG)) + { prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; ++prefix_size; } - switch (spec.type()) { + switch (spec.type()) + { case 0: - case 'd': { + case 'd': + { unsigned num_digits = internal::count_digits(abs_value); CharPtr p = prepare_int_buffer( num_digits, spec, prefix, prefix_size) + 1 - num_digits; @@ -1912,57 +2119,74 @@ void BasicWriter::write_int(T value, Spec spec) { break; } case 'x': - case 'X': { + case 'X': + { UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { + if (spec.flag(HASH_FLAG)) + { prefix[prefix_size++] = '0'; prefix[prefix_size++] = spec.type(); } unsigned num_digits = 0; - do { + do + { ++num_digits; - } while ((n >>= 4) != 0); + } + while ((n >>= 4) != 0); Char *p = get(prepare_int_buffer( num_digits, spec, prefix, prefix_size)); n = abs_value; const char *digits = spec.type() == 'x' ? "0123456789abcdef" : "0123456789ABCDEF"; - do { + do + { *p-- = digits[n & 0xf]; - } while ((n >>= 4) != 0); + } + while ((n >>= 4) != 0); break; } case 'b': - case 'B': { + case 'B': + { UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { + if (spec.flag(HASH_FLAG)) + { prefix[prefix_size++] = '0'; prefix[prefix_size++] = spec.type(); } unsigned num_digits = 0; - do { + do + { ++num_digits; - } while ((n >>= 1) != 0); + } + while ((n >>= 1) != 0); Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); n = abs_value; - do { + do + { *p-- = '0' + (n & 1); - } while ((n >>= 1) != 0); + } + while ((n >>= 1) != 0); break; } - case 'o': { + case 'o': + { UnsignedType n = abs_value; if (spec.flag(HASH_FLAG)) prefix[prefix_size++] = '0'; unsigned num_digits = 0; - do { + do + { ++num_digits; - } while ((n >>= 3) != 0); + } + while ((n >>= 3) != 0); Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); n = abs_value; - do { + do + { *p-- = '0' + (n & 7); - } while ((n >>= 3) != 0); + } + while ((n >>= 3) != 0); break; } default: @@ -1975,11 +2199,13 @@ void BasicWriter::write_int(T value, Spec spec) { template template void BasicWriter::write_double( - T value, const FormatSpec &spec) { + T value, const FormatSpec &spec) +{ // Check type. char type = spec.type(); bool upper = false; - switch (type) { + switch (type) + { case 0: type = 'g'; break; @@ -1993,7 +2219,7 @@ void BasicWriter::write_double( // MSVC's printf doesn't support 'F'. type = 'f'; #endif - // Fall through. + // Fall through. case 'E': case 'G': case 'A': @@ -2007,20 +2233,24 @@ void BasicWriter::write_double( char sign = 0; // Use getsign instead of value < 0 because the latter is always // false for NaN. - if (internal::getsign(static_cast(value))) { + if (internal::getsign(static_cast(value))) + { sign = '-'; value = -value; } - else if (spec.flag(SIGN_FLAG)) { + else if (spec.flag(SIGN_FLAG)) + { sign = spec.flag(PLUS_FLAG) ? '+' : ' '; } - if (value != value) { + if (value != value) + { // Format NaN ourselves because sprintf's output is not consistent // across platforms. std::size_t size = 4; const char *nan = upper ? " NAN" : " nan"; - if (!sign) { + if (!sign) + { --size; ++nan; } @@ -2030,12 +2260,14 @@ void BasicWriter::write_double( return; } - if (internal::isinfinity(value)) { + if (internal::isinfinity(value)) + { // Format infinity ourselves because sprintf's output is not consistent // across platforms. std::size_t size = 4; const char *inf = upper ? " INF" : " inf"; - if (!sign) { + if (!sign) + { --size; ++inf; } @@ -2047,7 +2279,8 @@ void BasicWriter::write_double( std::size_t offset = buffer_.size(); unsigned width = spec.width(); - if (sign) { + if (sign) + { buffer_.reserve(buffer_.size() + (std::max)(width, 1u)); if (width > 0) --width; @@ -2062,16 +2295,19 @@ void BasicWriter::write_double( unsigned width_for_sprintf = width; if (spec.flag(HASH_FLAG)) *format_ptr++ = '#'; - if (spec.align() == ALIGN_CENTER) { + if (spec.align() == ALIGN_CENTER) + { width_for_sprintf = 0; } - else { + else + { if (spec.align() == ALIGN_LEFT) *format_ptr++ = '-'; if (width != 0) *format_ptr++ = '*'; } - if (spec.precision() >= 0) { + if (spec.precision() >= 0) + { *format_ptr++ = '.'; *format_ptr++ = '*'; } @@ -2082,13 +2318,15 @@ void BasicWriter::write_double( // Format using snprintf. Char fill = static_cast(spec.fill()); - for (;;) { + for (;;) + { std::size_t size = buffer_.capacity() - offset; #if _MSC_VER // MSVC's vsnprintf_s doesn't work with zero size, so reserve // space for at least one extra character to make the size non-zero. // Note that the buffer's capacity will increase by more than 1. - if (size == 0) { + if (size == 0) + { buffer_.reserve(offset + 1); size = buffer_.capacity() - offset; } @@ -2096,27 +2334,33 @@ void BasicWriter::write_double( Char *start = &buffer_[offset]; int n = internal::CharTraits::format_float( start, size, format, width_for_sprintf, spec.precision(), value); - if (n >= 0 && offset + n < buffer_.capacity()) { - if (sign) { + if (n >= 0 && offset + n < buffer_.capacity()) + { + if (sign) + { if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || - *start != ' ') { + *start != ' ') + { *(start - 1) = sign; sign = 0; } - else { + else + { *(start - 1) = fill; } ++n; } if (spec.align() == ALIGN_CENTER && - spec.width() > static_cast(n)) { + spec.width() > static_cast(n)) + { unsigned width = spec.width(); CharPtr p = grow_buffer(width); std::copy(p, p + n, p + (width - n) / 2); fill_padding(p, spec.width(), n, fill); return; } - if (spec.fill() != ' ' || sign) { + if (spec.fill() != ' ' || sign) + { while (*start == ' ') *start++ = fill; if (sign) @@ -2166,7 +2410,8 @@ accessed as a C string with ``out.c_str()``. \endrst */ template > -class BasicMemoryWriter : public BasicWriter { +class BasicMemoryWriter : public BasicWriter +{ private: internal::MemoryBuffer buffer_; @@ -2180,13 +2425,15 @@ public: object to it. */ BasicMemoryWriter(BasicMemoryWriter &&other) - : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) { + : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) + { } /** Moves the content of the other ``BasicMemoryWriter`` object to this one. */ - BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { + BasicMemoryWriter &operator=(BasicMemoryWriter &&other) + { buffer_ = std::move(other.buffer_); return *this; } @@ -2198,7 +2445,8 @@ typedef BasicMemoryWriter WMemoryWriter; // Formats a value. template -void format(BasicFormatter &f, const Char *&format_str, const T &value) { +void format(BasicFormatter &f, const Char *&format_str, const T &value) +{ std::basic_ostringstream os; os << value; internal::Arg arg; @@ -2218,7 +2466,8 @@ void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT(true); /** A Windows error. */ -class WindowsError : public SystemError { +class WindowsError : public SystemError +{ private: void init(int error_code, StringRef format_str, ArgList args); @@ -2232,7 +2481,8 @@ public: *error_code* is a Windows error code as given by ``GetLastError``. \endrst */ - WindowsError(int error_code, StringRef message) { + WindowsError(int error_code, StringRef message) + { init(error_code, message, ArgList()); } FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef) @@ -2263,13 +2513,15 @@ Formats arguments and returns the result as a string. std::string message = format("The answer is {}", 42); \endrst */ -inline std::string format(StringRef format_str, ArgList args) { +inline std::string format(StringRef format_str, ArgList args) +{ MemoryWriter w; w.write(format_str, args); return w.str(); } -inline std::wstring format(WStringRef format_str, ArgList args) { +inline std::wstring format(WStringRef format_str, ArgList args) +{ WMemoryWriter w; w.write(format_str, args); return w.str(); @@ -2309,7 +2561,8 @@ print(cerr, "Don't {}!", "panic"); void print(std::ostream &os, StringRef format_str, ArgList args); template -void printf(BasicWriter &w, BasicStringRef format, ArgList args) { +void printf(BasicWriter &w, BasicStringRef format, ArgList args) +{ internal::PrintfFormatter().format(w, format, args); } @@ -2322,7 +2575,8 @@ Formats arguments and returns the result as a string. std::string message = fmt::sprintf("The answer is %d", 42); \endrst */ -inline std::string sprintf(StringRef format, ArgList args) { +inline std::string sprintf(StringRef format, ArgList args) +{ MemoryWriter w; printf(w, format, args); return w.str(); @@ -2348,14 +2602,16 @@ Prints formatted data to ``stdout``. fmt::printf("Elapsed time: %.2f seconds", 1.23); \endrst */ -inline int printf(StringRef format, ArgList args) { +inline int printf(StringRef format, ArgList args) +{ return fprintf(stdout, format, args); } /** Fast integer formatter. */ -class FormatInt { +class FormatInt +{ private: // Buffer should be large enough to hold all digits (digits10 + 1), // a sign and a null character. @@ -2364,9 +2620,11 @@ private: char *str_; // Formats value in reverse and returns the number of digits. - char *format_decimal(ULongLong value) { + char *format_decimal(ULongLong value) + { char *buffer_end = buffer_ + BUFFER_SIZE - 1; - while (value >= 100) { + while (value >= 100) + { // Integer division is slow so do it for a group of two digits instead // of for every digit. The idea comes from the talk by Alexandrescu // "Three Optimization Tips for C++". See speed-test for a comparison. @@ -2375,7 +2633,8 @@ private: *--buffer_end = internal::Data::DIGITS[index + 1]; *--buffer_end = internal::Data::DIGITS[index]; } - if (value < 10) { + if (value < 10) + { *--buffer_end = static_cast('0' + value); return buffer_end; } @@ -2385,7 +2644,8 @@ private: return buffer_end; } - void FormatSigned(LongLong value) { + void FormatSigned(LongLong value) + { ULongLong abs_value = static_cast(value); bool negative = value < 0; if (negative) @@ -2396,13 +2656,16 @@ private: } public: - explicit FormatInt(int value) { + explicit FormatInt(int value) + { FormatSigned(value); } - explicit FormatInt(long value) { + explicit FormatInt(long value) + { FormatSigned(value); } - explicit FormatInt(LongLong value) { + explicit FormatInt(LongLong value) + { FormatSigned(value); } explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} @@ -2412,7 +2675,8 @@ public: /** Returns the number of characters written to the output buffer. */ - std::size_t size() const { + std::size_t size() const + { return buffer_ - str_ + BUFFER_SIZE - 1; } @@ -2420,7 +2684,8 @@ public: Returns a pointer to the output buffer content. No terminating null character is appended. */ - const char *data() const { + const char *data() const + { return str_; } @@ -2428,7 +2693,8 @@ public: Returns a pointer to the output buffer content with terminating null character appended. */ - const char *c_str() const { + const char *c_str() const + { buffer_[BUFFER_SIZE - 1] = '\0'; return str_; } @@ -2436,7 +2702,8 @@ public: /** Returns the content of the output buffer as an `std::string`. */ - std::string str() const { + std::string str() const + { return std::string(str_, size()); } }; @@ -2445,14 +2712,18 @@ public: // a pointer to the end of the formatted string. This function doesn't // write a terminating null character. template -inline void format_decimal(char *&buffer, T value) { +inline void format_decimal(char *&buffer, T value) +{ typename internal::IntTraits::MainType abs_value = value; - if (internal::is_negative(value)) { + if (internal::is_negative(value)) + { *buffer++ = '-'; abs_value = 0 - abs_value; } - if (abs_value < 100) { - if (abs_value < 10) { + if (abs_value < 100) + { + if (abs_value < 10) + { *buffer++ = static_cast('0' + abs_value); return; } @@ -2572,7 +2843,8 @@ fmt::print(format, args...); #define FMT_VARIADIC_W(ReturnType, func, ...) \ FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) -namespace fmt { +namespace fmt +{ FMT_VARIADIC(std::string, format, StringRef) FMT_VARIADIC_W(std::wstring, format, WStringRef) FMT_VARIADIC(void, print, StringRef) diff --git a/include/spdlog/details/log_msg.h b/include/spdlog/details/log_msg.h index 30ff129b..3764e6cf 100644 --- a/include/spdlog/details/log_msg.h +++ b/include/spdlog/details/log_msg.h @@ -48,7 +48,7 @@ struct log_msg level(other.level), time(other.time), tm_time(other.tm_time) - { + { raw.write(other.raw.data(), other.raw.size()); formatted.write(other.formatted.data(), other.formatted.size()); } @@ -61,7 +61,7 @@ struct log_msg raw(std::move(other.raw)), formatted(std::move(other.formatted)) { - other.clear(); + other.clear(); } log_msg& operator=(log_msg&& other) @@ -75,7 +75,7 @@ struct log_msg tm_time = other.tm_time; raw = std::move(other.raw); formatted = std::move(other.formatted); - other.clear(); + other.clear(); return *this; } @@ -83,7 +83,7 @@ struct log_msg void clear() { - level = level::OFF; + level = level::OFF; raw.clear(); formatted.clear(); } diff --git a/include/spdlog/sinks/async_sink.h b/include/spdlog/sinks/async_sink.h index 8cff37fa..153d50b7 100644 --- a/include/spdlog/sinks/async_sink.h +++ b/include/spdlog/sinks/async_sink.h @@ -112,7 +112,7 @@ inline void spdlog::sinks::async_sink::_sink_it(const details::log_msg& msg) { _push_sentry(); _q.push(std::move(msg)); - + } inline void spdlog::sinks::async_sink::_thread_loop() @@ -131,9 +131,9 @@ inline void spdlog::sinks::async_sink::_thread_loop() { _formatter->format(msg); - for (auto &s : _sinks) + for (auto &s : _sinks) s->log(msg); - + } catch (const std::exception& ex) { From 0e3120ba51a4f7e2e683819cd6aa6c4f57bfb77c Mon Sep 17 00:00:00 2001 From: gabime Date: Tue, 2 Dec 2014 02:30:42 +0200 Subject: [PATCH 026/120] removed include iostream --- example/utils.h | 1 - include/spdlog/sinks/ostream_sink.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/example/utils.h b/example/utils.h index 25b0cb45..95dd9257 100644 --- a/example/utils.h +++ b/example/utils.h @@ -24,7 +24,6 @@ #pragma once -#include #include #include #include diff --git a/include/spdlog/sinks/ostream_sink.h b/include/spdlog/sinks/ostream_sink.h index b62e4b7e..378863c9 100644 --- a/include/spdlog/sinks/ostream_sink.h +++ b/include/spdlog/sinks/ostream_sink.h @@ -24,7 +24,7 @@ #pragma once -#include +#include #include #include From d89628bb173f0e43dbd93a0e375462a7fb234c28 Mon Sep 17 00:00:00 2001 From: gabime Date: Tue, 2 Dec 2014 02:38:31 +0200 Subject: [PATCH 027/120] fixed makefile --- bench/Makefile | 2 +- example/example.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bench/Makefile b/bench/Makefile index 4ffd5455..6a1e93ca 100644 --- a/bench/Makefile +++ b/bench/Makefile @@ -1,5 +1,5 @@ CXX = g++ -CXXFLAGS = --march=native -Wall -Wshadow -Wextra -pedantic -std=c++11 -pthread -Wl,--no-as-needed -I../include +CXXFLAGS = -march=native -Wall -Wshadow -Wextra -pedantic -std=c++11 -pthread -Wl,--no-as-needed -I../include CXX_RELEASE_FLAGS = -O3 -flto diff --git a/example/example.cpp b/example/example.cpp index 927578fe..4e464107 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -27,7 +27,7 @@ // #include #include "spdlog/spdlog.h" - +#include "spdlog/details/format.h" int main(int, char* []) { @@ -36,6 +36,8 @@ int main(int, char* []) try { + fmt::print("Hello man {} {:1f}\n", 1, 2.2); + return 0; std::string filename = "logs/spdlog_example"; // Set log level to all loggers to DEBUG and above spd::set_level(spd::level::DEBUG); From 243dc61e5888baa708e91e973662df5a6d4ae840 Mon Sep 17 00:00:00 2001 From: gabi Date: Tue, 2 Dec 2014 16:41:12 +0200 Subject: [PATCH 028/120] async using lockfree queue and bug fixes regarding usage of cppformat --- include/spdlog/async_logger.h | 6 +- .../async_log_helper.h} | 139 +++++++++++------- include/spdlog/details/async_logger_impl.h | 25 ++-- include/spdlog/details/file_helper.h | 2 +- include/spdlog/details/format.cc | 1 - include/spdlog/details/format.h | 4 +- include/spdlog/details/log_msg.h | 8 +- include/spdlog/details/mpcs_q.h | 78 +++++++--- .../spdlog/details/pattern_formatter_impl.h | 8 +- 9 files changed, 171 insertions(+), 100 deletions(-) rename include/spdlog/{sinks/async_sink.h => details/async_log_helper.h} (56%) diff --git a/include/spdlog/async_logger.h b/include/spdlog/async_logger.h index d2302c23..943a868a 100644 --- a/include/spdlog/async_logger.h +++ b/include/spdlog/async_logger.h @@ -37,9 +37,9 @@ namespace spdlog { -namespace sinks +namespace details { -class async_sink; +class async_log_helper; } class async_logger :public logger @@ -59,7 +59,7 @@ protected: private: log_clock::duration _shutdown_duration; - std::unique_ptr _as; + std::unique_ptr _async_log_helper; }; } diff --git a/include/spdlog/sinks/async_sink.h b/include/spdlog/details/async_log_helper.h similarity index 56% rename from include/spdlog/sinks/async_sink.h rename to include/spdlog/details/async_log_helper.h index 153d50b7..d9e19dce 100644 --- a/include/spdlog/sinks/async_sink.h +++ b/include/spdlog/details/async_log_helper.h @@ -22,7 +22,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -// async sink: +// async log helper : // Process logs asynchronously using a back thread. // // If the internal queue of log messages reaches its max size, @@ -30,36 +30,69 @@ // // If the back thread throws during logging, a spdlog::spdlog_ex exception // will be thrown in client's thread when tries to log the next message + #pragma once #include #include #include -#include "./base_sink.h" +#include "../sinks/sink.h" #include "../logger.h" -#include "../details/blocking_queue.h" -#include "../details/null_mutex.h" +#include "../details/mpcs_q.h" #include "../details/log_msg.h" #include "../details/format.h" namespace spdlog { -namespace sinks +namespace details { - -class async_sink : public base_sink < details::null_mutex > //single worker thread so null_mutex +class async_log_helper { + struct async_msg + { + std::string logger_name; + level::level_enum level; + log_clock::time_point time; + std::tm tm_time; + std::string raw_msg_str; + + async_msg() = default; + + async_msg(const details::log_msg& m) : + logger_name(m.logger_name), + level(m.level), + time(m.time), + tm_time(m.tm_time), + raw_msg_str(m.raw.data(), m.raw.size()) + { + + } + + + log_msg to_log_msg() + { + log_msg msg; + msg.logger_name = logger_name; + msg.level = level; + msg.time = time; + msg.tm_time = tm_time; + msg.raw << raw_msg_str; + return msg; + } + }; + public: - using q_type = details::blocking_queue < details::log_msg > ; + using q_type = details::mpsc_q < std::unique_ptr >; - explicit async_sink(const q_type::size_type max_queue_size); + explicit async_log_helper(size_t max_queue_size); + void log(const details::log_msg& msg); //Stop logging and join the back thread - ~async_sink(); + ~async_log_helper(); void add_sink(sink_ptr sink); void remove_sink(sink_ptr sink_ptr); void set_formatter(formatter_ptr); @@ -68,25 +101,28 @@ public: -protected: - void _sink_it(const details::log_msg& msg) override; - void _thread_loop(); + private: - std::vector> _sinks; + std::vector> _sinks; std::atomic _active; q_type _q; - std::thread _back_thread; + std::thread _worker_thread; std::mutex _mutex; - //Last exception thrown from the back thread - std::shared_ptr _last_backthread_ex; + // last exception thrown from the worker thread + std::shared_ptr _last_workerthread_ex; + + // worker thread formatter formatter_ptr _formatter; - //will throw last back thread exception or if backthread no active + // will throw last back thread exception or if worker hread no active void _push_sentry(); - //Clear all remaining messages(if any), stop the _back_thread and join it + // worker thread loop + void _thread_loop(); + + // clear all remaining messages(if any), stop the _worker_thread and join it void _join(); }; @@ -96,85 +132,87 @@ private: /////////////////////////////////////////////////////////////////////////////// // async_sink class implementation /////////////////////////////////////////////////////////////////////////////// -inline spdlog::sinks::async_sink::async_sink(const q_type::size_type max_queue_size) +inline spdlog::details::async_log_helper::async_log_helper(size_t max_queue_size) :_sinks(), _active(true), _q(max_queue_size), - _back_thread(&async_sink::_thread_loop, this) + _worker_thread(&async_log_helper::_thread_loop, this) {} -inline spdlog::sinks::async_sink::~async_sink() +inline spdlog::details::async_log_helper::~async_log_helper() { _join(); } -inline void spdlog::sinks::async_sink::_sink_it(const details::log_msg& msg) +inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) { _push_sentry(); - _q.push(std::move(msg)); + _q.push(std::unique_ptr(new async_msg(msg))); } -inline void spdlog::sinks::async_sink::_thread_loop() +inline void spdlog::details::async_log_helper::_thread_loop() { - std::chrono::seconds pop_timeout { 1 }; while (_active) { - q_type::item_type msg; - if (_q.pop(msg, pop_timeout)) - { - if (!_active) - return; + q_type::item_type async_msg; + if (_q.pop(async_msg)) + { try { - _formatter->format(msg); + details::log_msg log_msg = async_msg->to_log_msg(); + + _formatter->format(log_msg); for (auto &s : _sinks) - s->log(msg); + s->log(log_msg); } catch (const std::exception& ex) { - _last_backthread_ex = std::make_shared(ex.what()); + _last_workerthread_ex = std::make_shared(ex.what()); } catch (...) { - _last_backthread_ex = std::make_shared("Unknown exception"); + _last_workerthread_ex = std::make_shared("Unknown exception"); } - + } + else //Sleep and retry if empty + { + std::this_thread::sleep_for(std::chrono::microseconds(100)); } } } -inline void spdlog::sinks::async_sink::add_sink(spdlog::sink_ptr s) +inline void spdlog::details::async_log_helper::add_sink(spdlog::sink_ptr s) { std::lock_guard guard(_mutex); _sinks.push_back(s); } -inline void spdlog::sinks::async_sink::remove_sink(spdlog::sink_ptr s) +inline void spdlog::details::async_log_helper::remove_sink(spdlog::sink_ptr s) { std::lock_guard guard(_mutex); _sinks.erase(std::remove(_sinks.begin(), _sinks.end(), s), _sinks.end()); } -inline void spdlog::sinks::async_sink::set_formatter(formatter_ptr msg_formatter) +inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter) { _formatter = msg_formatter; } -inline void spdlog::sinks::async_sink::shutdown(const log_clock::duration& timeout) +inline void spdlog::details::async_log_helper::shutdown(const log_clock::duration& timeout) { if (timeout > std::chrono::milliseconds::zero()) { auto until = log_clock::now() + timeout; - while (_q.size() > 0 && log_clock::now() < until) + while (_q.approx_size() > 0 && log_clock::now() < until) { std::this_thread::sleep_for(std::chrono::milliseconds(5)); } @@ -182,13 +220,13 @@ inline void spdlog::sinks::async_sink::shutdown(const log_clock::duration& timeo _join(); } -#include -inline void spdlog::sinks::async_sink::_push_sentry() + +inline void spdlog::details::async_log_helper::_push_sentry() { - if (_last_backthread_ex) + if (_last_workerthread_ex) { - auto ex = std::move(_last_backthread_ex); - _last_backthread_ex.reset(); + auto ex = std::move(_last_workerthread_ex); + _last_workerthread_ex.reset(); throw *ex; } if (!_active) @@ -196,17 +234,18 @@ inline void spdlog::sinks::async_sink::_push_sentry() } -inline void spdlog::sinks::async_sink::_join() +inline void spdlog::details::async_log_helper::_join() { _active = false; - if (_back_thread.joinable()) + if (_worker_thread.joinable()) { try { - _back_thread.join(); + _worker_thread.join(); } catch (const std::system_error&) //Dont crash if thread not joinable - {} + { + } } } diff --git a/include/spdlog/details/async_logger_impl.h b/include/spdlog/details/async_logger_impl.h index e84f897d..963135d3 100644 --- a/include/spdlog/details/async_logger_impl.h +++ b/include/spdlog/details/async_logger_impl.h @@ -25,8 +25,7 @@ #pragma once -#include -#include "../sinks/async_sink.h" +#include "./async_log_helper.h" // // Async Logger implementation @@ -38,11 +37,11 @@ template inline spdlog::async_logger::async_logger(const std::string& logger_name, const It& begin, const It& end, size_t queue_size, const log_clock::duration& shutdown_duration) : logger(logger_name, begin, end), _shutdown_duration(shutdown_duration), - _as(std::unique_ptr(new sinks::async_sink(queue_size))) + _async_log_helper(new details::async_log_helper(queue_size)) { - _as->set_formatter(_formatter); + _async_log_helper->set_formatter(_formatter); for (auto &s : _sinks) - _as->add_sink(s); + _async_log_helper->add_sink(s); } inline spdlog::async_logger::async_logger(const std::string& logger_name, sinks_init_list sinks, size_t queue_size, const log_clock::duration& shutdown_duration) : @@ -52,21 +51,16 @@ inline spdlog::async_logger::async_logger(const std::string& logger_name, sink_p async_logger(logger_name, { single_sink }, queue_size, shutdown_duration) {} -inline void spdlog::async_logger::_log_msg(details::log_msg& msg) -{ - _as->log(msg); -} - inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter) { _formatter = msg_formatter; - _as->set_formatter(_formatter); + _async_log_helper->set_formatter(_formatter); } inline void spdlog::async_logger::_set_pattern(const std::string& pattern) { _formatter = std::make_shared(pattern); - _as->set_formatter(_formatter); + _async_log_helper->set_formatter(_formatter); } @@ -74,5 +68,10 @@ inline void spdlog::async_logger::_set_pattern(const std::string& pattern) inline void spdlog::async_logger::_stop() { set_level(level::OFF); - _as->shutdown(_shutdown_duration); + _async_log_helper->shutdown(_shutdown_duration); +} + +inline void spdlog::async_logger::_log_msg(details::log_msg& msg) +{ + _async_log_helper->log(msg); } diff --git a/include/spdlog/details/file_helper.h b/include/spdlog/details/file_helper.h index 7932a45b..ac0ef948 100644 --- a/include/spdlog/details/file_helper.h +++ b/include/spdlog/details/file_helper.h @@ -102,7 +102,7 @@ public: size_t size = msg.formatted.size(); auto data = msg.formatted.data(); - if(std::fwrite(data, sizeof(char), size, _fd) != size) + if(std::fwrite(data, 1, size, _fd) != size) throw spdlog_ex("Failed writing to file " + _filename); if(_auto_flush) diff --git a/include/spdlog/details/format.cc b/include/spdlog/details/format.cc index 06b8c846..76ef84eb 100644 --- a/include/spdlog/details/format.cc +++ b/include/spdlog/details/format.cc @@ -31,7 +31,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #undef _SCL_SECURE_NO_WARNINGS #define _SCL_SECURE_NO_WARNINGS -#include "format.h" #include diff --git a/include/spdlog/details/format.h b/include/spdlog/details/format.h index a9b51c21..c90e9212 100644 --- a/include/spdlog/details/format.h +++ b/include/spdlog/details/format.h @@ -1050,7 +1050,7 @@ public: { default: assert(false); - // Fall through. + // Fall through. case Arg::INT: return FMT_DISPATCH(visit_int(arg.int_value)); case Arg::UINT: @@ -2219,7 +2219,7 @@ void BasicWriter::write_double( // MSVC's printf doesn't support 'F'. type = 'f'; #endif - // Fall through. + // Fall through. case 'E': case 'G': case 'A': diff --git a/include/spdlog/details/log_msg.h b/include/spdlog/details/log_msg.h index 3764e6cf..00870bb2 100644 --- a/include/spdlog/details/log_msg.h +++ b/include/spdlog/details/log_msg.h @@ -48,9 +48,13 @@ struct log_msg level(other.level), time(other.time), tm_time(other.tm_time) + { - raw.write(other.raw.data(), other.raw.size()); - formatted.write(other.formatted.data(), other.formatted.size()); + if (other.raw.size()) + raw << fmt::BasicStringRef(other.raw.data(), other.raw.size()); + if (other.formatted.size()) + formatted << fmt::BasicStringRef(other.formatted.data(), other.formatted.size()); + } log_msg(log_msg&& other) : diff --git a/include/spdlog/details/mpcs_q.h b/include/spdlog/details/mpcs_q.h index 058d6ee4..d62d1775 100644 --- a/include/spdlog/details/mpcs_q.h +++ b/include/spdlog/details/mpcs_q.h @@ -1,7 +1,5 @@ -#pragma once -/*************************************************************************/ /* -Modified version of Intrusive MPSC node-based queue +A modified version of Intrusive MPSC node-based queue Original code from http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue @@ -32,9 +30,10 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov. +*/ /*************************************************************************/ -/* The code in its current form adds the license below: */ +/********* The code in its current form adds the license below: **********/ /*************************************************************************/ /* spdlog - an extremely fast and easy to use c++11 logging library. */ /* Copyright (c) 2014 Gabi Melman. */ @@ -59,6 +58,7 @@ should not be interpreted as representing official policies, either expressed or /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ +#pragma once #include namespace spdlog @@ -70,35 +70,40 @@ class mpsc_q { public: - mpsc_q(size_t size) :_stub(T()), _head(&_stub), _tail(&_stub) + using item_type = T; + mpsc_q(size_t max_size) : + _max_size(max_size), + _size(0), + _stub(), + _head(&_stub), + _tail(&_stub) { - _stub.next = nullptr; } ~mpsc_q() { - reset(); + clear(); } - void reset() + template + bool push(TT&& value) { - T dummy_val; - while (pop(dummy_val)); - } - - bool push(const T& value) - { - mpscq_node_t* new_node = new mpscq_node_t(value); + if (_size >= _max_size) + return false; + mpscq_node_t* new_node = new mpscq_node_t(std::forward(value)); push_node(new_node); + ++_size; return true; } + // Try to pop or return false immediatly is queue is empty bool pop(T& value) { mpscq_node_t* node = pop_node(); if (node != nullptr) { - value = node->value; + --_size; + value = std::move(node->value); delete(node); return true; } @@ -108,23 +113,48 @@ public: } } + // Empty the queue by popping all its elements + void clear() + { + + while (mpscq_node_t* node = pop_node()) + { + --_size; + delete(node); + + } + + } + + // Return approx size + size_t approx_size() const + { + return _size.load(); + } + private: struct mpscq_node_t { std::atomic next; T value; - explicit mpscq_node_t(const T& value) :next(nullptr), value(value) - { - } + mpscq_node_t() :next(nullptr) {} + explicit mpscq_node_t(const T& value): + next(nullptr), + value(value) {} + + explicit mpscq_node_t(T&& value) : + next(nullptr), + value(std::move(value)) {} }; + size_t _max_size; + std::atomic _size; mpscq_node_t _stub; std::atomic _head; mpscq_node_t* _tail; - - + // Lockfree push void push_node(mpscq_node_t* n) { n->next = nullptr; @@ -132,6 +162,8 @@ private: prev->next = n; } + // Clever lockfree pop algorithm by Dmitry Vyukov using single xchng instruction.. + // Return pointer to the poppdc node or nullptr if no items left in the queue mpscq_node_t* pop_node() { mpscq_node_t* tail = _tail; @@ -151,7 +183,7 @@ private: } mpscq_node_t* head = _head; if (tail != head) - return 0; + return nullptr; push_node(&_stub); next = tail->next; @@ -163,8 +195,6 @@ private: return nullptr; } - - }; } } \ No newline at end of file diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index 6a0c4ee9..8ee826a1 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -345,7 +345,7 @@ class v_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted.write(msg.raw.data(), msg.raw.size()); + msg.formatted << fmt::BasicStringRef(msg.raw.data(), msg.raw.size()); } }; @@ -413,7 +413,7 @@ class full_formatter :public flag_formatter << fmt::pad(static_cast(millis), 3, '0') << "] "; msg.formatted << '[' << msg.logger_name << "] [" << level::to_str(msg.level) << "] "; - msg.formatted.write(msg.raw.data(), msg.raw.size()); + msg.formatted << fmt::BasicStringRef(msg.raw.data(), msg.raw.size()); } }; @@ -460,7 +460,7 @@ inline void spdlog::pattern_formatter::handle_flag(char flag) { switch (flag) { - // logger name + // logger name case 'n': _formatters.push_back(std::unique_ptr(new details::name_formatter())); break; @@ -581,7 +581,7 @@ inline void spdlog::pattern_formatter::format(details::log_msg& msg) f->format(msg); } //write eol - msg.formatted.write(details::os::eol(), details::os::eol_size()); + msg.formatted << details::os::eol(); } catch(const fmt::FormatError& e) { From b943265b946fed349344a6e600e63450328be454 Mon Sep 17 00:00:00 2001 From: gabi Date: Tue, 2 Dec 2014 19:14:21 +0200 Subject: [PATCH 029/120] Better handling of empty queue --- include/spdlog/details/async_log_helper.h | 34 +++++++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index d9e19dce..7ea0ac04 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -87,6 +87,8 @@ class async_log_helper public: using q_type = details::mpsc_q < std::unique_ptr >; + using clock = std::chrono::monotonic_clock; + explicit async_log_helper(size_t max_queue_size); void log(const details::log_msg& msg); @@ -116,12 +118,17 @@ private: // worker thread formatter formatter_ptr _formatter; + // will throw last back thread exception or if worker hread no active void _push_sentry(); // worker thread loop void _thread_loop(); + // guess how much to sleep if queue is empty + static clock::duration spdlog::details::async_log_helper::_calc_pop_sleep(const clock::time_point& last_pop); + + // clear all remaining messages(if any), stop the _worker_thread and join it void _join(); @@ -154,15 +161,18 @@ inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) inline void spdlog::details::async_log_helper::_thread_loop() { + clock::time_point last_pop = clock::now(); while (_active) { q_type::item_type async_msg; if (_q.pop(async_msg)) { + + last_pop = clock::now(); + try { - details::log_msg log_msg = async_msg->to_log_msg(); _formatter->format(log_msg); @@ -179,13 +189,31 @@ inline void spdlog::details::async_log_helper::_thread_loop() _last_workerthread_ex = std::make_shared("Unknown exception"); } } - else //Sleep and retry if empty + //Sleep for a while if empty. + else { - std::this_thread::sleep_for(std::chrono::microseconds(100)); + std::this_thread::sleep_for(_calc_pop_sleep(last_pop)); } } } +//Try to guess sleep duration according to the time passed since last message +inline spdlog::details::async_log_helper::clock::duration spdlog::details::async_log_helper::_calc_pop_sleep(const clock::time_point& last_pop) +{ + using std::chrono::milliseconds; + using std::chrono::microseconds; + auto time_since_pop = clock::now() - last_pop; + + + if (time_since_pop > milliseconds(1000)) + return milliseconds(500); + if (time_since_pop > microseconds(0)) + return(time_since_pop / 2); + return microseconds(0); + + +} + inline void spdlog::details::async_log_helper::add_sink(spdlog::sink_ptr s) { std::lock_guard guard(_mutex); From 01344b6c8b0e9df182194b866281debde80f9506 Mon Sep 17 00:00:00 2001 From: gabi Date: Wed, 3 Dec 2014 00:27:25 +0200 Subject: [PATCH 030/120] mpcs_q removed default copy ctor and assignment --- include/spdlog/details/mpcs_q.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/include/spdlog/details/mpcs_q.h b/include/spdlog/details/mpcs_q.h index d62d1775..77511db3 100644 --- a/include/spdlog/details/mpcs_q.h +++ b/include/spdlog/details/mpcs_q.h @@ -71,7 +71,7 @@ class mpsc_q public: using item_type = T; - mpsc_q(size_t max_size) : + explicit mpsc_q(size_t max_size) : _max_size(max_size), _size(0), _stub(), @@ -80,6 +80,9 @@ public: { } + mpsc_q(const mpsc_q&) = delete; + mpsc_q& operator=(const mpsc_q&) = delete; + ~mpsc_q() { clear(); @@ -116,12 +119,10 @@ public: // Empty the queue by popping all its elements void clear() { - while (mpscq_node_t* node = pop_node()) { --_size; delete(node); - } } @@ -139,6 +140,9 @@ private: T value; mpscq_node_t() :next(nullptr) {} + mpscq_node_t(const mpscq_node_t&) = delete; + mpscq_node_t& operator=(const mpscq_node_t&) = delete; + explicit mpscq_node_t(const T& value): next(nullptr), value(value) {} From 80d09d8309330b5754683839ec4d3859145cd89a Mon Sep 17 00:00:00 2001 From: gabi Date: Wed, 3 Dec 2014 00:28:33 +0200 Subject: [PATCH 031/120] async_helper sleep_or_yield or full/empty queue --- include/spdlog/details/async_log_helper.h | 54 ++++++++++++++--------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index 7ea0ac04..f84b693f 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -125,8 +125,8 @@ private: // worker thread loop void _thread_loop(); - // guess how much to sleep if queue is empty - static clock::duration spdlog::details::async_log_helper::_calc_pop_sleep(const clock::time_point& last_pop); + // guess how much to sleep if queue is empty/full using last succesful op time as hint + static void _sleep_or_yield(const clock::time_point& last_op_time); // clear all remaining messages(if any), stop the _worker_thread and join it @@ -151,11 +151,21 @@ inline spdlog::details::async_log_helper::~async_log_helper() _join(); } + +//Try to push and block until succeeded inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) { _push_sentry(); - _q.push(std::unique_ptr(new async_msg(msg))); + //Only if queue is full, enter wait loop + if (!_q.push(std::unique_ptr < async_msg >(new async_msg(msg)))) + { + auto last_op_time = clock::now(); + while (!_q.push(std::unique_ptr < async_msg >(new async_msg(msg)))) + { + _sleep_or_yield(last_op_time); + } + } } inline void spdlog::details::async_log_helper::_thread_loop() @@ -192,27 +202,11 @@ inline void spdlog::details::async_log_helper::_thread_loop() //Sleep for a while if empty. else { - std::this_thread::sleep_for(_calc_pop_sleep(last_pop)); + _sleep_or_yield(last_pop); } } } -//Try to guess sleep duration according to the time passed since last message -inline spdlog::details::async_log_helper::clock::duration spdlog::details::async_log_helper::_calc_pop_sleep(const clock::time_point& last_pop) -{ - using std::chrono::milliseconds; - using std::chrono::microseconds; - auto time_since_pop = clock::now() - last_pop; - - - if (time_since_pop > milliseconds(1000)) - return milliseconds(500); - if (time_since_pop > microseconds(0)) - return(time_since_pop / 2); - return microseconds(0); - - -} inline void spdlog::details::async_log_helper::add_sink(spdlog::sink_ptr s) { @@ -249,6 +243,23 @@ inline void spdlog::details::async_log_helper::shutdown(const log_clock::duratio } +// Sleep or yield using the time passed since last message as a hint +inline void spdlog::details::async_log_helper::_sleep_or_yield(const clock::time_point& last_op_time) +{ + using std::chrono::milliseconds; + using std::this_thread::sleep_for; + using std::this_thread::yield; + + clock::duration sleep_duration; + auto time_since_op = clock::now() - last_op_time; + if (time_since_op > milliseconds(1000)) + sleep_for(milliseconds(500)); + else if (time_since_op > milliseconds(1)) + sleep_for(time_since_op / 2); + else + yield(); +} + inline void spdlog::details::async_log_helper::_push_sentry() { if (_last_workerthread_ex) @@ -278,3 +289,6 @@ inline void spdlog::details::async_log_helper::_join() } + + + From 3916674bc5d0bc2ed58f3a699014b37f560a7010 Mon Sep 17 00:00:00 2001 From: gabi Date: Wed, 3 Dec 2014 00:28:33 +0200 Subject: [PATCH 032/120] async_helper sleep_or_yield or full/empty queue --- include/spdlog/details/async_log_helper.h | 57 ++++++++++++++--------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index 7ea0ac04..92c2f18d 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -125,8 +125,8 @@ private: // worker thread loop void _thread_loop(); - // guess how much to sleep if queue is empty - static clock::duration spdlog::details::async_log_helper::_calc_pop_sleep(const clock::time_point& last_pop); + // guess how much to sleep if queue is empty/full using last succesful op time as hint + static void _sleep_or_yield(const clock::time_point& last_op_time); // clear all remaining messages(if any), stop the _worker_thread and join it @@ -151,11 +151,22 @@ inline spdlog::details::async_log_helper::~async_log_helper() _join(); } + +//Try to push and block until succeeded inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) { _push_sentry(); - _q.push(std::unique_ptr(new async_msg(msg))); + //Only if queue is full, enter wait loop + if (!_q.push(std::unique_ptr < async_msg >(new async_msg(msg)))) + { + auto last_op_time = clock::now(); + do + { + _sleep_or_yield(last_op_time); + } + while (!_q.push(std::unique_ptr < async_msg >(new async_msg(msg)))); + } } inline void spdlog::details::async_log_helper::_thread_loop() @@ -189,30 +200,14 @@ inline void spdlog::details::async_log_helper::_thread_loop() _last_workerthread_ex = std::make_shared("Unknown exception"); } } - //Sleep for a while if empty. + // sleep or yield if queue is empty. else { - std::this_thread::sleep_for(_calc_pop_sleep(last_pop)); + _sleep_or_yield(last_pop); } } } -//Try to guess sleep duration according to the time passed since last message -inline spdlog::details::async_log_helper::clock::duration spdlog::details::async_log_helper::_calc_pop_sleep(const clock::time_point& last_pop) -{ - using std::chrono::milliseconds; - using std::chrono::microseconds; - auto time_since_pop = clock::now() - last_pop; - - - if (time_since_pop > milliseconds(1000)) - return milliseconds(500); - if (time_since_pop > microseconds(0)) - return(time_since_pop / 2); - return microseconds(0); - - -} inline void spdlog::details::async_log_helper::add_sink(spdlog::sink_ptr s) { @@ -249,6 +244,23 @@ inline void spdlog::details::async_log_helper::shutdown(const log_clock::duratio } +// Sleep or yield using the time passed since last message as a hint +inline void spdlog::details::async_log_helper::_sleep_or_yield(const clock::time_point& last_op_time) +{ + using std::chrono::milliseconds; + using std::this_thread::sleep_for; + using std::this_thread::yield; + + clock::duration sleep_duration; + auto time_since_op = clock::now() - last_op_time; + if (time_since_op > milliseconds(1000)) + sleep_for(milliseconds(500)); + else if (time_since_op > milliseconds(1)) + sleep_for(time_since_op / 2); + else + yield(); +} + inline void spdlog::details::async_log_helper::_push_sentry() { if (_last_workerthread_ex) @@ -278,3 +290,6 @@ inline void spdlog::details::async_log_helper::_join() } + + + From 33b976a4c9d2a7913fe78f635db25966972acfc3 Mon Sep 17 00:00:00 2001 From: gabi Date: Wed, 3 Dec 2014 00:40:13 +0200 Subject: [PATCH 033/120] fix --- include/spdlog/details/async_log_helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index 92c2f18d..ddd16ecf 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -163,7 +163,7 @@ inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) auto last_op_time = clock::now(); do { - _sleep_or_yield(last_op_time); + _sleep_or_yield(last_op_time ; } while (!_q.push(std::unique_ptr < async_msg >(new async_msg(msg)))); } From 9e882c4dd228a481302a68414ac90e9a75a300f9 Mon Sep 17 00:00:00 2001 From: gabi Date: Wed, 3 Dec 2014 00:50:12 +0200 Subject: [PATCH 034/120] fix --- include/spdlog/details/async_log_helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index ddd16ecf..92c2f18d 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -163,7 +163,7 @@ inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) auto last_op_time = clock::now(); do { - _sleep_or_yield(last_op_time ; + _sleep_or_yield(last_op_time); } while (!_q.push(std::unique_ptr < async_msg >(new async_msg(msg)))); } From 98e4eb98f9fd88f206070cea9076239c2cf882d4 Mon Sep 17 00:00:00 2001 From: gabi Date: Wed, 3 Dec 2014 00:50:49 +0200 Subject: [PATCH 035/120] small optimization in default formatting (unsigned ints) --- .../spdlog/details/pattern_formatter_impl.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index 8ee826a1..bc2cc6f0 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -345,7 +345,7 @@ class v_formatter :public flag_formatter { void format(details::log_msg& msg) override { - msg.formatted << fmt::BasicStringRef(msg.raw.data(), msg.raw.size()); + msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); } }; @@ -404,16 +404,16 @@ class full_formatter :public flag_formatter msg.raw.str());*/ // Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads) - msg.formatted << '[' << msg.tm_time.tm_year + 1900 << '-' - << fmt::pad(msg.tm_time.tm_mon + 1, 2, '0') << '-' - << fmt::pad(msg.tm_time.tm_mday, 2, '0') << ' ' - << fmt::pad(msg.tm_time.tm_hour, 2, '0') << ':' - << fmt::pad(msg.tm_time.tm_min, 2, '0') << ':' - << fmt::pad(msg.tm_time.tm_sec, 2, '0') << '.' - << fmt::pad(static_cast(millis), 3, '0') << "] "; + msg.formatted << '[' << static_cast(msg.tm_time.tm_year + 1900) << '-' + << fmt::pad(static_cast(msg.tm_time.tm_mon + 1), 2, '0') << '-' + << fmt::pad(static_cast(msg.tm_time.tm_mday), 2, '0') << ' ' + << fmt::pad(static_cast(msg.tm_time.tm_hour), 2, '0') << ':' + << fmt::pad(static_cast(msg.tm_time.tm_min), 2, '0') << ':' + << fmt::pad(static_cast(msg.tm_time.tm_sec), 2, '0') << '.' + << fmt::pad(static_cast(millis), 3, '0') << "] "; msg.formatted << '[' << msg.logger_name << "] [" << level::to_str(msg.level) << "] "; - msg.formatted << fmt::BasicStringRef(msg.raw.data(), msg.raw.size()); + msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); } }; From 2c854cc8b758785b0079406f54cce8d017ed12ad Mon Sep 17 00:00:00 2001 From: gabime Date: Wed, 3 Dec 2014 01:15:25 +0200 Subject: [PATCH 036/120] fixed gcc shadow warnings --- include/spdlog/details/async_log_helper.h | 8 ++++---- include/spdlog/details/mpcs_q.h | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index 92c2f18d..094162de 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -87,7 +87,7 @@ class async_log_helper public: using q_type = details::mpsc_q < std::unique_ptr >; - using clock = std::chrono::monotonic_clock; + using clock = std::chrono::steady_clock; explicit async_log_helper(size_t max_queue_size); @@ -175,16 +175,16 @@ inline void spdlog::details::async_log_helper::_thread_loop() clock::time_point last_pop = clock::now(); while (_active) { - q_type::item_type async_msg; + q_type::item_type popped_msg; - if (_q.pop(async_msg)) + if (_q.pop(popped_msg)) { last_pop = clock::now(); try { - details::log_msg log_msg = async_msg->to_log_msg(); + details::log_msg log_msg = popped_msg->to_log_msg(); _formatter->format(log_msg); for (auto &s : _sinks) diff --git a/include/spdlog/details/mpcs_q.h b/include/spdlog/details/mpcs_q.h index 77511db3..c994307b 100644 --- a/include/spdlog/details/mpcs_q.h +++ b/include/spdlog/details/mpcs_q.h @@ -89,11 +89,11 @@ public: } template - bool push(TT&& value) + bool push(TT&& val) { if (_size >= _max_size) return false; - mpscq_node_t* new_node = new mpscq_node_t(std::forward(value)); + mpscq_node_t* new_node = new mpscq_node_t(std::forward(val)); push_node(new_node); ++_size; return true; @@ -143,13 +143,13 @@ private: mpscq_node_t(const mpscq_node_t&) = delete; mpscq_node_t& operator=(const mpscq_node_t&) = delete; - explicit mpscq_node_t(const T& value): + explicit mpscq_node_t(const T& val): next(nullptr), - value(value) {} + value(val) {} - explicit mpscq_node_t(T&& value) : + explicit mpscq_node_t(T&& val) : next(nullptr), - value(std::move(value)) {} + value(std::move(val)) {} }; size_t _max_size; @@ -201,4 +201,4 @@ private: }; } -} \ No newline at end of file +} From c63e9fae9d16a56f1f706dd84e59bfe6b1a04a90 Mon Sep 17 00:00:00 2001 From: gabime Date: Wed, 3 Dec 2014 01:48:20 +0200 Subject: [PATCH 037/120] async bench --- example/bench.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/bench.cpp b/example/bench.cpp index f7e51204..4e881685 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -91,7 +91,7 @@ int main(int argc, char* argv[]) cout << "*******************************************************************************\n"; - spdlog::set_async_mode(2500); + spdlog::set_async_mode(howmany); auto daily_st_async = spdlog::daily_logger_st("daily_async", "logs/daily_async", auto_flush); bench_mt(howmany, daily_st_async, threads); From 15f914f350baba8fa1d872393412952f8bba9f0b Mon Sep 17 00:00:00 2001 From: gabime Date: Wed, 3 Dec 2014 01:53:11 +0200 Subject: [PATCH 038/120] fix bench queue size --- bench/spdlog-bench-async.cpp | 4 ++-- bench/spdlog-bench-mt-async.cpp | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/bench/spdlog-bench-async.cpp b/bench/spdlog-bench-async.cpp index 9ec78472..eaaa131f 100644 --- a/bench/spdlog-bench-async.cpp +++ b/bench/spdlog-bench-async.cpp @@ -6,13 +6,13 @@ int main(int, char* []) { int howmany = 1000000; namespace spd = spdlog; - spd::set_async_mode(2500, std::chrono::seconds(0)); + spd::set_async_mode(howmany); ///Create a file rotating logger with 5mb size max and 3 rotated files auto logger = spd::rotating_logger_mt("file_logger", "logs/spd-sample", 10 *1024 * 1024 , 5); logger->set_pattern("[%Y-%b-%d %T.%e]: %v"); for(int i = 0 ; i < howmany; ++i) logger->info() << "spdlog message #" << i << ": This is some text for your pleasure"; - spd::stop(); + return 0; } diff --git a/bench/spdlog-bench-mt-async.cpp b/bench/spdlog-bench-mt-async.cpp index 58027020..aacf00d1 100644 --- a/bench/spdlog-bench-mt-async.cpp +++ b/bench/spdlog-bench-mt-async.cpp @@ -17,7 +17,7 @@ int main(int argc, char* argv[]) int howmany = 1000000; namespace spd = spdlog; - spd::set_async_mode(2500, std::chrono::seconds(0)); + spd::set_async_mode(howmany, std::chrono::seconds(0)); ///Create a file rotating logger with 5mb size max and 3 rotated files auto logger = spd::rotating_logger_mt("file_logger", "logs/spd-sample", 10 *1024 * 1024 , 5); @@ -45,6 +45,5 @@ int main(int argc, char* argv[]) t.join(); }; - spd::stop(); return 0; } From 9a7c62724a0ca936b1f1bca029378024cd313c7a Mon Sep 17 00:00:00 2001 From: gabime Date: Wed, 3 Dec 2014 02:06:50 +0200 Subject: [PATCH 039/120] removed uneeded file --- bench/results.txt | 80 ----------------------------------------------- bench/run_all.sh | 38 +++++++++++----------- 2 files changed, 19 insertions(+), 99 deletions(-) delete mode 100644 bench/results.txt diff --git a/bench/results.txt b/bench/results.txt deleted file mode 100644 index df7f94e3..00000000 --- a/bench/results.txt +++ /dev/null @@ -1,80 +0,0 @@ -Running benchmakrs (all with 1000,000 writes to the logs folder - -boost-bench (single thread).. - -real 0m4.779s -user 0m4.256s -sys 0m0.044s - - -glog-bench (single thread).. - -real 0m1.109s -user 0m0.967s -sys 0m0.140s - - -g2log-bench (single thread).. - -Exiting, log location: logs/g2log-bench.g2log.20141124-233419.log - -real 0m3.155s -user 0m4.255s -sys 0m0.874s - - -spdlog-bench (single thread) - -real 0m0.947s -user 0m0.914s -sys 0m0.032s - - ------------------------------------- -Multithreaded benchmarks.. ------------------------------------- -boost-bench-mt (10 threads, single logger).. - -real 0m15.151s -user 0m35.555s -sys 0m7.453s - - -glog-bench-mt (10 threads, single logger).. - -real 0m3.546s -user 0m9.836s -sys 0m10.985s - - -g2log-bench-mt (10 threads, single logger).. - -Exiting, log location: logs/g2log-bench-mt.g2log.20141124-233502.log - -real 0m3.500s -user 0m7.671s -sys 0m1.646s - - -spdlog-bench-mt (10 threads, single logger).. - -real 0m1.549s -user 0m6.994s -sys 0m2.969s - - ------------------------------------- -Async benchmarks.. ------------------------------------- -spdlog-bench-async (single thread).. - -real 0m1.455s -user 0m2.381s -sys 0m0.417s - - -spdlog-bench-mt-async (10 threads, single logger).. - -real 0m2.040s -user 0m4.076s -sys 0m2.822s diff --git a/bench/run_all.sh b/bench/run_all.sh index 4a437ece..4e0eb531 100755 --- a/bench/run_all.sh +++ b/bench/run_all.sh @@ -2,29 +2,29 @@ echo "Running benchmakrs (all with 1000,000 writes to the logs folder)" echo echo "boost-bench (single thread).." -time ./boost-bench -rm logs/* +for i in {1..3}; do time ./boost-bench; done +rm -f logs/* echo echo sleep 5 echo "glog-bench (single thread).." -time ./glog-bench -rm logs/* +for i in {1..3}; do time ./glog-bench; done +rm -f logs/* echo echo sleep 5 echo "g2log-bench (single thread).." -time ./g2log-bench -rm logs/* +for i in {1..3}; do time ./g2log-bench; done +rm -f logs/* echo echo sleep 5 echo "spdlog-bench (single thread)" -time ./spdlog-bench -rm logs/* +for i in {1..3}; do time ./spdlog-bench; done +rm -f logs/* echo echo sleep 5 @@ -32,29 +32,29 @@ echo "------------------------------------" echo "Multithreaded benchmarks.." echo "------------------------------------" echo "boost-bench-mt (10 threads, single logger)".. -time ./boost-bench-mt -rm logs/* +for i in {1..3}; do ./boost-bench-mt; done +rm -f logs/* echo echo sleep 5 echo "glog-bench-mt (10 threads, single logger)".. -time ./glog-bench-mt -rm logs/* +for i in {1..3}; do time ./glog-bench-mt; done +rm -f logs/* echo echo sleep 5 echo "g2log-bench-mt (10 threads, single logger)".. -time ./g2log-bench-mt -rm logs/* +for i in {1..3}; do time ./g2log-bench-mt; done +rm -f logs/* echo echo sleep 5 echo "spdlog-bench-mt (10 threads, single logger)".. -time ./spdlog-bench-mt -rm logs/* +for i in {1..3}; do time ./spdlog-bench-mt; done +rm -f logs/* echo echo sleep 5 @@ -64,14 +64,14 @@ echo "Async benchmarks.." echo "------------------------------------" echo "spdlog-bench-async (single thread)".. -time ./spdlog-bench-async -rm logs/* +for i in {1..3}; do time ./spdlog-bench-async; done +rm -f logs/* echo echo sleep 5 echo "spdlog-bench-mt-async (10 threads, single logger)".. -time ./spdlog-bench-mt-async +for i in {1..3}; do time ./spdlog-bench-mt-async; done From 8dcec193e87156d6b6ecbb85fd963e5a416b8b36 Mon Sep 17 00:00:00 2001 From: gabime Date: Wed, 3 Dec 2014 17:46:54 +0200 Subject: [PATCH 040/120] removed unised blocking_queue.h --- include/spdlog/details/blocking_queue.h | 155 ------------------------ 1 file changed, 155 deletions(-) delete mode 100644 include/spdlog/details/blocking_queue.h diff --git a/include/spdlog/details/blocking_queue.h b/include/spdlog/details/blocking_queue.h deleted file mode 100644 index 8fe01998..00000000 --- a/include/spdlog/details/blocking_queue.h +++ /dev/null @@ -1,155 +0,0 @@ -/*************************************************************************/ -/* spdlog - an extremely fast and easy to use c++11 logging library. */ -/* Copyright (c) 2014 Gabi Melman. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#pragma once - -// A blocking multi-consumer/multi-producer thread safe queue. -// Has max capacity and supports timeout on push or pop operations. - -#include -#include -#include -#include -#include - -namespace spdlog -{ -namespace details -{ - -template -class blocking_queue -{ -public: - using queue_type = std::queue; - using item_type = T; - using size_type = typename queue_type::size_type; - using clock = std::chrono::system_clock; - - explicit blocking_queue(size_type max_size) : - _max_size(max_size), - _q(), - _mutex() - { - } - blocking_queue(const blocking_queue&) = delete; - blocking_queue& operator=(const blocking_queue&) = delete; - ~blocking_queue() = default; - - size_type size() - { - std::lock_guard lock(_mutex); - return _q.size(); - } - - // Push copy of item into the back of the queue. - // If the queue is full, block the calling thread util there is room or timeout have passed. - // Return: false on timeout, true on successful push. - template - bool push(TT&& item, const std::chrono::duration& timeout) - { - { - std::unique_lock ul(_mutex); - if (is_full()) - { - if (!_item_popped_cond.wait_until(ul, clock::now() + timeout, [this]() - { - return !this->is_full(); - })) - return false; - } - _q.push(std::forward(item)); - } - _item_pushed_cond.notify_one(); - return true; - } - -// Push copy of item into the back of the queue. -// If the queue is full, block the calling thread until there is room. - template - void push(TT&& item) - { - while (!push(std::forward(item), std::chrono::seconds(60))); - } - -// Pop a copy of the front item in the queue into the given item ref. -// If the queue is empty, block the calling thread util there is item to pop or timeout have passed. -// Return: false on timeout , true on successful pop/ - template - bool pop(T& item, const std::chrono::duration& timeout) - { - { - std::unique_lock ul(_mutex); - if (is_empty()) - { - if (!_item_pushed_cond.wait_until(ul, clock::now() + timeout, [this]() - { - return !this->is_empty(); - })) - return false; - } - item = std::move(_q.front()); - _q.pop(); - } - _item_popped_cond.notify_one(); - return true; - } - -// Pop a copy of the front item in the queue into the given item ref. -// If the queue is empty, block the calling thread util there is item to pop. - void pop(T& item) - { - while (!pop(item, std::chrono::hours(1))); - } - -// Clear the queue - void clear() - { - { - std::unique_lock ul(_mutex); - queue_type().swap(_q); - } - _item_popped_cond.notify_all(); - } - -private: - size_type _max_size; - std::queue _q; - std::mutex _mutex; - std::condition_variable _item_pushed_cond; - std::condition_variable _item_popped_cond; - - inline bool is_full() - { - return _q.size() >= _max_size; - } - - inline bool is_empty() - { - return _q.size() == 0; - } -}; - -} -} From c215ee61045b697ccc4abd598342013c448f8fa9 Mon Sep 17 00:00:00 2001 From: gabime Date: Wed, 3 Dec 2014 17:49:52 +0200 Subject: [PATCH 041/120] bench fix --- example/bench.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/bench.cpp b/example/bench.cpp index 4e881685..d2401f82 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -138,7 +138,7 @@ void bench_mt(int howmany, std::shared_ptr log, int thread_count { int counter = ++msg_counter; if (counter > howmany) break; - log->info("Hello logger: msg number ") << counter; + log->info("Hello logger: msg number {}", counter); } })); } From 754cac85aca345bd66512c9f23f304817639ef25 Mon Sep 17 00:00:00 2001 From: gabime Date: Thu, 4 Dec 2014 11:48:53 +0200 Subject: [PATCH 042/120] defer localtime to formatter to improve async performace --- example/Makefile | 2 +- example/bench.cpp | 16 ++- include/spdlog/details/async_log_helper.h | 14 +- include/spdlog/details/line_logger.h | 2 +- include/spdlog/details/log_msg.h | 15 +- .../spdlog/details/pattern_formatter_impl.h | 131 +++++++++--------- 6 files changed, 88 insertions(+), 92 deletions(-) diff --git a/example/Makefile b/example/Makefile index 4208786a..746c7a9e 100644 --- a/example/Makefile +++ b/example/Makefile @@ -4,7 +4,7 @@ CXX_RELEASE_FLAGS = -O3 -flto CXX_DEBUG_FLAGS= -g -all: example bench +all: bench debug: example-debug bench-debug example: example.cpp diff --git a/example/bench.cpp b/example/bench.cpp index d2401f82..d9911808 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -64,12 +64,13 @@ int main(int argc, char* argv[]) if (argc > 2) threads = atoi(argv[2]); + cout << "*******************************************************************************\n"; cout << "Single thread, " << format(howmany) << " iterations, auto flush=" << auto_flush << endl; cout << "*******************************************************************************\n"; - auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st", file_size, rotating_files, auto_flush); - bench(howmany, rotating_st); + auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st", file_size, rotating_files, auto_flush); + bench(howmany, rotating_st); auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st", auto_flush); bench(howmany, daily_st); bench(howmany, spdlog::create("null_st")); @@ -92,8 +93,15 @@ int main(int argc, char* argv[]) spdlog::set_async_mode(howmany); - auto daily_st_async = spdlog::daily_logger_st("daily_async", "logs/daily_async", auto_flush); - bench_mt(howmany, daily_st_async, threads); + + for(int i = 0; i < 3; ++i) + { + auto as = spdlog::daily_logger_st("as", "logs/daily_async", auto_flush); + //bench_mt(howmany, spdlog::create("as"), threads); + bench_mt(howmany, as, threads); + as->stop(); + spdlog::drop("as"); + } spdlog::stop(); diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index 094162de..6fb51fa9 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -55,8 +55,7 @@ class async_log_helper { std::string logger_name; level::level_enum level; - log_clock::time_point time; - std::tm tm_time; + log_clock::time_point time; std::string raw_msg_str; async_msg() = default; @@ -64,21 +63,16 @@ class async_log_helper async_msg(const details::log_msg& m) : logger_name(m.logger_name), level(m.level), - time(m.time), - tm_time(m.tm_time), + time(m.time), raw_msg_str(m.raw.data(), m.raw.size()) - { - - } - + {} log_msg to_log_msg() { log_msg msg; msg.logger_name = logger_name; msg.level = level; - msg.time = time; - msg.tm_time = tm_time; + msg.time = time; msg.raw << raw_msg_str; return msg; } diff --git a/include/spdlog/details/line_logger.h b/include/spdlog/details/line_logger.h index 65251e50..091a48e5 100644 --- a/include/spdlog/details/line_logger.h +++ b/include/spdlog/details/line_logger.h @@ -65,7 +65,7 @@ public: { _log_msg.logger_name = _callback_logger->name(); _log_msg.time = log_clock::now(); - _log_msg.tm_time = details::os::localtime(log_clock::to_time_t(_log_msg.time)); + //_log_msg.tm_time = details::os::localtime(log_clock::to_time_t(_log_msg.time)); _callback_logger->_log_msg(_log_msg); } } diff --git a/include/spdlog/details/log_msg.h b/include/spdlog/details/log_msg.h index 00870bb2..b47e119e 100644 --- a/include/spdlog/details/log_msg.h +++ b/include/spdlog/details/log_msg.h @@ -37,8 +37,7 @@ struct log_msg log_msg(level::level_enum l): logger_name(), level(l), - time(), - tm_time(), + time(), raw(), formatted() {} @@ -46,9 +45,7 @@ struct log_msg log_msg(const log_msg& other) : logger_name(other.logger_name), level(other.level), - time(other.time), - tm_time(other.tm_time) - + time(other.time) { if (other.raw.size()) raw << fmt::BasicStringRef(other.raw.data(), other.raw.size()); @@ -60,8 +57,7 @@ struct log_msg log_msg(log_msg&& other) : logger_name(std::move(other.logger_name)), level(other.level), - time(std::move(other.time)), - tm_time(other.tm_time), + time(std::move(other.time)), raw(std::move(other.raw)), formatted(std::move(other.formatted)) { @@ -75,8 +71,7 @@ struct log_msg logger_name = std::move(other.logger_name); level = other.level; - time = std::move(other.time); - tm_time = other.tm_time; + time = std::move(other.time); raw = std::move(other.raw); formatted = std::move(other.formatted); other.clear(); @@ -95,7 +90,7 @@ struct log_msg std::string logger_name; level::level_enum level; log_clock::time_point time; - std::tm tm_time; + //std::tm tm_time; fmt::MemoryWriter raw; fmt::MemoryWriter formatted; }; diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index bc2cc6f0..81e0086c 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -43,7 +43,7 @@ class flag_formatter { public: virtual ~flag_formatter() {} - virtual void format(details::log_msg& msg) = 0; + virtual void format(details::log_msg& msg, const std::tm& tm_time) = 0; }; /////////////////////////////////////////////////////////////////////// @@ -53,7 +53,7 @@ namespace { class name_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm&) override { msg.formatted << msg.logger_name; } @@ -63,7 +63,7 @@ class name_formatter :public flag_formatter // log level appender class level_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm&) override { msg.formatted << level::to_str(msg.level); } @@ -87,9 +87,9 @@ static int to12h(const tm& t) static const std::string days[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; class a_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << days[msg.tm_time.tm_wday]; + msg.formatted << days[tm_time.tm_wday]; } }; @@ -97,9 +97,9 @@ class a_formatter :public flag_formatter static const std::string full_days[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; class A_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << full_days[msg.tm_time.tm_wday]; + msg.formatted << full_days[tm_time.tm_wday]; } }; @@ -107,9 +107,9 @@ class A_formatter :public flag_formatter static const std::string months[] { "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov", "Dec" }; class b_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted<< months[msg.tm_time.tm_mon]; + msg.formatted<< months[tm_time.tm_mon]; } }; @@ -117,9 +117,9 @@ class b_formatter :public flag_formatter static const std::string full_months[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; class B_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << full_months[msg.tm_time.tm_mon]; + msg.formatted << full_months[tm_time.tm_mon]; } }; @@ -139,15 +139,13 @@ static fmt::MemoryWriter& pad_n_join(fmt::MemoryWriter& w, int v1, int v2, int v } - - //Date and time representation (Thu Aug 23 15:35:46 2014) class c_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << days[msg.tm_time.tm_wday] << ' ' << months[msg.tm_time.tm_mon] << ' ' << msg.tm_time.tm_mday << ' '; - pad_n_join(msg.formatted, msg.tm_time.tm_hour, msg.tm_time.tm_min, msg.tm_time.tm_sec, ':') << ' ' << msg.tm_time.tm_year + 1900; + msg.formatted << days[tm_time.tm_wday] << ' ' << months[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' '; + pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900; } }; @@ -155,9 +153,9 @@ class c_formatter :public flag_formatter // year - 2 digit class C_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << fmt::pad(msg.tm_time.tm_year % 100, 2, '0'); + msg.formatted << fmt::pad(tm_time.tm_year % 100, 2, '0'); } }; @@ -166,9 +164,9 @@ class C_formatter :public flag_formatter // Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01 class D_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - pad_n_join(msg.formatted, msg.tm_time.tm_mon + 1, msg.tm_time.tm_mday, msg.tm_time.tm_year % 100, '/'); + pad_n_join(msg.formatted, tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_year % 100, '/'); } }; @@ -176,70 +174,70 @@ class D_formatter :public flag_formatter // year - 4 digit class Y_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << msg.tm_time.tm_year + 1900; + msg.formatted << tm_time.tm_year + 1900; } }; // month 1-12 class m_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << fmt::pad(msg.tm_time.tm_mon + 1, 2, '0'); + msg.formatted << fmt::pad(tm_time.tm_mon + 1, 2, '0'); } }; // day of month 1-31 class d_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << fmt::pad(msg.tm_time.tm_mday, 2, '0'); + msg.formatted << fmt::pad(tm_time.tm_mday, 2, '0'); } }; // hours in 24 format 0-23 class H_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << fmt::pad(msg.tm_time.tm_hour, 2, '0'); + msg.formatted << fmt::pad(tm_time.tm_hour, 2, '0'); } }; // hours in 12 format 1-12 class I_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << fmt::pad(to12h(msg.tm_time), 2, '0'); + msg.formatted << fmt::pad(to12h(tm_time), 2, '0'); } }; // ninutes 0-59 class M_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << fmt::pad(msg.tm_time.tm_min, 2, '0'); + msg.formatted << fmt::pad(tm_time.tm_min, 2, '0'); } }; // seconds 0-59 class S_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << fmt::pad(msg.tm_time.tm_sec, 2, '0'); + msg.formatted << fmt::pad(tm_time.tm_sec, 2, '0'); } }; // milliseconds class e_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm&) override { auto duration = msg.time.time_since_epoch(); auto millis = std::chrono::duration_cast(duration).count() % 1000; @@ -250,9 +248,9 @@ class e_formatter :public flag_formatter // AM/PM class p_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - msg.formatted << ampm(msg.tm_time); + msg.formatted << ampm(tm_time); } }; @@ -260,27 +258,27 @@ class p_formatter :public flag_formatter // 12 hour clock 02:55:02 pm class r_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - pad_n_join(msg.formatted, to12h(msg.tm_time), msg.tm_time.tm_min, msg.tm_time.tm_sec, ':') << ' ' << ampm(msg.tm_time); + pad_n_join(msg.formatted, to12h(tm_time), tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << ampm(tm_time); } }; // 24-hour HH:MM time, equivalent to %H:%M class R_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - pad_n_join(msg.formatted, msg.tm_time.tm_hour, msg.tm_time.tm_min, ':'); + pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, ':'); } }; // ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S class T_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { - pad_n_join(msg.formatted, msg.tm_time.tm_hour, msg.tm_time.tm_min, msg.tm_time.tm_sec, ':'); + pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':'); } }; @@ -295,14 +293,14 @@ public: z_formatter(const z_formatter&) = delete; z_formatter& operator=(const z_formatter&) = delete; - void format(log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { #ifdef _WIN32 - int total_minutes = get_cached_offset(msg); + int total_minutes = get_cached_offset(msg, tm_time); #else // No need to chache under gcc, // it is very fast (already stored in tm.tm_gmtoff) - int total_minutes = os::utc_minutes_offset(msg.tm_time); + int total_minutes = os::utc_minutes_offset(tm_time); #endif int h = total_minutes / 60; @@ -316,13 +314,13 @@ private: int _offset_minutes; std::mutex _mutex; - int get_cached_offset(const log_msg& msg) + int get_cached_offset(const log_msg& msg, const std::tm& tm_time) { using namespace std::chrono; std::lock_guard l(_mutex); if (msg.time - _last_update >= cache_refresh) { - _offset_minutes = os::utc_minutes_offset(msg.tm_time); + _offset_minutes = os::utc_minutes_offset(tm_time); _last_update = msg.time; } return _offset_minutes; @@ -334,7 +332,7 @@ private: //Thread id class t_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm&) override { msg.formatted << std::hash()(std::this_thread::get_id()); } @@ -343,7 +341,7 @@ class t_formatter :public flag_formatter class v_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm&) override { msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size()); } @@ -354,7 +352,7 @@ class ch_formatter :public flag_formatter public: explicit ch_formatter(char ch) : _ch(ch) {} - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm&) override { msg.formatted << _ch; } @@ -373,7 +371,7 @@ public: { _str += ch; } - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm&) override { msg.formatted << _str; } @@ -385,31 +383,31 @@ private: // pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v class full_formatter :public flag_formatter { - void format(details::log_msg& msg) override + void format(details::log_msg& msg, const std::tm& tm_time) override { auto duration = msg.time.time_since_epoch(); auto millis = std::chrono::duration_cast(duration).count() % 1000; /* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads), msg.formatted.write("[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} ", - msg.tm_time.tm_year + 1900, - msg.tm_time.tm_mon + 1, - msg.tm_time.tm_mday, - msg.tm_time.tm_hour, - msg.tm_time.tm_min, - msg.tm_time.tm_sec, + tm_time.tm_year + 1900, + tm_time.tm_mon + 1, + tm_time.tm_mday, + tm_time.tm_hour, + tm_time.tm_min, + tm_time.tm_sec, static_cast(millis), msg.logger_name, level::to_str(msg.level), msg.raw.str());*/ // Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads) - msg.formatted << '[' << static_cast(msg.tm_time.tm_year + 1900) << '-' - << fmt::pad(static_cast(msg.tm_time.tm_mon + 1), 2, '0') << '-' - << fmt::pad(static_cast(msg.tm_time.tm_mday), 2, '0') << ' ' - << fmt::pad(static_cast(msg.tm_time.tm_hour), 2, '0') << ':' - << fmt::pad(static_cast(msg.tm_time.tm_min), 2, '0') << ':' - << fmt::pad(static_cast(msg.tm_time.tm_sec), 2, '0') << '.' + msg.formatted << '[' << static_cast(tm_time.tm_year + 1900) << '-' + << fmt::pad(static_cast(tm_time.tm_mon + 1), 2, '0') << '-' + << fmt::pad(static_cast(tm_time.tm_mday), 2, '0') << ' ' + << fmt::pad(static_cast(tm_time.tm_hour), 2, '0') << ':' + << fmt::pad(static_cast(tm_time.tm_min), 2, '0') << ':' + << fmt::pad(static_cast(tm_time.tm_sec), 2, '0') << '.' << fmt::pad(static_cast(millis), 3, '0') << "] "; msg.formatted << '[' << msg.logger_name << "] [" << level::to_str(msg.level) << "] "; @@ -576,9 +574,10 @@ inline void spdlog::pattern_formatter::format(details::log_msg& msg) { try { + auto tm_time = details::os::localtime(log_clock::to_time_t(msg.time)); for (auto &f : _formatters) { - f->format(msg); + f->format(msg, tm_time); } //write eol msg.formatted << details::os::eol(); From 52d02af950633455736a86fad4dde74476d9cfe8 Mon Sep 17 00:00:00 2001 From: gabime Date: Fri, 5 Dec 2014 20:25:04 +0200 Subject: [PATCH 043/120] using mpmc bounded q for async and many async optimizations --- include/spdlog/details/async_log_helper.h | 127 ++++++++----- include/spdlog/details/format.h | 4 +- include/spdlog/details/line_logger.h | 1 - include/spdlog/details/log_msg.h | 9 +- include/spdlog/details/mpmc_bounded_q.h | 175 ++++++++++++++++++ .../spdlog/details/pattern_formatter_impl.h | 4 +- include/spdlog/sinks/ostream_sink.h | 2 +- 7 files changed, 261 insertions(+), 61 deletions(-) create mode 100644 include/spdlog/details/mpmc_bounded_q.h diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index 6fb51fa9..87aa709c 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -33,15 +33,14 @@ #pragma once -#include #include +#include #include #include "../sinks/sink.h" -#include "../logger.h" -#include "../details/mpcs_q.h" -#include "../details/log_msg.h" -#include "../details/format.h" +#include "./mpmc_bounded_q.h" +#include "./log_msg.h" +#include "./format.h" namespace spdlog @@ -49,42 +48,67 @@ namespace spdlog namespace details { + class async_log_helper { + // Async msg to move to/from the queue + // Movable only. should never be copied struct async_msg { std::string logger_name; level::level_enum level; - log_clock::time_point time; - std::string raw_msg_str; + log_clock::time_point time; + std::string txt; - async_msg() = default; + async_msg() = default; + ~async_msg() = default; + + async_msg(const async_msg&) = delete; + async_msg& operator=(async_msg& other) = delete; async_msg(const details::log_msg& m) : logger_name(m.logger_name), level(m.level), - time(m.time), - raw_msg_str(m.raw.data(), m.raw.size()) + time(m.time), + txt(m.raw.data(), m.raw.size()) {} - log_msg to_log_msg() + async_msg(async_msg&& other) : + logger_name(std::move(other.logger_name)), + level(std::move(other.level)), + time(std::move(other.time)), + txt(std::move(other.txt)) + {} + + async_msg& operator=(async_msg&& other) + { + logger_name = std::move(other.logger_name); + level = other.level; + time = std::move(other.time); + txt = std::move(other.txt); + return *this; + } + + + void fill_log_msg(log_msg &msg) { - log_msg msg; + msg.clear(); msg.logger_name = logger_name; msg.level = level; - msg.time = time; - msg.raw << raw_msg_str; - return msg; + msg.time = time; + msg.raw << txt; } }; public: - using q_type = details::mpsc_q < std::unique_ptr >; + using item_type = async_msg; + using q_type = details::mpmc_bounded_queue; + using clock = std::chrono::steady_clock; - explicit async_log_helper(size_t max_queue_size); + explicit async_log_helper(size_t queue_size); void log(const details::log_msg& msg); //Stop logging and join the back thread @@ -97,8 +121,6 @@ public: - - private: std::vector> _sinks; std::atomic _active; @@ -113,18 +135,19 @@ private: formatter_ptr _formatter; - // will throw last back thread exception or if worker hread no active - void _push_sentry(); + // will throw last worker thread exception or if worker thread no active + void throw_if_bad_worker(); // worker thread loop - void _thread_loop(); + void thread_loop(); // guess how much to sleep if queue is empty/full using last succesful op time as hint - static void _sleep_or_yield(const clock::time_point& last_op_time); + static void sleep_or_yield(const clock::time_point& last_op_time); // clear all remaining messages(if any), stop the _worker_thread and join it - void _join(); + void join_worker(); + }; } @@ -133,57 +156,60 @@ private: /////////////////////////////////////////////////////////////////////////////// // async_sink class implementation /////////////////////////////////////////////////////////////////////////////// -inline spdlog::details::async_log_helper::async_log_helper(size_t max_queue_size) +inline spdlog::details::async_log_helper::async_log_helper(size_t queue_size) :_sinks(), _active(true), - _q(max_queue_size), - _worker_thread(&async_log_helper::_thread_loop, this) + _q(queue_size), + _worker_thread(&async_log_helper::thread_loop, this) {} inline spdlog::details::async_log_helper::~async_log_helper() { - _join(); + join_worker(); } //Try to push and block until succeeded inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) { - _push_sentry(); + throw_if_bad_worker(); //Only if queue is full, enter wait loop - if (!_q.push(std::unique_ptr < async_msg >(new async_msg(msg)))) - { + //if (!_q.push(std::unique_ptr < async_msg >(new async_msg(msg)))) + //async_msg* as = new async_msg(msg); + //if (!_q.enqueue(std::unique_ptr(new async_msg(msg)))) + if (!_q.enqueue(std::move(async_msg(msg)))) + { auto last_op_time = clock::now(); do { - _sleep_or_yield(last_op_time); + sleep_or_yield(last_op_time); } - while (!_q.push(std::unique_ptr < async_msg >(new async_msg(msg)))); + while (!_q.enqueue(std::move(async_msg(msg)))); } + } -inline void spdlog::details::async_log_helper::_thread_loop() +inline void spdlog::details::async_log_helper::thread_loop() { + log_msg popped_log_msg; clock::time_point last_pop = clock::now(); + size_t counter = 0; while (_active) { q_type::item_type popped_msg; - if (_q.pop(popped_msg)) - { - + if (_q.dequeue(popped_msg)) + { last_pop = clock::now(); try { - details::log_msg log_msg = popped_msg->to_log_msg(); - - _formatter->format(log_msg); + popped_msg.fill_log_msg(popped_log_msg); + _formatter->format(popped_log_msg); for (auto &s : _sinks) - s->log(log_msg); - + s->log(popped_log_msg); } catch (const std::exception& ex) { @@ -196,8 +222,8 @@ inline void spdlog::details::async_log_helper::_thread_loop() } // sleep or yield if queue is empty. else - { - _sleep_or_yield(last_pop); + { + sleep_or_yield(last_pop); } } } @@ -226,6 +252,7 @@ inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_f inline void spdlog::details::async_log_helper::shutdown(const log_clock::duration& timeout) { + /* if (timeout > std::chrono::milliseconds::zero()) { auto until = log_clock::now() + timeout; @@ -234,12 +261,13 @@ inline void spdlog::details::async_log_helper::shutdown(const log_clock::duratio std::this_thread::sleep_for(std::chrono::milliseconds(5)); } } - _join(); + join_worker(); + */ } // Sleep or yield using the time passed since last message as a hint -inline void spdlog::details::async_log_helper::_sleep_or_yield(const clock::time_point& last_op_time) +inline void spdlog::details::async_log_helper::sleep_or_yield(const clock::time_point& last_op_time) { using std::chrono::milliseconds; using std::this_thread::sleep_for; @@ -255,7 +283,8 @@ inline void spdlog::details::async_log_helper::_sleep_or_yield(const clock::time yield(); } -inline void spdlog::details::async_log_helper::_push_sentry() +//throw if the worker thread threw an exception or not active +inline void spdlog::details::async_log_helper::throw_if_bad_worker() { if (_last_workerthread_ex) { @@ -264,11 +293,11 @@ inline void spdlog::details::async_log_helper::_push_sentry() throw *ex; } if (!_active) - throw(spdlog_ex("async_sink not active")); + throw(spdlog_ex("async logger is not active")); } -inline void spdlog::details::async_log_helper::_join() +inline void spdlog::details::async_log_helper::join_worker() { _active = false; if (_worker_thread.joinable()) diff --git a/include/spdlog/details/format.h b/include/spdlog/details/format.h index c90e9212..a9b51c21 100644 --- a/include/spdlog/details/format.h +++ b/include/spdlog/details/format.h @@ -1050,7 +1050,7 @@ public: { default: assert(false); - // Fall through. + // Fall through. case Arg::INT: return FMT_DISPATCH(visit_int(arg.int_value)); case Arg::UINT: @@ -2219,7 +2219,7 @@ void BasicWriter::write_double( // MSVC's printf doesn't support 'F'. type = 'f'; #endif - // Fall through. + // Fall through. case 'E': case 'G': case 'A': diff --git a/include/spdlog/details/line_logger.h b/include/spdlog/details/line_logger.h index 091a48e5..2a2bd2af 100644 --- a/include/spdlog/details/line_logger.h +++ b/include/spdlog/details/line_logger.h @@ -65,7 +65,6 @@ public: { _log_msg.logger_name = _callback_logger->name(); _log_msg.time = log_clock::now(); - //_log_msg.tm_time = details::os::localtime(log_clock::to_time_t(_log_msg.time)); _callback_logger->_log_msg(_log_msg); } } diff --git a/include/spdlog/details/log_msg.h b/include/spdlog/details/log_msg.h index b47e119e..abd9bd41 100644 --- a/include/spdlog/details/log_msg.h +++ b/include/spdlog/details/log_msg.h @@ -37,7 +37,7 @@ struct log_msg log_msg(level::level_enum l): logger_name(), level(l), - time(), + time(), raw(), formatted() {} @@ -57,7 +57,7 @@ struct log_msg log_msg(log_msg&& other) : logger_name(std::move(other.logger_name)), level(other.level), - time(std::move(other.time)), + time(std::move(other.time)), raw(std::move(other.raw)), formatted(std::move(other.formatted)) { @@ -71,15 +71,13 @@ struct log_msg logger_name = std::move(other.logger_name); level = other.level; - time = std::move(other.time); + time = std::move(other.time); raw = std::move(other.raw); formatted = std::move(other.formatted); other.clear(); return *this; } - - void clear() { level = level::OFF; @@ -90,7 +88,6 @@ struct log_msg std::string logger_name; level::level_enum level; log_clock::time_point time; - //std::tm tm_time; fmt::MemoryWriter raw; fmt::MemoryWriter formatted; }; diff --git a/include/spdlog/details/mpmc_bounded_q.h b/include/spdlog/details/mpmc_bounded_q.h new file mode 100644 index 00000000..53dfd108 --- /dev/null +++ b/include/spdlog/details/mpmc_bounded_q.h @@ -0,0 +1,175 @@ +/* +A modified version of Bounded MPMC queue by Dmitry Vyukov. + +Original code from: +http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue + +licensed by Dmitry Vyukov under the terms below: + +Simplified BSD license + +Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved. +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list +of conditions and the following disclaimer in the documentation and/or other materials +provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those of the authors and +should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov. +*/ + +/* +The code in its current form adds the license below: + +spdlog - an extremely fast and easy to use c++11 logging library. +Copyright (c) 2014 Gabi Melman. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#pragma once + +#include +#include "../common.h" + +namespace spdlog +{ +namespace details +{ + +template +class mpmc_bounded_queue +{ +public: + + using item_type = T; + mpmc_bounded_queue(size_t buffer_size) + : buffer_(new cell_t [buffer_size]), + buffer_mask_(buffer_size - 1) + { + //queue size must be power of two + if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0))) + throw spdlog_ex("async logger queue size must be power of two"); + + for (size_t i = 0; i != buffer_size; i += 1) + buffer_[i].sequence_.store(i, std::memory_order_relaxed); + enqueue_pos_.store(0, std::memory_order_relaxed); + dequeue_pos_.store(0, std::memory_order_relaxed); + } + + ~mpmc_bounded_queue() + { + delete [] buffer_; + } + + + bool enqueue(T&& data) + { + cell_t* cell; + size_t pos = enqueue_pos_.load(std::memory_order_relaxed); + for (;;) + { + cell = &buffer_[pos & buffer_mask_]; + size_t seq = cell->sequence_.load(std::memory_order_acquire); + intptr_t dif = (intptr_t)seq - (intptr_t)pos; + if (dif == 0) + { + if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) + break; + } + else if (dif < 0) + { + return false; + } + else + { + pos = enqueue_pos_.load(std::memory_order_relaxed); + } + } + cell->data_ = std::move(data); + cell->sequence_.store(pos + 1, std::memory_order_release); + return true; + } + + bool dequeue(T& data) + { + cell_t* cell; + size_t pos = dequeue_pos_.load(std::memory_order_relaxed); + for (;;) + { + cell = &buffer_[pos & buffer_mask_]; + size_t seq = + cell->sequence_.load(std::memory_order_acquire); + intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1); + if (dif == 0) + { + if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) + break; + } + else if (dif < 0) + return false; + else + pos = dequeue_pos_.load(std::memory_order_relaxed); + } + data = std::move(cell->data_); + cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release); + return true; + } + +private: + struct cell_t + { + std::atomic sequence_; + T data_; + }; + + static size_t const cacheline_size = 64; + typedef char cacheline_pad_t [cacheline_size]; + + cacheline_pad_t pad0_; + cell_t* const buffer_; + size_t const buffer_mask_; + cacheline_pad_t pad1_; + std::atomic enqueue_pos_; + cacheline_pad_t pad2_; + std::atomic dequeue_pos_; + cacheline_pad_t pad3_; + + mpmc_bounded_queue(mpmc_bounded_queue const&); + void operator = (mpmc_bounded_queue const&); +}; + +} // ns details +} // ns spdlog diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index 81e0086c..0d36da0d 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -458,7 +458,7 @@ inline void spdlog::pattern_formatter::handle_flag(char flag) { switch (flag) { - // logger name + // logger name case 'n': _formatters.push_back(std::unique_ptr(new details::name_formatter())); break; @@ -574,7 +574,7 @@ inline void spdlog::pattern_formatter::format(details::log_msg& msg) { try { - auto tm_time = details::os::localtime(log_clock::to_time_t(msg.time)); + auto tm_time = details::os::localtime(log_clock::to_time_t(msg.time)); for (auto &f : _formatters) { f->format(msg, tm_time); diff --git a/include/spdlog/sinks/ostream_sink.h b/include/spdlog/sinks/ostream_sink.h index 378863c9..68ecec87 100644 --- a/include/spdlog/sinks/ostream_sink.h +++ b/include/spdlog/sinks/ostream_sink.h @@ -24,7 +24,7 @@ #pragma once -#include +#include #include #include From 6255180e99b67e927d7e845ebdde3a3dfb6392fa Mon Sep 17 00:00:00 2001 From: gabime Date: Fri, 5 Dec 2014 20:59:38 +0200 Subject: [PATCH 044/120] small fixes in async_helper --- include/spdlog/details/async_log_helper.h | 54 ++++++++-------------- include/spdlog/details/async_logger_impl.h | 7 +-- 2 files changed, 20 insertions(+), 41 deletions(-) diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index 87aa709c..4d5e1513 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -37,6 +37,7 @@ #include #include +#include "../common.h" #include "../sinks/sink.h" #include "./mpmc_bounded_q.h" #include "./log_msg.h" @@ -108,38 +109,35 @@ public: using clock = std::chrono::steady_clock; - explicit async_log_helper(size_t queue_size); + async_log_helper(formatter_ptr formatter, const std::vector& sinks, size_t queue_size); void log(const details::log_msg& msg); //Stop logging and join the back thread - ~async_log_helper(); - void add_sink(sink_ptr sink); - void remove_sink(sink_ptr sink_ptr); + ~async_log_helper(); void set_formatter(formatter_ptr); //Wait to remaining items (if any) in the queue to be written and shutdown void shutdown(const log_clock::duration& timeout); -private: - std::vector> _sinks; - std::atomic _active; +private: + std::atomic _active; + formatter_ptr _formatter; + std::vector> _sinks; q_type _q; - std::thread _worker_thread; - std::mutex _mutex; + std::thread _worker_thread; // last exception thrown from the worker thread std::shared_ptr _last_workerthread_ex; + - // worker thread formatter - formatter_ptr _formatter; // will throw last worker thread exception or if worker thread no active void throw_if_bad_worker(); // worker thread loop - void thread_loop(); + void worker_loop(); // guess how much to sleep if queue is empty/full using last succesful op time as hint static void sleep_or_yield(const clock::time_point& last_op_time); @@ -156,11 +154,12 @@ private: /////////////////////////////////////////////////////////////////////////////// // async_sink class implementation /////////////////////////////////////////////////////////////////////////////// -inline spdlog::details::async_log_helper::async_log_helper(size_t queue_size) - :_sinks(), - _active(true), +inline spdlog::details::async_log_helper::async_log_helper(formatter_ptr formatter, const std::vector& sinks, size_t queue_size): + _active(false), + _formatter(formatter), + _sinks(sinks), _q(queue_size), - _worker_thread(&async_log_helper::thread_loop, this) + _worker_thread(&async_log_helper::worker_loop, this) {} inline spdlog::details::async_log_helper::~async_log_helper() @@ -190,12 +189,11 @@ inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) } -inline void spdlog::details::async_log_helper::thread_loop() +inline void spdlog::details::async_log_helper::worker_loop() { - log_msg popped_log_msg; - clock::time_point last_pop = clock::now(); - size_t counter = 0; + clock::time_point last_pop = clock::now(); + _active = true; while (_active) { q_type::item_type popped_msg; @@ -229,27 +227,11 @@ inline void spdlog::details::async_log_helper::thread_loop() } -inline void spdlog::details::async_log_helper::add_sink(spdlog::sink_ptr s) -{ - std::lock_guard guard(_mutex); - _sinks.push_back(s); -} - - -inline void spdlog::details::async_log_helper::remove_sink(spdlog::sink_ptr s) -{ - std::lock_guard guard(_mutex); - _sinks.erase(std::remove(_sinks.begin(), _sinks.end(), s), _sinks.end()); -} - - inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter) { _formatter = msg_formatter; } - - inline void spdlog::details::async_log_helper::shutdown(const log_clock::duration& timeout) { /* diff --git a/include/spdlog/details/async_logger_impl.h b/include/spdlog/details/async_logger_impl.h index 963135d3..03a09f9c 100644 --- a/include/spdlog/details/async_logger_impl.h +++ b/include/spdlog/details/async_logger_impl.h @@ -37,11 +37,8 @@ template inline spdlog::async_logger::async_logger(const std::string& logger_name, const It& begin, const It& end, size_t queue_size, const log_clock::duration& shutdown_duration) : logger(logger_name, begin, end), _shutdown_duration(shutdown_duration), - _async_log_helper(new details::async_log_helper(queue_size)) -{ - _async_log_helper->set_formatter(_formatter); - for (auto &s : _sinks) - _async_log_helper->add_sink(s); + _async_log_helper(new details::async_log_helper(_formatter, _sinks, queue_size)) +{ } inline spdlog::async_logger::async_logger(const std::string& logger_name, sinks_init_list sinks, size_t queue_size, const log_clock::duration& shutdown_duration) : From 9feb5fbaf0ba1f255f3b4269729a630ea1973431 Mon Sep 17 00:00:00 2001 From: gabime Date: Fri, 5 Dec 2014 21:44:30 +0200 Subject: [PATCH 045/120] disable Wshadow in gcc --- include/spdlog/details/format.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/include/spdlog/details/format.h b/include/spdlog/details/format.h index a9b51c21..82f65058 100644 --- a/include/spdlog/details/format.h +++ b/include/spdlog/details/format.h @@ -45,13 +45,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif #ifdef __GNUC__ +// Ignore shadow warnings +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wshadow" + # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) # define FMT_GCC_EXTENSION __extension__ // Disable warning about "long long" which is sometimes reported even // when using __extension__. # if FMT_GCC_VERSION >= 406 # pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wshadow" # pragma GCC diagnostic ignored "-Wlong-long" # endif #else @@ -2861,8 +2864,12 @@ FMT_VARIADIC(int, fprintf, std::FILE *, StringRef) # pragma GCC diagnostic pop #endif + #define FMT_HEADER_ONLY # include "format.cc" +#ifdef __GNUC__ +# pragma GCC diagnostic pop //pop -Wshadow warnings ignore +#endif #endif // FMT_FORMAT_H_ From d37bded99485d2959ca932c1d9ceaa99304d77e3 Mon Sep 17 00:00:00 2001 From: gabi Date: Sun, 7 Dec 2014 04:18:07 +0200 Subject: [PATCH 046/120] More improvements to the async logger --- include/spdlog/async_logger.h | 7 +- include/spdlog/details/async_log_helper.h | 211 ++++++++++----------- include/spdlog/details/async_logger_impl.h | 14 +- include/spdlog/details/registry.h | 6 +- include/spdlog/details/spdlog_impl.h | 4 +- include/spdlog/spdlog.h | 3 +- 6 files changed, 114 insertions(+), 131 deletions(-) diff --git a/include/spdlog/async_logger.h b/include/spdlog/async_logger.h index 943a868a..7438d156 100644 --- a/include/spdlog/async_logger.h +++ b/include/spdlog/async_logger.h @@ -46,9 +46,9 @@ class async_logger :public logger { public: template - async_logger(const std::string& name, const It& begin, const It& end, size_t queue_size, const log_clock::duration& shutdown_duration); - async_logger(const std::string& logger_name, sinks_init_list sinks, size_t queue_size, const log_clock::duration& shutdown_duration); - async_logger(const std::string& logger_name, sink_ptr single_sink, size_t queue_size, const log_clock::duration& shutdown_duration); + async_logger(const std::string& name, const It& begin, const It& end, size_t queue_size); + async_logger(const std::string& logger_name, sinks_init_list sinks, size_t queue_size); + async_logger(const std::string& logger_name, sink_ptr single_sink, size_t queue_size); protected: @@ -58,7 +58,6 @@ protected: void _stop() override; private: - log_clock::duration _shutdown_duration; std::unique_ptr _async_log_helper; }; } diff --git a/include/spdlog/details/async_log_helper.h b/include/spdlog/details/async_log_helper.h index 4d5e1513..af6efa26 100644 --- a/include/spdlog/details/async_log_helper.h +++ b/include/spdlog/details/async_log_helper.h @@ -52,8 +52,8 @@ namespace details class async_log_helper { - // Async msg to move to/from the queue - // Movable only. should never be copied + // Async msg to move to/from the queue + // Movable only. should never be copied struct async_msg { std::string logger_name; @@ -61,11 +61,11 @@ class async_log_helper log_clock::time_point time; std::string txt; - async_msg() = default; - ~async_msg() = default; + async_msg() = default; + ~async_msg() = default; - async_msg(const async_msg&) = delete; - async_msg& operator=(async_msg& other) = delete; + async_msg(const async_msg&) = delete; + async_msg& operator=(async_msg& other) = delete; async_msg(const details::log_msg& m) : logger_name(m.logger_name), @@ -74,26 +74,26 @@ class async_log_helper txt(m.raw.data(), m.raw.size()) {} - async_msg(async_msg&& other) : + async_msg(async_msg&& other) : logger_name(std::move(other.logger_name)), level(std::move(other.level)), time(std::move(other.time)), txt(std::move(other.txt)) {} - async_msg& operator=(async_msg&& other) - { - logger_name = std::move(other.logger_name); - level = other.level; - time = std::move(other.time); - txt = std::move(other.txt); - return *this; - } + async_msg& operator=(async_msg&& other) + { + logger_name = std::move(other.logger_name); + level = other.level; + time = std::move(other.time); + txt = std::move(other.txt); + return *this; + } void fill_log_msg(log_msg &msg) { - msg.clear(); + msg.clear(); msg.logger_name = logger_name; msg.level = level; msg.time = time; @@ -103,42 +103,41 @@ class async_log_helper public: - using item_type = async_msg; + using item_type = async_msg; using q_type = details::mpmc_bounded_queue; using clock = std::chrono::steady_clock; - async_log_helper(formatter_ptr formatter, const std::vector& sinks, size_t queue_size); + async_log_helper(formatter_ptr formatter, const std::vector& sinks, size_t queue_size); void log(const details::log_msg& msg); //Stop logging and join the back thread - ~async_log_helper(); + ~async_log_helper(); void set_formatter(formatter_ptr); - //Wait to remaining items (if any) in the queue to be written and shutdown - void shutdown(const log_clock::duration& timeout); - -private: - std::atomic _active; - formatter_ptr _formatter; - std::vector> _sinks; +private: + std::atomic _active; + formatter_ptr _formatter; + std::vector> _sinks; q_type _q; - std::thread _worker_thread; + std::thread _worker_thread; // last exception thrown from the worker thread std::shared_ptr _last_workerthread_ex; - - - // will throw last worker thread exception or if worker thread no active + // throw last worker thread exception or if worker thread is not active void throw_if_bad_worker(); - // worker thread loop + // worker thread main loop void worker_loop(); + //pop next message from the queue and process it + //return true if a message was available (queue was not empty), will set the last_pop to the pop time + bool process_next_msg(clock::time_point& last_pop); + // guess how much to sleep if queue is empty/full using last succesful op time as hint static void sleep_or_yield(const clock::time_point& last_op_time); @@ -146,7 +145,6 @@ private: // clear all remaining messages(if any), stop the _worker_thread and join it void join_worker(); - }; } } @@ -155,11 +153,11 @@ private: // async_sink class implementation /////////////////////////////////////////////////////////////////////////////// inline spdlog::details::async_log_helper::async_log_helper(formatter_ptr formatter, const std::vector& sinks, size_t queue_size): - _active(false), - _formatter(formatter), - _sinks(sinks), - _q(queue_size), - _worker_thread(&async_log_helper::worker_loop, this) + _active(true), + _formatter(formatter), + _sinks(sinks), + _q(queue_size), + _worker_thread(&async_log_helper::worker_loop, this) {} inline spdlog::details::async_log_helper::~async_log_helper() @@ -172,97 +170,92 @@ inline spdlog::details::async_log_helper::~async_log_helper() inline void spdlog::details::async_log_helper::log(const details::log_msg& msg) { throw_if_bad_worker(); - - //Only if queue is full, enter wait loop - //if (!_q.push(std::unique_ptr < async_msg >(new async_msg(msg)))) - //async_msg* as = new async_msg(msg); - //if (!_q.enqueue(std::unique_ptr(new async_msg(msg)))) - if (!_q.enqueue(std::move(async_msg(msg)))) - { + async_msg new_msg(msg); + if (!_q.enqueue(std::move(new_msg))) + { auto last_op_time = clock::now(); do { sleep_or_yield(last_op_time); } - while (!_q.enqueue(std::move(async_msg(msg)))); + while (!_q.enqueue(std::move(new_msg))); } - + } inline void spdlog::details::async_log_helper::worker_loop() { - log_msg popped_log_msg; - clock::time_point last_pop = clock::now(); - _active = true; + clock::time_point last_pop = clock::now(); while (_active) { - q_type::item_type popped_msg; - - if (_q.dequeue(popped_msg)) - { - last_pop = clock::now(); - - try - { - popped_msg.fill_log_msg(popped_log_msg); - _formatter->format(popped_log_msg); - for (auto &s : _sinks) - s->log(popped_log_msg); - } - catch (const std::exception& ex) - { - _last_workerthread_ex = std::make_shared(ex.what()); - } - catch (...) - { - _last_workerthread_ex = std::make_shared("Unknown exception"); - } - } - // sleep or yield if queue is empty. - else - { - sleep_or_yield(last_pop); - } + //Dont die if there are still messages in the q to process + while(process_next_msg(last_pop)); } } +inline bool spdlog::details::async_log_helper::process_next_msg(clock::time_point& last_pop) +{ + + async_msg incoming_async_msg; + log_msg incoming_log_msg; + + if (_q.dequeue(incoming_async_msg)) + { + last_pop = clock::now(); + try + { + incoming_async_msg.fill_log_msg(incoming_log_msg); + _formatter->format(incoming_log_msg); + for (auto &s : _sinks) + s->log(incoming_log_msg); + } + catch (const std::exception& ex) + { + _last_workerthread_ex = std::make_shared(std::string("async_logger worker thread exception: ") + ex.what()); + } + catch (...) + { + _last_workerthread_ex = std::make_shared("async_logger worker thread exception"); + } + return true; + } + // sleep or yield if queue is empty. + else + { + sleep_or_yield(last_pop); + return false; + } +} + inline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter) { _formatter = msg_formatter; } -inline void spdlog::details::async_log_helper::shutdown(const log_clock::duration& timeout) -{ - /* - if (timeout > std::chrono::milliseconds::zero()) - { - auto until = log_clock::now() + timeout; - while (_q.approx_size() > 0 && log_clock::now() < until) - { - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - } - join_worker(); - */ -} - -// Sleep or yield using the time passed since last message as a hint +// Sleep,yield or return immediatly using the time passed since last message as a hint inline void spdlog::details::async_log_helper::sleep_or_yield(const clock::time_point& last_op_time) { using std::chrono::milliseconds; - using std::this_thread::sleep_for; - using std::this_thread::yield; + using namespace std::this_thread; - clock::duration sleep_duration; auto time_since_op = clock::now() - last_op_time; - if (time_since_op > milliseconds(1000)) - sleep_for(milliseconds(500)); - else if (time_since_op > milliseconds(1)) - sleep_for(time_since_op / 2); - else - yield(); + + //spin upto 1 ms + if (time_since_op <= milliseconds(1)) + return; + + // yield upto 10ms + if (time_since_op <= milliseconds(10)) + return yield(); + + + // sleep for half of duration since last op + if (time_since_op <= milliseconds(100)) + return sleep_for(time_since_op / 2); + + return sleep_for(milliseconds(100)); } //throw if the worker thread threw an exception or not active @@ -282,17 +275,13 @@ inline void spdlog::details::async_log_helper::throw_if_bad_worker() inline void spdlog::details::async_log_helper::join_worker() { _active = false; - if (_worker_thread.joinable()) - { - try - { - _worker_thread.join(); - } - catch (const std::system_error&) //Dont crash if thread not joinable - { - } - } + try + { + _worker_thread.join(); + } + catch (const std::system_error&) //Dont crash if thread not joinable + {} } diff --git a/include/spdlog/details/async_logger_impl.h b/include/spdlog/details/async_logger_impl.h index 03a09f9c..0b3022ec 100644 --- a/include/spdlog/details/async_logger_impl.h +++ b/include/spdlog/details/async_logger_impl.h @@ -34,18 +34,17 @@ template -inline spdlog::async_logger::async_logger(const std::string& logger_name, const It& begin, const It& end, size_t queue_size, const log_clock::duration& shutdown_duration) : +inline spdlog::async_logger::async_logger(const std::string& logger_name, const It& begin, const It& end, size_t queue_size) : logger(logger_name, begin, end), - _shutdown_duration(shutdown_duration), _async_log_helper(new details::async_log_helper(_formatter, _sinks, queue_size)) -{ +{ } -inline spdlog::async_logger::async_logger(const std::string& logger_name, sinks_init_list sinks, size_t queue_size, const log_clock::duration& shutdown_duration) : - async_logger(logger_name, sinks.begin(), sinks.end(), queue_size, shutdown_duration) {} +inline spdlog::async_logger::async_logger(const std::string& logger_name, sinks_init_list sinks, size_t queue_size) : + async_logger(logger_name, sinks.begin(), sinks.end(), queue_size) {} -inline spdlog::async_logger::async_logger(const std::string& logger_name, sink_ptr single_sink, size_t queue_size, const log_clock::duration& shutdown_duration) : - async_logger(logger_name, { single_sink }, queue_size, shutdown_duration) {} +inline spdlog::async_logger::async_logger(const std::string& logger_name, sink_ptr single_sink, size_t queue_size) : + async_logger(logger_name, { single_sink }, queue_size) {} inline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter) @@ -65,7 +64,6 @@ inline void spdlog::async_logger::_set_pattern(const std::string& pattern) inline void spdlog::async_logger::_stop() { set_level(level::OFF); - _async_log_helper->shutdown(_shutdown_duration); } inline void spdlog::async_logger::_log_msg(details::log_msg& msg) diff --git a/include/spdlog/details/registry.h b/include/spdlog/details/registry.h index ee6c7d95..0e24ba26 100644 --- a/include/spdlog/details/registry.h +++ b/include/spdlog/details/registry.h @@ -61,7 +61,7 @@ public: return found->second; std::shared_ptr new_logger; if (_async_mode) - new_logger = std::make_shared(logger_name, sinks_begin, sinks_end, _async_q_size, _async_shutdown_duration); + new_logger = std::make_shared(logger_name, sinks_begin, sinks_end, _async_q_size); else new_logger = std::make_shared(logger_name, sinks_begin, sinks_end); @@ -114,12 +114,11 @@ public: l.second->set_level(log_level); } - void set_async_mode(size_t q_size, const log_clock::duration& shutdown_duration) + void set_async_mode(size_t q_size) { std::lock_guard lock(_mutex); _async_mode = true; _async_q_size = q_size; - _async_shutdown_duration = shutdown_duration; } void set_sync_mode() @@ -153,7 +152,6 @@ private: level::level_enum _level = level::INFO; bool _async_mode = false; size_t _async_q_size = 0; - log_clock::duration _async_shutdown_duration; }; } } diff --git a/include/spdlog/details/spdlog_impl.h b/include/spdlog/details/spdlog_impl.h index a3a76111..6b559064 100644 --- a/include/spdlog/details/spdlog_impl.h +++ b/include/spdlog/details/spdlog_impl.h @@ -133,9 +133,9 @@ inline void spdlog::set_level(level::level_enum log_level) } -inline void spdlog::set_async_mode(size_t queue_size, const log_clock::duration& shutdown_duration) +inline void spdlog::set_async_mode(size_t queue_size) { - details::registry::instance().set_async_mode(queue_size, shutdown_duration); + details::registry::instance().set_async_mode(queue_size); } inline void spdlog::set_sync_mode() diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h index 6db7ca3d..4841854e 100644 --- a/include/spdlog/spdlog.h +++ b/include/spdlog/spdlog.h @@ -65,9 +65,8 @@ void set_level(level::level_enum log_level); // // Turn on async mode and set the queue size for each async_logger -// shutdown_duration indicates max time to wait for the worker thread to log its messages before terminating. -void set_async_mode(size_t queue_size, const log_clock::duration& shutdown_duration = std::chrono::seconds(5)); +void set_async_mode(size_t queue_size); // Turn off async mode void set_sync_mode(); From 0dd4e552ed70d224f28004cf3f2b5b02f0d5c912 Mon Sep 17 00:00:00 2001 From: gabi Date: Sun, 7 Dec 2014 04:27:46 +0200 Subject: [PATCH 047/120] async_logger comments --- include/spdlog/async_logger.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/spdlog/async_logger.h b/include/spdlog/async_logger.h index 7438d156..ff88a3cf 100644 --- a/include/spdlog/async_logger.h +++ b/include/spdlog/async_logger.h @@ -24,10 +24,13 @@ #pragma once -// Async logger +// Very fast asynchronous logger (millions of logs per second on aregular desktop) +// Uses pre allocated lockfree queue for maximum throughput even under large number of threads. // Upon each log write the logger: -// 1. Checks if its log level is enough to log the message -// 2. Push a new copy of the message to a queue (uses sinks::async_sink for this) +// 1. Checks if its log level is enough to log the message +// 2. Push a new copy of the message to a queue or block the caller until space is available +// 3. will throw spdlog_ex upon exceptions +// Upong destruction, logs all remaining messages in the queue before destructing.. #include #include "common.h" From 4dc75adf9bdb0f5ea748745c1149789cce9ac4fe Mon Sep 17 00:00:00 2001 From: gabi Date: Sun, 7 Dec 2014 04:33:01 +0200 Subject: [PATCH 048/120] async_logger comments --- include/spdlog/async_logger.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/spdlog/async_logger.h b/include/spdlog/async_logger.h index ff88a3cf..518e61cf 100644 --- a/include/spdlog/async_logger.h +++ b/include/spdlog/async_logger.h @@ -24,12 +24,14 @@ #pragma once -// Very fast asynchronous logger (millions of logs per second on aregular desktop) +// Very fast asynchronous logger (millions of logs per second on an average desktop) // Uses pre allocated lockfree queue for maximum throughput even under large number of threads. +// Creates a single back thread to pop messages from the queue and log them. +// // Upon each log write the logger: // 1. Checks if its log level is enough to log the message -// 2. Push a new copy of the message to a queue or block the caller until space is available -// 3. will throw spdlog_ex upon exceptions +// 2. Push a new copy of the message to a queue (or block the caller until space is available in the queue) +// 3. will throw spdlog_ex upon log exceptions // Upong destruction, logs all remaining messages in the queue before destructing.. #include From f6adbeaf826c2aadef865be4309cf938e089c567 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 04:50:06 +0200 Subject: [PATCH 049/120] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fa4cfd00..8b36ac4d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,9 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* Variadic-template/stream call styles: ```logger.info("variadic", x, y) << "or stream" << z;``` +* *new* [cppformat](http://cppformat.github.io/) for formatting and extra performance: ```logger.info("The number {} in hex is {:X}", 255, 255) +* stream call style: ```logger.info("Hello") << " logger"; +* mixed calls style ```logger.info("Hello {}", name) << 1 << 2 << 3; * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: From 741bf8cde19e9c880a24d554962d3d733917ad9e Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:05:01 +0200 Subject: [PATCH 050/120] Update README.md --- README.md | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8b36ac4d..870df97b 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* *new* [cppformat](http://cppformat.github.io/) for formatting and extra performance: ```logger.info("The number {} in hex is {:X}", 255, 255) +* **new**! Now using the excellent [cppformat](http://cppformat.github.io/) for feature rich formatting and extra performance: ```logger.info("The number {} in hex is {:X}", 255, 255) * stream call style: ```logger.info("Hello") << " logger"; * mixed calls style ```logger.info("Hello {}", name) << 1 << 2 << 3; * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. @@ -29,7 +29,7 @@ Just copy the files to your build tree and use a C++11 compiler * Console logging. * Linux syslog. * Easily extendable with custom log targets (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface). -* Optional async logging . +* Optional, even faster, async logging . * Log levels. @@ -61,17 +61,28 @@ int main(int, char* []) std::string filename = "spdlog_example"; auto console = spd::stdout_logger_mt("console"); console->info("Welcome to spdlog!") ; - console->info() << "Creating file " << filename << ".."; + console->info("Creating file {}..", filename); auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3); file_logger->info("Log file message number", 1); for (int i = 0; i < 100; ++i) { - auto square = i*i; - file_logger->info() << i << '*' << i << '=' << square << " (" << "0x" << std::hex << square << ")"; + file_logger->info("{} * {} = {}, i, i, i*i ); } - + + + console->info("Easy padding in numbers like {:08d}", 12); + console->info("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); + console->info("Positional args are {1} {0}..", "too", "supported): + + console->info("{:<30}", "left aligned"); + console->info("{:>30}", "right aligned"); + console->info("{:^30}", "centered"); + + //see cppformat's full docs here: + //http://cppformat.readthedocs.org/en/stable/syntax.html + // Change log level to all loggers to warning and above spd::set_level(spd::level::WARN); console->info("This should not be displayed"); From 386a6e39e7ca0b6e5da5a2aceb05bf91c168b8ee Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:06:32 +0200 Subject: [PATCH 051/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 870df97b..1af60457 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new**! Now using the excellent [cppformat](http://cppformat.github.io/) for feature rich formatting and extra performance: ```logger.info("The number {} in hex is {:X}", 255, 255) +* **new**! Now using the excellent [cppformat](http://cppformat.github.io/) for providing the user feature rich (formatting)[http://cppformat.readthedocs.org/en/stable/syntax.html] and extra performance boost * stream call style: ```logger.info("Hello") << " logger"; * mixed calls style ```logger.info("Hello {}", name) << 1 << 2 << 3; * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. From 5e2638e7903e008f1d73267d1217591a1df13f95 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:08:13 +0200 Subject: [PATCH 052/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1af60457..2e292f77 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new**! Now using the excellent [cppformat](http://cppformat.github.io/) for providing the user feature rich (formatting)[http://cppformat.readthedocs.org/en/stable/syntax.html] and extra performance boost +* **new**! Feature rich [formatting](http://cppformat.readthedocs.org/en/stable/syntax.html) and extra performance boost using the excellent [cppformat](http://cppformat.github.io/) under the cover * stream call style: ```logger.info("Hello") << " logger"; * mixed calls style ```logger.info("Hello {}", name) << 1 << 2 << 3; * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. From ec3524ceb62d581486f960499a15e3048271f840 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:10:03 +0200 Subject: [PATCH 053/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e292f77..aab4bdc0 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new**! Feature rich [formatting](http://cppformat.readthedocs.org/en/stable/syntax.html) and extra performance boost using the excellent [cppformat](http://cppformat.github.io/) under the cover +* **new**! Feature rich [formatting](http://cppformat.readthedocs.org/en/stable/syntax.html) and extra performance boost using the excellent [cppformat](http://cppformat.github.io/) * stream call style: ```logger.info("Hello") << " logger"; * mixed calls style ```logger.info("Hello {}", name) << 1 << 2 << 3; * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. From a09eb090e02e46339f00feb8fba30375df54d0ee Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:10:31 +0200 Subject: [PATCH 054/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aab4bdc0..7f355ed4 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new**! Feature rich [formatting](http://cppformat.readthedocs.org/en/stable/syntax.html) and extra performance boost using the excellent [cppformat](http://cppformat.github.io/) +* **new**! Feature rich [formatting](http://cppformat.readthedocs.org/en/stable/syntax.html) and extra performance boost using the excellent [cppformat](http://cppformat.github.io/) library * stream call style: ```logger.info("Hello") << " logger"; * mixed calls style ```logger.info("Hello {}", name) << 1 << 2 << 3; * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. From f358782c0c102924014b463b4994035ac8f82008 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:12:01 +0200 Subject: [PATCH 055/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f355ed4..f9de398f 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new**! Feature rich [formatting](http://cppformat.readthedocs.org/en/stable/syntax.html) and extra performance boost using the excellent [cppformat](http://cppformat.github.io/) library +* **new**! Feature rich [fromat string API](http://cppformat.readthedocs.org/en/stable/syntax.html) and extra performance boost using the excellent [cppformat](http://cppformat.github.io/) library * stream call style: ```logger.info("Hello") << " logger"; * mixed calls style ```logger.info("Hello {}", name) << 1 << 2 << 3; * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. From 72a1f29c2ef18e207fb715443977014cd2401c24 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:13:56 +0200 Subject: [PATCH 056/120] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f9de398f..27b5fb07 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,9 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new**! Feature rich [fromat string API](http://cppformat.readthedocs.org/en/stable/syntax.html) and extra performance boost using the excellent [cppformat](http://cppformat.github.io/) library -* stream call style: ```logger.info("Hello") << " logger"; -* mixed calls style ```logger.info("Hello {}", name) << 1 << 2 << 3; +* **new**! Feature rich [fromat string API](http://cppformat.readthedocs.org/en/stable/syntax.html) and extra performance boost using the excellent [cppformat](http://cppformat.github.io/) library: +**```logger.info("Hello {}+{}={}", 1, 2, 3); +* ostream call style ```logger.info("Hello {}", name) << 1 << 2 << 3; * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: From 8d0ad01d79576744815fc1db78cbb42ae79731a5 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:17:22 +0200 Subject: [PATCH 057/120] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 27b5fb07..ccebc8c3 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,9 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new**! Feature rich [fromat string API](http://cppformat.readthedocs.org/en/stable/syntax.html) and extra performance boost using the excellent [cppformat](http://cppformat.github.io/) library: -**```logger.info("Hello {}+{}={}", 1, 2, 3); -* ostream call style ```logger.info("Hello {}", name) << 1 << 2 << 3; +* **new**! Feature rich [cppfromat call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library: +```logger.info("Hello {}+{}={}", 1, 2, 3);``` +* ostream call style ```logger.info() << "Hello << "logger"; * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: From 5e03120c9ecdb5045d6f14e6196a9f31217aad8b Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:18:27 +0200 Subject: [PATCH 058/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ccebc8c3..9446ea7e 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Just copy the files to your build tree and use a C++11 compiler * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. * **new**! Feature rich [cppfromat call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library: -```logger.info("Hello {}+{}={}", 1, 2, 3);``` +```logger.info("Hello {}, {}..", "world", "again");``` * ostream call style ```logger.info() << "Hello << "logger"; * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. From 5b81c59902877454a750c2005cdebfd54c70de92 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:19:07 +0200 Subject: [PATCH 059/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9446ea7e..10a3e448 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Just copy the files to your build tree and use a C++11 compiler * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. * **new**! Feature rich [cppfromat call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library: -```logger.info("Hello {}, {}..", "world", "again");``` + * ```logger.info("Hello {}, {}..", "world", "again");``` * ostream call style ```logger.info() << "Hello << "logger"; * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. From 5f47247841158b72021e3ff3672d575ec0f453b1 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:20:24 +0200 Subject: [PATCH 060/120] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 10a3e448..e2d751e5 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,7 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new**! Feature rich [cppfromat call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library: - * ```logger.info("Hello {}, {}..", "world", "again");``` +* **new**! Feature rich [cppfromat call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library:```logger.info("Hello {} !!", "world");``` * ostream call style ```logger.info() << "Hello << "logger"; * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. From 9997e2e412aac245f496f5061f361321101e15e8 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:23:50 +0200 Subject: [PATCH 061/120] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e2d751e5..70406985 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ Just copy the files to your build tree and use a C++11 compiler * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. * **new**! Feature rich [cppfromat call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library:```logger.info("Hello {} !!", "world");``` -* ostream call style ```logger.info() << "Hello << "logger"; +* ostream call style ```logger.info() << "Hello << "logger";``` +* Mixed cppformat/ostream call style ```logger.info("{} + {} = ", 1, 2) << "?";``` * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: From 1e7cc4cec578a95bdf047d697ef10d79f32056c6 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:26:08 +0200 Subject: [PATCH 062/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 70406985..f4891ee3 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Just copy the files to your build tree and use a C++11 compiler * Console logging. * Linux syslog. * Easily extendable with custom log targets (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface). -* Optional, even faster, async logging . +* Optional, (extremly fast!), async logging. * Log levels. From 69689cae80d4a38c22bf3e634e2e670fa6422509 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:29:56 +0200 Subject: [PATCH 063/120] Update README.md --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f4891ee3..a2a91670 100644 --- a/README.md +++ b/README.md @@ -64,13 +64,11 @@ int main(int, char* []) console->info("Creating file {}..", filename); auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3); - file_logger->info("Log file message number", 1); + file_logger->info("Log file message number {}..", 1); - for (int i = 0; i < 100; ++i) - { - file_logger->info("{} * {} = {}, i, i, i*i ); - } - + for (int j = 1; j <= 10; ++j) + for (int i = 1; i < 10; ++i) + file_logger->info("{} * {} equals {}, i, j, i*j ); console->info("Easy padding in numbers like {:08d}", 12); console->info("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); From c7432b8ece47461fe4419541cac42c90d40451df Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:30:18 +0200 Subject: [PATCH 064/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a2a91670..a47fa6c1 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ int main(int, char* []) for (int j = 1; j <= 10; ++j) for (int i = 1; i < 10; ++i) - file_logger->info("{} * {} equals {}, i, j, i*j ); + file_logger->info("{} * {} equals {}, i, j, i*j ); console->info("Easy padding in numbers like {:08d}", 12); console->info("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); From 58975841751e765b0cb8fa2ef12ce79e799b58c2 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:33:33 +0200 Subject: [PATCH 065/120] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a47fa6c1..42499d8f 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,8 @@ int main(int, char* []) file_logger->info("{} * {} equals {}, i, j, i*j ); console->info("Easy padding in numbers like {:08d}", 12); - console->info("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); + console->info("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); + console->infor("Supprot for floats {:03.2f}", 1.23456); console->info("Positional args are {1} {0}..", "too", "supported): console->info("{:<30}", "left aligned"); From 76436d07cc45de58a5047d2012d2af5d2179b83f Mon Sep 17 00:00:00 2001 From: gabime Date: Sun, 7 Dec 2014 05:48:32 +0200 Subject: [PATCH 066/120] bench and examples updates --- bench/spdlog-bench-async.cpp | 6 +- bench/spdlog-bench-mt-async.cpp | 8 +- example/bench.cpp | 11 +- include/spdlog/details/fast_istostr.h | 130 ---------------- include/spdlog/details/mpcs_q.h | 204 -------------------------- 5 files changed, 13 insertions(+), 346 deletions(-) delete mode 100644 include/spdlog/details/fast_istostr.h delete mode 100644 include/spdlog/details/mpcs_q.h diff --git a/bench/spdlog-bench-async.cpp b/bench/spdlog-bench-async.cpp index eaaa131f..c9fea752 100644 --- a/bench/spdlog-bench-async.cpp +++ b/bench/spdlog-bench-async.cpp @@ -4,7 +4,7 @@ int main(int, char* []) { - int howmany = 1000000; + int howmany = 1048576; namespace spd = spdlog; spd::set_async_mode(howmany); ///Create a file rotating logger with 5mb size max and 3 rotated files @@ -14,5 +14,9 @@ int main(int, char* []) for(int i = 0 ; i < howmany; ++i) logger->info() << "spdlog message #" << i << ": This is some text for your pleasure"; + + //because spdlog async logger waits for the back thread logger to finish all messages upon destrcuting, + //and we want to measure only the time it took to push those messages to the backthread.. + abort(); return 0; } diff --git a/bench/spdlog-bench-mt-async.cpp b/bench/spdlog-bench-mt-async.cpp index aacf00d1..a0949b7f 100644 --- a/bench/spdlog-bench-mt-async.cpp +++ b/bench/spdlog-bench-mt-async.cpp @@ -14,10 +14,10 @@ int main(int argc, char* argv[]) if(argc > 1) thread_count = atoi(argv[1]); - int howmany = 1000000; + int howmany = 1048576; namespace spd = spdlog; - spd::set_async_mode(howmany, std::chrono::seconds(0)); + spd::set_async_mode(howmany); ///Create a file rotating logger with 5mb size max and 3 rotated files auto logger = spd::rotating_logger_mt("file_logger", "logs/spd-sample", 10 *1024 * 1024 , 5); @@ -45,5 +45,7 @@ int main(int argc, char* argv[]) t.join(); }; - return 0; + //because spdlog async logger waits for the back thread logger to finish all messages upon destrcuting, + //and we want to measure only the time it took to push those messages to the backthread.. + abort(); } diff --git a/example/bench.cpp b/example/bench.cpp index d9911808..03eca854 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -50,7 +50,7 @@ void bench_mt(int howmany, std::shared_ptr log, int thread_count int main(int argc, char* argv[]) { - int howmany = 1000000; + int howmany = 1048576; int threads = 10; bool auto_flush = false; int file_size = 30 * 1024 * 1024; @@ -94,17 +94,12 @@ int main(int argc, char* argv[]) spdlog::set_async_mode(howmany); - for(int i = 0; i < 3; ++i) + for(int i = 0; i < 5; ++i) { auto as = spdlog::daily_logger_st("as", "logs/daily_async", auto_flush); - //bench_mt(howmany, spdlog::create("as"), threads); - bench_mt(howmany, as, threads); - as->stop(); + bench_mt(howmany, as, threads); spdlog::drop("as"); } - - spdlog::stop(); - } catch (std::exception &ex) { diff --git a/include/spdlog/details/fast_istostr.h b/include/spdlog/details/fast_istostr.h deleted file mode 100644 index 55500955..00000000 --- a/include/spdlog/details/fast_istostr.h +++ /dev/null @@ -1,130 +0,0 @@ -/*************************************************************************/ -/* spdlog - an extremely fast and easy to use c++11 logging library. */ -/* Copyright (c) 2014 Gabi Melman. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#pragma once -#include - -//Fast to int to string -//Base on :http://stackoverflow.com/a/4351484/192001 -//Modified version to pad zeros according to padding arg - -namespace spdlog -{ -namespace details -{ - -const char digit_pairs[201] = -{ - "00010203040506070809" - "10111213141516171819" - "20212223242526272829" - "30313233343536373839" - "40414243444546474849" - "50515253545556575859" - "60616263646566676869" - "70717273747576777879" - "80818283848586878889" - "90919293949596979899" -}; - - -inline std::string& fast_itostr(int n, std::string& s, size_t padding) -{ - if (n == 0) - { - s = std::string(padding, '0'); - return s; - } - - int sign = -(n < 0); - unsigned int val = static_cast((n^sign) - sign); - - size_t size; - if (val >= 10000) - { - if (val >= 10000000) - { - if (val >= 1000000000) - size = 10; - else if (val >= 100000000) - size = 9; - else - size = 8; - } - else - { - if (val >= 1000000) - size = 7; - else if (val >= 100000) - size = 6; - else - size = 5; - } - } - else - { - if (val >= 100) - { - if (val >= 1000) - size = 4; - else - size = 3; - } - else - { - if (val >= 10) - size = 2; - else - size = 1; - } - } - size -= sign; - if (size < padding) - size = padding; - - s.resize(size); - char* c = &s[0]; - if (sign) - *c = '-'; - - c += size - 1; - while (val >= 100) - { - size_t pos = val % 100; - val /= 100; - *(short*)(c - 1) = *(short*)(digit_pairs + 2 * pos); - c -= 2; - } - while (val > 0) - { - *c-- = static_cast('0' + (val % 10)); - val /= 10; - } - - while (c >= s.data()) - *c-- = '0'; - return s; -} -} -} diff --git a/include/spdlog/details/mpcs_q.h b/include/spdlog/details/mpcs_q.h deleted file mode 100644 index c994307b..00000000 --- a/include/spdlog/details/mpcs_q.h +++ /dev/null @@ -1,204 +0,0 @@ -/* -A modified version of Intrusive MPSC node-based queue - -Original code from -http://www.1024cores.net/home/lock-free-algorithms/queues/intrusive-mpsc-node-based-queue -licensed by Dmitry Vyukov under the terms below: - -Simplified BSD license - -Copyright (c) 2010-2011 Dmitry Vyukov. All rights reserved. -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, this list of -conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list -of conditions and the following disclaimer in the documentation and/or other materials -provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, -OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those of the authors and -should not be interpreted as representing official policies, either expressed or implied, of Dmitry Vyukov. -*/ - -/*************************************************************************/ -/********* The code in its current form adds the license below: **********/ -/*************************************************************************/ -/* spdlog - an extremely fast and easy to use c++11 logging library. */ -/* Copyright (c) 2014 Gabi Melman. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#pragma once - -#include -namespace spdlog -{ -namespace details -{ -template -class mpsc_q -{ - -public: - using item_type = T; - explicit mpsc_q(size_t max_size) : - _max_size(max_size), - _size(0), - _stub(), - _head(&_stub), - _tail(&_stub) - { - } - - mpsc_q(const mpsc_q&) = delete; - mpsc_q& operator=(const mpsc_q&) = delete; - - ~mpsc_q() - { - clear(); - } - - template - bool push(TT&& val) - { - if (_size >= _max_size) - return false; - mpscq_node_t* new_node = new mpscq_node_t(std::forward(val)); - push_node(new_node); - ++_size; - return true; - } - - // Try to pop or return false immediatly is queue is empty - bool pop(T& value) - { - mpscq_node_t* node = pop_node(); - if (node != nullptr) - { - --_size; - value = std::move(node->value); - delete(node); - return true; - } - else - { - return false; - } - } - - // Empty the queue by popping all its elements - void clear() - { - while (mpscq_node_t* node = pop_node()) - { - --_size; - delete(node); - } - - } - - // Return approx size - size_t approx_size() const - { - return _size.load(); - } - -private: - struct mpscq_node_t - { - std::atomic next; - T value; - - mpscq_node_t() :next(nullptr) {} - mpscq_node_t(const mpscq_node_t&) = delete; - mpscq_node_t& operator=(const mpscq_node_t&) = delete; - - explicit mpscq_node_t(const T& val): - next(nullptr), - value(val) {} - - explicit mpscq_node_t(T&& val) : - next(nullptr), - value(std::move(val)) {} - }; - - size_t _max_size; - std::atomic _size; - mpscq_node_t _stub; - std::atomic _head; - mpscq_node_t* _tail; - - // Lockfree push - void push_node(mpscq_node_t* n) - { - n->next = nullptr; - mpscq_node_t* prev = _head.exchange(n); - prev->next = n; - } - - // Clever lockfree pop algorithm by Dmitry Vyukov using single xchng instruction.. - // Return pointer to the poppdc node or nullptr if no items left in the queue - mpscq_node_t* pop_node() - { - mpscq_node_t* tail = _tail; - mpscq_node_t* next = tail->next; - if (tail == &_stub) - { - if (nullptr == next) - return nullptr; - _tail = next; - tail = next; - next = next->next; - } - if (next) - { - _tail = next; - return tail; - } - mpscq_node_t* head = _head; - if (tail != head) - return nullptr; - - push_node(&_stub); - next = tail->next; - if (next) - { - _tail = next; - return tail; - } - return nullptr; - } - -}; -} -} From ac99e725fb078063c055f410eef7b345d4fa02ac Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 05:55:50 +0200 Subject: [PATCH 067/120] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fa4cfd00..22c8180c 100644 --- a/README.md +++ b/README.md @@ -35,12 +35,12 @@ Just copy the files to your build tree and use a C++11 compiler ## Benchmarks -Below are some [benchmarks](bench) comparing the time needed to log 1,000,000 lines to file under Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz: +Below are some [benchmarks](bench) comparing the time needed to log 1,000,000 lines to file under Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz (the best of 3 runs for each logger): |threads|boost log|glog|g2log|spdlog|spdlog async mode| |-------|:-------:|:-----:|------:|------:|------:| -|1|4.779s|1.109s|3.155s|0.947s|1.455s -|10|15.151ss|3.546s|3.500s|1.549s|2.040s| +|1|4.779s|1.109s|3.155s|0.319s|0.212s +|10|15.151ss|3.546s|3.500s|0.641s|0.199s| From 1e1bb1cd0fc73ce8c31b6994a960325e695005a8 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:01:10 +0200 Subject: [PATCH 068/120] Update README.md --- README.md | 92 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 42499d8f..3e6ac70e 100644 --- a/README.md +++ b/README.md @@ -49,48 +49,93 @@ Below are some [benchmarks](bench) comparing the time needed to log 1,000,000 li ## Usage Example ```c++ +/*************************************************************************/ +/* spdlog - an extremely fast and easy to use c++11 logging library. */ +/* Copyright (c) 2014 Gabi Melman. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +// +// spdlog usage example +// #include #include "spdlog/spdlog.h" +#include "spdlog/details/format.h" int main(int, char* []) { + namespace spd = spdlog; try { - std::string filename = "spdlog_example"; + std::string filename = "logs/spdlog_example"; + // Set log level to all loggers to DEBUG and above + spd::set_level(spd::level::DEBUG); + + + //Create console, multithreaded logger auto console = spd::stdout_logger_mt("console"); console->info("Welcome to spdlog!") ; - console->info("Creating file {}..", filename); + console->info("An info message example {}..", 1); + console->info() << "Streams are supported too " << 1; - auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3); - file_logger->info("Log file message number {}..", 1); - - for (int j = 1; j <= 10; ++j) - for (int i = 1; i < 10; ++i) - file_logger->info("{} * {} equals {}, i, j, i*j ); - + console->info("Easy padding in numbers like {:08d}", 12); console->info("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); - console->infor("Supprot for floats {:03.2f}", 1.23456); - console->info("Positional args are {1} {0}..", "too", "supported): - + console->info("Support for floats {:03.2f}", 1.23456); + console->info("Positional args are {1} {0}..", "too", "supported"); + console->info("{:<30}", "left aligned"); console->info("{:>30}", "right aligned"); console->info("{:^30}", "centered"); - //see cppformat's full docs here: - //http://cppformat.readthedocs.org/en/stable/syntax.html - - // Change log level to all loggers to warning and above - spd::set_level(spd::level::WARN); - console->info("This should not be displayed"); - console->warn("This should!"); - spd::set_level(spd::level::INFO); + //Create a file rotating logger with 5mb size max and 3 rotated files + auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3); + file_logger->info("Log file message number", 1); - // Change format pattern to all loggers - spd::set_pattern(" **** %Y-%m-%d %H:%M:%S.%e %l **** %v"); - spd::get("console")->info("This is another message with different format"); + + spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***"); + file_logger->info("This is another message with custom format"); + + spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function"); + + SPDLOG_TRACE(file_logger, "This is a trace message (only #ifdef _DEBUG)", 123); + + // + // Asynchronous logging is easy.. + // Just call spdlog::set_async_mode(max_q_size) and all created loggers from now on will be asynchronous.. + // + size_t max_q_size = 1048576; + spdlog::set_async_mode(max_q_size); + auto async_file= spd::daily_logger_st("async_file_logger", "logs/async_log.txt"); + async_file->info() << "This is async log.." << "Should be very fast!"; + + // + // syslog example + // +#ifdef __linux__ + auto syslog_logger = spd::syslog_logger("syslog"); + syslog_logger->warn("This is warning that will end up in syslog. This is Linux only!"); +#endif } catch (const spd::spdlog_ex& ex) { @@ -98,4 +143,5 @@ int main(int, char* []) } return 0; } + ``` From 2acc7843731cc24629e0a90b6e3332561544fbe8 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:01:51 +0200 Subject: [PATCH 069/120] Update README.md --- README.md | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/README.md b/README.md index 3e6ac70e..f87c77e1 100644 --- a/README.md +++ b/README.md @@ -49,36 +49,8 @@ Below are some [benchmarks](bench) comparing the time needed to log 1,000,000 li ## Usage Example ```c++ -/*************************************************************************/ -/* spdlog - an extremely fast and easy to use c++11 logging library. */ -/* Copyright (c) 2014 Gabi Melman. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -// -// spdlog usage example -// #include #include "spdlog/spdlog.h" -#include "spdlog/details/format.h" int main(int, char* []) { From 159165665d97b980ee70cce4456b775ea394f4bf Mon Sep 17 00:00:00 2001 From: gabime Date: Sun, 7 Dec 2014 06:02:46 +0200 Subject: [PATCH 070/120] fixed example --- example/Makefile | 2 +- example/example.cpp | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/example/Makefile b/example/Makefile index 746c7a9e..4208786a 100644 --- a/example/Makefile +++ b/example/Makefile @@ -4,7 +4,7 @@ CXX_RELEASE_FLAGS = -O3 -flto CXX_DEBUG_FLAGS= -g -all: bench +all: example bench debug: example-debug bench-debug example: example.cpp diff --git a/example/example.cpp b/example/example.cpp index 4e464107..6acc94ba 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -26,8 +26,8 @@ // spdlog usage example // #include -#include "spdlog/spdlog.h" -#include "spdlog/details/format.h" +#include "spdlog/spdlog.h"ls + int main(int, char* []) { @@ -36,8 +36,6 @@ int main(int, char* []) try { - fmt::print("Hello man {} {:1f}\n", 1, 2.2); - return 0; std::string filename = "logs/spdlog_example"; // Set log level to all loggers to DEBUG and above spd::set_level(spd::level::DEBUG); @@ -46,9 +44,19 @@ int main(int, char* []) //Create console, multithreaded logger auto console = spd::stdout_logger_mt("console"); console->info("Welcome to spdlog!") ; - console->info("An info message example", "...", 1, 2, 3.5); + console->info("An info message example {}..", 1); console->info() << "Streams are supported too " << 1; + + console->info("Easy padding in numbers like {:08d}", 12); + console->info("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); + console->info("Support for floats {:03.2f}", 1.23456); + console->info("Positional args are {1} {0}..", "too", "supported"); + + console->info("{:<30}", "left aligned"); + console->info("{:>30}", "right aligned"); + console->info("{:^30}", "centered"); + //Create a file rotating logger with 5mb size max and 3 rotated files auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3); file_logger->info("Log file message number", 1); @@ -65,7 +73,7 @@ int main(int, char* []) // Asynchronous logging is easy.. // Just call spdlog::set_async_mode(max_q_size) and all created loggers from now on will be asynchronous.. // - size_t max_q_size = 100000; + size_t max_q_size = 1048576; spdlog::set_async_mode(max_q_size); auto async_file= spd::daily_logger_st("async_file_logger", "logs/async_log.txt"); async_file->info() << "This is async log.." << "Should be very fast!"; From 524bc26179e3ca71e15fdfaf0a1ad0607821f9eb Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:05:44 +0200 Subject: [PATCH 071/120] Update README.md --- README.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f87c77e1..ec66d00e 100644 --- a/README.md +++ b/README.md @@ -34,17 +34,14 @@ Just copy the files to your build tree and use a C++11 compiler - ## Benchmarks -Below are some [benchmarks](bench) comparing the time needed to log 1,000,000 lines to file under Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz: +Below are some [benchmarks](bench) comparing the time needed to log 1,000,000 lines to file under Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz (the best of 3 runs for each logger): |threads|boost log|glog|g2log|spdlog|spdlog async mode| |-------|:-------:|:-----:|------:|------:|------:| -|1|4.779s|1.109s|3.155s|0.947s|1.455s -|10|15.151ss|3.546s|3.500s|1.549s|2.040s| - - +|1|4.779s|1.109s|3.155s|0.319s|0.212s +|10|15.151ss|3.546s|3.500s|0.641s|0.199s| ## Usage Example From 9b9556fb69eadb30585260a809d22080655c92e1 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:16:15 +0200 Subject: [PATCH 072/120] Update README.md --- README.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/README.md b/README.md index ec66d00e..0141f21a 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,9 @@ Very fast, header only, C++ logging library. - ## Install Just copy the files to your build tree and use a C++11 compiler - ## Tested on: * gcc 4.8.1 and above * clang 3.5 @@ -38,7 +36,7 @@ Just copy the files to your build tree and use a C++11 compiler Below are some [benchmarks](bench) comparing the time needed to log 1,000,000 lines to file under Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz (the best of 3 runs for each logger): -|threads|boost log|glog|g2log|spdlog|spdlog async mode| +|threads|boost log|glog|g2logasync mode|spdlog|spdlog async mode| |-------|:-------:|:-----:|------:|------:|------:| |1|4.779s|1.109s|3.155s|0.319s|0.212s |10|15.151ss|3.546s|3.500s|0.641s|0.199s| @@ -51,23 +49,19 @@ Below are some [benchmarks](bench) comparing the time needed to log 1,000,000 li int main(int, char* []) { - namespace spd = spdlog; - try { std::string filename = "logs/spdlog_example"; // Set log level to all loggers to DEBUG and above spd::set_level(spd::level::DEBUG); - //Create console, multithreaded logger auto console = spd::stdout_logger_mt("console"); console->info("Welcome to spdlog!") ; console->info("An info message example {}..", 1); console->info() << "Streams are supported too " << 1; - console->info("Easy padding in numbers like {:08d}", 12); console->info("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); console->info("Support for floats {:03.2f}", 1.23456); @@ -81,7 +75,6 @@ int main(int, char* []) auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3); file_logger->info("Log file message number", 1); - spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***"); file_logger->info("This is another message with custom format"); @@ -110,7 +103,6 @@ int main(int, char* []) { std::cout << "Log failed: " << ex.what() << std::endl; } - return 0; } ``` From 06ce050ab05666aa575cd168521933084c02238d Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:18:28 +0200 Subject: [PATCH 073/120] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0141f21a..d1d63a39 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new**! Feature rich [cppfromat call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library:```logger.info("Hello {} !!", "world");``` +* **new**! Feature rich [cppfromat call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library: +* ```logger.info("Hello {} !!", "world");``` * ostream call style ```logger.info() << "Hello << "logger";``` * Mixed cppformat/ostream call style ```logger.info("{} + {} = ", 1, 2) << "?";``` * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. From c55a0c89749194f2939bace3b6b4f57083a30e03 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:23:53 +0200 Subject: [PATCH 074/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d1d63a39..c0a3c299 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new**! Feature rich [cppfromat call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library: +* **new**! Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library: * ```logger.info("Hello {} !!", "world");``` * ostream call style ```logger.info() << "Hello << "logger";``` * Mixed cppformat/ostream call style ```logger.info("{} + {} = ", 1, 2) << "?";``` From a0d92cb58a416df9cc719328702b153bd7dd4a04 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:25:45 +0200 Subject: [PATCH 075/120] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c0a3c299..45b206f5 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,10 @@ int main(int, char* []) console->info("{:>30}", "right aligned"); console->info("{:^30}", "centered"); + //See full cppformat documation here: + //http://cppformat.readthedocs.org/en/stable/syntax.html + + //Create a file rotating logger with 5mb size max and 3 rotated files auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3); file_logger->info("Log file message number", 1); From 9d3e2d1fa8dac365f28670bd1c931424dc796ccc Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:26:33 +0200 Subject: [PATCH 076/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 45b206f5..7de2ab2b 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ int main(int, char* []) console->info("{:>30}", "right aligned"); console->info("{:^30}", "centered"); - //See full cppformat documation here: + //See cppformat syntax documation here: //http://cppformat.readthedocs.org/en/stable/syntax.html From 007e7eee828985493050705549f63b36a24e4bc1 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:27:40 +0200 Subject: [PATCH 077/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7de2ab2b..3607e16e 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Just copy the files to your build tree and use a C++11 compiler * mingw with g++ 4.9.x ##Features -* Very fast - performance is the primary goal (see becnhmarks below). +* Very fast - performance is the primary goal (see [becnhmarks](#benchmarks) below). * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. From 6c60db188b15504b48e21dea70381bc573d57f04 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:34:51 +0200 Subject: [PATCH 078/120] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3607e16e..e2843601 100644 --- a/README.md +++ b/README.md @@ -16,19 +16,19 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new**! Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library: +* **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library: * ```logger.info("Hello {} !!", "world");``` * ostream call style ```logger.info() << "Hello << "logger";``` * Mixed cppformat/ostream call style ```logger.info("{} + {} = ", 1, 2) << "?";``` * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. +* **new!** Extremly fast option; async logging using lockfree queues * Various log targets: * Rotating log files. * Daily log files. * Console logging. * Linux syslog. * Easily extendable with custom log targets (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface). -* Optional, (extremly fast!), async logging. * Log levels. From 830c77270b67909656b21b85d1d714e74124c970 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:36:54 +0200 Subject: [PATCH 079/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e2843601..5c2175ed 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Just copy the files to your build tree and use a C++11 compiler * Mixed cppformat/ostream call style ```logger.info("{} + {} = ", 1, 2) << "?";``` * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. -* **new!** Extremly fast option; async logging using lockfree queues +* **new!** Extremly fast asynchronous logging(optional) using lockfree queues * Various log targets: * Rotating log files. * Daily log files. From ab5169e028704e0c2b04b445363262d02b41f4fb Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:38:05 +0200 Subject: [PATCH 080/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5c2175ed..d3f2b626 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Just copy the files to your build tree and use a C++11 compiler * Mixed cppformat/ostream call style ```logger.info("{} + {} = ", 1, 2) << "?";``` * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. -* **new!** Extremly fast asynchronous logging(optional) using lockfree queues +* **new!** Extremly fast asynchronous logging(optional) using lockfree queues and finely tuned implementation * Various log targets: * Rotating log files. * Daily log files. From 6c5dc5a6c127ef0d4d2cf4a66fadd355dd48a10e Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:40:17 +0200 Subject: [PATCH 081/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d3f2b626..1ef7eea1 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,9 @@ Just copy the files to your build tree and use a C++11 compiler * ```logger.info("Hello {} !!", "world");``` * ostream call style ```logger.info() << "Hello << "logger";``` * Mixed cppformat/ostream call style ```logger.info("{} + {} = ", 1, 2) << "?";``` +* **new!** Extremly fast asynchronous logging (optional) using lockfree queues. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. -* **new!** Extremly fast asynchronous logging(optional) using lockfree queues and finely tuned implementation * Various log targets: * Rotating log files. * Daily log files. From ce5c75065f4a97c3af39ac4fa12f7a4b98e3c7dd Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:40:59 +0200 Subject: [PATCH 082/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ef7eea1..44e9442c 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Just copy the files to your build tree and use a C++11 compiler Below are some [benchmarks](bench) comparing the time needed to log 1,000,000 lines to file under Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz (the best of 3 runs for each logger): -|threads|boost log|glog|g2logasync mode|spdlog|spdlog async mode| +|threads|boost log|glog|g2log async mode|spdlog|spdlog async mode| |-------|:-------:|:-----:|------:|------:|------:| |1|4.779s|1.109s|3.155s|0.319s|0.212s |10|15.151ss|3.546s|3.500s|0.641s|0.199s| From c615ac32bd238d1f8188b3163f3b024fb3fe2499 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:44:16 +0200 Subject: [PATCH 083/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 44e9442c..732afda0 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Just copy the files to your build tree and use a C++11 compiler * ```logger.info("Hello {} !!", "world");``` * ostream call style ```logger.info() << "Hello << "logger";``` * Mixed cppformat/ostream call style ```logger.info("{} + {} = ", 1, 2) << "?";``` -* **new!** Extremly fast asynchronous logging (optional) using lockfree queues. +* **new!** Optional, extremly fast asynchronous mode using lockfree queues and deffered formatting. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: From 1899e6c481cdad364a0276861ba1c0b573db8f14 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:45:37 +0200 Subject: [PATCH 084/120] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 732afda0..d907ecbd 100644 --- a/README.md +++ b/README.md @@ -91,8 +91,8 @@ int main(int, char* []) // Asynchronous logging is easy.. // Just call spdlog::set_async_mode(max_q_size) and all created loggers from now on will be asynchronous.. // - size_t max_q_size = 1048576; - spdlog::set_async_mode(max_q_size); + size_t q_size = 1048576; //queue size must be power of 2 + spdlog::set_async_mode(q_size); auto async_file= spd::daily_logger_st("async_file_logger", "logs/async_log.txt"); async_file->info() << "This is async log.." << "Should be very fast!"; From 02827707986b9948c5e01f3916dc664fc2684c6a Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:46:18 +0200 Subject: [PATCH 085/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d907ecbd..2c00d755 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Just copy the files to your build tree and use a C++11 compiler * ```logger.info("Hello {} !!", "world");``` * ostream call style ```logger.info() << "Hello << "logger";``` * Mixed cppformat/ostream call style ```logger.info("{} + {} = ", 1, 2) << "?";``` -* **new!** Optional, extremly fast asynchronous mode using lockfree queues and deffered formatting. +* **new!** Optional, extremly fast asynchronous mode using lockfree queues, pre allocated memory and deffered formatting. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: From ebaf209f1147dec3d7be69a0eedfeb5d3dade9f2 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:47:10 +0200 Subject: [PATCH 086/120] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 2c00d755..9ffc6bc4 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,6 @@ Just copy the files to your build tree and use a C++11 compiler * **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library: * ```logger.info("Hello {} !!", "world");``` * ostream call style ```logger.info() << "Hello << "logger";``` -* Mixed cppformat/ostream call style ```logger.info("{} + {} = ", 1, 2) << "?";``` * **new!** Optional, extremly fast asynchronous mode using lockfree queues, pre allocated memory and deffered formatting. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. From f06f82b9a6e1cc65f6197a05a7acf7eb6940038a Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:47:43 +0200 Subject: [PATCH 087/120] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9ffc6bc4..8292902f 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,8 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library: -* ```logger.info("Hello {} !!", "world");``` -* ostream call style ```logger.info() << "Hello << "logger";``` +* **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library:```logger.info("Hello {} !!", "world");``` +* ostream call style: ```logger.info() << "Hello << "logger";``` * **new!** Optional, extremly fast asynchronous mode using lockfree queues, pre allocated memory and deffered formatting. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. From 53ffeea35f425d17c6b789d02587cc9fb6590b43 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:49:44 +0200 Subject: [PATCH 088/120] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8292902f..f4a9e975 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library:```logger.info("Hello {} !!", "world");``` +* **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library - +* cppformat call style ```logger.info("Hello {} {:08x}!!", "world", 42);``` * ostream call style: ```logger.info() << "Hello << "logger";``` * **new!** Optional, extremly fast asynchronous mode using lockfree queues, pre allocated memory and deffered formatting. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. From 8213cd89d7af8682b54149fe2362c2092ad34999 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 06:51:04 +0200 Subject: [PATCH 089/120] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f4a9e975..2388c5a1 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library - -* cppformat call style ```logger.info("Hello {} {:08x}!!", "world", 42);``` +* **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library. +* Example: ```logger.info("Hello {} {:08x}!!", "world", 42);``` * ostream call style: ```logger.info() << "Hello << "logger";``` * **new!** Optional, extremly fast asynchronous mode using lockfree queues, pre allocated memory and deffered formatting. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. From 7f174a2b2fb458490924021eca33ffbfdb7feb70 Mon Sep 17 00:00:00 2001 From: gabime Date: Sun, 7 Dec 2014 06:54:25 +0200 Subject: [PATCH 090/120] fixed example and bench --- example/bench.cpp | 4 ---- example/example.cpp | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/example/bench.cpp b/example/bench.cpp index 12dcb923..9b6f41f0 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -52,11 +52,7 @@ int main(int argc, char* argv[]) int howmany = 1048576; int threads = 10; -<<<<<<< HEAD - bool auto_flush = false; -======= bool auto_flush = false; ->>>>>>> cppformat int file_size = 30 * 1024 * 1024; int rotating_files = 5; diff --git a/example/example.cpp b/example/example.cpp index 6acc94ba..00039dea 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -26,7 +26,7 @@ // spdlog usage example // #include -#include "spdlog/spdlog.h"ls +#include "spdlog/spdlog.h" int main(int, char* []) @@ -49,7 +49,7 @@ int main(int, char* []) console->info("Easy padding in numbers like {:08d}", 12); - console->info("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42); + console->info("Support for int: {0:d}; hex: {0:08x}; oct: {0:o}; bin: {0:b}", 42); console->info("Support for floats {:03.2f}", 1.23456); console->info("Positional args are {1} {0}..", "too", "supported"); From db4b146173205eba21095cd9680ff4f055ed49e2 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 07:10:52 +0200 Subject: [PATCH 091/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2388c5a1..b035d908 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Just copy the files to your build tree and use a C++11 compiler * Console logging. * Linux syslog. * Easily extendable with custom log targets (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface). -* Log levels. +* Severity based filtering - can be modified in runtime. From 5db6c5163cee2d653b198e5d74dc10a51f873991 Mon Sep 17 00:00:00 2001 From: gabime Date: Sun, 7 Dec 2014 07:16:37 +0200 Subject: [PATCH 092/120] exmaple --- example/example.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/example/example.cpp b/example/example.cpp index 00039dea..9efa07ee 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -59,8 +59,10 @@ int main(int, char* []) //Create a file rotating logger with 5mb size max and 3 rotated files auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3); - file_logger->info("Log file message number", 1); - + + file_logger->info("Log file message number", 1); + for(int i = 0; i < 10; ++i) + file_logger->info("{} * {} equals {:>10}", i, i, i*i); spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***"); file_logger->info("This is another message with custom format"); From e9adfde98198b616203b704561ea304da62886de Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 07:16:45 +0200 Subject: [PATCH 093/120] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b035d908..c801a0a0 100644 --- a/README.md +++ b/README.md @@ -74,10 +74,11 @@ int main(int, char* []) //See cppformat syntax documation here: //http://cppformat.readthedocs.org/en/stable/syntax.html - //Create a file rotating logger with 5mb size max and 3 rotated files auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3); file_logger->info("Log file message number", 1); + for(int i = 0; i < 10; ++i) + file_logger->info("{} * {} equals {:>10}", i, i, i*i); spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***"); file_logger->info("This is another message with custom format"); @@ -94,7 +95,7 @@ int main(int, char* []) spdlog::set_async_mode(q_size); auto async_file= spd::daily_logger_st("async_file_logger", "logs/async_log.txt"); async_file->info() << "This is async log.." << "Should be very fast!"; - + // // syslog example // From 6313174bf1d5f6b6e0dde2a3e4250a47ecc3cda2 Mon Sep 17 00:00:00 2001 From: gabime Date: Sun, 7 Dec 2014 07:18:43 +0200 Subject: [PATCH 094/120] astyle --- bench/spdlog-bench-async.cpp | 8 +- bench/spdlog-bench-mt-async.cpp | 6 +- example/bench.cpp | 20 +-- example/example.cpp | 12 +- include/spdlog/details/mpmc_bounded_q.h | 170 ++++++++++++------------ 5 files changed, 108 insertions(+), 108 deletions(-) diff --git a/bench/spdlog-bench-async.cpp b/bench/spdlog-bench-async.cpp index c9fea752..d30e8677 100644 --- a/bench/spdlog-bench-async.cpp +++ b/bench/spdlog-bench-async.cpp @@ -14,9 +14,9 @@ int main(int, char* []) for(int i = 0 ; i < howmany; ++i) logger->info() << "spdlog message #" << i << ": This is some text for your pleasure"; - - //because spdlog async logger waits for the back thread logger to finish all messages upon destrcuting, - //and we want to measure only the time it took to push those messages to the backthread.. - abort(); + + //because spdlog async logger waits for the back thread logger to finish all messages upon destrcuting, + //and we want to measure only the time it took to push those messages to the backthread.. + abort(); return 0; } diff --git a/bench/spdlog-bench-mt-async.cpp b/bench/spdlog-bench-mt-async.cpp index a0949b7f..f7d424a1 100644 --- a/bench/spdlog-bench-mt-async.cpp +++ b/bench/spdlog-bench-mt-async.cpp @@ -45,7 +45,7 @@ int main(int argc, char* argv[]) t.join(); }; - //because spdlog async logger waits for the back thread logger to finish all messages upon destrcuting, - //and we want to measure only the time it took to push those messages to the backthread.. - abort(); + //because spdlog async logger waits for the back thread logger to finish all messages upon destrcuting, + //and we want to measure only the time it took to push those messages to the backthread.. + abort(); } diff --git a/example/bench.cpp b/example/bench.cpp index 9b6f41f0..be9a0c27 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -69,8 +69,8 @@ int main(int argc, char* argv[]) cout << "Single thread, " << format(howmany) << " iterations, auto flush=" << auto_flush << endl; cout << "*******************************************************************************\n"; - auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st", file_size, rotating_files, auto_flush); - bench(howmany, rotating_st); + auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st", file_size, rotating_files, auto_flush); + bench(howmany, rotating_st); auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st", auto_flush); bench(howmany, daily_st); bench(howmany, spdlog::create("null_st")); @@ -79,8 +79,8 @@ int main(int argc, char* argv[]) cout << threads << " threads sharing same logger, " << format(howmany) << " iterations, auto_flush=" << auto_flush << endl; cout << "*******************************************************************************\n"; - auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", file_size, rotating_files, auto_flush); - bench_mt(howmany, rotating_mt, threads); + auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", file_size, rotating_files, auto_flush); + bench_mt(howmany, rotating_mt, threads); auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt", auto_flush); @@ -94,12 +94,12 @@ int main(int argc, char* argv[]) spdlog::set_async_mode(howmany); - for(int i = 0; i < 5; ++i) - { - auto as = spdlog::daily_logger_st("as", "logs/daily_async", auto_flush); - bench_mt(howmany, as, threads); - spdlog::drop("as"); - } + for(int i = 0; i < 5; ++i) + { + auto as = spdlog::daily_logger_st("as", "logs/daily_async", auto_flush); + bench_mt(howmany, as, threads); + spdlog::drop("as"); + } } catch (std::exception &ex) { diff --git a/example/example.cpp b/example/example.cpp index 9efa07ee..d07cf801 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -47,7 +47,7 @@ int main(int, char* []) console->info("An info message example {}..", 1); console->info() << "Streams are supported too " << 1; - + console->info("Easy padding in numbers like {:08d}", 12); console->info("Support for int: {0:d}; hex: {0:08x}; oct: {0:o}; bin: {0:b}", 42); console->info("Support for floats {:03.2f}", 1.23456); @@ -56,13 +56,13 @@ int main(int, char* []) console->info("{:<30}", "left aligned"); console->info("{:>30}", "right aligned"); console->info("{:^30}", "centered"); - + //Create a file rotating logger with 5mb size max and 3 rotated files auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3); - - file_logger->info("Log file message number", 1); - for(int i = 0; i < 10; ++i) - file_logger->info("{} * {} equals {:>10}", i, i, i*i); + + file_logger->info("Log file message number", 1); + for(int i = 0; i < 10; ++i) + file_logger->info("{} * {} equals {:>10}", i, i, i*i); spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***"); file_logger->info("This is another message with custom format"); diff --git a/include/spdlog/details/mpmc_bounded_q.h b/include/spdlog/details/mpmc_bounded_q.h index 53dfd108..7cbcfd70 100644 --- a/include/spdlog/details/mpmc_bounded_q.h +++ b/include/spdlog/details/mpmc_bounded_q.h @@ -74,101 +74,101 @@ class mpmc_bounded_queue { public: - using item_type = T; - mpmc_bounded_queue(size_t buffer_size) - : buffer_(new cell_t [buffer_size]), - buffer_mask_(buffer_size - 1) - { - //queue size must be power of two - if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0))) - throw spdlog_ex("async logger queue size must be power of two"); + using item_type = T; + mpmc_bounded_queue(size_t buffer_size) + : buffer_(new cell_t [buffer_size]), + buffer_mask_(buffer_size - 1) + { + //queue size must be power of two + if(!((buffer_size >= 2) && ((buffer_size & (buffer_size - 1)) == 0))) + throw spdlog_ex("async logger queue size must be power of two"); - for (size_t i = 0; i != buffer_size; i += 1) - buffer_[i].sequence_.store(i, std::memory_order_relaxed); - enqueue_pos_.store(0, std::memory_order_relaxed); - dequeue_pos_.store(0, std::memory_order_relaxed); - } + for (size_t i = 0; i != buffer_size; i += 1) + buffer_[i].sequence_.store(i, std::memory_order_relaxed); + enqueue_pos_.store(0, std::memory_order_relaxed); + dequeue_pos_.store(0, std::memory_order_relaxed); + } - ~mpmc_bounded_queue() - { - delete [] buffer_; - } + ~mpmc_bounded_queue() + { + delete [] buffer_; + } - bool enqueue(T&& data) - { - cell_t* cell; - size_t pos = enqueue_pos_.load(std::memory_order_relaxed); - for (;;) - { - cell = &buffer_[pos & buffer_mask_]; - size_t seq = cell->sequence_.load(std::memory_order_acquire); - intptr_t dif = (intptr_t)seq - (intptr_t)pos; - if (dif == 0) - { - if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) - break; - } - else if (dif < 0) - { - return false; - } - else - { - pos = enqueue_pos_.load(std::memory_order_relaxed); - } - } - cell->data_ = std::move(data); - cell->sequence_.store(pos + 1, std::memory_order_release); - return true; - } + bool enqueue(T&& data) + { + cell_t* cell; + size_t pos = enqueue_pos_.load(std::memory_order_relaxed); + for (;;) + { + cell = &buffer_[pos & buffer_mask_]; + size_t seq = cell->sequence_.load(std::memory_order_acquire); + intptr_t dif = (intptr_t)seq - (intptr_t)pos; + if (dif == 0) + { + if (enqueue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) + break; + } + else if (dif < 0) + { + return false; + } + else + { + pos = enqueue_pos_.load(std::memory_order_relaxed); + } + } + cell->data_ = std::move(data); + cell->sequence_.store(pos + 1, std::memory_order_release); + return true; + } - bool dequeue(T& data) - { - cell_t* cell; - size_t pos = dequeue_pos_.load(std::memory_order_relaxed); - for (;;) - { - cell = &buffer_[pos & buffer_mask_]; - size_t seq = - cell->sequence_.load(std::memory_order_acquire); - intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1); - if (dif == 0) - { - if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) - break; - } - else if (dif < 0) - return false; - else - pos = dequeue_pos_.load(std::memory_order_relaxed); - } - data = std::move(cell->data_); - cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release); - return true; - } + bool dequeue(T& data) + { + cell_t* cell; + size_t pos = dequeue_pos_.load(std::memory_order_relaxed); + for (;;) + { + cell = &buffer_[pos & buffer_mask_]; + size_t seq = + cell->sequence_.load(std::memory_order_acquire); + intptr_t dif = (intptr_t)seq - (intptr_t)(pos + 1); + if (dif == 0) + { + if (dequeue_pos_.compare_exchange_weak(pos, pos + 1, std::memory_order_relaxed)) + break; + } + else if (dif < 0) + return false; + else + pos = dequeue_pos_.load(std::memory_order_relaxed); + } + data = std::move(cell->data_); + cell->sequence_.store(pos + buffer_mask_ + 1, std::memory_order_release); + return true; + } private: - struct cell_t - { - std::atomic sequence_; - T data_; - }; + struct cell_t + { + std::atomic sequence_; + T data_; + }; - static size_t const cacheline_size = 64; - typedef char cacheline_pad_t [cacheline_size]; + static size_t const cacheline_size = 64; + typedef char cacheline_pad_t [cacheline_size]; - cacheline_pad_t pad0_; - cell_t* const buffer_; - size_t const buffer_mask_; - cacheline_pad_t pad1_; - std::atomic enqueue_pos_; - cacheline_pad_t pad2_; - std::atomic dequeue_pos_; - cacheline_pad_t pad3_; + cacheline_pad_t pad0_; + cell_t* const buffer_; + size_t const buffer_mask_; + cacheline_pad_t pad1_; + std::atomic enqueue_pos_; + cacheline_pad_t pad2_; + std::atomic dequeue_pos_; + cacheline_pad_t pad3_; - mpmc_bounded_queue(mpmc_bounded_queue const&); - void operator = (mpmc_bounded_queue const&); + mpmc_bounded_queue(mpmc_bounded_queue const&); + void operator = (mpmc_bounded_queue const&); }; } // ns details From 03a09705ff03d9b5ad8a55edf1debf753fba04bd Mon Sep 17 00:00:00 2001 From: gabime Date: Sun, 7 Dec 2014 07:24:46 +0200 Subject: [PATCH 095/120] example --- example/example.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/example/example.cpp b/example/example.cpp index d07cf801..0cfa326f 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -73,9 +73,10 @@ int main(int, char* []) // // Asynchronous logging is easy.. - // Just call spdlog::set_async_mode(max_q_size) and all created loggers from now on will be asynchronous.. + // Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous.. + // Note: queue size must be power of 2! // - size_t max_q_size = 1048576; + size_t max_q_size = 1048576; spdlog::set_async_mode(max_q_size); auto async_file= spd::daily_logger_st("async_file_logger", "logs/async_log.txt"); async_file->info() << "This is async log.." << "Should be very fast!"; From d8ceed165108342009b002f87b48af1b1d408e94 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 07:36:04 +0200 Subject: [PATCH 096/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c801a0a0..b1be9799 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Just copy the files to your build tree and use a C++11 compiler * **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library. * Example: ```logger.info("Hello {} {:08x}!!", "world", 42);``` * ostream call style: ```logger.info() << "Hello << "logger";``` -* **new!** Optional, extremly fast asynchronous mode using lockfree queues, pre allocated memory and deffered formatting. +* **new!** Extremely fast asynchronous mode(optional) using lockfree queues and other tricks, pre allocated memory and deffered formatting. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: From 932c16e7f9b80333d40af8e9d359875cf500d0a4 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 07:36:27 +0200 Subject: [PATCH 097/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b1be9799..6fb9e857 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Just copy the files to your build tree and use a C++11 compiler * **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library. * Example: ```logger.info("Hello {} {:08x}!!", "world", 42);``` * ostream call style: ```logger.info() << "Hello << "logger";``` -* **new!** Extremely fast asynchronous mode(optional) using lockfree queues and other tricks, pre allocated memory and deffered formatting. +* **new!** Extremely fast asynchronous mode (optional) using lockfree queues and other tricks, pre allocated memory and deffered formatting. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: From 81217e2330cc3b49f02013711b3b08c4bfb1b6d0 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 07:37:50 +0200 Subject: [PATCH 098/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6fb9e857..499b9dbd 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Just copy the files to your build tree and use a C++11 compiler * **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library. * Example: ```logger.info("Hello {} {:08x}!!", "world", 42);``` * ostream call style: ```logger.info() << "Hello << "logger";``` -* **new!** Extremely fast asynchronous mode (optional) using lockfree queues and other tricks, pre allocated memory and deffered formatting. +* **new!** Extremely fast asynchronous mode (optional) - use of lockfree queues and other tricks to reach millions of logs per seconds. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: From 46439d7040d7b4f1903c6dfea9b39dd70b4f0604 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 07:40:20 +0200 Subject: [PATCH 099/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 499b9dbd..ba05db72 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Just copy the files to your build tree and use a C++11 compiler * **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library. * Example: ```logger.info("Hello {} {:08x}!!", "world", 42);``` * ostream call style: ```logger.info() << "Hello << "logger";``` -* **new!** Extremely fast asynchronous mode (optional) - use of lockfree queues and other tricks to reach millions of logs per seconds. +* **new!** Extremely fast asynchronous mode (optional) - use of lockfree queues and other tricks to reach millions log calls per second. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: From 7a93d944b8ad0209bbf566f11a361fce4e742166 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 07:41:11 +0200 Subject: [PATCH 100/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ba05db72..61b61af1 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Just copy the files to your build tree and use a C++11 compiler * **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library. * Example: ```logger.info("Hello {} {:08x}!!", "world", 42);``` * ostream call style: ```logger.info() << "Hello << "logger";``` -* **new!** Extremely fast asynchronous mode (optional) - use of lockfree queues and other tricks to reach millions log calls per second. +* **new!** Extremely fast asynchronous mode (optional) - use of lockfree queues and other tricks to reach millions calls per second from multiple threads. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: From ffb4ae828212d19cf8a5965e4d66af863f90aeda Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 07:41:38 +0200 Subject: [PATCH 101/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 61b61af1..90368773 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Just copy the files to your build tree and use a C++11 compiler * **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library. * Example: ```logger.info("Hello {} {:08x}!!", "world", 42);``` * ostream call style: ```logger.info() << "Hello << "logger";``` -* **new!** Extremely fast asynchronous mode (optional) - use of lockfree queues and other tricks to reach millions calls per second from multiple threads. +* **new!** Extremely fast asynchronous mode (optional) - use of lockfree queues and other tricks to reach millions of calls per second from multiple threads. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: From 13b29915d5575a8892d963f9a6a8028dda1e420c Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 07:43:40 +0200 Subject: [PATCH 102/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 90368773..d1f1b6fb 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Just copy the files to your build tree and use a C++11 compiler * Console logging. * Linux syslog. * Easily extendable with custom log targets (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface). -* Severity based filtering - can be modified in runtime. +* Severity based filtering - threshold levels can be modified in runtime. From dbdda39683eff3c7a7c5e59a6b8c66d45a67ae83 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 09:36:33 +0200 Subject: [PATCH 103/120] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index d1f1b6fb..15c03812 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,6 @@ int main(int, char* []) //Create a file rotating logger with 5mb size max and 3 rotated files auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3); - file_logger->info("Log file message number", 1); for(int i = 0; i < 10; ++i) file_logger->info("{} * {} equals {:>10}", i, i, i*i); From c77e0fa8372b9c993176af59680b433f904e5d2d Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 09:41:21 +0200 Subject: [PATCH 104/120] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 15c03812..7db77140 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,7 @@ int main(int, char* []) for(int i = 0; i < 10; ++i) file_logger->info("{} * {} equals {:>10}", i, i, i*i); + //Customize msg format spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***"); file_logger->info("This is another message with custom format"); From b1a495dbb096099de3752dadc8b20732ba0ba5b5 Mon Sep 17 00:00:00 2001 From: gabi Date: Sun, 7 Dec 2014 16:34:22 +0200 Subject: [PATCH 105/120] Fixed linkage errors under VC on the new version --- include/spdlog/details/format.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/spdlog/details/format.cc b/include/spdlog/details/format.cc index 76ef84eb..2a8a2932 100644 --- a/include/spdlog/details/format.cc +++ b/include/spdlog/details/format.cc @@ -445,7 +445,7 @@ FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) { #ifdef _WIN32 -fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { +FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { int length = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0); static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16"; @@ -458,14 +458,14 @@ fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { FMT_THROW(WindowsError(GetLastError(), ERROR)); } -fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { +FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { if (int error_code = convert(s)) { FMT_THROW(WindowsError(error_code, "cannot convert string from UTF-16 to UTF-8")); } } -int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { +FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0); if (length == 0) return GetLastError(); @@ -477,7 +477,7 @@ int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { return 0; } -void fmt::WindowsError::init( +FMT_FUNC void fmt::WindowsError::init( int error_code, StringRef format_str, ArgList args) { error_code_ = error_code; MemoryWriter w; @@ -510,7 +510,7 @@ FMT_FUNC void fmt::internal::format_system_error( } #ifdef _WIN32 -void fmt::internal::format_windows_error( +FMT_FUNC void fmt::internal::format_windows_error( fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { class String { @@ -1090,7 +1090,7 @@ FMT_FUNC void fmt::report_system_error( } #ifdef _WIN32 -void fmt::report_windows_error( +FMT_FUNC void fmt::report_windows_error( int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { report_error(internal::format_windows_error, error_code, message); } From c87c6b64b92462c9595239866a4bf3f8ec40074f Mon Sep 17 00:00:00 2001 From: gabi Date: Sun, 7 Dec 2014 18:47:59 +0200 Subject: [PATCH 106/120] Fix linkage errors --- example/bench.cpp | 88 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 28 deletions(-) diff --git a/example/bench.cpp b/example/bench.cpp index be9a0c27..84402f7f 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -46,60 +46,90 @@ using namespace utils; void bench(int howmany, std::shared_ptr log); void bench_mt(int howmany, std::shared_ptr log, int thread_count); - +void f(); int main(int argc, char* argv[]) { + int howmany = 1048576; int threads = 10; bool auto_flush = false; int file_size = 30 * 1024 * 1024; int rotating_files = 5; + //spdlog::set_pattern("%x %X.%e %v"); + auto console = spdlog::stdout_logger_mt("console"); + + f(); + console->info("Welcome to spdlog!"); + console->info("An info message example {}..", 1); + console->info() << "Streams are supported too " << 1; + + + console->info("Easy padding in numbers like {:08d}", 12); + console->info("Support for int: {0:d}; hex: {0:08x}; oct: {0:o}; bin: {0:b}", 42); + console->info("Support for floats {:03.2f}", 1.23456); + console->info("Positional args are {1} {0}..", "too", "supported"); + + console->info("{:<30}", "left aligned"); + console->info("{:>30}", "right aligned"); + console->info("{:^30}", "centered"); + + + //return 0; + + try { - if(argc > 1) howmany = atoi(argv[1]); if (argc > 2) threads = atoi(argv[2]); + /* cout << "*******************************************************************************\n"; + cout << "Single thread, " << format(howmany) << " iterations, flush every " << auto_flush << " lines"<< endl; + cout << "*******************************************************************************\n"; - cout << "*******************************************************************************\n"; - cout << "Single thread, " << format(howmany) << " iterations, auto flush=" << auto_flush << endl; - cout << "*******************************************************************************\n"; + auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st", file_size, rotating_files, auto_flush); + bench(howmany, rotating_st); + auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st", auto_flush); + bench(howmany, daily_st); + bench(howmany, spdlog::create("null_st")); - auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st", file_size, rotating_files, auto_flush); - bench(howmany, rotating_st); - auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st", auto_flush); - bench(howmany, daily_st); - bench(howmany, spdlog::create("null_st")); + cout << "\n*******************************************************************************\n"; + cout << threads << " threads sharing same logger, " << format(howmany) << " iterations, flush every " << auto_flush << " lines" << endl; + cout << "*******************************************************************************\n"; + + auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", file_size, rotating_files, auto_flush); + bench_mt(howmany, rotating_mt, threads); + */ + + //auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt", auto_flush); + //bench_mt(howmany, daily_mt, threads); + + + //spdlog::set_pattern("%T %z"); + //while (true) + // bench_mt(howmany, spdlog::create("null_st"), 8); cout << "\n*******************************************************************************\n"; - cout << threads << " threads sharing same logger, " << format(howmany) << " iterations, auto_flush=" << auto_flush << endl; + cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " iterations, flush every " << auto_flush << " lines" << endl; cout << "*******************************************************************************\n"; - auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", file_size, rotating_files, auto_flush); - bench_mt(howmany, rotating_mt, threads); + //spdlog::set_async_mode(howmany); + //auto as = spdlog::rotating_logger_st("as", "logs/rotating_async", file_size, rotating_files, auto_flush); - auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt", auto_flush); - bench_mt(howmany, daily_mt, threads); - bench(howmany, spdlog::create("null_mt")); - - cout << "\n*******************************************************************************\n"; - cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " iterations, auto_flush=" << auto_flush << endl; - cout << "*******************************************************************************\n"; - - - spdlog::set_async_mode(howmany); - - for(int i = 0; i < 5; ++i) + while (true) { - auto as = spdlog::daily_logger_st("as", "logs/daily_async", auto_flush); + auto as = std::make_shared("as", std::make_shared(), howmany); bench_mt(howmany, as, threads); - spdlog::drop("as"); } + + + //cin.ignore(); + + } catch (std::exception &ex) { @@ -116,7 +146,7 @@ void bench(int howmany, std::shared_ptr log) auto start = system_clock::now(); for (auto i = 0; i < howmany; ++i) { - log->info("Hello logger: msg number {}", i); + log->info("Hello logger: msg number ", i); } @@ -129,10 +159,12 @@ void bench(int howmany, std::shared_ptr log) void bench_mt(int howmany, std::shared_ptr log, int thread_count) { + cout << log->name() << "...\t\t" << flush; std::atomic msg_counter {0}; vector threads; auto start = system_clock::now(); + for (int t = 0; t < thread_count; ++t) { threads.push_back(std::thread([&]() From 961d5b947df5ad61260782406789720db1920e29 Mon Sep 17 00:00:00 2001 From: gabi Date: Sun, 7 Dec 2014 18:49:34 +0200 Subject: [PATCH 107/120] Undo commit --- example/bench.cpp | 95 ++++++++++++++++------------------------------- 1 file changed, 31 insertions(+), 64 deletions(-) diff --git a/example/bench.cpp b/example/bench.cpp index 84402f7f..c06c71e3 100644 --- a/example/bench.cpp +++ b/example/bench.cpp @@ -46,90 +46,60 @@ using namespace utils; void bench(int howmany, std::shared_ptr log); void bench_mt(int howmany, std::shared_ptr log, int thread_count); -void f(); + int main(int argc, char* argv[]) { - int howmany = 1048576; int threads = 10; bool auto_flush = false; int file_size = 30 * 1024 * 1024; int rotating_files = 5; - //spdlog::set_pattern("%x %X.%e %v"); - auto console = spdlog::stdout_logger_mt("console"); - - f(); - console->info("Welcome to spdlog!"); - console->info("An info message example {}..", 1); - console->info() << "Streams are supported too " << 1; - - - console->info("Easy padding in numbers like {:08d}", 12); - console->info("Support for int: {0:d}; hex: {0:08x}; oct: {0:o}; bin: {0:b}", 42); - console->info("Support for floats {:03.2f}", 1.23456); - console->info("Positional args are {1} {0}..", "too", "supported"); - - console->info("{:<30}", "left aligned"); - console->info("{:>30}", "right aligned"); - console->info("{:^30}", "centered"); - - - //return 0; - - try { + if(argc > 1) howmany = atoi(argv[1]); if (argc > 2) threads = atoi(argv[2]); - /* cout << "*******************************************************************************\n"; - cout << "Single thread, " << format(howmany) << " iterations, flush every " << auto_flush << " lines"<< endl; - cout << "*******************************************************************************\n"; - auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st", file_size, rotating_files, auto_flush); - bench(howmany, rotating_st); - auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st", auto_flush); - bench(howmany, daily_st); - bench(howmany, spdlog::create("null_st")); - - cout << "\n*******************************************************************************\n"; - cout << threads << " threads sharing same logger, " << format(howmany) << " iterations, flush every " << auto_flush << " lines" << endl; - cout << "*******************************************************************************\n"; - - auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", file_size, rotating_files, auto_flush); - bench_mt(howmany, rotating_mt, threads); - */ - - //auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt", auto_flush); - //bench_mt(howmany, daily_mt, threads); - - - //spdlog::set_pattern("%T %z"); - //while (true) - // bench_mt(howmany, spdlog::create("null_st"), 8); - - cout << "\n*******************************************************************************\n"; - cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " iterations, flush every " << auto_flush << " lines" << endl; + cout << "*******************************************************************************\n"; + cout << "Single thread, " << format(howmany) << " iterations, auto flush=" << auto_flush << endl; cout << "*******************************************************************************\n"; - //spdlog::set_async_mode(howmany); + auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st", file_size, rotating_files, auto_flush); + bench(howmany, rotating_st); + auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st", auto_flush); + bench(howmany, daily_st); + bench(howmany, spdlog::create("null_st")); - //auto as = spdlog::rotating_logger_st("as", "logs/rotating_async", file_size, rotating_files, auto_flush); + cout << "\n*******************************************************************************\n"; + cout << threads << " threads sharing same logger, " << format(howmany) << " iterations, auto_flush=" << auto_flush << endl; + cout << "*******************************************************************************\n"; - while (true) + auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", file_size, rotating_files, auto_flush); + bench_mt(howmany, rotating_mt, threads); + + + auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt", auto_flush); + bench_mt(howmany, daily_mt, threads); + bench(howmany, spdlog::create("null_mt")); + + cout << "\n*******************************************************************************\n"; + cout << "async logging.. " << threads << " threads sharing same logger, " << format(howmany) << " iterations, auto_flush=" << auto_flush << endl; + cout << "*******************************************************************************\n"; + + + spdlog::set_async_mode(howmany); + + for(int i = 0; i < 5; ++i) { - auto as = std::make_shared("as", std::make_shared(), howmany); + auto as = spdlog::daily_logger_st("as", "logs/daily_async", auto_flush); bench_mt(howmany, as, threads); + spdlog::drop("as"); } - - - //cin.ignore(); - - } catch (std::exception &ex) { @@ -146,7 +116,7 @@ void bench(int howmany, std::shared_ptr log) auto start = system_clock::now(); for (auto i = 0; i < howmany; ++i) { - log->info("Hello logger: msg number ", i); + log->info("Hello logger: msg number {}", i); } @@ -159,12 +129,10 @@ void bench(int howmany, std::shared_ptr log) void bench_mt(int howmany, std::shared_ptr log, int thread_count) { - cout << log->name() << "...\t\t" << flush; std::atomic msg_counter {0}; vector threads; auto start = system_clock::now(); - for (int t = 0; t < thread_count; ++t) { threads.push_back(std::thread([&]() @@ -189,4 +157,3 @@ void bench_mt(int howmany, std::shared_ptr log, int thread_count auto delta_d = duration_cast> (delta).count(); cout << format(int(howmany / delta_d)) << "/sec" << endl; } - From 65a1e5690c33e3257136ecaee20c4aaec4e8c2c5 Mon Sep 17 00:00:00 2001 From: gabi Date: Sun, 7 Dec 2014 18:49:51 +0200 Subject: [PATCH 108/120] fixed vs linkage errors --- include/spdlog/details/format.cc | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/spdlog/details/format.cc b/include/spdlog/details/format.cc index 2a8a2932..8ef64ab9 100644 --- a/include/spdlog/details/format.cc +++ b/include/spdlog/details/format.cc @@ -138,7 +138,7 @@ typedef void(*FormatFunc)(fmt::Writer &, int, fmt::StringRef); // ERANGE - buffer is not large enough to store the error message // other - failure // Buffer should be at least of size 1. -int safe_strerror( +FMT_FUNC int safe_strerror( int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) { assert(buffer != 0 && buffer_size != 0); int result = 0; @@ -166,8 +166,8 @@ int safe_strerror( return result; } -void format_error_code(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT(true) { +FMT_FUNC void format_error_code(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT(true) { // Report error code making sure that the output fits into // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential // bad_alloc. @@ -184,8 +184,8 @@ void format_error_code(fmt::Writer &out, int error_code, assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE); } -void report_error(FormatFunc func, - int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { +FMT_FUNC void report_error(FormatFunc func, + int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { fmt::MemoryWriter full_message; func(full_message, error_code, message); // Use Writer::data instead of Writer::c_str to avoid potential memory @@ -206,7 +206,7 @@ public: // Parses an unsigned integer advancing s to the end of the parsed input. // This function assumes that the first character of s is a digit. template -int parse_nonnegative_int(const Char *&s) { +FMT_FUNC int parse_nonnegative_int(const Char *&s) { assert('0' <= *s && *s <= '9'); unsigned value = 0; do { @@ -232,7 +232,7 @@ inline void require_numeric_argument(const Arg &arg, char spec) { } template -void check_sign(const Char *&s, const Arg &arg) { +FMT_FUNC void check_sign(const Char *&s, const Arg &arg) { char sign = static_cast(*s); require_numeric_argument(arg, sign); if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { @@ -372,7 +372,7 @@ FMT_FUNC void fmt::SystemError::init( } template -int fmt::internal::CharTraits::format_float( +FMT_FUNC int fmt::internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value) { if (width == 0) { @@ -386,7 +386,7 @@ int fmt::internal::CharTraits::format_float( } template -int fmt::internal::CharTraits::format_float( +FMT_FUNC int fmt::internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value) { if (width == 0) { @@ -623,7 +623,7 @@ public: template template -void fmt::BasicWriter::write_str( +FMT_FUNC void fmt::BasicWriter::write_str( const Arg::StringValue &str, const FormatSpec &spec) { // Check if StrChar is convertible to Char. internal::CharTraits::convert(StrChar()); @@ -678,7 +678,7 @@ inline Arg fmt::internal::FormatterBase::get_arg( } template -void fmt::internal::PrintfFormatter::parse_flags( +FMT_FUNC void fmt::internal::PrintfFormatter::parse_flags( FormatSpec &spec, const Char *&s) { for (;;) { switch (*s++) { @@ -705,7 +705,7 @@ void fmt::internal::PrintfFormatter::parse_flags( } template -Arg fmt::internal::PrintfFormatter::get_arg( +FMT_FUNC Arg fmt::internal::PrintfFormatter::get_arg( const Char *s, unsigned arg_index) { const char *error = 0; Arg arg = arg_index == UINT_MAX ? @@ -716,7 +716,7 @@ Arg fmt::internal::PrintfFormatter::get_arg( } template -unsigned fmt::internal::PrintfFormatter::parse_header( +FMT_FUNC unsigned fmt::internal::PrintfFormatter::parse_header( const Char *&s, FormatSpec &spec) { unsigned arg_index = UINT_MAX; Char c = *s; @@ -752,7 +752,7 @@ unsigned fmt::internal::PrintfFormatter::parse_header( } template -void fmt::internal::PrintfFormatter::format( +FMT_FUNC void fmt::internal::PrintfFormatter::format( BasicWriter &writer, BasicStringRef format, const ArgList &args) { const Char *start = format.c_str(); @@ -923,7 +923,7 @@ void fmt::internal::PrintfFormatter::format( } template -const Char *fmt::BasicFormatter::format( +FMT_FUNC const Char *fmt::BasicFormatter::format( const Char *&format_str, const Arg &arg) { const Char *s = format_str; FormatSpec spec; @@ -1063,7 +1063,7 @@ const Char *fmt::BasicFormatter::format( } template -void fmt::BasicFormatter::format( +FMT_FUNC void fmt::BasicFormatter::format( BasicStringRef format_str, const ArgList &args) { const Char *s = start_ = format_str.c_str(); set_args(args); From 2b6df8dfae682c31465648f2e3f1a548e69d773d Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 20:19:33 +0200 Subject: [PATCH 109/120] Update README.md --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7db77140..aee13ad9 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,8 @@ Just copy the files to your build tree and use a C++11 compiler * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. * **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library. -* Example: ```logger.info("Hello {} {:08x}!!", "world", 42);``` -* ostream call style: ```logger.info() << "Hello << "logger";``` -* **new!** Extremely fast asynchronous mode (optional) - use of lockfree queues and other tricks to reach millions of calls per second from multiple threads. +* ostream call style. +* Extremely fast asynchronous mode (optional) - use of lockfree queues and other tricks to reach millions of calls per second from multiple threads. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. * Various log targets: From 8aceca9e7c63fae0d768eb92c4931da13e54a361 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 20:20:27 +0200 Subject: [PATCH 110/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aee13ad9..678f1110 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Just copy the files to your build tree and use a C++11 compiler * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. * **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library. -* ostream call style. +* Optional ostream call style. * Extremely fast asynchronous mode (optional) - use of lockfree queues and other tricks to reach millions of calls per second from multiple threads. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers. From 4ee43eb2098eeef236c3065c93148529de77a541 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 20:21:43 +0200 Subject: [PATCH 111/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 678f1110..162655b8 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new!** Feature rich cppfromat [call style](http://cppformat.readthedocs.org/en/stable/syntax.html) using the excellent [cppformat](http://cppformat.github.io/) library. +* **new!** Feature rich cppfromat [call style](#usage-example) using the excellent [cppformat](http://cppformat.github.io/) library. * Optional ostream call style. * Extremely fast asynchronous mode (optional) - use of lockfree queues and other tricks to reach millions of calls per second from multiple threads. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. From 12169033c36e7b2de2f4db0d949a2f4f28bf677f Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 20:26:42 +0200 Subject: [PATCH 112/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 162655b8..a44fc047 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Just copy the files to your build tree and use a C++11 compiler * Headers only. * No dependencies. * Cross platform - Linux / Windows on 32/64 bits. -* **new!** Feature rich cppfromat [call style](#usage-example) using the excellent [cppformat](http://cppformat.github.io/) library. +* **new!** Feature rich [call style](#usage-example) using the excellent [cppformat](http://cppformat.github.io/) library. * Optional ostream call style. * Extremely fast asynchronous mode (optional) - use of lockfree queues and other tricks to reach millions of calls per second from multiple threads. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. From eb325333337aeff4144c274400a983219865d2f9 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Sun, 7 Dec 2014 20:27:21 +0200 Subject: [PATCH 113/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a44fc047..f2238866 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Just copy the files to your build tree and use a C++11 compiler ##Features * Very fast - performance is the primary goal (see [becnhmarks](#benchmarks) below). * Headers only. -* No dependencies. +* No dependencies - just copy and use. * Cross platform - Linux / Windows on 32/64 bits. * **new!** Feature rich [call style](#usage-example) using the excellent [cppformat](http://cppformat.github.io/) library. * Optional ostream call style. From d0dcc13f7c265bd86e926f260b08ed3dffc10a58 Mon Sep 17 00:00:00 2001 From: gabi Date: Mon, 8 Dec 2014 00:09:54 +0200 Subject: [PATCH 114/120] small cleanup --- include/spdlog/details/line_logger.h | 22 ++++++++++++---------- include/spdlog/details/logger_impl.h | 21 ++++++--------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/include/spdlog/details/line_logger.h b/include/spdlog/details/line_logger.h index 2a2bd2af..cf54bb79 100644 --- a/include/spdlog/details/line_logger.h +++ b/include/spdlog/details/line_logger.h @@ -69,25 +69,27 @@ public: } } - template - void write(const T& what) - { - if (_enabled) - { - _log_msg.raw << what; - } - } template void write(const std::string& fmt, const Args&... args) { - _log_msg.raw.write(fmt, args...); + if (!_enabled) + return; + try + { + _log_msg.raw.write(fmt, args...); + } + catch (const fmt::FormatError& e) + { + throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what())); + } } template line_logger& operator<<(const T& what) { - write(what); + if (_enabled) + _log_msg.raw << what; return *this; } diff --git a/include/spdlog/details/logger_impl.h b/include/spdlog/details/logger_impl.h index 62e8a6e5..286dde48 100644 --- a/include/spdlog/details/logger_impl.h +++ b/include/spdlog/details/logger_impl.h @@ -71,18 +71,7 @@ inline spdlog::details::line_logger spdlog::logger::_log(level::level_enum lvl, { bool msg_enabled = should_log(lvl); details::line_logger l(this, lvl, msg_enabled); - if (msg_enabled) - { - try - { - l.write(fmt, args...); - } - catch(const fmt::FormatError& e) - { - throw spdlog_ex(fmt::format("formatting error while processing format string '{}': {}", fmt, e.what())); - } - - } + l.write(fmt, args...); return l; } @@ -151,7 +140,6 @@ inline spdlog::details::line_logger spdlog::logger::emerg(const std::string& fmt // //API to support logger.info() << ".." calls // - inline spdlog::details::line_logger spdlog::logger::_log(level::level_enum lvl) { bool msg_enabled = should_log(lvl); @@ -213,7 +201,8 @@ inline spdlog::details::line_logger spdlog::logger::emerg() // - +// name and level +// inline const std::string& spdlog::logger::name() const { return _name; @@ -239,7 +228,9 @@ inline void spdlog::logger::stop() _stop(); } -/* protected virtual */ +// +// protected virtual called at end of each user log call (if enabled) by the line_logger +// inline void spdlog::logger::_log_msg(details::log_msg& msg) { _formatter->format(msg); From 4637cf35df9a7e4dcb40b1affd49cb54360ebd7e Mon Sep 17 00:00:00 2001 From: gabi Date: Mon, 8 Dec 2014 00:55:45 +0200 Subject: [PATCH 115/120] Improved perf by using const char* instead of std::string& when accepting format strings --- include/spdlog/details/line_logger.h | 2 +- include/spdlog/details/logger_impl.h | 22 +++++++++++----------- include/spdlog/logger.h | 22 +++++++++++----------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/include/spdlog/details/line_logger.h b/include/spdlog/details/line_logger.h index cf54bb79..7160f6da 100644 --- a/include/spdlog/details/line_logger.h +++ b/include/spdlog/details/line_logger.h @@ -71,7 +71,7 @@ public: template - void write(const std::string& fmt, const Args&... args) + void write(const char* fmt, const Args&... args) { if (!_enabled) return; diff --git a/include/spdlog/details/logger_impl.h b/include/spdlog/details/logger_impl.h index 286dde48..3f2360b0 100644 --- a/include/spdlog/details/logger_impl.h +++ b/include/spdlog/details/logger_impl.h @@ -67,7 +67,7 @@ inline void spdlog::logger::set_pattern(const std::string& pattern) // cppformat API of the form logger.info("hello {} {}", "world", 1); // template -inline spdlog::details::line_logger spdlog::logger::_log(level::level_enum lvl, const std::string& fmt, const Args&... args) +inline spdlog::details::line_logger spdlog::logger::_log(level::level_enum lvl, const char* fmt, const Args&... args) { bool msg_enabled = should_log(lvl); details::line_logger l(this, lvl, msg_enabled); @@ -76,61 +76,61 @@ inline spdlog::details::line_logger spdlog::logger::_log(level::level_enum lvl, } template -inline spdlog::details::line_logger spdlog::logger::log(const std::string& fmt, const Args&... args) +inline spdlog::details::line_logger spdlog::logger::log(const char* fmt, const Args&... args) { return _log(level::ALWAYS, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::trace(const std::string& fmt, const Args&... args) +inline spdlog::details::line_logger spdlog::logger::trace(const char* fmt, const Args&... args) { return _log(level::TRACE, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::debug(const std::string& fmt, const Args&... args) +inline spdlog::details::line_logger spdlog::logger::debug(const char* fmt, const Args&... args) { return _log(level::DEBUG, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::info(const std::string& fmt, const Args&... args) +inline spdlog::details::line_logger spdlog::logger::info(const char* fmt, const Args&... args) { return _log(level::INFO, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::notice(const std::string& fmt, const Args&... args) +inline spdlog::details::line_logger spdlog::logger::notice(const char* fmt, const Args&... args) { return _log(level::NOTICE, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::warn(const std::string& fmt, const Args&... args) +inline spdlog::details::line_logger spdlog::logger::warn(const char* fmt, const Args&... args) { return _log(level::WARN, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::error(const std::string& fmt, const Args&... args) +inline spdlog::details::line_logger spdlog::logger::error(const char* fmt, const Args&... args) { return _log(level::ERR, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::critical(const std::string& fmt, const Args&... args) +inline spdlog::details::line_logger spdlog::logger::critical(const char* fmt, const Args&... args) { return _log(level::CRITICAL, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::alert(const std::string& fmt, const Args&... args) +inline spdlog::details::line_logger spdlog::logger::alert(const char* fmt, const Args&... args) { return _log(level::ALERT, fmt, args...); } template -inline spdlog::details::line_logger spdlog::logger::emerg(const std::string& fmt, const Args&... args) +inline spdlog::details::line_logger spdlog::logger::emerg(const char* fmt, const Args&... args) { return _log(level::EMERG, fmt, args...); } diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h index cc7fb58b..095c34a9 100644 --- a/include/spdlog/logger.h +++ b/include/spdlog/logger.h @@ -65,16 +65,16 @@ public: //Stop logging void stop(); - template details::line_logger log(const std::string& fmt, const Args&... args); - template details::line_logger trace(const std::string& fmt, const Args&... args); - template details::line_logger debug(const std::string& fmt, const Args&... args); - template details::line_logger info(const std::string& fmt, const Args&... args); - template details::line_logger notice(const std::string& fmt, const Args&... args); - template details::line_logger warn(const std::string& fmt, const Args&... args); - template details::line_logger error(const std::string& fmt, const Args&... args); - template details::line_logger critical(const std::string& fmt, const Args&... args); - template details::line_logger alert(const std::string& fmt, const Args&... args); - template details::line_logger emerg(const std::string& fmt, const Args&... args); + template details::line_logger log(const char* fmt, const Args&... args); + template details::line_logger trace(const char* fmt, const Args&... args); + template details::line_logger debug(const char* fmt, const Args&... args); + template details::line_logger info(const char* fmt, const Args&... args); + template details::line_logger notice(const char* fmt, const Args&... args); + template details::line_logger warn(const char* fmt, const Args&... args); + template details::line_logger error(const char* fmt, const Args&... args); + template details::line_logger critical(const char* fmt, const Args&... args); + template details::line_logger alert(const char* fmt, const Args&... args); + template details::line_logger emerg(const char* fmt, const Args&... args); //API to support logger.info() << ".." calls @@ -100,7 +100,7 @@ protected: virtual void _set_formatter(formatter_ptr); virtual void _stop(); details::line_logger _log(level::level_enum lvl); - template details::line_logger _log(level::level_enum lvl, const std::string& fmt, const Args&... args); + template details::line_logger _log(level::level_enum lvl, const char* fmt, const Args&... args); friend details::line_logger; From b774059ae6e9d8f7fb062f2c30de0f9880b7f71c Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Mon, 8 Dec 2014 11:38:33 +0200 Subject: [PATCH 116/120] Update README.md --- README.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f2238866..7d010f97 100644 --- a/README.md +++ b/README.md @@ -69,16 +69,14 @@ int main(int, char* []) console->info("{:<30}", "left aligned"); console->info("{:>30}", "right aligned"); console->info("{:^30}", "centered"); - - //See cppformat syntax documation here: - //http://cppformat.readthedocs.org/en/stable/syntax.html - + //Create a file rotating logger with 5mb size max and 3 rotated files - auto file_logger = spd::rotating_logger_mt("file_logger", filename, 1024 * 1024 * 5, 3); + auto file_logger = spd::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3); + file_logger->set_level(spd::level::INFO); for(int i = 0; i < 10; ++i) file_logger->info("{} * {} equals {:>10}", i, i, i*i); - //Customize msg format + //Customize msg format for all messages spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***"); file_logger->info("This is another message with custom format"); @@ -87,8 +85,8 @@ int main(int, char* []) SPDLOG_TRACE(file_logger, "This is a trace message (only #ifdef _DEBUG)", 123); // - // Asynchronous logging is easy.. - // Just call spdlog::set_async_mode(max_q_size) and all created loggers from now on will be asynchronous.. + // Asynchronous logging is very fast.. + // Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous.. // size_t q_size = 1048576; //queue size must be power of 2 spdlog::set_async_mode(q_size); From 5cf9437ae7ff7f226aaa5c2ad52f66cbe20a6645 Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Mon, 8 Dec 2014 11:39:50 +0200 Subject: [PATCH 117/120] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 7d010f97..a6174bfb 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,6 @@ int main(int, char* []) namespace spd = spdlog; try { - std::string filename = "logs/spdlog_example"; // Set log level to all loggers to DEBUG and above spd::set_level(spd::level::DEBUG); From d817994bd251ff29da9c6528e38dc66735bf6079 Mon Sep 17 00:00:00 2001 From: gabi Date: Tue, 9 Dec 2014 00:01:11 +0200 Subject: [PATCH 118/120] Moved namespace fmt to be under spdlog::details to minimize namespace pollution for the users --- include/spdlog/details/format.cc | 215 +++++++++--------- include/spdlog/details/format.h | 15 +- .../spdlog/details/pattern_formatter_impl.h | 6 +- include/spdlog/sinks/file_sinks.h | 4 +- 4 files changed, 125 insertions(+), 115 deletions(-) diff --git a/include/spdlog/details/format.cc b/include/spdlog/details/format.cc index 8ef64ab9..070bf614 100644 --- a/include/spdlog/details/format.cc +++ b/include/spdlog/details/format.cc @@ -1,5 +1,8 @@ /* -Formatting library for C++ + +Modified version of cppformat formatting library + +Orginal license: Copyright (c) 2012 - 2014, Victor Zverovich All rights reserved. @@ -49,9 +52,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # undef ERROR #endif -using fmt::LongLong; -using fmt::ULongLong; -using fmt::internal::Arg; +using spdlog::details::fmt::LongLong; +using spdlog::details::fmt::ULongLong; +using spdlog::details::fmt::internal::Arg; // Check if exceptions are disabled. #if __GNUC__ && !__EXCEPTIONS @@ -127,7 +130,7 @@ struct IntChecker { const char RESET_COLOR[] = "\x1b[0m"; -typedef void(*FormatFunc)(fmt::Writer &, int, fmt::StringRef); +typedef void(*FormatFunc)(spdlog::details::fmt::Writer &, int, spdlog::details::fmt::StringRef); // Portable thread-safe version of strerror. // Sets buffer to point to a string describing the error code. @@ -166,27 +169,27 @@ FMT_FUNC int safe_strerror( return result; } -FMT_FUNC void format_error_code(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT(true) { +FMT_FUNC void format_error_code(spdlog::details::fmt::Writer &out, int error_code, + spdlog::details::fmt::StringRef message) FMT_NOEXCEPT(true) { // Report error code making sure that the output fits into // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential // bad_alloc. out.clear(); static const char SEP[] = ": "; static const char ERROR[] = "error "; - fmt::internal::IntTraits::MainType ec_value = error_code; + spdlog::details::fmt::internal::IntTraits::MainType ec_value = error_code; // Subtract 2 to account for terminating null characters in SEP and ERROR. std::size_t error_code_size = - sizeof(SEP) + sizeof(ERROR) + fmt::internal::count_digits(ec_value) - 2; - if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size) + sizeof(SEP) + sizeof(ERROR) + spdlog::details::fmt::internal::count_digits(ec_value) - 2; + if (message.size() <= spdlog::details::fmt::internal::INLINE_BUFFER_SIZE - error_code_size) out << message << SEP; out << ERROR << error_code; - assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE); + assert(out.size() <= spdlog::details::fmt::internal::INLINE_BUFFER_SIZE); } FMT_FUNC void report_error(FormatFunc func, - int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { - fmt::MemoryWriter full_message; + int error_code, spdlog::details::fmt::StringRef message) FMT_NOEXCEPT(true) { + spdlog::details::fmt::MemoryWriter full_message; func(full_message, error_code, message); // Use Writer::data instead of Writer::c_str to avoid potential memory // allocation. @@ -195,7 +198,7 @@ FMT_FUNC void report_error(FormatFunc func, } // IsZeroInt::visit(arg) returns true iff arg is a zero integer. -class IsZeroInt : public fmt::internal::ArgVisitor { +class IsZeroInt : public spdlog::details::fmt::internal::ArgVisitor { public: template bool visit_any_int(T value) { @@ -219,15 +222,15 @@ FMT_FUNC int parse_nonnegative_int(const Char *&s) { value = new_value; } while ('0' <= *s && *s <= '9'); if (value > INT_MAX) - FMT_THROW(fmt::FormatError("number is too big")); + FMT_THROW(spdlog::details::fmt::FormatError("number is too big")); return value; } inline void require_numeric_argument(const Arg &arg, char spec) { if (arg.type > Arg::LAST_NUMERIC_TYPE) { std::string message = - fmt::format("format specifier '{}' requires numeric argument", spec); - FMT_THROW(fmt::FormatError(message)); + spdlog::details::fmt::format("format specifier '{}' requires numeric argument", spec); + FMT_THROW(spdlog::details::fmt::FormatError(message)); } } @@ -236,71 +239,71 @@ FMT_FUNC void check_sign(const Char *&s, const Arg &arg) { char sign = static_cast(*s); require_numeric_argument(arg, sign); if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { - FMT_THROW(fmt::FormatError(fmt::format( - "format specifier '{}' requires signed argument", sign))); + FMT_THROW(spdlog::details::fmt::FormatError(spdlog::details::fmt::format( + "format specifier '{}' requires signed argument", sign))); } ++s; } // Checks if an argument is a valid printf width specifier and sets // left alignment if it is negative. -class WidthHandler : public fmt::internal::ArgVisitor { +class WidthHandler : public spdlog::details::fmt::internal::ArgVisitor { private: - fmt::FormatSpec &spec_; + spdlog::details::fmt::FormatSpec &spec_; public: - explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {} + explicit WidthHandler(spdlog::details::fmt::FormatSpec &spec) : spec_(spec) {} unsigned visit_unhandled_arg() { - FMT_THROW(fmt::FormatError("width is not integer")); + FMT_THROW(spdlog::details::fmt::FormatError("width is not integer")); return 0; } template unsigned visit_any_int(T value) { - typedef typename fmt::internal::IntTraits::MainType UnsignedType; + typedef typename spdlog::details::fmt::internal::IntTraits::MainType UnsignedType; UnsignedType width = value; - if (fmt::internal::is_negative(value)) { - spec_.align_ = fmt::ALIGN_LEFT; + if (spdlog::details::fmt::internal::is_negative(value)) { + spec_.align_ = spdlog::details::fmt::ALIGN_LEFT; width = 0 - width; } if (width > INT_MAX) - FMT_THROW(fmt::FormatError("number is too big")); + FMT_THROW(spdlog::details::fmt::FormatError("number is too big")); return static_cast(width); } }; class PrecisionHandler : - public fmt::internal::ArgVisitor { + public spdlog::details::fmt::internal::ArgVisitor { public: unsigned visit_unhandled_arg() { - FMT_THROW(fmt::FormatError("precision is not integer")); + FMT_THROW(spdlog::details::fmt::FormatError("precision is not integer")); return 0; } template int visit_any_int(T value) { if (!IntChecker::is_signed>::fits_in_int(value)) - FMT_THROW(fmt::FormatError("number is too big")); + FMT_THROW(spdlog::details::fmt::FormatError("number is too big")); return static_cast(value); } }; // Converts an integer argument to an integral type T for printf. template -class ArgConverter : public fmt::internal::ArgVisitor, void> { +class ArgConverter : public spdlog::details::fmt::internal::ArgVisitor, void> { private: - fmt::internal::Arg &arg_; + spdlog::details::fmt::internal::Arg &arg_; wchar_t type_; public: - ArgConverter(fmt::internal::Arg &arg, wchar_t type) + ArgConverter(spdlog::details::fmt::internal::Arg &arg, wchar_t type) : arg_(arg), type_(type) {} template void visit_any_int(U value) { bool is_signed = type_ == 'd' || type_ == 'i'; - using fmt::internal::Arg; + using spdlog::details::fmt::internal::Arg; if (sizeof(T) <= sizeof(int)) { // Extra casts are used to silence warnings. if (is_signed) { @@ -310,31 +313,31 @@ public: else { arg_.type = Arg::UINT; arg_.uint_value = static_cast( - static_cast::Type>(value)); + static_cast::Type>(value)); } } else { if (is_signed) { arg_.type = Arg::LONG_LONG; arg_.long_long_value = - static_cast::Type>(value); + static_cast::Type>(value); } else { arg_.type = Arg::ULONG_LONG; arg_.ulong_long_value = - static_cast::Type>(value); + static_cast::Type>(value); } } } }; // Converts an integer argument to char for printf. -class CharConverter : public fmt::internal::ArgVisitor { +class CharConverter : public spdlog::details::fmt::internal::ArgVisitor { private: - fmt::internal::Arg &arg_; + spdlog::details::fmt::internal::Arg &arg_; public: - explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {} + explicit CharConverter(spdlog::details::fmt::internal::Arg &arg) : arg_(arg) {} template void visit_any_int(T value) { @@ -362,7 +365,7 @@ inline Arg::StringValue ignore_incompatible_str( } } // namespace -FMT_FUNC void fmt::SystemError::init( +FMT_FUNC void spdlog::details::fmt::SystemError::init( int error_code, StringRef format_str, ArgList args) { error_code_ = error_code; MemoryWriter w; @@ -372,7 +375,7 @@ FMT_FUNC void fmt::SystemError::init( } template -FMT_FUNC int fmt::internal::CharTraits::format_float( +FMT_FUNC int spdlog::details::fmt::internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value) { if (width == 0) { @@ -386,7 +389,7 @@ FMT_FUNC int fmt::internal::CharTraits::format_float( } template -FMT_FUNC int fmt::internal::CharTraits::format_float( +FMT_FUNC int spdlog::details::fmt::internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value) { if (width == 0) { @@ -400,7 +403,7 @@ FMT_FUNC int fmt::internal::CharTraits::format_float( } template -const char fmt::internal::BasicData::DIGITS[] = +const char spdlog::details::fmt::internal::BasicData::DIGITS[] = "0001020304050607080910111213141516171819" "2021222324252627282930313233343536373839" "4041424344454647484950515253545556575859" @@ -419,12 +422,12 @@ const char fmt::internal::BasicData::DIGITS[] = factor * 1000000000 template -const uint32_t fmt::internal::BasicData::POWERS_OF_10_32[] = { +const uint32_t spdlog::details::fmt::internal::BasicData::POWERS_OF_10_32[] = { 0, FMT_POWERS_OF_10(1) }; template -const uint64_t fmt::internal::BasicData::POWERS_OF_10_64[] = { +const uint64_t spdlog::details::fmt::internal::BasicData::POWERS_OF_10_64[] = { 0, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(ULongLong(1000000000)), @@ -433,19 +436,19 @@ const uint64_t fmt::internal::BasicData::POWERS_OF_10_64[] = { ULongLong(1000000000) * ULongLong(1000000000) * 10 }; -FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) { +FMT_FUNC void spdlog::details::fmt::internal::report_unknown_type(char code, const char *type) { if (std::isprint(static_cast(code))) { - FMT_THROW(fmt::FormatError( - fmt::format("unknown format code '{}' for {}", code, type))); + FMT_THROW(spdlog::details::fmt::FormatError( + spdlog::details::fmt::format("unknown format code '{}' for {}", code, type))); } - FMT_THROW(fmt::FormatError( - fmt::format("unknown format code '\\x{:02x}' for {}", - static_cast(code), type))); + FMT_THROW(spdlog::details::fmt::FormatError( + spdlog::details::fmt::format("unknown format code '\\x{:02x}' for {}", + static_cast(code), type))); } #ifdef _WIN32 -FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { +FMT_FUNC spdlog::details::fmt::internal::UTF8ToUTF16::UTF8ToUTF16(spdlog::details::fmt::StringRef s) { int length = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0); static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16"; @@ -458,14 +461,14 @@ FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { FMT_THROW(WindowsError(GetLastError(), ERROR)); } -FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { +FMT_FUNC spdlog::details::fmt::internal::UTF16ToUTF8::UTF16ToUTF8(spdlog::details::fmt::WStringRef s) { if (int error_code = convert(s)) { FMT_THROW(WindowsError(error_code, "cannot convert string from UTF-16 to UTF-8")); } } -FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { +FMT_FUNC int spdlog::details::fmt::internal::UTF16ToUTF8::convert(spdlog::details::fmt::WStringRef s) { int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0); if (length == 0) return GetLastError(); @@ -477,7 +480,7 @@ FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { return 0; } -FMT_FUNC void fmt::WindowsError::init( +FMT_FUNC void spdlog::details::fmt::WindowsError::init( int error_code, StringRef format_str, ArgList args) { error_code_ = error_code; MemoryWriter w; @@ -488,9 +491,9 @@ FMT_FUNC void fmt::WindowsError::init( #endif -FMT_FUNC void fmt::internal::format_system_error( - fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT(true) { +FMT_FUNC void spdlog::details::fmt::internal::format_system_error( + spdlog::details::fmt::Writer &out, int error_code, + spdlog::details::fmt::StringRef message) FMT_NOEXCEPT(true) { FMT_TRY { MemoryBuffer buffer; buffer.resize(INLINE_BUFFER_SIZE); @@ -510,9 +513,9 @@ FMT_FUNC void fmt::internal::format_system_error( } #ifdef _WIN32 -FMT_FUNC void fmt::internal::format_windows_error( - fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT(true) { +FMT_FUNC void spdlog::details::fmt::internal::format_windows_error( + spdlog::details::fmt::Writer &out, int error_code, + spdlog::details::fmt::StringRef message) FMT_NOEXCEPT(true) { class String { private: LPWSTR str_; @@ -548,17 +551,17 @@ FMT_FUNC void fmt::internal::format_windows_error( // An argument formatter. template -class fmt::internal::ArgFormatter : - public fmt::internal::ArgVisitor, void> { +class spdlog::details::fmt::internal::ArgFormatter : + public spdlog::details::fmt::internal::ArgVisitor, void> { private: - fmt::BasicFormatter &formatter_; - fmt::BasicWriter &writer_; - fmt::FormatSpec &spec_; + spdlog::details::fmt::BasicFormatter &formatter_; + spdlog::details::fmt::BasicWriter &writer_; + spdlog::details::fmt::FormatSpec &spec_; const Char *format_; public: ArgFormatter( - fmt::BasicFormatter &f, fmt::FormatSpec &s, const Char *fmt) + spdlog::details::fmt::BasicFormatter &f, spdlog::details::fmt::FormatSpec &s, const Char *fmt) : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {} template @@ -579,16 +582,16 @@ public: } if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) FMT_THROW(FormatError("invalid format specifier for char")); - typedef typename fmt::BasicWriter::CharPtr CharPtr; + typedef typename spdlog::details::fmt::BasicWriter::CharPtr CharPtr; CharPtr out = CharPtr(); if (spec_.width_ > 1) { Char fill = static_cast(spec_.fill()); out = writer_.grow_buffer(spec_.width_); - if (spec_.align_ == fmt::ALIGN_RIGHT) { + if (spec_.align_ == spdlog::details::fmt::ALIGN_RIGHT) { std::fill_n(out, spec_.width_ - 1, fill); out += spec_.width_ - 1; } - else if (spec_.align_ == fmt::ALIGN_CENTER) { + else if (spec_.align_ == spdlog::details::fmt::ALIGN_CENTER) { out = writer_.fill_padding(out, spec_.width_, 1, fill); } else { @@ -610,8 +613,8 @@ public: void visit_pointer(const void *value) { if (spec_.type_ && spec_.type_ != 'p') - fmt::internal::report_unknown_type(spec_.type_, "pointer"); - spec_.flags_ = fmt::HASH_FLAG; + spdlog::details::fmt::internal::report_unknown_type(spec_.type_, "pointer"); + spec_.flags_ = spdlog::details::fmt::HASH_FLAG; spec_.type_ = 'x'; writer_.write_int(reinterpret_cast(value), spec_); } @@ -623,7 +626,7 @@ public: template template -FMT_FUNC void fmt::BasicWriter::write_str( +FMT_FUNC void spdlog::details::fmt::BasicWriter::write_str( const Arg::StringValue &str, const FormatSpec &spec) { // Check if StrChar is convertible to Char. internal::CharTraits::convert(StrChar()); @@ -641,7 +644,7 @@ FMT_FUNC void fmt::BasicWriter::write_str( } template -inline Arg fmt::BasicFormatter::parse_arg_index(const Char *&s) { +inline Arg spdlog::details::fmt::BasicFormatter::parse_arg_index(const Char *&s) { const char *error = 0; Arg arg = *s < '0' || *s > '9' ? next_arg(error) : get_arg(parse_nonnegative_int(s), error); @@ -652,7 +655,7 @@ inline Arg fmt::BasicFormatter::parse_arg_index(const Char *&s) { return arg; } -FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( +FMT_FUNC Arg spdlog::details::fmt::internal::FormatterBase::do_get_arg( unsigned arg_index, const char *&error) { Arg arg = args_[arg_index]; if (arg.type == Arg::NONE) @@ -660,14 +663,14 @@ FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( return arg; } -inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) { +inline Arg spdlog::details::fmt::internal::FormatterBase::next_arg(const char *&error) { if (next_arg_index_ >= 0) return do_get_arg(next_arg_index_++, error); error = "cannot switch from manual to automatic argument indexing"; return Arg(); } -inline Arg fmt::internal::FormatterBase::get_arg( +inline Arg spdlog::details::fmt::internal::FormatterBase::get_arg( unsigned arg_index, const char *&error) { if (next_arg_index_ <= 0) { next_arg_index_ = -1; @@ -678,7 +681,7 @@ inline Arg fmt::internal::FormatterBase::get_arg( } template -FMT_FUNC void fmt::internal::PrintfFormatter::parse_flags( +FMT_FUNC void spdlog::details::fmt::internal::PrintfFormatter::parse_flags( FormatSpec &spec, const Char *&s) { for (;;) { switch (*s++) { @@ -705,7 +708,7 @@ FMT_FUNC void fmt::internal::PrintfFormatter::parse_flags( } template -FMT_FUNC Arg fmt::internal::PrintfFormatter::get_arg( +FMT_FUNC Arg spdlog::details::fmt::internal::PrintfFormatter::get_arg( const Char *s, unsigned arg_index) { const char *error = 0; Arg arg = arg_index == UINT_MAX ? @@ -716,7 +719,7 @@ FMT_FUNC Arg fmt::internal::PrintfFormatter::get_arg( } template -FMT_FUNC unsigned fmt::internal::PrintfFormatter::parse_header( +FMT_FUNC unsigned spdlog::details::fmt::internal::PrintfFormatter::parse_header( const Char *&s, FormatSpec &spec) { unsigned arg_index = UINT_MAX; Char c = *s; @@ -752,7 +755,7 @@ FMT_FUNC unsigned fmt::internal::PrintfFormatter::parse_header( } template -FMT_FUNC void fmt::internal::PrintfFormatter::format( +FMT_FUNC void spdlog::details::fmt::internal::PrintfFormatter::format( BasicWriter &writer, BasicStringRef format, const ArgList &args) { const Char *start = format.c_str(); @@ -806,7 +809,7 @@ FMT_FUNC void fmt::internal::PrintfFormatter::format( break; case 'l': if (*s == 'l') - ArgConverter(arg, *++s).visit(arg); + ArgConverter(arg, *++s).visit(arg); else ArgConverter(arg, *s).visit(arg); break; @@ -923,7 +926,7 @@ FMT_FUNC void fmt::internal::PrintfFormatter::format( } template -FMT_FUNC const Char *fmt::BasicFormatter::format( +FMT_FUNC const Char *spdlog::details::fmt::BasicFormatter::format( const Char *&format_str, const Arg &arg) { const Char *s = format_str; FormatSpec spec; @@ -1063,7 +1066,7 @@ FMT_FUNC const Char *fmt::BasicFormatter::format( } template -FMT_FUNC void fmt::BasicFormatter::format( +FMT_FUNC void spdlog::details::fmt::BasicFormatter::format( BasicStringRef format_str, const ArgList &args) { const Char *s = start_ = format_str.c_str(); set_args(args); @@ -1084,35 +1087,35 @@ FMT_FUNC void fmt::BasicFormatter::format( write(writer_, start_, s); } -FMT_FUNC void fmt::report_system_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { +FMT_FUNC void spdlog::details::fmt::report_system_error( + int error_code, spdlog::details::fmt::StringRef message) FMT_NOEXCEPT(true) { report_error(internal::format_system_error, error_code, message); } #ifdef _WIN32 -FMT_FUNC void fmt::report_windows_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { +FMT_FUNC void spdlog::details::fmt::report_windows_error( + int error_code, spdlog::details::fmt::StringRef message) FMT_NOEXCEPT(true) { report_error(internal::format_windows_error, error_code, message); } #endif -FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) { +FMT_FUNC void spdlog::details::fmt::print(std::FILE *f, StringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); std::fwrite(w.data(), 1, w.size(), f); } -FMT_FUNC void fmt::print(StringRef format_str, ArgList args) { +FMT_FUNC void spdlog::details::fmt::print(StringRef format_str, ArgList args) { print(stdout, format_str, args); } -FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) { +FMT_FUNC void spdlog::details::fmt::print(std::ostream &os, StringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); os.write(w.data(), w.size()); } -FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) { +FMT_FUNC void spdlog::details::fmt::print_colored(Color c, StringRef format, ArgList args) { char escape[] = "\x1b[30m"; escape[3] = '0' + static_cast(c); std::fputs(escape, stdout); @@ -1120,7 +1123,7 @@ FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) { std::fputs(RESET_COLOR, stdout); } -FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) { +FMT_FUNC int spdlog::details::fmt::fprintf(std::FILE *f, StringRef format, ArgList args) { MemoryWriter w; printf(w, format, args); std::size_t size = w.size(); @@ -1129,40 +1132,40 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) { // Explicit instantiations for char. -template const char *fmt::BasicFormatter::format( - const char *&format_str, const fmt::internal::Arg &arg); +template const char *spdlog::details::fmt::BasicFormatter::format( + const char *&format_str, const spdlog::details::fmt::internal::Arg &arg); -template void fmt::BasicFormatter::format( +template void spdlog::details::fmt::BasicFormatter::format( BasicStringRef format, const ArgList &args); -template void fmt::internal::PrintfFormatter::format( +template void spdlog::details::fmt::internal::PrintfFormatter::format( BasicWriter &writer, BasicStringRef format, const ArgList &args); -template int fmt::internal::CharTraits::format_float( +template int spdlog::details::fmt::internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, double value); -template int fmt::internal::CharTraits::format_float( +template int spdlog::details::fmt::internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, long double value); // Explicit instantiations for wchar_t. -template const wchar_t *fmt::BasicFormatter::format( - const wchar_t *&format_str, const fmt::internal::Arg &arg); +template const wchar_t *spdlog::details::fmt::BasicFormatter::format( + const wchar_t *&format_str, const spdlog::details::fmt::internal::Arg &arg); -template void fmt::BasicFormatter::format( +template void spdlog::details::fmt::BasicFormatter::format( BasicStringRef format, const ArgList &args); -template void fmt::internal::PrintfFormatter::format( +template void spdlog::details::fmt::internal::PrintfFormatter::format( BasicWriter &writer, BasicStringRef format, const ArgList &args); -template int fmt::internal::CharTraits::format_float( +template int spdlog::details::fmt::internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, double value); -template int fmt::internal::CharTraits::format_float( +template int spdlog::details::fmt::internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, long double value); diff --git a/include/spdlog/details/format.h b/include/spdlog/details/format.h index 82f65058..337b4ab8 100644 --- a/include/spdlog/details/format.h +++ b/include/spdlog/details/format.h @@ -115,7 +115,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&); \ void operator=(const TypeName&) - +namespace spdlog { +namespace details { namespace fmt { @@ -1053,7 +1054,7 @@ public: { default: assert(false); - // Fall through. + // Fall through. case Arg::INT: return FMT_DISPATCH(visit_int(arg.int_value)); case Arg::UINT: @@ -2222,7 +2223,7 @@ void BasicWriter::write_double( // MSVC's printf doesn't support 'F'. type = 'f'; #endif - // Fall through. + // Fall through. case 'E': case 'G': case 'A': @@ -2739,7 +2740,9 @@ inline void format_decimal(char *&buffer, T value) internal::format_decimal(buffer, abs_value, num_digits); buffer += num_digits; } -} +} // ns fmt +} // ns deatils +} // ns spdlog #if FMT_GCC_VERSION // Use the system_header pragma to suppress warnings about variadic macros @@ -2846,6 +2849,8 @@ fmt::print(format, args...); #define FMT_VARIADIC_W(ReturnType, func, ...) \ FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) +namespace spdlog { +namespace details { namespace fmt { FMT_VARIADIC(std::string, format, StringRef) @@ -2858,6 +2863,8 @@ FMT_VARIADIC(std::string, sprintf, StringRef) FMT_VARIADIC(int, printf, StringRef) FMT_VARIADIC(int, fprintf, std::FILE *, StringRef) } +} +} // Restore warnings. #if FMT_GCC_VERSION >= 406 diff --git a/include/spdlog/details/pattern_formatter_impl.h b/include/spdlog/details/pattern_formatter_impl.h index 0d36da0d..1b31ced4 100644 --- a/include/spdlog/details/pattern_formatter_impl.h +++ b/include/spdlog/details/pattern_formatter_impl.h @@ -458,7 +458,7 @@ inline void spdlog::pattern_formatter::handle_flag(char flag) { switch (flag) { - // logger name + // logger name case 'n': _formatters.push_back(std::unique_ptr(new details::name_formatter())); break; @@ -582,8 +582,8 @@ inline void spdlog::pattern_formatter::format(details::log_msg& msg) //write eol msg.formatted << details::os::eol(); } - catch(const fmt::FormatError& e) + catch(const details::fmt::FormatError& e) { - throw spdlog_ex(fmt::format("formatting error while processing format string: {}", e.what())); + throw spdlog_ex(details::fmt::format("formatting error while processing format string: {}", e.what())); } } diff --git a/include/spdlog/sinks/file_sinks.h b/include/spdlog/sinks/file_sinks.h index 26d5d0e1..37a3abc7 100644 --- a/include/spdlog/sinks/file_sinks.h +++ b/include/spdlog/sinks/file_sinks.h @@ -99,7 +99,7 @@ protected: private: static std::string calc_filename(const std::string& filename, std::size_t index, const std::string& extension) { - fmt::MemoryWriter w; + details::fmt::MemoryWriter w; if (index) w.write("{}.{}.{}", filename, index, extension); else @@ -196,7 +196,7 @@ private: static std::string calc_filename(const std::string& basename, const std::string& extension) { std::tm tm = spdlog::details::os::localtime(); - fmt::MemoryWriter w; + details::fmt::MemoryWriter w; w.write("{}.{:04d}-{:02d}-{:02d}.{}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, extension); return w.str(); } From 3e516699516765d66dca878358d6cc97727d0e52 Mon Sep 17 00:00:00 2001 From: gabi Date: Tue, 9 Dec 2014 00:12:42 +0200 Subject: [PATCH 119/120] Removed global #defines from format.cc --- include/spdlog/details/format.cc | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/include/spdlog/details/format.cc b/include/spdlog/details/format.cc index 070bf614..bb1c5abf 100644 --- a/include/spdlog/details/format.cc +++ b/include/spdlog/details/format.cc @@ -28,11 +28,6 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// Disable useless MSVC warnings. -#undef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#undef _SCL_SECURE_NO_WARNINGS -#define _SCL_SECURE_NO_WARNINGS #include @@ -49,7 +44,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # include # endif # include -# undef ERROR #endif using spdlog::details::fmt::LongLong; @@ -176,14 +170,14 @@ FMT_FUNC void format_error_code(spdlog::details::fmt::Writer &out, int error_cod // bad_alloc. out.clear(); static const char SEP[] = ": "; - static const char ERROR[] = "error "; + static const char FMT_ERROR[] = "error "; spdlog::details::fmt::internal::IntTraits::MainType ec_value = error_code; - // Subtract 2 to account for terminating null characters in SEP and ERROR. + // Subtract 2 to account for terminating null characters in SEP and FMT_ERROR. std::size_t error_code_size = - sizeof(SEP) + sizeof(ERROR) + spdlog::details::fmt::internal::count_digits(ec_value) - 2; + sizeof(SEP) + sizeof(FMT_ERROR) + spdlog::details::fmt::internal::count_digits(ec_value) - 2; if (message.size() <= spdlog::details::fmt::internal::INLINE_BUFFER_SIZE - error_code_size) out << message << SEP; - out << ERROR << error_code; + out << FMT_ERROR << error_code; assert(out.size() <= spdlog::details::fmt::internal::INLINE_BUFFER_SIZE); } @@ -451,14 +445,14 @@ FMT_FUNC void spdlog::details::fmt::internal::report_unknown_type(char code, con FMT_FUNC spdlog::details::fmt::internal::UTF8ToUTF16::UTF8ToUTF16(spdlog::details::fmt::StringRef s) { int length = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0); - static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16"; + static const char FMT_ERROR[] = "cannot convert string from UTF-8 to UTF-16"; if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR)); + FMT_THROW(WindowsError(GetLastError(), FMT_ERROR)); buffer_.resize(length); length = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length); if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR)); + FMT_THROW(WindowsError(GetLastError(), FMT_ERROR)); } FMT_FUNC spdlog::details::fmt::internal::UTF16ToUTF8::UTF16ToUTF8(spdlog::details::fmt::WStringRef s) { From e0089dbdc03b3e8f7f9a39b6e3f037a7a48d17ff Mon Sep 17 00:00:00 2001 From: Gabi Melman Date: Tue, 9 Dec 2014 01:36:41 +0200 Subject: [PATCH 120/120] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6174bfb..15643950 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Just copy the files to your build tree and use a C++11 compiler * No dependencies - just copy and use. * Cross platform - Linux / Windows on 32/64 bits. * **new!** Feature rich [call style](#usage-example) using the excellent [cppformat](http://cppformat.github.io/) library. -* Optional ostream call style. +* ostream call style is supported too. * Extremely fast asynchronous mode (optional) - use of lockfree queues and other tricks to reach millions of calls per second from multiple threads. * [Custom](https://github.com/gabime/spdlog/wiki/Custom-formatting) formatting. * Multi/Single threaded loggers.