Skip to content

Commit f3c0d6f

Browse files
committed
Consolidate implementation details
1 parent 7bb6fcb commit f3c0d6f

File tree

1 file changed

+133
-156
lines changed

1 file changed

+133
-156
lines changed

include/fmt/std.h

Lines changed: 133 additions & 156 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
# include <type_traits>
2424
# include <typeinfo>
2525
# include <utility>
26-
# include <vector>
2726

2827
// Check FMT_CPLUSPLUS to suppress a bogus warning in MSVC.
2928
# if FMT_CPLUSPLUS >= 201703L
@@ -79,11 +78,11 @@
7978
# endif
8079
#endif
8180

82-
#if FMT_CPP_LIB_FILESYSTEM
8381
FMT_BEGIN_NAMESPACE
84-
8582
namespace detail {
8683

84+
#if FMT_CPP_LIB_FILESYSTEM
85+
8786
template <typename Char, typename PathChar>
8887
auto get_path_string(const std::filesystem::path& p,
8988
const std::basic_string<PathChar>& native) {
@@ -111,8 +110,136 @@ void write_escaped_path(basic_memory_buffer<Char>& quoted,
111110
}
112111
}
113112

113+
#endif // FMT_CPP_LIB_FILESYSTEM
114+
115+
#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
116+
template <typename Char, typename OutputIt, typename T>
117+
auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt {
118+
if constexpr (has_to_string_view<T>::value)
119+
return write_escaped_string<Char>(out, detail::to_string_view(v));
120+
if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v);
121+
return write<Char>(out, v);
122+
}
123+
#endif
124+
125+
#if FMT_CPP_LIB_VARIANT
126+
127+
template <typename T>
128+
using variant_index_sequence =
129+
std::make_index_sequence<std::variant_size<T>::value>;
130+
131+
template <typename> struct is_variant_like_ : std::false_type {};
132+
template <typename... Types>
133+
struct is_variant_like_<std::variant<Types...>> : std::true_type {};
134+
135+
// formattable element check.
136+
template <typename T, typename C> class is_variant_formattable_ {
137+
template <std::size_t... Is>
138+
static std::conjunction<
139+
is_formattable<std::variant_alternative_t<Is, T>, C>...>
140+
check(std::index_sequence<Is...>);
141+
142+
public:
143+
static constexpr const bool value =
144+
decltype(check(variant_index_sequence<T>{}))::value;
145+
};
146+
147+
#endif // FMT_CPP_LIB_VARIANT
148+
149+
#if FMT_USE_RTTI
150+
template <typename Char, typename OutputIt>
151+
auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt {
152+
# ifdef FMT_HAS_ABI_CXA_DEMANGLE
153+
int status = 0;
154+
std::size_t size = 0;
155+
std::unique_ptr<char, void (*)(void*)> demangled_name_ptr(
156+
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
157+
158+
string_view demangled_name_view;
159+
if (demangled_name_ptr) {
160+
demangled_name_view = demangled_name_ptr.get();
161+
162+
// Normalization of stdlib inline namespace names.
163+
// libc++ inline namespaces.
164+
// std::__1::* -> std::*
165+
// std::__1::__fs::* -> std::*
166+
// libstdc++ inline namespaces.
167+
// std::__cxx11::* -> std::*
168+
// std::filesystem::__cxx11::* -> std::filesystem::*
169+
if (demangled_name_view.starts_with("std::")) {
170+
char* begin = demangled_name_ptr.get();
171+
char* to = begin + 5; // std::
172+
for (char *from = to, *end = begin + demangled_name_view.size();
173+
from < end;) {
174+
// This is safe, because demangled_name is NUL-terminated.
175+
if (from[0] == '_' && from[1] == '_') {
176+
char* next = from + 1;
177+
while (next < end && *next != ':') next++;
178+
if (next[0] == ':' && next[1] == ':') {
179+
from = next + 2;
180+
continue;
181+
}
182+
}
183+
*to++ = *from++;
184+
}
185+
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
186+
}
187+
} else {
188+
demangled_name_view = string_view(ti.name());
189+
}
190+
return detail::write_bytes<Char>(out, demangled_name_view);
191+
# elif FMT_MSC_VERSION
192+
const string_view demangled_name(ti.name());
193+
for (std::size_t i = 0; i < demangled_name.size(); ++i) {
194+
auto sub = demangled_name;
195+
sub.remove_prefix(i);
196+
if (sub.starts_with("enum ")) {
197+
i += 4;
198+
continue;
199+
}
200+
if (sub.starts_with("class ") || sub.starts_with("union ")) {
201+
i += 5;
202+
continue;
203+
}
204+
if (sub.starts_with("struct ")) {
205+
i += 6;
206+
continue;
207+
}
208+
if (*sub.begin() != ' ') *out++ = *sub.begin();
209+
}
210+
return out;
211+
# else
212+
return detail::write_bytes<Char>(out, string_view(ti.name()));
213+
# endif
214+
}
215+
#endif // FMT_USE_RTTI
216+
217+
template <typename T, typename Enable = void>
218+
struct has_flip : std::false_type {};
219+
220+
template <typename T>
221+
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
222+
: std::true_type {};
223+
224+
template <typename T> struct is_bit_reference_like {
225+
static constexpr const bool value =
226+
std::is_convertible<T, bool>::value &&
227+
std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
228+
};
229+
230+
// Workaround for libc++ incompatibility with C++ standard.
231+
// According to the Standard, `bitset::operator[] const` returns bool.
232+
#ifdef _LIBCPP_VERSION
233+
template <typename C>
234+
struct is_bit_reference_like<std::__bit_const_reference<C>> {
235+
static constexpr const bool value = true;
236+
};
237+
#endif
238+
114239
} // namespace detail
115240

