22# include <type_traits>
28# if FMT_CPLUSPLUS >= 201703L
29# if FMT_HAS_INCLUDE(<filesystem>)
32# if FMT_HAS_INCLUDE(<variant>)
35# if FMT_HAS_INCLUDE(<optional>)
41# if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<source_location>)
42# include <source_location>
44# if FMT_CPLUSPLUS > 202002L && FMT_HAS_INCLUDE(<expected>)
49#if FMT_HAS_INCLUDE(<version>)
54#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
58# ifndef __GABIXX_CXXABI_H__
59# define FMT_HAS_ABI_CXA_DEMANGLE
64#ifndef FMT_CPP_LIB_FILESYSTEM
65# ifdef __cpp_lib_filesystem
66# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem
68# define FMT_CPP_LIB_FILESYSTEM 0
72#ifndef FMT_CPP_LIB_VARIANT
73# ifdef __cpp_lib_variant
74# define FMT_CPP_LIB_VARIANT __cpp_lib_variant
76# define FMT_CPP_LIB_VARIANT 0
80#if FMT_CPP_LIB_FILESYSTEM
85template <
typename Char,
typename PathChar>
86auto get_path_string(
const std::filesystem::path& p,
87 const std::basic_string<PathChar>& native) {
88 if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>)
91 return p.string<Char>();
94template <
typename Char,
typename PathChar>
95void write_escaped_path(basic_memory_buffer<Char>& quoted,
96 const std::filesystem::path& p,
97 const std::basic_string<PathChar>& native) {
98 if constexpr (std::is_same_v<Char, char> &&
99 std::is_same_v<PathChar, wchar_t>) {
100 auto buf = basic_memory_buffer<wchar_t>();
101 write_escaped_string<wchar_t>(std::back_inserter(buf), native);
102 bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()});
103 FMT_ASSERT(valid,
"invalid utf16");
104 }
else if constexpr (std::is_same_v<Char, PathChar>) {
105 write_escaped_string<std::filesystem::path::value_type>(
106 std::back_inserter(quoted), native);
108 write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
115template <
typename Char>
struct formatter<std::filesystem::path, Char> {
118 detail::arg_ref<Char> width_ref_;
123 FMT_CONSTEXPR
void set_debug_format(
bool set =
true) { debug_ = set; }
125 template <
typename ParseContext> FMT_CONSTEXPR
auto parse(ParseContext& ctx) {
126 auto it = ctx.begin(), end = ctx.end();
127 if (it == end)
return it;
129 it = detail::parse_align(it, end, specs_);
130 if (it == end)
return it;
132 it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
133 if (it != end && *it ==
'?') {
137 if (it != end && (*it ==
'g')) path_type_ = detail::to_ascii(*it++);
141 template <
typename FormatContext>
142 auto format(
const std::filesystem::path& p, FormatContext& ctx)
const {
145 !path_type_ ? p.native()
146 : p.generic_string<std::filesystem::path::value_type>();
148 detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
151 auto s = detail::get_path_string<Char>(p, path_string);
152 return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
154 auto quoted = basic_memory_buffer<Char>();
155 detail::write_escaped_path(quoted, p, path_string);
156 return detail::write(ctx.out(),
157 basic_string_view<Char>(quoted.
data(), quoted.
size()),
162class path :
public std::filesystem::path {
164 auto display_string() const -> std::
string {
165 const std::filesystem::path& base = *
this;
166 return fmt::format(FMT_STRING(
"{}"), base);
168 auto system_string() const -> std::
string {
return string(); }
170 auto generic_display_string() const -> std::
string {
171 const std::filesystem::path& base = *
this;
172 return fmt::format(FMT_STRING(
"{:g}"), base);
174 auto generic_system_string() const -> std::
string {
return generic_string(); }
182template <std::
size_t N,
typename Char>
183struct formatter<std::bitset<N>, Char> : nested_formatter<string_view> {
187 const std::bitset<N>& bs;
189 template <
typename OutputIt>
190 FMT_CONSTEXPR
auto operator()(OutputIt out) -> OutputIt {
191 for (
auto pos = N; pos > 0; --pos) {
192 out = detail::write<Char>(out, bs[pos - 1] ? Char(
'1') : Char(
'0'));
200 template <
typename FormatContext>
201 auto format(
const std::bitset<N>& bs, FormatContext& ctx)
const
202 ->
decltype(ctx.out()) {
203 return write_padded(ctx, writer{bs});
208template <
typename Char>
212#ifdef __cpp_lib_optional
215template <
typename T,
typename Char>
217 std::enable_if_t<is_formattable<T, Char>::value>> {
223 static constexpr basic_string_view<Char> none =
224 detail::string_literal<Char,
'n',
'o',
'n',
'e'>{};
227 FMT_CONSTEXPR
static auto maybe_set_debug_format(U& u,
bool set)
228 ->
decltype(u.set_debug_format(set)) {
229 u.set_debug_format(set);
233 FMT_CONSTEXPR
static void maybe_set_debug_format(U&, ...) {}
236 template <
typename ParseContext> FMT_CONSTEXPR
auto parse(ParseContext& ctx) {
237 maybe_set_debug_format(underlying_,
true);
238 return underlying_.parse(ctx);
241 template <
typename FormatContext>
242 auto format(
const std::optional<T>& opt, FormatContext& ctx)
const
243 ->
decltype(ctx.out()) {
244 if (!opt)
return detail::write<Char>(ctx.out(), none);
246 auto out = ctx.out();
247 out = detail::write<Char>(out, optional);
249 out = underlying_.format(*opt, ctx);
250 return detail::write(out,
')');
256#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
261template <
typename Char,
typename OutputIt,
typename T>
262auto write_escaped_alternative(OutputIt out,
const T& v) -> OutputIt {
264 return write_escaped_string<Char>(out, detail::to_string_view(v));
265 if constexpr (std::is_same_v<T, Char>)
return write_escaped_char(out, v);
266 return write<Char>(out, v);
274#ifdef __cpp_lib_expected
278template <
typename T,
typename E,
typename Char>
279struct formatter<std::expected<T, E>, Char,
280 std::enable_if_t<is_formattable<T, Char>::value &&
281 is_formattable<E, Char>::value>> {
282 template <
typename ParseContext>
283 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
decltype(ctx.begin()) {
287 template <
typename FormatContext>
288 auto format(
const std::expected<T, E>& value, FormatContext& ctx)
const
289 ->
decltype(ctx.out()) {
290 auto out = ctx.out();
292 if (value.has_value()) {
293 out = detail::write<Char>(out,
"expected(");
294 out = detail::write_escaped_alternative<Char>(out, *value);
296 out = detail::write<Char>(out,
"unexpected(");
297 out = detail::write_escaped_alternative<Char>(out, value.error());
306#ifdef __cpp_lib_source_location
309template <>
struct formatter<std::source_location> {
310 template <
typename ParseContext> FMT_CONSTEXPR
auto parse(ParseContext& ctx) {
314 template <
typename FormatContext>
315 auto format(
const std::source_location& loc, FormatContext& ctx)
const
316 ->
decltype(ctx.out()) {
317 auto out = ctx.out();
318 out = detail::write(out, loc.file_name());
319 out = detail::write(out,
':');
320 out = detail::write<char>(out, loc.line());
321 out = detail::write(out,
':');
322 out = detail::write<char>(out, loc.column());
323 out = detail::write(out,
": ");
324 out = detail::write(out, loc.function_name());
331#if FMT_CPP_LIB_VARIANT
336using variant_index_sequence =
337 std::make_index_sequence<std::variant_size<T>::value>;
339template <
typename>
struct is_variant_like_ : std::false_type {};
340template <
typename... Types>
341struct is_variant_like_<std::variant<Types...>> : std::true_type {};
344template <
typename T,
typename C>
class is_variant_formattable_ {
345 template <std::size_t... Is>
346 static std::conjunction<
347 is_formattable<std::variant_alternative_t<Is, T>, C>...>
348 check(std::index_sequence<Is...>);
351 static constexpr const bool value =
352 decltype(check(variant_index_sequence<T>{}))::value;
357template <
typename T>
struct is_variant_like {
358 static constexpr const bool value = detail::is_variant_like_<T>::value;
361template <
typename T,
typename C>
struct is_variant_formattable {
362 static constexpr const bool value =
363 detail::is_variant_formattable_<T, C>::value;
368 template <
typename ParseContext>
369 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
decltype(ctx.begin()) {
373 template <
typename FormatContext>
374 auto format(
const std::monostate&, FormatContext& ctx)
const
375 ->
decltype(ctx.out()) {
376 return detail::write<Char>(ctx.out(),
"monostate");
381template <
typename Variant,
typename Char>
384 std::enable_if_t<std::conjunction_v<
385 is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
386 template <
typename ParseContext>
387 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
decltype(ctx.begin()) {
391 template <
typename FormatContext>
392 auto format(
const Variant& value, FormatContext& ctx)
const
393 ->
decltype(ctx.out()) {
394 auto out = ctx.out();
396 out = detail::write<Char>(out,
"variant(");
400 out = detail::write_escaped_alternative<Char>(out, v);
404 FMT_CATCH(
const std::bad_variant_access&) {
405 detail::write<Char>(out,
"valueless by exception");
416template <
typename Char>
struct formatter<std::error_code, Char> {
417 template <
typename ParseContext>
418 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
decltype(ctx.begin()) {
422 template <
typename FormatContext>
423 FMT_CONSTEXPR
auto format(
const std::error_code& ec, FormatContext& ctx)
const
424 ->
decltype(ctx.out()) {
425 auto out = ctx.out();
426 out = detail::write_bytes<Char>(out, ec.category().name(),
format_specs());
427 out = detail::write<Char>(out, Char(
':'));
428 out = detail::write<Char>(out, ec.value());
436template <
typename Char,
typename OutputIt>
437auto write_demangled_name(OutputIt out,
const std::type_info& ti) -> OutputIt {
438# ifdef FMT_HAS_ABI_CXA_DEMANGLE
440 std::size_t size = 0;
441 std::unique_ptr<char, void (*)(
void*)> demangled_name_ptr(
442 abi::__cxa_demangle(ti.name(),
nullptr, &size, &status), &std::free);
444 string_view demangled_name_view;
445 if (demangled_name_ptr) {
446 demangled_name_view = demangled_name_ptr.get();
455 if (demangled_name_view.starts_with(
"std::")) {
456 char* begin = demangled_name_ptr.get();
457 char* to = begin + 5;
458 for (
char *from = to, *end = begin + demangled_name_view.
size();
461 if (from[0] ==
'_' && from[1] ==
'_') {
462 char* next = from + 1;
463 while (next < end && *next !=
':') next++;
464 if (next[0] ==
':' && next[1] ==
':') {
471 demangled_name_view = {begin, detail::to_unsigned(to - begin)};
474 demangled_name_view = string_view(ti.name());
476 return detail::write_bytes<Char>(out, demangled_name_view);
477# elif FMT_MSC_VERSION
478 const string_view demangled_name(ti.name());
479 for (std::size_t i = 0; i < demangled_name.size(); ++i) {
480 auto sub = demangled_name;
481 sub.remove_prefix(i);
482 if (sub.starts_with(
"enum ")) {
486 if (sub.starts_with(
"class ") || sub.starts_with(
"union ")) {
490 if (sub.starts_with(
"struct ")) {
494 if (*sub.begin() !=
' ') *out++ = *sub.begin();
498 return detail::write_bytes<Char>(out, string_view(ti.name()));
505template <
typename Char>
509 FMT_CONSTEXPR
auto parse(basic_format_parse_context<Char>& ctx)
510 ->
decltype(ctx.begin()) {
514 template <
typename Context>
515 auto format(
const std::type_info& ti, Context& ctx)
const
516 ->
decltype(ctx.out()) {
517 return detail::write_demangled_name<Char>(ctx.out(), ti);
523template <
typename T,
typename Char>
526 typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
528 bool with_typename_ =
false;
532 ->
decltype(ctx.
begin()) {
533 auto it = ctx.
begin();
534 auto end = ctx.
end();
535 if (it == end || *it ==
'}')
return it;
538 with_typename_ = FMT_USE_RTTI != 0;
543 template <
typename Context>
544 auto format(
const std::exception& ex, Context& ctx)
const
545 ->
decltype(ctx.out()) {
546 auto out = ctx.out();
548 if (with_typename_) {
549 out = detail::write_demangled_name<Char>(out,
typeid(ex));
554 return detail::write_bytes<Char>(out, string_view(ex.what()));
560template <
typename T,
typename Enable =
void>
564struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
568 static constexpr const bool value =
569 std::is_convertible<T, bool>::value &&
573#ifdef _LIBCPP_VERSION
579 static constexpr const bool value =
true;
590template <
typename BitRef,
typename Char>
591struct formatter<BitRef, Char,
592 enable_if_t<detail::is_bit_reference_like<BitRef>::value>>
593 : formatter<bool, Char> {
594 template <
typename FormatContext>
595 FMT_CONSTEXPR
auto format(
const BitRef& v, FormatContext& ctx)
const
596 ->
decltype(ctx.out()) {
597 return formatter<bool, Char>::format(v, ctx);
601template <
typename T,
typename Deleter>
602auto ptr(
const std::unique_ptr<T, Deleter>& p) ->
const void* {
605template <
typename T>
auto ptr(
const std::shared_ptr<T>& p) ->
const void* {
610template <
typename T,
typename Char>
611struct formatter<std::atomic<T>, Char,
612 enable_if_t<is_formattable<T, Char>::value>>
613 : formatter<T, Char> {
614 template <
typename FormatContext>
615 auto format(
const std::atomic<T>& v, FormatContext& ctx)
const
616 ->
decltype(ctx.out()) {
617 return formatter<T, Char>::format(v.load(), ctx);
621#ifdef __cpp_lib_atomic_flag_test
623template <
typename Char>
625 template <
typename FormatContext>
626 auto format(
const std::atomic_flag& v, FormatContext& ctx)
const
627 ->
decltype(ctx.out()) {
634template <
typename T,
typename Char>
struct formatter<std::complex<T>, Char> {
638 template <
typename FormatContext,
typename OutputIt>
639 FMT_CONSTEXPR
auto do_format(
const std::complex<T>& c,
641 FormatContext& ctx, OutputIt out)
const
645 out = detail::write<Char>(out, c.real(), specs, ctx.locale());
646 specs.sign = sign::plus;
647 out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
648 if (!detail::isfinite(c.imag())) *out++ = Char(
' ');
653 out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
654 if (!detail::isfinite(c.imag())) *out++ = Char(
' ');
661 ->
decltype(ctx.begin()) {
662 if (ctx.begin() == ctx.end() || *ctx.begin() ==
'}')
return ctx.begin();
663 return parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx,
667 template <
typename FormatContext>
668 auto format(
const std::complex<T>& c, FormatContext& ctx)
const
669 ->
decltype(ctx.out()) {
671 if (specs.width_ref.kind != detail::arg_id_kind::none ||
672 specs.precision_ref.kind != detail::arg_id_kind::none) {
673 detail::handle_dynamic_spec<detail::width_checker>(specs.width,
674 specs.width_ref, ctx);
675 detail::handle_dynamic_spec<detail::precision_checker>(
676 specs.precision, specs.precision_ref, ctx);
679 if (specs.width == 0)
return do_format(c, specs, ctx, ctx.out());
683 outer_specs.width = specs.width;
684 outer_specs.fill = specs.fill;
685 outer_specs.align = specs.align;
689 specs.align = align::none;
692 return detail::write<Char>(ctx.out(),
constexpr auto end() const noexcept -> iterator
Returns an iterator past the end of the format string range being parsed.
Definition base.h:775
constexpr auto begin() const noexcept -> iterator
Definition base.h:770
constexpr auto size() const noexcept -> size_t
Returns the string size.
Definition base.h:555
constexpr auto size() const noexcept -> size_t
Returns the size of this buffer.
Definition base.h:894
FMT_CONSTEXPR auto data() noexcept -> T *
Returns a pointer to the buffer data (not null-terminated).
Definition base.h:900