diff --git a/include/spdlog/common.h b/include/spdlog/common.h index 6f95f835..4d6bbc3b 100644 --- a/include/spdlog/common.h +++ b/include/spdlog/common.h @@ -16,20 +16,13 @@ #include #include "details/null_mutex.h" +#include "source_loc.h" #include "tweakme.h" #if __has_include() #include #endif -#if __cpp_lib_source_location >= 201907 - #include - #define SPDLOG_HAVE_STD_SOURCE_LOCATION -#elif __has_include() - #include - #define SPDLOG_HAVE_EXPERIMENTAL_SOURCE_LOCATION -#endif - #ifdef SPDLOG_USE_STD_FORMAT #if __cpp_lib_format >= 202207L #include @@ -94,7 +87,7 @@ class sink; #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) using filename_t = std::wstring; - // allow macro expansion to occur in SPDLOG_FILENAME_T +// allow macro expansion to occur in SPDLOG_FILENAME_T #define SPDLOG_FILENAME_T_INNER(s) L##s #define SPDLOG_FILENAME_T(s) SPDLOG_FILENAME_T_INNER(s) #else @@ -180,6 +173,7 @@ using atomic_level_t = std::atomic; [[nodiscard]] constexpr size_t level_to_number(level lvl) noexcept { return static_cast(lvl); } + constexpr auto levels_count = level_to_number(level::n_levels); constexpr std::array level_string_views SPDLOG_LEVEL_NAMES; constexpr std::array short_level_names SPDLOG_SHORT_LEVEL_NAMES; @@ -214,7 +208,9 @@ enum class pattern_time_type { class SPDLOG_API spdlog_ex : public std::exception { public: explicit spdlog_ex(std::string msg); + spdlog_ex(const std::string &msg, int last_errno); + [[nodiscard]] const char *what() const noexcept override; private: @@ -222,54 +218,27 @@ private: }; [[noreturn]] SPDLOG_API void throw_spdlog_ex(const std::string &msg, int last_errno); + [[noreturn]] SPDLOG_API void throw_spdlog_ex(std::string msg); -struct source_loc { - constexpr source_loc() = default; - constexpr source_loc(const char *filename_in, - std::uint_least32_t line_in, - const char *funcname_in) - : filename{filename_in}, - line{line_in}, - funcname{funcname_in} {} - -#ifdef SPDLOG_HAVE_STD_SOURCE_LOCATION - static constexpr source_loc current( - const std::source_location source_location = std::source_location::current()) { - return source_loc{source_location.file_name(), source_location.line(), - source_location.function_name()}; - } -#elif defined(SPDLOG_HAVE_EXPERIMENTAL_SOURCE_LOCATION) - static constexpr source_loc current(const std::experimental::source_location source_location = - std::experimental::source_location::current()) { - return source_loc{source_location.file_name(), source_location.line(), - source_location.function_name()}; - } -#else // no source location support - static constexpr source_loc current() { return source_loc{}; } -#endif - - [[nodiscard]] constexpr bool empty() const noexcept { return line == 0; } - const char *filename{nullptr}; - std::uint_least32_t line{0}; - const char *funcname{nullptr}; -}; - // trick to capture format string and caller's source location with variadic template. // see logger::info() etc. to understand how it's used. struct loc_with_fmt { source_loc loc; string_view_t fmt_string; + template > constexpr loc_with_fmt(S fmt_str, source_loc loc = source_loc::current()) noexcept : loc(loc), fmt_string(fmt_str) {} #ifndef SPDLOG_USE_STD_FORMAT + constexpr loc_with_fmt(fmt::runtime_format_string fmt_str, source_loc loc = source_loc::current()) noexcept : loc(loc), fmt_string(fmt_str.str) {} + #endif }; @@ -324,11 +293,13 @@ template } #endif #else // {fmt} version + template [[nodiscard]] constexpr fmt::basic_string_view to_string_view( fmt::basic_format_string fmt) noexcept { return fmt; } + #endif } // namespace details diff --git a/include/spdlog/source_loc.h b/include/spdlog/source_loc.h new file mode 100644 index 00000000..aad271cc --- /dev/null +++ b/include/spdlog/source_loc.h @@ -0,0 +1,74 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once +#include + +#if __has_include() + #include +#endif + +#if __cpp_lib_source_location >= 201907 + #include + #define SPDLOG_HAVE_STD_SOURCE_LOCATION +#elif __has_include() + #include + #define SPDLOG_HAVE_EXPERIMENTAL_SOURCE_LOCATION +#endif + +namespace spdlog { +// source location - either initiated from std::source_location or from +// std::experimental::source_location or empty +struct source_loc { + constexpr source_loc() = default; + constexpr source_loc(const char *filename_in, + std::uint_least32_t line_in, + const char *funcname_in) + : filename{filename_in}, + short_filename{basename(filename_in)}, + line{line_in}, + funcname{funcname_in} {} + +#ifdef SPDLOG_HAVE_STD_SOURCE_LOCATION + static constexpr source_loc current( + const std::source_location source_location = std::source_location::current()) { + return source_loc{source_location.file_name(), source_location.line(), + source_location.function_name()}; + } +#elif defined(SPDLOG_HAVE_EXPERIMENTAL_SOURCE_LOCATION) + static constexpr source_loc current(const std::experimental::source_location source_location = + std::experimental::source_location::current()) { + return source_loc{source_location.file_name(), source_location.line(), + source_location.function_name()}; + } +#else // no source location support + static constexpr source_loc current() { return source_loc{}; } +#endif + + [[nodiscard]] constexpr bool empty() const noexcept { + return line == 0 || filename == nullptr || short_filename == nullptr; + } + + const char *filename{nullptr}; + const char *short_filename{nullptr}; + std::uint_least32_t line{0}; + const char *funcname{nullptr}; + + // return filename without the leading path + static constexpr const char *basename(const char *path) { + const char *file = path; + while (*path) { +#ifdef _WIN32 + if (*path == '\\' || *path == '/') +#else + if (*path == '/') +#endif + { + file = path + 1; + } + ++path; + } + return file; + } +}; +} // namespace spdlog \ No newline at end of file diff --git a/src/pattern_formatter.cpp b/src/pattern_formatter.cpp index 40f0448a..81212d1c 100644 --- a/src/pattern_formatter.cpp +++ b/src/pattern_formatter.cpp @@ -679,35 +679,12 @@ public: explicit short_filename_formatter(padding_info padinfo) : flag_formatter(padinfo) {} -#ifdef _MSC_VER - #pragma warning(push) - #pragma warning(disable : 4127) // consider using 'if constexpr' instead -#endif // _MSC_VER - static const char *basename(const char *filename) { - // if the size is 2 (1 character + null terminator) we can use the more efficient strrchr - // the branch will be elided by optimizations - if (sizeof(os::folder_seps) == 2) { - const char *rv = std::strrchr(filename, os::folder_seps[0]); - return rv != nullptr ? rv + 1 : filename; - } else { - const std::reverse_iterator begin(filename + std::strlen(filename)); - const std::reverse_iterator end(filename); - - const auto it = std::find_first_of(begin, end, std::begin(os::folder_seps), - std::end(os::folder_seps) - 1); - return it != end ? it.base() : filename; - } - } -#ifdef _MSC_VER - #pragma warning(pop) -#endif // _MSC_VER - void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override { if (msg.source.empty()) { ScopedPadder p(0, padinfo_, dest); return; } - auto filename = basename(msg.source.filename); + const char *filename = msg.source.short_filename; size_t text_size = padinfo_.enabled() ? std::char_traits::length(filename) : 0; ScopedPadder p(text_size, padinfo_, dest); fmt_helper::append_string_view(filename, dest); @@ -841,9 +818,7 @@ public: // add source location if present if (!msg.source.empty()) { dest.push_back('['); - const char *filename = - details::short_filename_formatter::basename( - msg.source.filename); + const char *filename = msg.source.short_filename; fmt_helper::append_string_view(filename, dest); dest.push_back(':'); fmt_helper::append_int(msg.source.line, dest);