19# include <type_traits>
28#if FMT_HAS_INCLUDE(<version>)
34# if FMT_CPLUSPLUS >= 201703L
35# if FMT_HAS_INCLUDE(<filesystem>)
38# if FMT_HAS_INCLUDE(<variant>)
41# if FMT_HAS_INCLUDE(<optional>)
46# if FMT_HAS_INCLUDE(<expected>) && FMT_CPLUSPLUS > 202002L
50# if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<source_location>)
51# include <source_location>
56#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
60# ifndef __GABIXX_CXXABI_H__
61# define FMT_HAS_ABI_CXA_DEMANGLE
68# if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || defined(_CPPRTTI) || \
69 defined(__INTEL_RTTI__) || defined(__RTTI)
70# define FMT_USE_TYPEID 1
72# define FMT_USE_TYPEID 0
77#ifndef FMT_CPP_LIB_FILESYSTEM
78# ifdef __cpp_lib_filesystem
79# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem
81# define FMT_CPP_LIB_FILESYSTEM 0
85#ifndef FMT_CPP_LIB_VARIANT
86# ifdef __cpp_lib_variant
87# define FMT_CPP_LIB_VARIANT __cpp_lib_variant
89# define FMT_CPP_LIB_VARIANT 0
93#if FMT_CPP_LIB_FILESYSTEM
98template <
typename Char,
typename PathChar>
99auto get_path_string(
const std::filesystem::path& p,
100 const std::basic_string<PathChar>& native) {
101 if constexpr (std::is_same_v<Char, char> && std::is_same_v<PathChar, wchar_t>)
102 return to_utf8<wchar_t>(native, to_utf8_error_policy::replace);
104 return p.string<Char>();
107template <
typename Char,
typename PathChar>
109 const std::filesystem::path& p,
110 const std::basic_string<PathChar>& native) {
111 if constexpr (std::is_same_v<Char, char> &&
112 std::is_same_v<PathChar, wchar_t>) {
114 write_escaped_string<wchar_t>(std::back_inserter(buf), native);
115 bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()});
116 FMT_ASSERT(valid,
"invalid utf16");
117 }
else if constexpr (std::is_same_v<Char, PathChar>) {
118 write_escaped_string<std::filesystem::path::value_type>(
119 std::back_inserter(quoted), native);
121 write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
128template <
typename Char>
struct formatter<std::filesystem::path, Char> {
136 FMT_CONSTEXPR
void set_debug_format(
bool set =
true) { debug_ = set; }
138 template <
typename ParseContext> FMT_CONSTEXPR
auto parse(ParseContext& ctx) {
139 auto it = ctx.begin(), end = ctx.end();
140 if (it == end)
return it;
142 it = detail::parse_align(it, end, specs_);
143 if (it == end)
return it;
145 it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
146 if (it != end && *it ==
'?') {
150 if (it != end && (*it ==
'g')) path_type_ = detail::to_ascii(*it++);
154 template <
typename FormatContext>
155 auto format(
const std::filesystem::path& p, FormatContext& ctx)
const {
158 !path_type_ ? p.native()
159 : p.generic_string<std::filesystem::path::value_type>();
161 detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
164 auto s = detail::get_path_string<Char>(p, path_string);
168 detail::write_escaped_path(quoted, p, path_string);
169 return detail::write(ctx.out(),
179template <std::
size_t N,
typename Char>
184 const std::bitset<N>& bs;
186 template <
typename OutputIt>
187 FMT_CONSTEXPR
auto operator()(OutputIt out) -> OutputIt {
188 for (
auto pos = N; pos > 0; --pos) {
189 out = detail::write<Char>(out, bs[pos - 1] ? Char(
'1') : Char(
'0'));
197 template <
typename FormatContext>
198 auto format(
const std::bitset<N>& bs, FormatContext& ctx)
const
199 ->
decltype(ctx.out()) {
200 return write_padded(ctx, writer{bs});
205template <
typename Char>
209#ifdef __cpp_lib_optional
212template <
typename T,
typename Char>
214 std::enable_if_t<is_formattable<T, Char>::value>> {
224 FMT_CONSTEXPR
static auto maybe_set_debug_format(U& u,
bool set)
225 ->
decltype(u.set_debug_format(set)) {
226 u.set_debug_format(set);
230 FMT_CONSTEXPR
static void maybe_set_debug_format(U&, ...) {}
233 template <
typename ParseContext> FMT_CONSTEXPR
auto parse(ParseContext& ctx) {
234 maybe_set_debug_format(underlying_,
true);
235 return underlying_.parse(ctx);
238 template <
typename FormatContext>
239 auto format(
const std::optional<T>& opt, FormatContext& ctx)
const
240 ->
decltype(ctx.out()) {
241 if (!opt)
return detail::write<Char>(ctx.out(), none);
243 auto out = ctx.out();
244 out = detail::write<Char>(out, optional);
246 out = underlying_.format(*opt, ctx);
247 return detail::write(out,
')');
253#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
258template <
typename Char,
typename OutputIt,
typename T>
259auto write_escaped_alternative(OutputIt out,
const T& v) -> OutputIt {
260 if constexpr (has_to_string_view<T>::value)
261 return write_escaped_string<Char>(out, detail::to_string_view(v));
262 if constexpr (std::is_same_v<T, Char>)
return write_escaped_char(out, v);
263 return write<Char>(out, v);
271#ifdef __cpp_lib_expected
275template <
typename T,
typename E,
typename Char>
276struct formatter<std::expected<T, E>, Char,
277 std::enable_if_t<is_formattable<T, Char>::value &&
278 is_formattable<E, Char>::value>> {
279 template <
typename ParseContext>
280 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
decltype(ctx.begin()) {
284 template <
typename FormatContext>
285 auto format(
const std::expected<T, E>& value, FormatContext& ctx)
const
286 ->
decltype(ctx.out()) {
287 auto out = ctx.out();
289 if (value.has_value()) {
290 out = detail::write<Char>(out,
"expected(");
291 out = detail::write_escaped_alternative<Char>(out, value.value());
293 out = detail::write<Char>(out,
"unexpected(");
294 out = detail::write_escaped_alternative<Char>(out, value.error());
303#ifdef __cpp_lib_source_location
306template <>
struct formatter<std::source_location> {
307 template <
typename ParseContext> FMT_CONSTEXPR
auto parse(ParseContext& ctx) {
311 template <
typename FormatContext>
312 auto format(
const std::source_location& loc, FormatContext& ctx)
const
313 ->
decltype(ctx.out()) {
314 auto out = ctx.out();
315 out = detail::write(out, loc.file_name());
316 out = detail::write(out,
':');
317 out = detail::write<char>(out, loc.line());
318 out = detail::write(out,
':');
319 out = detail::write<char>(out, loc.column());
320 out = detail::write(out,
": ");
321 out = detail::write(out, loc.function_name());
328#if FMT_CPP_LIB_VARIANT
333using variant_index_sequence =
334 std::make_index_sequence<std::variant_size<T>::value>;
336template <
typename>
struct is_variant_like_ : std::false_type {};
337template <
typename... Types>
338struct is_variant_like_<std::variant<Types...>> : std::true_type {};
341template <
typename T,
typename C>
class is_variant_formattable_ {
342 template <std::size_t... Is>
343 static std::conjunction<
344 is_formattable<std::variant_alternative_t<Is, T>, C>...>
345 check(std::index_sequence<Is...>);
348 static constexpr const bool value =
349 decltype(check(variant_index_sequence<T>{}))::value;
354template <
typename T>
struct is_variant_like {
355 static constexpr const bool value = detail::is_variant_like_<T>::value;
358template <
typename T,
typename C>
struct is_variant_formattable {
359 static constexpr const bool value =
360 detail::is_variant_formattable_<T, C>::value;
365 template <
typename ParseContext>
366 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
decltype(ctx.begin()) {
370 template <
typename FormatContext>
371 auto format(
const std::monostate&, FormatContext& ctx)
const
372 ->
decltype(ctx.out()) {
373 return detail::write<Char>(ctx.out(),
"monostate");
378template <
typename Variant,
typename Char>
381 std::enable_if_t<std::conjunction_v<
382 is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
383 template <
typename ParseContext>
384 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
decltype(ctx.begin()) {
388 template <
typename FormatContext>
389 auto format(
const Variant& value, FormatContext& ctx)
const
390 ->
decltype(ctx.out()) {
391 auto out = ctx.out();
393 out = detail::write<Char>(out,
"variant(");
397 out = detail::write_escaped_alternative<Char>(out, v);
401 FMT_CATCH(
const std::bad_variant_access&) {
402 detail::write<Char>(out,
"valueless by exception");
413template <
typename Char>
struct formatter<std::error_code, Char> {
414 template <
typename ParseContext>
415 FMT_CONSTEXPR
auto parse(ParseContext& ctx) ->
decltype(ctx.begin()) {
419 template <
typename FormatContext>
420 FMT_CONSTEXPR
auto format(
const std::error_code& ec, FormatContext& ctx)
const
421 ->
decltype(ctx.out()) {
422 auto out = ctx.out();
423 out = detail::write_bytes<Char>(out, ec.category().name(),
format_specs());
424 out = detail::write<Char>(out, Char(
':'));
425 out = detail::write<Char>(out, ec.value());
431template <
typename T,
typename Char>
434 typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
436 bool with_typename_ =
false;
440 ->
decltype(ctx.
begin()) {
441 auto it = ctx.
begin();
442 auto end = ctx.
end();
443 if (it == end || *it ==
'}')
return it;
446 with_typename_ = FMT_USE_TYPEID != 0;
451 template <
typename Context>
452 auto format(
const std::exception& ex, Context& ctx)
const
453 ->
decltype(ctx.out()) {
454 auto out = ctx.out();
456 return detail::write_bytes<Char>(out,
string_view(ex.what()));
459 const std::type_info& ti =
typeid(ex);
460# ifdef FMT_HAS_ABI_CXA_DEMANGLE
462 std::size_t size = 0;
463 std::unique_ptr<char, void (*)(
void*)> demangled_name_ptr(
464 abi::__cxa_demangle(ti.name(),
nullptr, &size, &status), &std::free);
467 if (demangled_name_ptr) {
468 demangled_name_view = demangled_name_ptr.get();
477 if (demangled_name_view.starts_with(
"std::")) {
478 char* begin = demangled_name_ptr.get();
479 char* to = begin + 5;
480 for (
char *from = to, *end = begin + demangled_name_view.size();
483 if (from[0] ==
'_' && from[1] ==
'_') {
484 char* next = from + 1;
485 while (next < end && *next !=
':') next++;
486 if (next[0] ==
':' && next[1] ==
':') {
493 demangled_name_view = {begin, detail::to_unsigned(to - begin)};
498 out = detail::write_bytes<Char>(out, demangled_name_view);
499# elif FMT_MSC_VERSION
501 if (demangled_name_view.starts_with(
"class "))
502 demangled_name_view.remove_prefix(6);
503 else if (demangled_name_view.starts_with(
"struct "))
504 demangled_name_view.remove_prefix(7);
505 out = detail::write_bytes<Char>(out, demangled_name_view);
507 out = detail::write_bytes<Char>(out,
string_view(ti.name())
512 return detail::write_bytes<Char>(out,
string_view(ex.what()));
519template <
typename T,
typename Enable =
void>
523struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
527 static constexpr const bool value =
528 std::is_convertible<T, bool>::value &&
532#ifdef _LIBCPP_VERSION
538 static constexpr const bool value =
true;
549template <
typename BitRef,
typename Char>
551 enable_if_t<detail::is_bit_reference_like<BitRef>::value>>
553 template <
typename FormatContext>
554 FMT_CONSTEXPR
auto format(
const BitRef& v, FormatContext& ctx)
const
555 ->
decltype(ctx.out()) {
560template <
typename T,
typename Deleter>
561auto ptr(
const std::unique_ptr<T, Deleter>& p) ->
const void* {
564template <
typename T>
auto ptr(
const std::shared_ptr<T>& p) ->
const void* {
569template <
typename T,
typename Char>
571 enable_if_t<is_formattable<T, Char>::value>>
573 template <
typename FormatContext>
574 auto format(
const std::atomic<T>& v, FormatContext& ctx)
const
575 ->
decltype(ctx.out()) {
580#ifdef __cpp_lib_atomic_flag_test
582template <
typename Char>
584 template <
typename FormatContext>
585 auto format(
const std::atomic_flag& v, FormatContext& ctx)
const
586 ->
decltype(ctx.out()) {
593template <
typename F,
typename Char>
599 const std::complex<F>& c;
601 template <
typename OutputIt>
602 FMT_CONSTEXPR
auto operator()(OutputIt out) -> OutputIt {
607 f->nested(c.real()), f->nested(c.imag()));
611 f->nested(c.imag()));
616 template <
typename FormatContext>
617 auto format(
const std::complex<F>& c, FormatContext& ctx)
const
618 ->
decltype(ctx.out()) {
619 return this->write_padded(ctx, writer{
this, c});
constexpr auto end() const noexcept -> iterator
Definition base.h:753
constexpr auto begin() const noexcept -> iterator
Definition base.h:746
constexpr auto size() const noexcept -> size_t
Definition base.h:880
FMT_CONSTEXPR auto data() noexcept -> T *
Definition base.h:886
Definition datatypes.h:12