cpp-common/bt2c/fmt.hpp: use `wise_enum::string_type` in `EnableIfIsWiseEnum` definition
[babeltrace.git] / src / cpp-common / vendor / fmt / 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 #include <atomic>
12 #include <bitset>
13 #include <cstdlib>
14 #include <exception>
15 #include <memory>
16 #include <thread>
17 #include <type_traits>
18 #include <typeinfo>
19 #include <utility>
20 #include <vector>
21
22 #include "format.h"
23 #include "ostream.h"
24
25 #if FMT_HAS_INCLUDE(<version>)
26 # include <version>
27 #endif
28 // Checking FMT_CPLUSPLUS for warning suppression in MSVC.
29 #if FMT_CPLUSPLUS >= 201703L
30 # if FMT_HAS_INCLUDE(<filesystem>)
31 # include <filesystem>
32 # endif
33 # if FMT_HAS_INCLUDE(<variant>)
34 # include <variant>
35 # endif
36 # if FMT_HAS_INCLUDE(<optional>)
37 # include <optional>
38 # endif
39 #endif
40
41 // GCC 4 does not support FMT_HAS_INCLUDE.
42 #if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
43 # include <cxxabi.h>
44 // Android NDK with gabi++ library on some architectures does not implement
45 // abi::__cxa_demangle().
46 # ifndef __GABIXX_CXXABI_H__
47 # define FMT_HAS_ABI_CXA_DEMANGLE
48 # endif
49 #endif
50
51 // Check if typeid is available.
52 #ifndef FMT_USE_TYPEID
53 // __RTTI is for EDG compilers. In MSVC typeid is available without RTTI.
54 # if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || FMT_MSC_VERSION || \
55 defined(__INTEL_RTTI__) || defined(__RTTI)
56 # define FMT_USE_TYPEID 1
57 # else
58 # define FMT_USE_TYPEID 0
59 # endif
60 #endif
61
62 #ifdef __cpp_lib_filesystem
63 FMT_BEGIN_NAMESPACE
64
65 namespace detail {
66
67 template <typename Char> auto get_path_string(const std::filesystem::path& p) {
68 return p.string<Char>();
69 }
70
71 template <typename Char>
72 void write_escaped_path(basic_memory_buffer<Char>& quoted,
73 const std::filesystem::path& p) {
74 write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
75 }
76
77 # ifdef _WIN32
78 template <>
79 inline auto get_path_string<char>(const std::filesystem::path& p) {
80 return to_utf8<wchar_t>(p.native(), to_utf8_error_policy::replace);
81 }
82
83 template <>
84 inline void write_escaped_path<char>(memory_buffer& quoted,
85 const std::filesystem::path& p) {
86 auto buf = basic_memory_buffer<wchar_t>();
87 write_escaped_string<wchar_t>(std::back_inserter(buf), p.native());
88 bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()});
89 FMT_ASSERT(valid, "invalid utf16");
90 }
91 # endif // _WIN32
92
93 template <>
94 inline void write_escaped_path<std::filesystem::path::value_type>(
95 basic_memory_buffer<std::filesystem::path::value_type>& quoted,
96 const std::filesystem::path& p) {
97 write_escaped_string<std::filesystem::path::value_type>(
98 std::back_inserter(quoted), p.native());
99 }
100
101 } // namespace detail
102
103 FMT_EXPORT
104 template <typename Char> struct formatter<std::filesystem::path, Char> {
105 private:
106 format_specs<Char> specs_;
107 detail::arg_ref<Char> width_ref_;
108 bool debug_ = false;
109
110 public:
111 FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
112
113 template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
114 auto it = ctx.begin(), end = ctx.end();
115 if (it == end) return it;
116
117 it = detail::parse_align(it, end, specs_);
118 if (it == end) return it;
119
120 it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
121 if (it != end && *it == '?') {
122 debug_ = true;
123 ++it;
124 }
125 return it;
126 }
127
128 template <typename FormatContext>
129 auto format(const std::filesystem::path& p, FormatContext& ctx) const {
130 auto specs = specs_;
131 detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
132 ctx);
133 if (!debug_) {
134 auto s = detail::get_path_string<Char>(p);
135 return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
136 }
137 auto quoted = basic_memory_buffer<Char>();
138 detail::write_escaped_path(quoted, p);
139 return detail::write(ctx.out(),
140 basic_string_view<Char>(quoted.data(), quoted.size()),
141 specs);
142 }
143 };
144 FMT_END_NAMESPACE
145 #endif
146
147 FMT_BEGIN_NAMESPACE
148 FMT_EXPORT
149 template <typename Char>
150 struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
151 FMT_END_NAMESPACE
152
153 #ifdef __cpp_lib_optional
154 FMT_BEGIN_NAMESPACE
155 FMT_EXPORT
156 template <typename T, typename Char>
157 struct formatter<std::optional<T>, Char,
158 std::enable_if_t<is_formattable<T, Char>::value>> {
159 private:
160 formatter<T, Char> underlying_;
161 static constexpr basic_string_view<Char> optional =
162 detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
163 '('>{};
164 static constexpr basic_string_view<Char> none =
165 detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
166
167 template <class U>
168 FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
169 -> decltype(u.set_debug_format(set)) {
170 u.set_debug_format(set);
171 }
172
173 template <class U>
174 FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
175
176 public:
177 template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
178 maybe_set_debug_format(underlying_, true);
179 return underlying_.parse(ctx);
180 }
181
182 template <typename FormatContext>
183 auto format(std::optional<T> const& opt, FormatContext& ctx) const
184 -> decltype(ctx.out()) {
185 if (!opt) return detail::write<Char>(ctx.out(), none);
186
187 auto out = ctx.out();
188 out = detail::write<Char>(out, optional);
189 ctx.advance_to(out);
190 out = underlying_.format(*opt, ctx);
191 return detail::write(out, ')');
192 }
193 };
194 FMT_END_NAMESPACE
195 #endif // __cpp_lib_optional
196
197 #ifdef __cpp_lib_variant
198 FMT_BEGIN_NAMESPACE
199 namespace detail {
200
201 template <typename T>
202 using variant_index_sequence =
203 std::make_index_sequence<std::variant_size<T>::value>;
204
205 template <typename> struct is_variant_like_ : std::false_type {};
206 template <typename... Types>
207 struct is_variant_like_<std::variant<Types...>> : std::true_type {};
208
209 // formattable element check.
210 template <typename T, typename C> class is_variant_formattable_ {
211 template <std::size_t... Is>
212 static std::conjunction<
213 is_formattable<std::variant_alternative_t<Is, T>, C>...>
214 check(std::index_sequence<Is...>);
215
216 public:
217 static constexpr const bool value =
218 decltype(check(variant_index_sequence<T>{}))::value;
219 };
220
221 template <typename Char, typename OutputIt, typename T>
222 auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt {
223 if constexpr (is_string<T>::value)
224 return write_escaped_string<Char>(out, detail::to_string_view(v));
225 else if constexpr (std::is_same_v<T, Char>)
226 return write_escaped_char(out, v);
227 else
228 return write<Char>(out, v);
229 }
230
231 } // namespace detail
232
233 template <typename T> struct is_variant_like {
234 static constexpr const bool value = detail::is_variant_like_<T>::value;
235 };
236
237 template <typename T, typename C> struct is_variant_formattable {
238 static constexpr const bool value =
239 detail::is_variant_formattable_<T, C>::value;
240 };
241
242 FMT_EXPORT
243 template <typename Char> struct formatter<std::monostate, Char> {
244 template <typename ParseContext>
245 FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
246 return ctx.begin();
247 }
248
249 template <typename FormatContext>
250 auto format(const std::monostate&, FormatContext& ctx) const
251 -> decltype(ctx.out()) {
252 return detail::write<Char>(ctx.out(), "monostate");
253 }
254 };
255
256 FMT_EXPORT
257 template <typename Variant, typename Char>
258 struct formatter<
259 Variant, Char,
260 std::enable_if_t<std::conjunction_v<
261 is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
262 template <typename ParseContext>
263 FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
264 return ctx.begin();
265 }
266
267 template <typename FormatContext>
268 auto format(const Variant& value, FormatContext& ctx) const
269 -> decltype(ctx.out()) {
270 auto out = ctx.out();
271
272 out = detail::write<Char>(out, "variant(");
273 FMT_TRY {
274 std::visit(
275 [&](const auto& v) {
276 out = detail::write_variant_alternative<Char>(out, v);
277 },
278 value);
279 }
280 FMT_CATCH(const std::bad_variant_access&) {
281 detail::write<Char>(out, "valueless by exception");
282 }
283 *out++ = ')';
284 return out;
285 }
286 };
287 FMT_END_NAMESPACE
288 #endif // __cpp_lib_variant
289
290 FMT_BEGIN_NAMESPACE
291 FMT_EXPORT
292 template <typename Char> struct formatter<std::error_code, Char> {
293 template <typename ParseContext>
294 FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
295 return ctx.begin();
296 }
297
298 template <typename FormatContext>
299 FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
300 -> decltype(ctx.out()) {
301 auto out = ctx.out();
302 out = detail::write_bytes(out, ec.category().name(), format_specs<Char>());
303 out = detail::write<Char>(out, Char(':'));
304 out = detail::write<Char>(out, ec.value());
305 return out;
306 }
307 };
308
309 FMT_EXPORT
310 template <typename T, typename Char>
311 struct formatter<
312 T, Char,
313 typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
314 private:
315 bool with_typename_ = false;
316
317 public:
318 FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
319 -> decltype(ctx.begin()) {
320 auto it = ctx.begin();
321 auto end = ctx.end();
322 if (it == end || *it == '}') return it;
323 if (*it == 't') {
324 ++it;
325 with_typename_ = FMT_USE_TYPEID != 0;
326 }
327 return it;
328 }
329
330 template <typename OutputIt>
331 auto format(const std::exception& ex,
332 basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
333 format_specs<Char> spec;
334 auto out = ctx.out();
335 if (!with_typename_)
336 return detail::write_bytes(out, string_view(ex.what()), spec);
337
338 #if FMT_USE_TYPEID
339 const std::type_info& ti = typeid(ex);
340 # ifdef FMT_HAS_ABI_CXA_DEMANGLE
341 int status = 0;
342 std::size_t size = 0;
343 std::unique_ptr<char, decltype(&std::free)> demangled_name_ptr(
344 abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
345
346 string_view demangled_name_view;
347 if (demangled_name_ptr) {
348 demangled_name_view = demangled_name_ptr.get();
349
350 // Normalization of stdlib inline namespace names.
351 // libc++ inline namespaces.
352 // std::__1::* -> std::*
353 // std::__1::__fs::* -> std::*
354 // libstdc++ inline namespaces.
355 // std::__cxx11::* -> std::*
356 // std::filesystem::__cxx11::* -> std::filesystem::*
357 if (demangled_name_view.starts_with("std::")) {
358 char* begin = demangled_name_ptr.get();
359 char* to = begin + 5; // std::
360 for (char *from = to, *end = begin + demangled_name_view.size();
361 from < end;) {
362 // This is safe, because demangled_name is NUL-terminated.
363 if (from[0] == '_' && from[1] == '_') {
364 char* next = from + 1;
365 while (next < end && *next != ':') next++;
366 if (next[0] == ':' && next[1] == ':') {
367 from = next + 2;
368 continue;
369 }
370 }
371 *to++ = *from++;
372 }
373 demangled_name_view = {begin, detail::to_unsigned(to - begin)};
374 }
375 } else {
376 demangled_name_view = string_view(ti.name());
377 }
378 out = detail::write_bytes(out, demangled_name_view, spec);
379 # elif FMT_MSC_VERSION
380 string_view demangled_name_view(ti.name());
381 if (demangled_name_view.starts_with("class "))
382 demangled_name_view.remove_prefix(6);
383 else if (demangled_name_view.starts_with("struct "))
384 demangled_name_view.remove_prefix(7);
385 out = detail::write_bytes(out, demangled_name_view, spec);
386 # else
387 out = detail::write_bytes(out, string_view(ti.name()), spec);
388 # endif
389 *out++ = ':';
390 *out++ = ' ';
391 return detail::write_bytes(out, string_view(ex.what()), spec);
392 #endif
393 }
394 };
395
396 namespace detail {
397
398 template <typename T, typename Enable = void>
399 struct has_flip : std::false_type {};
400
401 template <typename T>
402 struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
403 : std::true_type {};
404
405 template <typename T> struct is_bit_reference_like {
406 static constexpr const bool value =
407 std::is_convertible<T, bool>::value &&
408 std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
409 };
410
411 #ifdef _LIBCPP_VERSION
412
413 // Workaround for libc++ incompatibility with C++ standard.
414 // According to the Standard, `bitset::operator[] const` returns bool.
415 template <typename C>
416 struct is_bit_reference_like<std::__bit_const_reference<C>> {
417 static constexpr const bool value = true;
418 };
419
420 #endif
421
422 } // namespace detail
423
424 // We can't use std::vector<bool, Allocator>::reference and
425 // std::bitset<N>::reference because the compiler can't deduce Allocator and N
426 // in partial specialization.
427 FMT_EXPORT
428 template <typename BitRef, typename Char>
429 struct formatter<BitRef, Char,
430 enable_if_t<detail::is_bit_reference_like<BitRef>::value>>
431 : formatter<bool, Char> {
432 template <typename FormatContext>
433 FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const
434 -> decltype(ctx.out()) {
435 return formatter<bool, Char>::format(v, ctx);
436 }
437 };
438
439 FMT_EXPORT
440 template <typename T, typename Char>
441 struct formatter<std::atomic<T>, Char,
442 enable_if_t<is_formattable<T, Char>::value>>
443 : formatter<T, Char> {
444 template <typename FormatContext>
445 auto format(const std::atomic<T>& v, FormatContext& ctx) const
446 -> decltype(ctx.out()) {
447 return formatter<T, Char>::format(v.load(), ctx);
448 }
449 };
450
451 #ifdef __cpp_lib_atomic_flag_test
452 FMT_EXPORT
453 template <typename Char>
454 struct formatter<std::atomic_flag, Char>
455 : formatter<bool, Char> {
456 template <typename FormatContext>
457 auto format(const std::atomic_flag& v, FormatContext& ctx) const
458 -> decltype(ctx.out()) {
459 return formatter<bool, Char>::format(v.test(), ctx);
460 }
461 };
462 #endif // __cpp_lib_atomic_flag_test
463
464 FMT_END_NAMESPACE
465 #endif // FMT_STD_H_
This page took 0.039772 seconds and 4 git commands to generate.