diff options
| author | Dan Engelbrecht <[email protected]> | 2026-03-23 20:39:32 +0100 |
|---|---|---|
| committer | Dan Engelbrecht <[email protected]> | 2026-03-23 20:39:32 +0100 |
| commit | 840b600525c7c6fd43395863c15ce955d9216b71 (patch) | |
| tree | 79e017fd6ced67650defddb3f10f40c6efc3d841 /thirdparty/fmt | |
| parent | 5.7.25 (diff) | |
| parent | Cross-platform process metrics support (#887) (diff) | |
| download | zen-de/v5.7.25-hotpatch.tar.xz zen-de/v5.7.25-hotpatch.zip | |
Merge remote-tracking branch 'origin/main' into de/v5.7.25-hotpatchde/v5.7.25-hotpatch
Diffstat (limited to 'thirdparty/fmt')
| -rw-r--r-- | thirdparty/fmt/ChangeLog.md | 74 | ||||
| -rw-r--r-- | thirdparty/fmt/doc/api.md | 50 | ||||
| -rw-r--r-- | thirdparty/fmt/doc/syntax.md | 10 | ||||
| -rw-r--r-- | thirdparty/fmt/include/fmt/base.h | 34 | ||||
| -rw-r--r-- | thirdparty/fmt/include/fmt/chrono.h | 9 | ||||
| -rw-r--r-- | thirdparty/fmt/include/fmt/color.h | 2 | ||||
| -rw-r--r-- | thirdparty/fmt/include/fmt/compile.h | 5 | ||||
| -rw-r--r-- | thirdparty/fmt/include/fmt/format-inl.h | 7 | ||||
| -rw-r--r-- | thirdparty/fmt/include/fmt/format.h | 28 | ||||
| -rw-r--r-- | thirdparty/fmt/include/fmt/os.h | 17 | ||||
| -rw-r--r-- | thirdparty/fmt/include/fmt/ranges.h | 19 | ||||
| -rw-r--r-- | thirdparty/fmt/include/fmt/std.h | 164 | ||||
| -rw-r--r-- | thirdparty/fmt/src/format.cc | 2 | ||||
| -rwxr-xr-x | thirdparty/fmt/support/mkdocs | 26 | ||||
| -rw-r--r-- | thirdparty/fmt/test/std-test.cc | 52 |
15 files changed, 367 insertions, 132 deletions
diff --git a/thirdparty/fmt/ChangeLog.md b/thirdparty/fmt/ChangeLog.md index b91b6f62b..e96f9df8c 100644 --- a/thirdparty/fmt/ChangeLog.md +++ b/thirdparty/fmt/ChangeLog.md @@ -1,3 +1,77 @@ +# 12.1.0 - 2025-10-29 + +- Optimized `buffer::append`, resulting in up to ~16% improvement on spdlog + benchmarks (https://github.com/fmtlib/fmt/pull/4541). Thanks @fyrsta7. + +- Worked around an ABI incompatibility in `std::locale_ref` between clang and + gcc (https://github.com/fmtlib/fmt/issues/4573). + +- Made `std::variant` and `std::expected` formatters work with `format_as` + (https://github.com/fmtlib/fmt/issues/4574, + https://github.com/fmtlib/fmt/pull/4575). Thanks @phprus. + +- Made `fmt::join<string_view>` work with C++ modules + (https://github.com/fmtlib/fmt/issues/4379, + https://github.com/fmtlib/fmt/pull/4577). Thanks @Arghnews. + +- Exported `fmt::is_compiled_string` and `operator""_cf` from the module + (https://github.com/fmtlib/fmt/pull/4544). Thanks @CrackedMatter. + +- Fixed a compatibility issue with C++ modules in clang + (https://github.com/fmtlib/fmt/pull/4548). Thanks @tsarn. + +- Added support for cv-qualified types to the `std::optional` formatter + (https://github.com/fmtlib/fmt/issues/4561, + https://github.com/fmtlib/fmt/pull/4562). Thanks @OleksandrKvl. + +- Added demangling support (used in exception and `std::type_info` formatters) + for libc++ and clang-cl + (https://github.com/fmtlib/fmt/issues/4542, + https://github.com/fmtlib/fmt/pull/4560, + https://github.com/fmtlib/fmt/issues/4568, + https://github.com/fmtlib/fmt/pull/4571). + Thanks @FatihBAKIR and @rohitsutreja. + +- Switched to global `malloc`/`free` to enable allocator customization + (https://github.com/fmtlib/fmt/issues/4569, + https://github.com/fmtlib/fmt/pull/4570). Thanks @rohitsutreja. + +- Made the `FMT_USE_CONSTEVAL` macro configurable by users + (https://github.com/fmtlib/fmt/pull/4546). Thanks @SnapperTT. + +- Fixed compilation with locales disabled in the header-only mode + (https://github.com/fmtlib/fmt/issues/4550). + +- Fixed compilation with clang 21 and `-std=c++20` + (https://github.com/fmtlib/fmt/issues/4552). + +- Fixed a dynamic linking issue with clang-cl + (https://github.com/fmtlib/fmt/issues/4576, + https://github.com/fmtlib/fmt/pull/4584). Thanks @FatihBAKIR. + +- Fixed a warning suppression leakage on gcc + (https://github.com/fmtlib/fmt/pull/4588). Thanks @ZedThree. + +- Made more internal color APIs `constexpr` + (https://github.com/fmtlib/fmt/pull/4581). Thanks @ishani. + +- Fixed compatibility with clang as a host compiler for NVCC + (https://github.com/fmtlib/fmt/pull/4564). Thanks @valgur. + +- Fixed various warnings and lint issues + (https://github.com/fmtlib/fmt/issues/4565, + https://github.com/fmtlib/fmt/pull/4572, + https://github.com/fmtlib/fmt/pull/4557). + Thanks @LiangHuDream and @teruyamato0731. + +- Improved documentation + (https://github.com/fmtlib/fmt/issues/4549, + https://github.com/fmtlib/fmt/pull/4551, + https://github.com/fmtlib/fmt/issues/4566, + https://github.com/fmtlib/fmt/pull/4567, + https://github.com/fmtlib/fmt/pull/4578,). + Thanks @teruyamato0731, @petersteneteg and @zimmerman-dev. + # 12.0.0 - 2025-09-17 - Optimized the default floating point formatting diff --git a/thirdparty/fmt/doc/api.md b/thirdparty/fmt/doc/api.md index 2c584abc0..9fbc9f2fe 100644 --- a/thirdparty/fmt/doc/api.md +++ b/thirdparty/fmt/doc/api.md @@ -708,3 +708,53 @@ following differences: `std::to_chars` which tries to generate the smallest number of characters (ignoring redundant digits and sign in exponent) and may procude more decimal digits than necessary. + +## Configuration Options + +{fmt} provides configuration via CMake options and preprocessor macros to +enable or disable features and to optimize for binary size. For example, you +can disable OS-specific APIs defined in `fmt/os.h` with `-DFMT_OS=OFF` when +configuring CMake. + +### CMake Options + +- **`FMT_OS`**: When set to `OFF`, disables OS-specific APIs (`fmt/os.h`). +- **`FMT_UNICODE`**: When set of `OFF`, disables Unicode support on + Windows/MSVC. Unicode support is always enabled on other platforms. + +### Macros + +- **`FMT_HEADER_ONLY`**: Enables the header-only mode when defined. It is an + alternative to using the `fmt::fmt-header-only` CMake target. + Default: not defined. + +- **`FMT_USE_EXCEPTIONS`**: Disables the use of exceptions when set to `0`. + Default: `1` (`0` if compiled with `-fno-exceptions`). + +- **`FMT_USE_LOCALE`**: When set to `0`, disables locale support. + Default: `1` (`0` when `FMT_OPTIMIZE_SIZE > 1`). + +- **`FMT_CUSTOM_ASSERT_FAIL`**: When set to `1`, allows users to provide a + custom `fmt::assert_fail` function which is called on assertion failures and, + if exceptions are disabled, on runtime errors. Default: `0`. + +- **`FMT_BUILTIN_TYPES`**: When set to `0`, disables built-in handling of + arithmetic and string types other than `int`. This reduces library size at + the cost of per-call overhead. Default: `1`. + +- **`FMT_OPTIMIZE_SIZE`**: Controls binary size optimizations: + - `0` - off (default) + - `1` - disables locale support and applies some optimizations + - `2` - disables some Unicode features, named arguments and applies more + aggresive optimizations + +### Binary Size Optimization + +To minimize the binary footprint of {fmt} as much as possible at the cost of +some features, you can use the following configuration: + +- CMake options: + - `FMT_OS=OFF` +- Macros: + - `FMT_BUILTIN_TYPES=0` + - `FMT_OPTIMIZE_SIZE=2` diff --git a/thirdparty/fmt/doc/syntax.md b/thirdparty/fmt/doc/syntax.md index 46d7d2fd2..ac5128233 100644 --- a/thirdparty/fmt/doc/syntax.md +++ b/thirdparty/fmt/doc/syntax.md @@ -251,7 +251,7 @@ The available integer presentation types are: <td><code>'b'</code></td> <td> Binary format. Outputs the number in base 2. Using the <code>'#'</code> - option with this type adds the prefix <code>"0b"</code> to the output value. + option with this type adds the prefix <code>"0b"</code> to the output value. </td> </tr> <tr> @@ -718,7 +718,7 @@ These modifiers are only supported for the `'H'`, `'I'`, `'M'`, `'S'`, `'U'`, Format specifications for range types have the following syntax: <pre><code class="language-json" ->range_format_spec ::= ["n"][range_type][range_underlying_spec]</code> +>range_format_spec ::= ["n"][range_type][":" range_underlying_spec]</code> </pre> The `'n'` option formats the range without the opening and closing brackets. @@ -761,14 +761,16 @@ fmt::print("{::}", std::vector{'h', 'e', 'l', 'l', 'o'}); // Output: [h, e, l, l, o] fmt::print("{::d}", std::vector{'h', 'e', 'l', 'l', 'o'}); // Output: [104, 101, 108, 108, 111] +fmt::print("{:n:f}", std::array{std::numbers::pi, std::numbers::e}); +// Output: 3.141593, 2.718282 ``` ## Format Examples This section contains examples of the format syntax and comparison with -the printf formatting. +the `printf` formatting. -In most of the cases the syntax is similar to the printf formatting, +In most of the cases the syntax is similar to the `printf` formatting, with the addition of the `{}` and with `:` used instead of `%`. For example, `"%03.2f"` can be translated to `"{:03.2f}"`. diff --git a/thirdparty/fmt/include/fmt/base.h b/thirdparty/fmt/include/fmt/base.h index 42e192aca..0d5786778 100644 --- a/thirdparty/fmt/include/fmt/base.h +++ b/thirdparty/fmt/include/fmt/base.h @@ -21,7 +21,7 @@ #endif // The fmt library version in the form major * 10000 + minor * 100 + patch. -#define FMT_VERSION 120000 +#define FMT_VERSION 120100 // Detect compiler versions. #if defined(__clang__) && !defined(__ibmxl__) @@ -114,7 +114,9 @@ #endif // Detect consteval, C++20 constexpr extensions and std::is_constant_evaluated. -#if !defined(__cpp_lib_is_constant_evaluated) +#ifdef FMT_USE_CONSTEVAL +// Use the provided definition. +#elif !defined(__cpp_lib_is_constant_evaluated) # define FMT_USE_CONSTEVAL 0 #elif FMT_CPLUSPLUS < 201709L # define FMT_USE_CONSTEVAL 0 @@ -234,6 +236,7 @@ FMT_PRAGMA_GCC(optimize("Og")) # define FMT_GCC_OPTIMIZED #endif FMT_PRAGMA_CLANG(diagnostic push) +FMT_PRAGMA_GCC(diagnostic push) #ifdef FMT_ALWAYS_INLINE // Use the provided definition. @@ -414,8 +417,12 @@ inline auto map(int128_opt) -> monostate { return {}; } inline auto map(uint128_opt) -> monostate { return {}; } #endif -#ifndef FMT_USE_BITINT -# define FMT_USE_BITINT (FMT_CLANG_VERSION >= 1500) +#ifdef FMT_USE_BITINT +// Use the provided definition. +#elif FMT_CLANG_VERSION >= 1500 && !defined(__CUDACC__) +# define FMT_USE_BITINT 1 +#else +# define FMT_USE_BITINT 0 #endif #if FMT_USE_BITINT @@ -918,7 +925,10 @@ class locale_ref { constexpr locale_ref() : locale_(nullptr) {} template <typename Locale, FMT_ENABLE_IF(sizeof(Locale::collate) != 0)> - locale_ref(const Locale& loc); + locale_ref(const Locale& loc) : locale_(&loc) { + // Check if std::isalpha is found via ADL to reduce the chance of misuse. + isalpha('x', loc); + } inline explicit operator bool() const noexcept { return locale_ != nullptr; } #endif // FMT_USE_LOCALE @@ -1844,12 +1854,17 @@ template <typename T> class buffer { void append(const U* begin, const U* end) { while (begin != end) { + auto size = size_; + auto free_cap = capacity_ - size; auto count = to_unsigned(end - begin); - try_reserve(size_ + count); - auto free_cap = capacity_ - size_; - if (free_cap < count) count = free_cap; + if (free_cap < count) { + grow_(*this, size + count); + size = size_; + free_cap = capacity_ - size; + count = count < free_cap ? count : free_cap; + } // A loop is faster than memcpy on small sizes. - T* out = ptr_ + size_; + T* out = ptr_ + size; for (size_t i = 0; i < count; ++i) out[i] = begin[i]; size_ += count; begin += count; @@ -2983,6 +2998,7 @@ FMT_INLINE void println(format_string<T...> fmt, T&&... args) { return fmt::println(stdout, fmt, static_cast<T&&>(args)...); } +FMT_PRAGMA_GCC(diagnostic pop) FMT_PRAGMA_CLANG(diagnostic pop) FMT_PRAGMA_GCC(pop_options) FMT_END_EXPORT diff --git a/thirdparty/fmt/include/fmt/chrono.h b/thirdparty/fmt/include/fmt/chrono.h index a788d3ecf..9fbeeed67 100644 --- a/thirdparty/fmt/include/fmt/chrono.h +++ b/thirdparty/fmt/include/fmt/chrono.h @@ -1594,8 +1594,13 @@ class get_locale { public: inline get_locale(bool localized, locale_ref loc) : has_locale_(localized) { - if (localized) - ::new (&locale_) std::locale(loc.template get<std::locale>()); + if (!localized) return; + ignore_unused(loc); + ::new (&locale_) std::locale( +#if FMT_USE_LOCALE + loc.template get<std::locale>() +#endif + ); } inline ~get_locale() { if (has_locale_) locale_.~locale(); diff --git a/thirdparty/fmt/include/fmt/color.h b/thirdparty/fmt/include/fmt/color.h index b69c14886..2cbc53ca3 100644 --- a/thirdparty/fmt/include/fmt/color.h +++ b/thirdparty/fmt/include/fmt/color.h @@ -429,7 +429,7 @@ template <typename Char> struct ansi_color_escape { private: static constexpr size_t num_emphases = 8; - Char buffer[7u + 4u * num_emphases]; + Char buffer[7u + 4u * num_emphases] = {}; size_t size = 0; static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, diff --git a/thirdparty/fmt/include/fmt/compile.h b/thirdparty/fmt/include/fmt/compile.h index f711ba41e..64eb7a20d 100644 --- a/thirdparty/fmt/include/fmt/compile.h +++ b/thirdparty/fmt/include/fmt/compile.h @@ -15,9 +15,10 @@ #include "format.h" FMT_BEGIN_NAMESPACE +FMT_BEGIN_EXPORT // A compile-time string which is compiled into fast formatting code. -FMT_EXPORT class compiled_string {}; +class compiled_string {}; template <typename S> struct is_compiled_string : std::is_base_of<compiled_string, S> {}; @@ -59,6 +60,8 @@ template <detail::fixed_string Str> constexpr auto operator""_cf() { } // namespace literals #endif +FMT_END_EXPORT + namespace detail { template <typename T, typename... Tail> diff --git a/thirdparty/fmt/include/fmt/format-inl.h b/thirdparty/fmt/include/fmt/format-inl.h index 9d568dca1..945cb912a 100644 --- a/thirdparty/fmt/include/fmt/format-inl.h +++ b/thirdparty/fmt/include/fmt/format-inl.h @@ -36,7 +36,7 @@ FMT_BEGIN_NAMESPACE FMT_FUNC void assert_fail(const char* file, int line, const char* message) { // Use unchecked std::fprintf to avoid triggering another assertion when // writing to stderr fails. - fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); + std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); abort(); } #endif @@ -47,11 +47,6 @@ using std::locale; using std::numpunct; using std::use_facet; } // namespace detail - -template <typename Locale, enable_if_t<(sizeof(Locale::collate) != 0), int>> -locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { - static_assert(std::is_same<Locale, std::locale>::value, ""); -} #else namespace detail { struct locale {}; diff --git a/thirdparty/fmt/include/fmt/format.h b/thirdparty/fmt/include/fmt/format.h index c3a1bda09..4a6530072 100644 --- a/thirdparty/fmt/include/fmt/format.h +++ b/thirdparty/fmt/include/fmt/format.h @@ -40,11 +40,18 @@ #include "base.h" +// libc++ supports string_view in pre-c++17. +#if FMT_HAS_INCLUDE(<string_view>) && \ + (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION)) +# define FMT_USE_STRING_VIEW +#endif + #ifndef FMT_MODULE +# include <stdlib.h> // malloc, free + # include <cmath> // std::signbit # include <cstddef> // std::byte # include <cstdint> // uint32_t -# include <cstdlib> // std::malloc, std::free # include <cstring> // std::memcpy # include <limits> // std::numeric_limits # include <new> // std::bad_alloc @@ -61,11 +68,8 @@ # include <bit> // std::bit_cast # endif -// libc++ supports string_view in pre-c++17. -# if FMT_HAS_INCLUDE(<string_view>) && \ - (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION)) +# if defined(FMT_USE_STRING_VIEW) # include <string_view> -# define FMT_USE_STRING_VIEW # endif # if FMT_MSC_VERSION @@ -744,12 +748,12 @@ template <typename T> struct allocator : private std::decay<void> { auto allocate(size_t n) -> T* { FMT_ASSERT(n <= max_value<size_t>() / sizeof(T), ""); - T* p = static_cast<T*>(std::malloc(n * sizeof(T))); + T* p = static_cast<T*>(malloc(n * sizeof(T))); if (!p) FMT_THROW(std::bad_alloc()); return p; } - void deallocate(T* p, size_t) { std::free(p); } + void deallocate(T* p, size_t) { free(p); } constexpr friend auto operator==(allocator, allocator) noexcept -> bool { return true; // All instances of this allocator are equivalent. @@ -759,6 +763,14 @@ template <typename T> struct allocator : private std::decay<void> { } }; +template <typename Formatter> +FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set) + -> decltype(f.set_debug_format(set)) { + f.set_debug_format(set); +} +template <typename Formatter> +FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {} + } // namespace detail FMT_BEGIN_EXPORT @@ -2506,7 +2518,7 @@ FMT_CONSTEXPR20 auto write_fixed(OutputIt out, const DecimalFP& f, auto grouping = Grouping(loc, specs.localized()); size += grouping.count_separators(exp); return write_padded<Char, align::right>( - out, specs, to_unsigned(size), [&](iterator it) { + out, specs, static_cast<size_t>(size), [&](iterator it) { if (s != sign::none) *it++ = detail::getsign<Char>(s); it = write_significand<Char>(it, f.significand, significand_size, f.exponent, grouping); diff --git a/thirdparty/fmt/include/fmt/os.h b/thirdparty/fmt/include/fmt/os.h index 40cdcdd4f..94d730de2 100644 --- a/thirdparty/fmt/include/fmt/os.h +++ b/thirdparty/fmt/include/fmt/os.h @@ -136,10 +136,9 @@ FMT_API std::system_error vwindows_error(int error_code, string_view fmt, * **Example**: * * // This throws a system_error with the description - * // cannot open file 'madeup': The system cannot find the file - * specified. - * // or similar (system message may vary). - * const char *filename = "madeup"; + * // cannot open file 'foo': The system cannot find the file specified. + * // or similar (system message may vary) if the file doesn't exist. + * const char *filename = "foo"; * LPOFSTRUCT of = LPOFSTRUCT(); * HFILE file = OpenFile(filename, &of, OF_READ); * if (file == HFILE_ERROR) { @@ -365,17 +364,17 @@ FMT_INLINE_VARIABLE constexpr auto buffer_size = detail::buffer_size(); /// A fast buffered output stream for writing from a single thread. Writing from /// multiple threads without external synchronization may result in a data race. -class FMT_API ostream : private detail::buffer<char> { +class ostream : private detail::buffer<char> { private: file file_; - ostream(cstring_view path, const detail::ostream_params& params); + FMT_API ostream(cstring_view path, const detail::ostream_params& params); - static void grow(buffer<char>& buf, size_t); + FMT_API static void grow(buffer<char>& buf, size_t); public: - ostream(ostream&& other) noexcept; - ~ostream(); + FMT_API ostream(ostream&& other) noexcept; + FMT_API ~ostream(); operator writer() { detail::buffer<char>& buf = *this; diff --git a/thirdparty/fmt/include/fmt/ranges.h b/thirdparty/fmt/include/fmt/ranges.h index 24c61e93b..36b38e296 100644 --- a/thirdparty/fmt/include/fmt/ranges.h +++ b/thirdparty/fmt/include/fmt/ranges.h @@ -18,6 +18,13 @@ #include "format.h" +#if FMT_HAS_CPP_ATTRIBUTE(clang::lifetimebound) +# define FMT_LIFETIMEBOUND [[clang::lifetimebound]] +#else +# define FMT_LIFETIMEBOUND +#endif +FMT_PRAGMA_CLANG(diagnostic error "-Wreturn-stack-address") + FMT_BEGIN_NAMESPACE FMT_EXPORT @@ -234,14 +241,6 @@ using range_reference_type = template <typename Range> using uncvref_type = remove_cvref_t<range_reference_type<Range>>; -template <typename Formatter> -FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set) - -> decltype(f.set_debug_format(set)) { - f.set_debug_format(set); -} -template <typename Formatter> -FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {} - template <typename T> struct range_format_kind_ : std::integral_constant<range_format, @@ -821,12 +820,12 @@ auto join(Range&& r, string_view sep) * * **Example**: * - * auto t = std::tuple<int, char>{1, 'a'}; + * auto t = std::tuple<int, char>(1, 'a'); * fmt::print("{}", fmt::join(t, ", ")); * // Output: 1, a */ template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)> -FMT_CONSTEXPR auto join(const Tuple& tuple, string_view sep) +FMT_CONSTEXPR auto join(const Tuple& tuple FMT_LIFETIMEBOUND, string_view sep) -> tuple_join_view<Tuple, char> { return {tuple, sep}; } diff --git a/thirdparty/fmt/include/fmt/std.h b/thirdparty/fmt/include/fmt/std.h index 5cf106181..184c6d26d 100644 --- a/thirdparty/fmt/include/fmt/std.h +++ b/thirdparty/fmt/include/fmt/std.h @@ -111,12 +111,17 @@ void write_escaped_path(basic_memory_buffer<Char>& quoted, #endif // FMT_CPP_LIB_FILESYSTEM #if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT -template <typename Char, typename OutputIt, typename T> -auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt { + +template <typename Char, typename OutputIt, typename T, typename FormatContext> +auto write_escaped_alternative(OutputIt out, const T& v, FormatContext& ctx) + -> OutputIt { if constexpr (has_to_string_view<T>::value) return write_escaped_string<Char>(out, detail::to_string_view(v)); if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v); - return write<Char>(out, v); + + formatter<std::remove_cv_t<T>, Char> underlying; + maybe_set_debug_format(underlying, true); + return underlying.format(v, ctx); } #endif @@ -139,50 +144,39 @@ template <typename Variant, typename Char> class is_variant_formattable { #endif // FMT_CPP_LIB_VARIANT #if FMT_USE_RTTI - -template <typename OutputIt> -auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt { -# ifdef FMT_HAS_ABI_CXA_DEMANGLE - int status = 0; - size_t size = 0; - std::unique_ptr<char, void (*)(void*)> demangled_name_ptr( - abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free); - - string_view demangled_name_view; - if (demangled_name_ptr) { - demangled_name_view = demangled_name_ptr.get(); - - // Normalization of stdlib inline namespace names. - // libc++ inline namespaces. - // std::__1::* -> std::* - // std::__1::__fs::* -> std::* - // libstdc++ inline namespaces. - // std::__cxx11::* -> std::* - // std::filesystem::__cxx11::* -> std::filesystem::* - if (demangled_name_view.starts_with("std::")) { - char* begin = demangled_name_ptr.get(); - char* to = begin + 5; // std:: - for (char *from = to, *end = begin + demangled_name_view.size(); - from < end;) { - // This is safe, because demangled_name is NUL-terminated. - if (from[0] == '_' && from[1] == '_') { - char* next = from + 1; - while (next < end && *next != ':') next++; - if (next[0] == ':' && next[1] == ':') { - from = next + 2; - continue; - } +inline auto normalize_libcxx_inline_namespaces(string_view demangled_name_view, + char* begin) -> string_view { + // Normalization of stdlib inline namespace names. + // libc++ inline namespaces. + // std::__1::* -> std::* + // std::__1::__fs::* -> std::* + // libstdc++ inline namespaces. + // std::__cxx11::* -> std::* + // std::filesystem::__cxx11::* -> std::filesystem::* + if (demangled_name_view.starts_with("std::")) { + char* to = begin + 5; // std:: + for (const char *from = to, *end = begin + demangled_name_view.size(); + from < end;) { + // This is safe, because demangled_name is NUL-terminated. + if (from[0] == '_' && from[1] == '_') { + const char* next = from + 1; + while (next < end && *next != ':') next++; + if (next[0] == ':' && next[1] == ':') { + from = next + 2; + continue; } - *to++ = *from++; } - demangled_name_view = {begin, detail::to_unsigned(to - begin)}; + *to++ = *from++; } - } else { - demangled_name_view = string_view(ti.name()); + demangled_name_view = {begin, detail::to_unsigned(to - begin)}; } - return detail::write_bytes<char>(out, demangled_name_view); -# elif FMT_MSC_VERSION - const string_view demangled_name(ti.name()); + return demangled_name_view; +} + +template <class OutputIt> +auto normalize_msvc_abi_name(string_view abi_name_view, OutputIt out) + -> OutputIt { + const string_view demangled_name(abi_name_view); for (size_t i = 0; i < demangled_name.size(); ++i) { auto sub = demangled_name; sub.remove_prefix(i); @@ -201,6 +195,39 @@ auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt { if (*sub.begin() != ' ') *out++ = *sub.begin(); } return out; +} + +template <typename OutputIt> +auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt { +# ifdef FMT_HAS_ABI_CXA_DEMANGLE + int status = 0; + size_t size = 0; + std::unique_ptr<char, void (*)(void*)> demangled_name_ptr( + abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &free); + + string_view demangled_name_view; + if (demangled_name_ptr) { + demangled_name_view = normalize_libcxx_inline_namespaces( + demangled_name_ptr.get(), demangled_name_ptr.get()); + } else { + demangled_name_view = string_view(ti.name()); + } + return detail::write_bytes<char>(out, demangled_name_view); +# elif FMT_MSC_VERSION && defined(_MSVC_STL_UPDATE) + return normalize_msvc_abi_name(ti.name(), out); +# elif FMT_MSC_VERSION && defined(_LIBCPP_VERSION) + const string_view demangled_name = ti.name(); + std::string name_copy(demangled_name.size(), '\0'); + // normalize_msvc_abi_name removes class, struct, union etc that MSVC has in + // front of types + name_copy.erase(normalize_msvc_abi_name(demangled_name, name_copy.begin()), + name_copy.end()); + // normalize_libcxx_inline_namespaces removes the inline __1, __2, etc + // namespaces libc++ uses for ABI versioning On MSVC ABI + libc++ + // environments, we need to eliminate both of them. + const string_view normalized_name = + normalize_libcxx_inline_namespaces(name_copy, name_copy.data()); + return detail::write_bytes<char>(out, normalized_name); # else return detail::write_bytes<char>(out, string_view(ti.name())); # endif @@ -255,21 +282,6 @@ template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* { #if FMT_CPP_LIB_FILESYSTEM -class path : public std::filesystem::path { - public: - auto display_string() const -> std::string { - const std::filesystem::path& base = *this; - return fmt::format(FMT_STRING("{}"), base); - } - auto system_string() const -> std::string { return string(); } - - auto generic_display_string() const -> std::string { - const std::filesystem::path& base = *this; - return fmt::format(FMT_STRING("{:g}"), base); - } - auto generic_system_string() const -> std::string { return generic_string(); } -}; - template <typename Char> struct formatter<std::filesystem::path, Char> { private: format_specs specs_; @@ -319,6 +331,21 @@ template <typename Char> struct formatter<std::filesystem::path, Char> { } }; +class path : public std::filesystem::path { + public: + auto display_string() const -> std::string { + const std::filesystem::path& base = *this; + return fmt::format(FMT_STRING("{}"), base); + } + auto system_string() const -> std::string { return string(); } + + auto generic_display_string() const -> std::string { + const std::filesystem::path& base = *this; + return fmt::format(FMT_STRING("{:g}"), base); + } + auto generic_system_string() const -> std::string { return generic_string(); } +}; + #endif // FMT_CPP_LIB_FILESYSTEM template <size_t N, typename Char> @@ -353,25 +380,16 @@ template <typename T, typename Char> struct formatter<std::optional<T>, Char, std::enable_if_t<is_formattable<T, Char>::value>> { private: - formatter<T, Char> underlying_; + formatter<std::remove_cv_t<T>, Char> underlying_; static constexpr basic_string_view<Char> optional = detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l', '('>{}; static constexpr basic_string_view<Char> none = detail::string_literal<Char, 'n', 'o', 'n', 'e'>{}; - template <class U> - FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set) - -> decltype(u.set_debug_format(set)) { - u.set_debug_format(set); - } - - template <class U> - FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {} - public: FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) { - maybe_set_debug_format(underlying_, true); + detail::maybe_set_debug_format(underlying_, true); return underlying_.parse(ctx); } @@ -407,10 +425,10 @@ struct formatter<std::expected<T, E>, Char, if (value.has_value()) { out = detail::write<Char>(out, "expected("); if constexpr (!std::is_void<T>::value) - out = detail::write_escaped_alternative<Char>(out, *value); + out = detail::write_escaped_alternative<Char>(out, *value, ctx); } else { out = detail::write<Char>(out, "unexpected("); - out = detail::write_escaped_alternative<Char>(out, value.error()); + out = detail::write_escaped_alternative<Char>(out, value.error(), ctx); } *out++ = ')'; return out; @@ -474,7 +492,7 @@ struct formatter<Variant, Char, FMT_TRY { std::visit( [&](const auto& v) { - out = detail::write_escaped_alternative<Char>(out, v); + out = detail::write_escaped_alternative<Char>(out, v, ctx); }, value); } @@ -495,6 +513,8 @@ template <> struct formatter<std::error_code> { bool debug_ = false; public: + FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } + FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* { auto it = ctx.begin(), end = ctx.end(); if (it == end) return it; diff --git a/thirdparty/fmt/src/format.cc b/thirdparty/fmt/src/format.cc index 05d0105bc..526082e34 100644 --- a/thirdparty/fmt/src/format.cc +++ b/thirdparty/fmt/src/format.cc @@ -10,7 +10,7 @@ FMT_BEGIN_NAMESPACE #if FMT_USE_LOCALE -template FMT_API locale_ref::locale_ref(const std::locale& loc); +template FMT_API locale_ref::locale_ref(const std::locale& loc); // DEPRECATED! template FMT_API auto locale_ref::get<std::locale>() const -> std::locale; #endif diff --git a/thirdparty/fmt/support/mkdocs b/thirdparty/fmt/support/mkdocs index 610d81d67..94eddae3f 100755 --- a/thirdparty/fmt/support/mkdocs +++ b/thirdparty/fmt/support/mkdocs @@ -2,6 +2,10 @@ # A script to invoke mkdocs with the correct environment. # Additionally supports deploying via mike: # ./mkdocs deploy [mike-deploy-options] +# For example: +# ./mkdocs deploy <version> +# This will checkout the website to fmt/build/fmt.dev and deploy documentation +# <version> there. import errno, os, shutil, sys from subprocess import call @@ -40,7 +44,7 @@ config_path = os.path.join(support_dir, 'mkdocs.yml') args = sys.argv[1:] if len(args) > 0: command = args[0] - if command == 'deploy': + if command == 'deploy' or command == 'set-default': git_url = 'https://github.com/' if 'CI' in os.environ else '[email protected]:' site_repo = git_url + 'fmtlib/fmt.dev.git' @@ -64,14 +68,18 @@ if len(args) > 0: if ret != 0 or version == 'dev': sys.exit(ret) current_doc_path = os.path.join(site_dir, version) - os.makedirs(current_doc_path, exist_ok=True) - redirect_page_path = os.path.join(current_doc_path, 'api.html') - with open(redirect_page_path, "w") as file: - file.write(redirect_page) - ret = call(['git', 'add', redirect_page_path], cwd=site_dir) - if ret != 0: - sys.exit(ret) - ret = call(['git', 'commit', '--amend', '--no-edit'], cwd=site_dir) + # mike stages files added by deploy for deletion for unclear reason, + # undo it. + ret = call(['git', 'reset', '--hard'], cwd=site_dir) + if False: + os.makedirs(current_doc_path, exist_ok=True) + redirect_page_path = os.path.join(current_doc_path, 'api.html') + with open(redirect_page_path, "w") as file: + file.write(redirect_page) + ret = call(['git', 'add', redirect_page_path], cwd=site_dir) + if ret != 0: + sys.exit(ret) + ret = call(['git', 'commit', '--amend', '--no-edit'], cwd=site_dir) sys.exit(ret) elif not command.startswith('-'): args += ['-f', config_path] diff --git a/thirdparty/fmt/test/std-test.cc b/thirdparty/fmt/test/std-test.cc index f5b4e7e85..18f6bd3fc 100644 --- a/thirdparty/fmt/test/std-test.cc +++ b/thirdparty/fmt/test/std-test.cc @@ -13,6 +13,7 @@ #include <vector> #include "fmt/os.h" // fmt::system_category +#include "fmt/ranges.h" #include "gtest-extra.h" // StartsWith #ifdef __cpp_lib_filesystem @@ -145,6 +146,7 @@ TEST(std_test, optional) { EXPECT_FALSE((fmt::is_formattable<unformattable>::value)); EXPECT_FALSE((fmt::is_formattable<std::optional<unformattable>>::value)); EXPECT_TRUE((fmt::is_formattable<std::optional<int>>::value)); + EXPECT_TRUE((fmt::is_formattable<std::optional<const int>>::value)); #endif } @@ -196,7 +198,33 @@ class my_class { return fmt::to_string(elm.av); } }; + +class my_class_int { + public: + int av; + + private: + friend auto format_as(const my_class_int& elm) -> int { return elm.av; } +}; } // namespace my_nso + +TEST(std_test, expected_format_as) { +#ifdef __cpp_lib_expected + EXPECT_EQ( + fmt::format( + "{}", std::expected<my_nso::my_number, int>{my_nso::my_number::one}), + "expected(\"first\")"); + EXPECT_EQ( + fmt::format("{}", + std::expected<my_nso::my_class, int>{my_nso::my_class{7}}), + "expected(\"7\")"); + EXPECT_EQ(fmt::format("{}", + std::expected<my_nso::my_class_int, int>{ + my_nso::my_class_int{8}}), + "expected(8)"); +#endif +} + TEST(std_test, optional_format_as) { #ifdef __cpp_lib_optional EXPECT_EQ(fmt::format("{}", std::optional<my_nso::my_number>{}), "none"); @@ -205,6 +233,8 @@ TEST(std_test, optional_format_as) { EXPECT_EQ(fmt::format("{}", std::optional<my_nso::my_class>{}), "none"); EXPECT_EQ(fmt::format("{}", std::optional{my_nso::my_class{7}}), "optional(\"7\")"); + EXPECT_EQ(fmt::format("{}", std::optional{my_nso::my_class_int{8}}), + "optional(8)"); #endif } @@ -274,6 +304,24 @@ TEST(std_test, variant) { #endif } +TEST(std_test, variant_format_as) { +#ifdef __cpp_lib_variant + + EXPECT_EQ(fmt::format("{}", std::variant<my_nso::my_number>{}), + "variant(\"first\")"); + EXPECT_EQ(fmt::format( + "{}", std::variant<my_nso::my_number>{my_nso::my_number::one}), + "variant(\"first\")"); + EXPECT_EQ( + fmt::format("{}", std::variant<my_nso::my_class>{my_nso::my_class{7}}), + "variant(\"7\")"); + EXPECT_EQ( + fmt::format("{}", + std::variant<my_nso::my_class_int>{my_nso::my_class_int{8}}), + "variant(8)"); +#endif +} + TEST(std_test, error_code) { auto& generic = std::generic_category(); EXPECT_EQ(fmt::format("{}", std::error_code(42, generic)), "generic:42"); @@ -288,6 +336,10 @@ TEST(std_test, error_code) { EXPECT_EQ(fmt::format("{:s}", ec), ec.message()); EXPECT_EQ(fmt::format("{:?}", std::error_code(42, generic)), "\"generic:42\""); + EXPECT_EQ(fmt::format("{}", + std::map<std::error_code, int>{ + {std::error_code(42, generic), 0}}), + "{\"generic:42\": 0}"); } template <typename Catch> void exception_test() { |