241+
#if FMT_CPP_LIB_FILESYSTEM
242+
116243
template <typename Char> struct formatter<std::filesystem::path, Char> {
117244
private:
118245
format_specs specs_;
@@ -177,10 +304,8 @@ class path : public std::filesystem::path {
177304
auto generic_system_string() const -> std::string { return generic_string(); }
178305
};
179306

180-
FMT_END_NAMESPACE
181307
#endif // FMT_CPP_LIB_FILESYSTEM
182308

183-
FMT_BEGIN_NAMESPACE
184309
template <std::size_t N, typename Char>
185310
struct formatter<std::bitset<N>, Char>
186311
: nested_formatter<basic_string_view<Char>, Char> {
@@ -209,10 +334,8 @@ struct formatter<std::bitset<N>, Char>
209334

210335
template <typename Char>
211336
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
212-
FMT_END_NAMESPACE
213337

214338
#ifdef __cpp_lib_optional
215-
FMT_BEGIN_NAMESPACE
216339
template <typename T, typename Char>
217340
struct formatter<std::optional<T>, Char,
218341
std::enable_if_t<is_formattable<T, Char>::value>> {
@@ -251,30 +374,9 @@ struct formatter<std::optional<T>, Char,
251374
return detail::write(out, ')');
252375
}
253376
};
254-
FMT_END_NAMESPACE
255377
#endif // __cpp_lib_optional
256378

257-
#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
258-
259-
FMT_BEGIN_NAMESPACE
260-
namespace detail {
261-
262-
template <typename Char, typename OutputIt, typename T>
263-
auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt {
264-
if constexpr (has_to_string_view<T>::value)
265-
return write_escaped_string<Char>(out, detail::to_string_view(v));
266-
if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v);
267-
return write<Char>(out, v);
268-
}
269-
270-
} // namespace detail
271-
272-
FMT_END_NAMESPACE
273-
#endif
274-
275379
#ifdef __cpp_lib_expected
276-
FMT_BEGIN_NAMESPACE
277-
278380
template <typename T, typename E, typename Char>
279381
struct formatter<std::expected<T, E>, Char,
280382
std::enable_if_t<(std::is_void<T>::value ||
@@ -301,11 +403,9 @@ struct formatter<std::expected<T, E>, Char,
301403
return out;
302404
}
303405
};
304-
FMT_END_NAMESPACE
305406
#endif // __cpp_lib_expected
306407

307408
#ifdef __cpp_lib_source_location
308-
FMT_BEGIN_NAMESPACE
309409
template <> struct formatter<std::source_location> {
310410
FMT_CONSTEXPR auto parse(parse_context<>& ctx) { return ctx.begin(); }
311411

@@ -323,34 +423,9 @@ template <> struct formatter<std::source_location> {
323423
return out;
324424
}
325425
};
326-
FMT_END_NAMESPACE
327426
#endif
328427

329428
#if FMT_CPP_LIB_VARIANT
330-
FMT_BEGIN_NAMESPACE
331-
namespace detail {
332-
333-
template <typename T>
334-
using variant_index_sequence =
335-
std::make_index_sequence<std::variant_size<T>::value>;
336-
337-
template <typename> struct is_variant_like_ : std::false_type {};
338-
template <typename... Types>
339-
struct is_variant_like_<std::variant<Types...>> : std::true_type {};
340-
341-
// formattable element check.
342-
template <typename T, typename C> class is_variant_formattable_ {
343-
template <std::size_t... Is>
344-
static std::conjunction<
345-
is_formattable<std::variant_alternative_t<Is, T>, C>...>
346-
check(std::index_sequence<Is...>);
347-
348-
public:
349-
static constexpr const bool value =
350-
decltype(check(variant_index_sequence<T>{}))::value;
351-
};
352-
353-
} // namespace detail
354429

