aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/fmt
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2026-03-23 20:39:32 +0100
committerDan Engelbrecht <[email protected]>2026-03-23 20:39:32 +0100
commit840b600525c7c6fd43395863c15ce955d9216b71 (patch)
tree79e017fd6ced67650defddb3f10f40c6efc3d841 /thirdparty/fmt
parent5.7.25 (diff)
parentCross-platform process metrics support (#887) (diff)
downloadzen-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.md74
-rw-r--r--thirdparty/fmt/doc/api.md50
-rw-r--r--thirdparty/fmt/doc/syntax.md10
-rw-r--r--thirdparty/fmt/include/fmt/base.h34
-rw-r--r--thirdparty/fmt/include/fmt/chrono.h9
-rw-r--r--thirdparty/fmt/include/fmt/color.h2
-rw-r--r--thirdparty/fmt/include/fmt/compile.h5
-rw-r--r--thirdparty/fmt/include/fmt/format-inl.h7
-rw-r--r--thirdparty/fmt/include/fmt/format.h28
-rw-r--r--thirdparty/fmt/include/fmt/os.h17
-rw-r--r--thirdparty/fmt/include/fmt/ranges.h19
-rw-r--r--thirdparty/fmt/include/fmt/std.h164
-rw-r--r--thirdparty/fmt/src/format.cc2
-rwxr-xr-xthirdparty/fmt/support/mkdocs26
-rw-r--r--thirdparty/fmt/test/std-test.cc52
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() {