RavEngine
Loading...
Searching...
No Matches
std.h
1// Formatting library for C++ - formatters for standard library types
2//
3// Copyright (c) 2012 - present, Victor Zverovich
4// All rights reserved.
5//
6// For the license information refer to format.h.
7
8#ifndef FMT_STD_H_
9#define FMT_STD_H_
10
11#ifndef FMT_IMPORT_STD
12# include <atomic>
13# include <bitset>
14# include <complex>
15# include <cstdlib>
16# include <exception>
17# include <memory>
18# include <thread>
19# include <type_traits>
20# include <typeinfo>
21# include <utility>
22# include <vector>
23#endif
24
25#include "format.h"
26#include "ostream.h"
27
28#if FMT_HAS_INCLUDE(<version>)
29# include <version>
30#endif
31
32#ifndef FMT_IMPORT_STD
33// Checking FMT_CPLUSPLUS for warning suppression in MSVC.
34# if FMT_CPLUSPLUS >= 201703L
35# if FMT_HAS_INCLUDE(<filesystem>)
36# include <filesystem>
37# endif
38# if FMT_HAS_INCLUDE(<variant>)
39# include <variant>
40# endif
41# if FMT_HAS_INCLUDE(<optional>)
42# include <optional>
43# endif
44# endif
45
46# if FMT_HAS_INCLUDE(<expected>) && FMT_CPLUSPLUS > 202002L
47# include <expected>
48# endif
49
50# if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE(<source_location>)
51# include <source_location>
52# endif
53#endif
54
55// GCC 4 does not support FMT_HAS_INCLUDE.
56#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
57# include <cxxabi.h>
58// Android NDK with gabi++ library on some architectures does not implement
59// abi::__cxa_demangle().
60# ifndef __GABIXX_CXXABI_H__
61# define FMT_HAS_ABI_CXA_DEMANGLE
62# endif
63#endif
64
65// Check if typeid is available.
66#ifndef FMT_USE_TYPEID
67// __RTTI is for EDG compilers. _CPPRTTI is for MSVC.
68# if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || defined(_CPPRTTI) || \
69 defined(__INTEL_RTTI__) || defined(__RTTI)
70# define FMT_USE_TYPEID 1
71# else
72# define FMT_USE_TYPEID 0
73# endif
74#endif
75
76// For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined.
77#ifndef FMT_CPP_LIB_FILESYSTEM
78# ifdef __cpp_lib_filesystem
79# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem
80# else
81# define FMT_CPP_LIB_FILESYSTEM 0
82# endif
83#endif
84
85#ifndef FMT_CPP_LIB_VARIANT
86# ifdef __cpp_lib_variant
87# define FMT_CPP_LIB_VARIANT __cpp_lib_variant
88# else
89# define FMT_CPP_LIB_VARIANT 0
90# endif
91#endif
92
93#if FMT_CPP_LIB_FILESYSTEM
94FMT_BEGIN_NAMESPACE
95
96namespace detail {
97
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);
103 else
104 return p.string<Char>();
105}
106
107template <typename Char, typename PathChar>
108void write_escaped_path(basic_memory_buffer<Char>& quoted,
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>) {
113 auto buf = basic_memory_buffer<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);
120 } else {
121 write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
122 }
123}
124
125} // namespace detail
126
127FMT_EXPORT
128template <typename Char> struct formatter<std::filesystem::path, Char> {
129 private:
130 format_specs specs_;
131 detail::arg_ref<Char> width_ref_;
132 bool debug_ = false;
133 char path_type_ = 0;
134
135 public:
136 FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
137
138 template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
139 auto it = ctx.begin(), end = ctx.end();
140 if (it == end) return it;
141
142 it = detail::parse_align(it, end, specs_);
143 if (it == end) return it;
144
145 it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
146 if (it != end && *it == '?') {
147 debug_ = true;
148 ++it;
149 }
150 if (it != end && (*it == 'g')) path_type_ = detail::to_ascii(*it++);
151 return it;
152 }
153
154 template <typename FormatContext>
155 auto format(const std::filesystem::path& p, FormatContext& ctx) const {
156 auto specs = specs_;
157 auto path_string =
158 !path_type_ ? p.native()
159 : p.generic_string<std::filesystem::path::value_type>();
160
161 detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
162 ctx);
163 if (!debug_) {
164 auto s = detail::get_path_string<Char>(p, path_string);
165 return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
166 }
167 auto quoted = basic_memory_buffer<Char>();
168 detail::write_escaped_path(quoted, p, path_string);
169 return detail::write(ctx.out(),
170 basic_string_view<Char>(quoted.data(), quoted.size()),
171 specs);
172 }
173};
174FMT_END_NAMESPACE
175#endif // FMT_CPP_LIB_FILESYSTEM
176
177FMT_BEGIN_NAMESPACE
178FMT_EXPORT
179template <std::size_t N, typename Char>
180struct formatter<std::bitset<N>, Char> : nested_formatter<string_view> {
181 private:
182 // Functor because C++11 doesn't support generic lambdas.
183 struct writer {
184 const std::bitset<N>& bs;
185
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'));
190 }
191
192 return out;
193 }
194 };
195
196 public:
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});
201 }
202};
203
204FMT_EXPORT
205template <typename Char>
206struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
207FMT_END_NAMESPACE
208
209#ifdef __cpp_lib_optional
210FMT_BEGIN_NAMESPACE
211FMT_EXPORT
212template <typename T, typename Char>
213struct formatter<std::optional<T>, Char,
214 std::enable_if_t<is_formattable<T, Char>::value>> {
215 private:
216 formatter<T, Char> underlying_;
217 static constexpr basic_string_view<Char> optional =
218 detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
219 '('>{};
220 static constexpr basic_string_view<Char> none =
221 detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
222
223 template <class U>
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);
227 }
228
229 template <class U>
230 FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
231
232 public:
233 template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
234 maybe_set_debug_format(underlying_, true);
235 return underlying_.parse(ctx);
236 }
237
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);
242
243 auto out = ctx.out();
244 out = detail::write<Char>(out, optional);
245 ctx.advance_to(out);
246 out = underlying_.format(*opt, ctx);
247 return detail::write(out, ')');
248 }
249};
250FMT_END_NAMESPACE
251#endif // __cpp_lib_optional
252
253#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
254
255FMT_BEGIN_NAMESPACE
256namespace detail {
257
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);
264}
265
266} // namespace detail
267
268FMT_END_NAMESPACE
269#endif
270
271#ifdef __cpp_lib_expected
272FMT_BEGIN_NAMESPACE
273
274FMT_EXPORT
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()) {
281 return ctx.begin();
282 }
283
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();
288
289 if (value.has_value()) {
290 out = detail::write<Char>(out, "expected(");
291 out = detail::write_escaped_alternative<Char>(out, value.value());
292 } else {
293 out = detail::write<Char>(out, "unexpected(");
294 out = detail::write_escaped_alternative<Char>(out, value.error());
295 }
296 *out++ = ')';
297 return out;
298 }
299};
300FMT_END_NAMESPACE
301#endif // __cpp_lib_expected
302
303#ifdef __cpp_lib_source_location
304FMT_BEGIN_NAMESPACE
305FMT_EXPORT
306template <> struct formatter<std::source_location> {
307 template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
308 return ctx.begin();
309 }
310
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());
322 return out;
323 }
324};
325FMT_END_NAMESPACE
326#endif
327
328#if FMT_CPP_LIB_VARIANT
329FMT_BEGIN_NAMESPACE
330namespace detail {
331
332template <typename T>
333using variant_index_sequence =
334 std::make_index_sequence<std::variant_size<T>::value>;
335
336template <typename> struct is_variant_like_ : std::false_type {};
337template <typename... Types>
338struct is_variant_like_<std::variant<Types...>> : std::true_type {};
339
340// formattable element check.
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...>);
346
347 public:
348 static constexpr const bool value =
349 decltype(check(variant_index_sequence<T>{}))::value;
350};
351
352} // namespace detail
353
354template <typename T> struct is_variant_like {
355 static constexpr const bool value = detail::is_variant_like_<T>::value;
356};
357
358template <typename T, typename C> struct is_variant_formattable {
359 static constexpr const bool value =
360 detail::is_variant_formattable_<T, C>::value;
361};
362
363FMT_EXPORT
364template <typename Char> struct formatter<std::monostate, Char> {
365 template <typename ParseContext>
366 FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
367 return ctx.begin();
368 }
369
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");
374 }
375};
376
377FMT_EXPORT
378template <typename Variant, typename Char>
379struct formatter<
380 Variant, 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()) {
385 return ctx.begin();
386 }
387
388 template <typename FormatContext>
389 auto format(const Variant& value, FormatContext& ctx) const
390 -> decltype(ctx.out()) {
391 auto out = ctx.out();
392
393 out = detail::write<Char>(out, "variant(");
394 FMT_TRY {
395 std::visit(
396 [&](const auto& v) {
397 out = detail::write_escaped_alternative<Char>(out, v);
398 },
399 value);
400 }
401 FMT_CATCH(const std::bad_variant_access&) {
402 detail::write<Char>(out, "valueless by exception");
403 }
404 *out++ = ')';
405 return out;
406 }
407};
408FMT_END_NAMESPACE
409#endif // FMT_CPP_LIB_VARIANT
410
411FMT_BEGIN_NAMESPACE
412FMT_EXPORT
413template <typename Char> struct formatter<std::error_code, Char> {
414 template <typename ParseContext>
415 FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
416 return ctx.begin();
417 }
418
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());
426 return out;
427 }
428};
429
430FMT_EXPORT
431template <typename T, typename Char>
433 T, Char, // DEPRECATED! Mixing code unit types.
434 typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
435 private:
436 bool with_typename_ = false;
437
438 public:
439 FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
440 -> decltype(ctx.begin()) {
441 auto it = ctx.begin();
442 auto end = ctx.end();
443 if (it == end || *it == '}') return it;
444 if (*it == 't') {
445 ++it;
446 with_typename_ = FMT_USE_TYPEID != 0;
447 }
448 return it;
449 }
450
451 template <typename Context>
452 auto format(const std::exception& ex, Context& ctx) const
453 -> decltype(ctx.out()) {
454 auto out = ctx.out();
455 if (!with_typename_)
456 return detail::write_bytes<Char>(out, string_view(ex.what()));
457
458#if FMT_USE_TYPEID
459 const std::type_info& ti = typeid(ex);
460# ifdef FMT_HAS_ABI_CXA_DEMANGLE
461 int status = 0;
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);
465
466 string_view demangled_name_view;
467 if (demangled_name_ptr) {
468 demangled_name_view = demangled_name_ptr.get();
469
470 // Normalization of stdlib inline namespace names.
471 // libc++ inline namespaces.
472 // std::__1::* -> std::*
473 // std::__1::__fs::* -> std::*
474 // libstdc++ inline namespaces.
475 // std::__cxx11::* -> std::*
476 // std::filesystem::__cxx11::* -> std::filesystem::*
477 if (demangled_name_view.starts_with("std::")) {
478 char* begin = demangled_name_ptr.get();
479 char* to = begin + 5; // std::
480 for (char *from = to, *end = begin + demangled_name_view.size();
481 from < end;) {
482 // This is safe, because demangled_name is NUL-terminated.
483 if (from[0] == '_' && from[1] == '_') {
484 char* next = from + 1;
485 while (next < end && *next != ':') next++;
486 if (next[0] == ':' && next[1] == ':') {
487 from = next + 2;
488 continue;
489 }
490 }
491 *to++ = *from++;
492 }
493 demangled_name_view = {begin, detail::to_unsigned(to - begin)};
494 }
495 } else {
496 demangled_name_view = string_view(ti.name());
497 }
498 out = detail::write_bytes<Char>(out, demangled_name_view);
499# elif FMT_MSC_VERSION
500 string_view demangled_name_view(ti.name());
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);
506# else
507 out = detail::write_bytes<Char>(out, string_view(ti.name())
508 });
509# endif
510 *out++ = ':';
511 *out++ = ' ';
512 return detail::write_bytes<Char>(out, string_view(ex.what()));
513#endif
514 }
515};
516
517namespace detail {
518
519template <typename T, typename Enable = void>
520struct has_flip : std::false_type {};
521
522template <typename T>
523struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
524 : std::true_type {};
525
526template <typename T> struct is_bit_reference_like {
527 static constexpr const bool value =
528 std::is_convertible<T, bool>::value &&
529 std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
530};
531
532#ifdef _LIBCPP_VERSION
533
534// Workaround for libc++ incompatibility with C++ standard.
535// According to the Standard, `bitset::operator[] const` returns bool.
536template <typename C>
537struct is_bit_reference_like<std::__bit_const_reference<C>> {
538 static constexpr const bool value = true;
539};
540
541#endif
542
543} // namespace detail
544
545// We can't use std::vector<bool, Allocator>::reference and
546// std::bitset<N>::reference because the compiler can't deduce Allocator and N
547// in partial specialization.
548FMT_EXPORT
549template <typename BitRef, typename Char>
550struct formatter<BitRef, Char,
551 enable_if_t<detail::is_bit_reference_like<BitRef>::value>>
552 : formatter<bool, Char> {
553 template <typename FormatContext>
554 FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const
555 -> decltype(ctx.out()) {
556 return formatter<bool, Char>::format(v, ctx);
557 }
558};
559
560template <typename T, typename Deleter>
561auto ptr(const std::unique_ptr<T, Deleter>& p) -> const void* {
562 return p.get();
563}
564template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* {
565 return p.get();
566}
567
568FMT_EXPORT
569template <typename T, typename Char>
570struct formatter<std::atomic<T>, Char,
571 enable_if_t<is_formattable<T, Char>::value>>
572 : formatter<T, Char> {
573 template <typename FormatContext>
574 auto format(const std::atomic<T>& v, FormatContext& ctx) const
575 -> decltype(ctx.out()) {
576 return formatter<T, Char>::format(v.load(), ctx);
577 }
578};
579
580#ifdef __cpp_lib_atomic_flag_test
581FMT_EXPORT
582template <typename Char>
583struct formatter<std::atomic_flag, Char> : formatter<bool, Char> {
584 template <typename FormatContext>
585 auto format(const std::atomic_flag& v, FormatContext& ctx) const
586 -> decltype(ctx.out()) {
587 return formatter<bool, Char>::format(v.test(), ctx);
588 }
589};
590#endif // __cpp_lib_atomic_flag_test
591
592FMT_EXPORT
593template <typename F, typename Char>
594struct formatter<std::complex<F>, Char> : nested_formatter<F, Char> {
595 private:
596 // Functor because C++11 doesn't support generic lambdas.
597 struct writer {
598 const formatter<std::complex<F>, Char>* f;
599 const std::complex<F>& c;
600
601 template <typename OutputIt>
602 FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt {
603 if (c.real() != 0) {
604 auto format_full = detail::string_literal<Char, '(', '{', '}', '+', '{',
605 '}', 'i', ')'>{};
606 return fmt::format_to(out, basic_string_view<Char>(format_full),
607 f->nested(c.real()), f->nested(c.imag()));
608 }
609 auto format_imag = detail::string_literal<Char, '{', '}', 'i'>{};
610 return fmt::format_to(out, basic_string_view<Char>(format_imag),
611 f->nested(c.imag()));
612 }
613 };
614
615 public:
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});
620 }
621};
622
623FMT_END_NAMESPACE
624#endif // FMT_STD_H_
Definition base.h:727
constexpr auto end() const noexcept -> iterator
Definition base.h:753
constexpr auto begin() const noexcept -> iterator
Definition base.h:746
Definition format.h:838
Definition base.h:484
constexpr auto size() const noexcept -> size_t
Definition base.h:880
FMT_CONSTEXPR auto data() noexcept -> T *
Definition base.h:886
Definition base.h:1310
Definition ostream.h:114
Definition datatypes.h:12
Definition base.h:2179
Definition std.h:520
Definition std.h:526
Definition base.h:616
Definition base.h:2152
Definition base.h:1130
Definition base.h:323
Definition format.h:4162