355430
template <typename T> struct is_variant_like {
356431
static constexpr const bool value = detail::is_variant_like_<T>::value;
@@ -402,10 +477,9 @@ struct formatter<
402477
return out;
403478
}
404479
};
405-
FMT_END_NAMESPACE
480+
406481
#endif // FMT_CPP_LIB_VARIANT
407482

408-
FMT_BEGIN_NAMESPACE
409483
template <> struct formatter<std::error_code> {
410484
private:
411485
format_specs specs_;
@@ -459,76 +533,6 @@ template <> struct formatter<std::error_code> {
459533
};
460534

461535
#if FMT_USE_RTTI
462-
namespace detail {
463-
464-
template <typename Char, typename OutputIt>
465-
auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt {
466-
# ifdef FMT_HAS_ABI_CXA_DEMANGLE
467-
int status = 0;
468-
std::size_t size = 0;
469-
std::unique_ptr<char, void (*)(void*)> demangled_name_ptr(
470-
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
471-
472-
string_view demangled_name_view;
473-
if (demangled_name_ptr) {
474-
demangled_name_view = demangled_name_ptr.get();
475-
476-
// Normalization of stdlib inline namespace names.
477-
// libc++ inline namespaces.
478-
// std::__1::* -> std::*
479-
// std::__1::__fs::* -> std::*
480-
// libstdc++ inline namespaces.
481-
// std::__cxx11::* -> std::*
482-
// std::filesystem::__cxx11::* -> std::filesystem::*
483-
if (demangled_name_view.starts_with("std::")) {
484-
char* begin = demangled_name_ptr.get();
485-
char* to = begin + 5; // std::
486-
for (char *from = to, *end = begin + demangled_name_view.size();
487-
from < end;) {
488-
// This is safe, because demangled_name is NUL-terminated.
489-
if (from[0] == '_' && from[1] == '_') {
490-
char* next = from + 1;
491-
while (next < end && *next != ':') next++;
492-
if (next[0] == ':' && next[1] == ':') {
493-
from = next + 2;
494-
continue;
495-
}
496-
}
497-
*to++ = *from++;
498-
}
499-
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
500-
}
501-
} else {
502-
demangled_name_view = string_view(ti.name());
503-
}
504-
return detail::write_bytes<Char>(out, demangled_name_view);
505-
# elif FMT_MSC_VERSION
506-
const string_view demangled_name(ti.name());
507-
for (std::size_t i = 0; i < demangled_name.size(); ++i) {
508-
auto sub = demangled_name;
509-
sub.remove_prefix(i);
510-
if (sub.starts_with("enum ")) {
511-
i += 4;
512-
continue;
513-
}
514-
if (sub.starts_with("class ") || sub.starts_with("union ")) {
515-
i += 5;
516-
continue;
517-
}
518-
if (sub.starts_with("struct ")) {
519-
i += 6;
520-
continue;
521-
}
522-
if (*sub.begin() != ' ') *out++ = *sub.begin();
523-
}
524-
return out;
525-
# else
526-
return detail::write_bytes<Char>(out, string_view(ti.name()));
527-
# endif
528-
}
529-
530-
} // namespace detail
531-
532536
template <typename Char>
533537
struct formatter<std::type_info, Char // DEPRECATED! Mixing code unit types.
534538
> {
@@ -543,7 +547,7 @@ struct formatter<std::type_info, Char // DEPRECATED! Mixing code unit types.
543547
return detail::write_demangled_name<Char>(ctx.out(), ti);
544548
}
545549
};
546-
#endif
550+
#endif // FMT_USE_RTTI
547551

548552
template <typename T, typename Char>
549553
struct formatter<
@@ -579,34 +583,6 @@ struct formatter<
579583
}
580584
};
581585

582-
namespace detail {
583-
584-
template <typename T, typename Enable = void>
585-
struct has_flip : std::false_type {};
586-
587-
template <typename T>
588-
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
589-
: std::true_type {};
590-
591-
template <typename T> struct is_bit_reference_like {
592-
static constexpr const bool value =
593-
std::is_convertible<T, bool>::value &&
594-
std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
595-
};
596-
597-
#ifdef _LIBCPP_VERSION
598-
599-
// Workaround for libc++ incompatibility with C++ standard.
600-
// According to the Standard, `bitset::operator[] const` returns bool.
601-
template <typename C>
602-
struct is_bit_reference_like<std::__bit_const_reference<C>> {
603-
static constexpr const bool value = true;
604-
};
605-
606-
#endif
607-
608-
} // namespace detail
609-
610586
// We can't use std::vector<bool, Allocator>::reference and
611587
// std::bitset<N>::reference because the compiler can't deduce Allocator and N
612588
// in partial specialization.
@@ -725,4 +701,5 @@ struct formatter<std::reference_wrapper<T>, Char,
725701
};
726702

727703
FMT_END_NAMESPACE
704+
728705
#endif // FMT_STD_H_

0 commit comments

Comments
 (0)