File indexing completed on 2025-12-26 11:16:16
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef FMT_STD_H_
0009 #define FMT_STD_H_
0010
0011 #include "format.h"
0012 #include "ostream.h"
0013
0014 #ifndef FMT_MODULE
0015 # include <atomic>
0016 # include <bitset>
0017 # include <complex>
0018 # include <cstdlib>
0019 # include <exception>
0020 # include <functional>
0021 # include <memory>
0022 # include <thread>
0023 # include <type_traits>
0024 # include <typeinfo>
0025 # include <utility>
0026 # include <vector>
0027
0028
0029 # if FMT_CPLUSPLUS >= 201703L
0030 # if FMT_HAS_INCLUDE(<filesystem>) && \
0031 (!defined(FMT_CPP_LIB_FILESYSTEM) || FMT_CPP_LIB_FILESYSTEM != 0)
0032 # include <filesystem>
0033 # endif
0034 # if FMT_HAS_INCLUDE(<variant>)
0035 # include <variant>
0036 # endif
0037 # if FMT_HAS_INCLUDE(<optional>)
0038 # include <optional>
0039 # endif
0040 # endif
0041
0042
0043 # if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<source_location>)
0044 # include <source_location>
0045 # endif
0046 # if FMT_CPLUSPLUS > 202002L && FMT_HAS_INCLUDE(<expected>)
0047 # include <expected>
0048 # endif
0049 #endif
0050
0051 #if FMT_HAS_INCLUDE(<version>)
0052 # include <version>
0053 #endif
0054
0055
0056 #if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
0057 # include <cxxabi.h>
0058
0059
0060 # ifndef __GABIXX_CXXABI_H__
0061 # define FMT_HAS_ABI_CXA_DEMANGLE
0062 # endif
0063 #endif
0064
0065
0066 #ifndef FMT_CPP_LIB_FILESYSTEM
0067 # ifdef __cpp_lib_filesystem
0068 # define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem
0069 # else
0070 # define FMT_CPP_LIB_FILESYSTEM 0
0071 # endif
0072 #endif
0073
0074 #ifndef FMT_CPP_LIB_VARIANT
0075 # ifdef __cpp_lib_variant
0076 # define FMT_CPP_LIB_VARIANT __cpp_lib_variant
0077 # else
0078 # define FMT_CPP_LIB_VARIANT 0
0079 # endif
0080 #endif
0081
0082 #if FMT_CPP_LIB_FILESYSTEM
0083 FMT_BEGIN_NAMESPACE
0084
0085 namespace detail {
0086
0087 template <typename Char, typename PathChar>
0088 auto get_path_string(const std::filesystem::path& p,
0089 const std::basic_string<PathChar>& native) {
0090 if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>)
0091 return to_utf8<wchar_t>(native, to_utf8_error_policy::replace);
0092 else
0093 return p.string<Char>();
0094 }
0095
0096 template <typename Char, typename PathChar>
0097 void write_escaped_path(basic_memory_buffer<Char>& quoted,
0098 const std::filesystem::path& p,
0099 const std::basic_string<PathChar>& native) {
0100 if constexpr (std::is_same_v<Char, char> &&
0101 std::is_same_v<PathChar, wchar_t>) {
0102 auto buf = basic_memory_buffer<wchar_t>();
0103 write_escaped_string<wchar_t>(std::back_inserter(buf), native);
0104 bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()});
0105 FMT_ASSERT(valid, "invalid utf16");
0106 } else if constexpr (std::is_same_v<Char, PathChar>) {
0107 write_escaped_string<std::filesystem::path::value_type>(
0108 std::back_inserter(quoted), native);
0109 } else {
0110 write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
0111 }
0112 }
0113
0114 }
0115
0116 template <typename Char> struct formatter<std::filesystem::path, Char> {
0117 private:
0118 format_specs specs_;
0119 detail::arg_ref<Char> width_ref_;
0120 bool debug_ = false;
0121 char path_type_ = 0;
0122
0123 public:
0124 FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
0125
0126 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
0127 auto it = ctx.begin(), end = ctx.end();
0128 if (it == end) return it;
0129
0130 it = detail::parse_align(it, end, specs_);
0131 if (it == end) return it;
0132
0133 Char c = *it;
0134 if ((c >= '0' && c <= '9') || c == '{')
0135 it = detail::parse_width(it, end, specs_, width_ref_, ctx);
0136 if (it != end && *it == '?') {
0137 debug_ = true;
0138 ++it;
0139 }
0140 if (it != end && (*it == 'g')) path_type_ = detail::to_ascii(*it++);
0141 return it;
0142 }
0143
0144 template <typename FormatContext>
0145 auto format(const std::filesystem::path& p, FormatContext& ctx) const {
0146 auto specs = specs_;
0147 auto path_string =
0148 !path_type_ ? p.native()
0149 : p.generic_string<std::filesystem::path::value_type>();
0150
0151 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
0152 ctx);
0153 if (!debug_) {
0154 auto s = detail::get_path_string<Char>(p, path_string);
0155 return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
0156 }
0157 auto quoted = basic_memory_buffer<Char>();
0158 detail::write_escaped_path(quoted, p, path_string);
0159 return detail::write(ctx.out(),
0160 basic_string_view<Char>(quoted.data(), quoted.size()),
0161 specs);
0162 }
0163 };
0164
0165 class path : public std::filesystem::path {
0166 public:
0167 auto display_string() const -> std::string {
0168 const std::filesystem::path& base = *this;
0169 return fmt::format(FMT_STRING("{}"), base);
0170 }
0171 auto system_string() const -> std::string { return string(); }
0172
0173 auto generic_display_string() const -> std::string {
0174 const std::filesystem::path& base = *this;
0175 return fmt::format(FMT_STRING("{:g}"), base);
0176 }
0177 auto generic_system_string() const -> std::string { return generic_string(); }
0178 };
0179
0180 FMT_END_NAMESPACE
0181 #endif
0182
0183 FMT_BEGIN_NAMESPACE
0184 template <std::size_t N, typename Char>
0185 struct formatter<std::bitset<N>, Char>
0186 : nested_formatter<basic_string_view<Char>, Char> {
0187 private:
0188
0189 struct writer {
0190 const std::bitset<N>& bs;
0191
0192 template <typename OutputIt>
0193 FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt {
0194 for (auto pos = N; pos > 0; --pos) {
0195 out = detail::write<Char>(out, bs[pos - 1] ? Char('1') : Char('0'));
0196 }
0197
0198 return out;
0199 }
0200 };
0201
0202 public:
0203 template <typename FormatContext>
0204 auto format(const std::bitset<N>& bs, FormatContext& ctx) const
0205 -> decltype(ctx.out()) {
0206 return this->write_padded(ctx, writer{bs});
0207 }
0208 };
0209
0210 template <typename Char>
0211 struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
0212 FMT_END_NAMESPACE
0213
0214 #ifdef __cpp_lib_optional
0215 FMT_BEGIN_NAMESPACE
0216 template <typename T, typename Char>
0217 struct formatter<std::optional<T>, Char,
0218 std::enable_if_t<is_formattable<T, Char>::value>> {
0219 private:
0220 formatter<T, Char> underlying_;
0221 static constexpr basic_string_view<Char> optional =
0222 detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
0223 '('>{};
0224 static constexpr basic_string_view<Char> none =
0225 detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
0226
0227 template <class U>
0228 FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
0229 -> decltype(u.set_debug_format(set)) {
0230 u.set_debug_format(set);
0231 }
0232
0233 template <class U>
0234 FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
0235
0236 public:
0237 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
0238 maybe_set_debug_format(underlying_, true);
0239 return underlying_.parse(ctx);
0240 }
0241
0242 template <typename FormatContext>
0243 auto format(const std::optional<T>& opt, FormatContext& ctx) const
0244 -> decltype(ctx.out()) {
0245 if (!opt) return detail::write<Char>(ctx.out(), none);
0246
0247 auto out = ctx.out();
0248 out = detail::write<Char>(out, optional);
0249 ctx.advance_to(out);
0250 out = underlying_.format(*opt, ctx);
0251 return detail::write(out, ')');
0252 }
0253 };
0254 FMT_END_NAMESPACE
0255 #endif
0256
0257 #if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
0258
0259 FMT_BEGIN_NAMESPACE
0260 namespace detail {
0261
0262 template <typename Char, typename OutputIt, typename T>
0263 auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt {
0264 if constexpr (has_to_string_view<T>::value)
0265 return write_escaped_string<Char>(out, detail::to_string_view(v));
0266 if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v);
0267 return write<Char>(out, v);
0268 }
0269
0270 }
0271
0272 FMT_END_NAMESPACE
0273 #endif
0274
0275 #ifdef __cpp_lib_expected
0276 FMT_BEGIN_NAMESPACE
0277
0278 template <typename T, typename E, typename Char>
0279 struct formatter<std::expected<T, E>, Char,
0280 std::enable_if_t<(std::is_void<T>::value ||
0281 is_formattable<T, Char>::value) &&
0282 is_formattable<E, Char>::value>> {
0283 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
0284 return ctx.begin();
0285 }
0286
0287 template <typename FormatContext>
0288 auto format(const std::expected<T, E>& value, FormatContext& ctx) const
0289 -> decltype(ctx.out()) {
0290 auto out = ctx.out();
0291
0292 if (value.has_value()) {
0293 out = detail::write<Char>(out, "expected(");
0294 if constexpr (!std::is_void<T>::value)
0295 out = detail::write_escaped_alternative<Char>(out, *value);
0296 } else {
0297 out = detail::write<Char>(out, "unexpected(");
0298 out = detail::write_escaped_alternative<Char>(out, value.error());
0299 }
0300 *out++ = ')';
0301 return out;
0302 }
0303 };
0304 FMT_END_NAMESPACE
0305 #endif
0306
0307 #ifdef __cpp_lib_source_location
0308 FMT_BEGIN_NAMESPACE
0309 template <> struct formatter<std::source_location> {
0310 FMT_CONSTEXPR auto parse(parse_context<>& ctx) { return ctx.begin(); }
0311
0312 template <typename FormatContext>
0313 auto format(const std::source_location& loc, FormatContext& ctx) const
0314 -> decltype(ctx.out()) {
0315 auto out = ctx.out();
0316 out = detail::write(out, loc.file_name());
0317 out = detail::write(out, ':');
0318 out = detail::write<char>(out, loc.line());
0319 out = detail::write(out, ':');
0320 out = detail::write<char>(out, loc.column());
0321 out = detail::write(out, ": ");
0322 out = detail::write(out, loc.function_name());
0323 return out;
0324 }
0325 };
0326 FMT_END_NAMESPACE
0327 #endif
0328
0329 #if FMT_CPP_LIB_VARIANT
0330 FMT_BEGIN_NAMESPACE
0331 namespace detail {
0332
0333 template <typename T>
0334 using variant_index_sequence =
0335 std::make_index_sequence<std::variant_size<T>::value>;
0336
0337 template <typename> struct is_variant_like_ : std::false_type {};
0338 template <typename... Types>
0339 struct is_variant_like_<std::variant<Types...>> : std::true_type {};
0340
0341
0342 template <typename T, typename C> class is_variant_formattable_ {
0343 template <std::size_t... Is>
0344 static std::conjunction<
0345 is_formattable<std::variant_alternative_t<Is, T>, C>...>
0346 check(std::index_sequence<Is...>);
0347
0348 public:
0349 static constexpr const bool value =
0350 decltype(check(variant_index_sequence<T>{}))::value;
0351 };
0352
0353 }
0354
0355 template <typename T> struct is_variant_like {
0356 static constexpr const bool value = detail::is_variant_like_<T>::value;
0357 };
0358
0359 template <typename T, typename C> struct is_variant_formattable {
0360 static constexpr const bool value =
0361 detail::is_variant_formattable_<T, C>::value;
0362 };
0363
0364 template <typename Char> struct formatter<std::monostate, Char> {
0365 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
0366 return ctx.begin();
0367 }
0368
0369 template <typename FormatContext>
0370 auto format(const std::monostate&, FormatContext& ctx) const
0371 -> decltype(ctx.out()) {
0372 return detail::write<Char>(ctx.out(), "monostate");
0373 }
0374 };
0375
0376 template <typename Variant, typename Char>
0377 struct formatter<
0378 Variant, Char,
0379 std::enable_if_t<std::conjunction_v<
0380 is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
0381 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
0382 return ctx.begin();
0383 }
0384
0385 template <typename FormatContext>
0386 auto format(const Variant& value, FormatContext& ctx) const
0387 -> decltype(ctx.out()) {
0388 auto out = ctx.out();
0389
0390 out = detail::write<Char>(out, "variant(");
0391 FMT_TRY {
0392 std::visit(
0393 [&](const auto& v) {
0394 out = detail::write_escaped_alternative<Char>(out, v);
0395 },
0396 value);
0397 }
0398 FMT_CATCH(const std::bad_variant_access&) {
0399 detail::write<Char>(out, "valueless by exception");
0400 }
0401 *out++ = ')';
0402 return out;
0403 }
0404 };
0405 FMT_END_NAMESPACE
0406 #endif
0407
0408 FMT_BEGIN_NAMESPACE
0409 template <> struct formatter<std::error_code> {
0410 private:
0411 format_specs specs_;
0412 detail::arg_ref<char> width_ref_;
0413 bool debug_ = false;
0414
0415 public:
0416 FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* {
0417 auto it = ctx.begin(), end = ctx.end();
0418 if (it == end) return it;
0419
0420 it = detail::parse_align(it, end, specs_);
0421
0422 char c = *it;
0423 if (it != end && ((c >= '0' && c <= '9') || c == '{'))
0424 it = detail::parse_width(it, end, specs_, width_ref_, ctx);
0425
0426 if (it != end && *it == '?') {
0427 debug_ = true;
0428 ++it;
0429 }
0430 if (it != end && *it == 's') {
0431 specs_.set_type(presentation_type::string);
0432 ++it;
0433 }
0434 return it;
0435 }
0436
0437 template <typename FormatContext>
0438 FMT_CONSTEXPR20 auto format(const std::error_code& ec,
0439 FormatContext& ctx) const -> decltype(ctx.out()) {
0440 auto specs = specs_;
0441 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
0442 ctx);
0443 auto buf = memory_buffer();
0444 if (specs_.type() == presentation_type::string) {
0445 buf.append(ec.message());
0446 } else {
0447 buf.append(string_view(ec.category().name()));
0448 buf.push_back(':');
0449 detail::write<char>(appender(buf), ec.value());
0450 }
0451 auto quoted = memory_buffer();
0452 auto str = string_view(buf.data(), buf.size());
0453 if (debug_) {
0454 detail::write_escaped_string<char>(std::back_inserter(quoted), str);
0455 str = string_view(quoted.data(), quoted.size());
0456 }
0457 return detail::write<char>(ctx.out(), str, specs);
0458 }
0459 };
0460
0461 #if FMT_USE_RTTI
0462 namespace detail {
0463
0464 template <typename Char, typename OutputIt>
0465 auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt {
0466 # ifdef FMT_HAS_ABI_CXA_DEMANGLE
0467 int status = 0;
0468 std::size_t size = 0;
0469 std::unique_ptr<char, void (*)(void*)> demangled_name_ptr(
0470 abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
0471
0472 string_view demangled_name_view;
0473 if (demangled_name_ptr) {
0474 demangled_name_view = demangled_name_ptr.get();
0475
0476
0477
0478
0479
0480
0481
0482
0483 if (demangled_name_view.starts_with("std::")) {
0484 char* begin = demangled_name_ptr.get();
0485 char* to = begin + 5;
0486 for (char *from = to, *end = begin + demangled_name_view.size();
0487 from < end;) {
0488
0489 if (from[0] == '_' && from[1] == '_') {
0490 char* next = from + 1;
0491 while (next < end && *next != ':') next++;
0492 if (next[0] == ':' && next[1] == ':') {
0493 from = next + 2;
0494 continue;
0495 }
0496 }
0497 *to++ = *from++;
0498 }
0499 demangled_name_view = {begin, detail::to_unsigned(to - begin)};
0500 }
0501 } else {
0502 demangled_name_view = string_view(ti.name());
0503 }
0504 return detail::write_bytes<Char>(out, demangled_name_view);
0505 # elif FMT_MSC_VERSION
0506 const string_view demangled_name(ti.name());
0507 for (std::size_t i = 0; i < demangled_name.size(); ++i) {
0508 auto sub = demangled_name;
0509 sub.remove_prefix(i);
0510 if (sub.starts_with("enum ")) {
0511 i += 4;
0512 continue;
0513 }
0514 if (sub.starts_with("class ") || sub.starts_with("union ")) {
0515 i += 5;
0516 continue;
0517 }
0518 if (sub.starts_with("struct ")) {
0519 i += 6;
0520 continue;
0521 }
0522 if (*sub.begin() != ' ') *out++ = *sub.begin();
0523 }
0524 return out;
0525 # else
0526 return detail::write_bytes<Char>(out, string_view(ti.name()));
0527 # endif
0528 }
0529
0530 }
0531
0532 template <typename Char>
0533 struct formatter<std::type_info, Char
0534 > {
0535 public:
0536 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
0537 return ctx.begin();
0538 }
0539
0540 template <typename Context>
0541 auto format(const std::type_info& ti, Context& ctx) const
0542 -> decltype(ctx.out()) {
0543 return detail::write_demangled_name<Char>(ctx.out(), ti);
0544 }
0545 };
0546 #endif
0547
0548 template <typename T, typename Char>
0549 struct formatter<
0550 T, Char,
0551 typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
0552 private:
0553 bool with_typename_ = false;
0554
0555 public:
0556 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
0557 auto it = ctx.begin();
0558 auto end = ctx.end();
0559 if (it == end || *it == '}') return it;
0560 if (*it == 't') {
0561 ++it;
0562 with_typename_ = FMT_USE_RTTI != 0;
0563 }
0564 return it;
0565 }
0566
0567 template <typename Context>
0568 auto format(const std::exception& ex, Context& ctx) const
0569 -> decltype(ctx.out()) {
0570 auto out = ctx.out();
0571 #if FMT_USE_RTTI
0572 if (with_typename_) {
0573 out = detail::write_demangled_name<Char>(out, typeid(ex));
0574 *out++ = ':';
0575 *out++ = ' ';
0576 }
0577 #endif
0578 return detail::write_bytes<Char>(out, string_view(ex.what()));
0579 }
0580 };
0581
0582 namespace detail {
0583
0584 template <typename T, typename Enable = void>
0585 struct has_flip : std::false_type {};
0586
0587 template <typename T>
0588 struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
0589 : std::true_type {};
0590
0591 template <typename T> struct is_bit_reference_like {
0592 static constexpr const bool value =
0593 std::is_convertible<T, bool>::value &&
0594 std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
0595 };
0596
0597 #ifdef _LIBCPP_VERSION
0598
0599
0600
0601 template <typename C>
0602 struct is_bit_reference_like<std::__bit_const_reference<C>> {
0603 static constexpr const bool value = true;
0604 };
0605
0606 #endif
0607
0608 }
0609
0610
0611
0612
0613 template <typename BitRef, typename Char>
0614 struct formatter<BitRef, Char,
0615 enable_if_t<detail::is_bit_reference_like<BitRef>::value>>
0616 : formatter<bool, Char> {
0617 template <typename FormatContext>
0618 FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const
0619 -> decltype(ctx.out()) {
0620 return formatter<bool, Char>::format(v, ctx);
0621 }
0622 };
0623
0624 template <typename T, typename Deleter>
0625 auto ptr(const std::unique_ptr<T, Deleter>& p) -> const void* {
0626 return p.get();
0627 }
0628 template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* {
0629 return p.get();
0630 }
0631
0632 template <typename T, typename Char>
0633 struct formatter<std::atomic<T>, Char,
0634 enable_if_t<is_formattable<T, Char>::value>>
0635 : formatter<T, Char> {
0636 template <typename FormatContext>
0637 auto format(const std::atomic<T>& v, FormatContext& ctx) const
0638 -> decltype(ctx.out()) {
0639 return formatter<T, Char>::format(v.load(), ctx);
0640 }
0641 };
0642
0643 #ifdef __cpp_lib_atomic_flag_test
0644 template <typename Char>
0645 struct formatter<std::atomic_flag, Char> : formatter<bool, Char> {
0646 template <typename FormatContext>
0647 auto format(const std::atomic_flag& v, FormatContext& ctx) const
0648 -> decltype(ctx.out()) {
0649 return formatter<bool, Char>::format(v.test(), ctx);
0650 }
0651 };
0652 #endif
0653
0654 template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
0655 private:
0656 detail::dynamic_format_specs<Char> specs_;
0657
0658 template <typename FormatContext, typename OutputIt>
0659 FMT_CONSTEXPR auto do_format(const std::complex<T>& c,
0660 detail::dynamic_format_specs<Char>& specs,
0661 FormatContext& ctx, OutputIt out) const
0662 -> OutputIt {
0663 if (c.real() != 0) {
0664 *out++ = Char('(');
0665 out = detail::write<Char>(out, c.real(), specs, ctx.locale());
0666 specs.set_sign(sign::plus);
0667 out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
0668 if (!detail::isfinite(c.imag())) *out++ = Char(' ');
0669 *out++ = Char('i');
0670 *out++ = Char(')');
0671 return out;
0672 }
0673 out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
0674 if (!detail::isfinite(c.imag())) *out++ = Char(' ');
0675 *out++ = Char('i');
0676 return out;
0677 }
0678
0679 public:
0680 FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
0681 if (ctx.begin() == ctx.end() || *ctx.begin() == '}') return ctx.begin();
0682 return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
0683 detail::type_constant<T, Char>::value);
0684 }
0685
0686 template <typename FormatContext>
0687 auto format(const std::complex<T>& c, FormatContext& ctx) const
0688 -> decltype(ctx.out()) {
0689 auto specs = specs_;
0690 if (specs.dynamic()) {
0691 detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
0692 specs.width_ref, ctx);
0693 detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
0694 specs.precision_ref, ctx);
0695 }
0696
0697 if (specs.width == 0) return do_format(c, specs, ctx, ctx.out());
0698 auto buf = basic_memory_buffer<Char>();
0699
0700 auto outer_specs = format_specs();
0701 outer_specs.width = specs.width;
0702 outer_specs.copy_fill_from(specs);
0703 outer_specs.set_align(specs.align());
0704
0705 specs.width = 0;
0706 specs.set_fill({});
0707 specs.set_align(align::none);
0708
0709 do_format(c, specs, ctx, basic_appender<Char>(buf));
0710 return detail::write<Char>(ctx.out(),
0711 basic_string_view<Char>(buf.data(), buf.size()),
0712 outer_specs);
0713 }
0714 };
0715
0716 template <typename T, typename Char>
0717 struct formatter<std::reference_wrapper<T>, Char,
0718 enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value>>
0719 : formatter<remove_cvref_t<T>, Char> {
0720 template <typename FormatContext>
0721 auto format(std::reference_wrapper<T> ref, FormatContext& ctx) const
0722 -> decltype(ctx.out()) {
0723 return formatter<remove_cvref_t<T>, Char>::format(ref.get(), ctx);
0724 }
0725 };
0726
0727 FMT_END_NAMESPACE
0728 #endif