diff options
Diffstat (limited to '')
-rw-r--r-- | src/fmtlib/fmt/std.h | 210 |
1 files changed, 163 insertions, 47 deletions
diff --git a/src/fmtlib/fmt/std.h b/src/fmtlib/fmt/std.h index 4c2a28c..b4e055c 100644 --- a/src/fmtlib/fmt/std.h +++ b/src/fmtlib/fmt/std.h @@ -8,6 +8,8 @@ #ifndef FMT_STD_H_ #define FMT_STD_H_ +#include <atomic> +#include <bitset> #include <cstdlib> #include <exception> #include <memory> @@ -15,7 +17,9 @@ #include <type_traits> #include <typeinfo> #include <utility> +#include <vector> +#include "format.h" #include "ostream.h" #if FMT_HAS_INCLUDE(<version>) @@ -44,27 +48,48 @@ # endif #endif +// Check if typeid is available. +#ifndef FMT_USE_TYPEID +// __RTTI is for EDG compilers. In MSVC typeid is available without RTTI. +# if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || FMT_MSC_VERSION || \ + defined(__INTEL_RTTI__) || defined(__RTTI) +# define FMT_USE_TYPEID 1 +# else +# define FMT_USE_TYPEID 0 +# endif +#endif + #ifdef __cpp_lib_filesystem FMT_BEGIN_NAMESPACE namespace detail { +template <typename Char> auto get_path_string(const std::filesystem::path& p) { + return p.string<Char>(); +} + template <typename Char> void write_escaped_path(basic_memory_buffer<Char>& quoted, const std::filesystem::path& p) { write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>()); } + # ifdef _WIN32 template <> +inline auto get_path_string<char>(const std::filesystem::path& p) { + return to_utf8<wchar_t>(p.native(), to_utf8_error_policy::replace); +} + +template <> inline void write_escaped_path<char>(memory_buffer& quoted, const std::filesystem::path& p) { auto buf = basic_memory_buffer<wchar_t>(); write_escaped_string<wchar_t>(std::back_inserter(buf), p.native()); - // Convert UTF-16 to UTF-8. - if (!unicode_to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()})) - FMT_THROW(std::runtime_error("invalid utf16")); + bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()}); + FMT_ASSERT(valid, "invalid utf16"); } -# endif +# endif // _WIN32 + template <> inline void write_escaped_path<std::filesystem::path::value_type>( basic_memory_buffer<std::filesystem::path::value_type>& quoted, @@ -75,36 +100,59 @@ inline void write_escaped_path<std::filesystem::path::value_type>( } // namespace detail -FMT_MODULE_EXPORT -template <typename Char> -struct formatter<std::filesystem::path, Char> - : formatter<basic_string_view<Char>> { +FMT_EXPORT +template <typename Char> struct formatter<std::filesystem::path, Char> { + private: + format_specs<Char> specs_; + detail::arg_ref<Char> width_ref_; + bool debug_ = false; + + public: + FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; } + template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) { - auto out = formatter<basic_string_view<Char>>::parse(ctx); - this->set_debug_format(false); - return out; + auto it = ctx.begin(), end = ctx.end(); + if (it == end) return it; + + it = detail::parse_align(it, end, specs_); + if (it == end) return it; + + it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); + if (it != end && *it == '?') { + debug_ = true; + ++it; + } + return it; } + template <typename FormatContext> - auto format(const std::filesystem::path& p, FormatContext& ctx) const -> - typename FormatContext::iterator { + auto format(const std::filesystem::path& p, FormatContext& ctx) const { + auto specs = specs_; + detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_, + ctx); + if (!debug_) { + auto s = detail::get_path_string<Char>(p); + return detail::write(ctx.out(), basic_string_view<Char>(s), specs); + } auto quoted = basic_memory_buffer<Char>(); detail::write_escaped_path(quoted, p); - return formatter<basic_string_view<Char>>::format( - basic_string_view<Char>(quoted.data(), quoted.size()), ctx); + return detail::write(ctx.out(), + basic_string_view<Char>(quoted.data(), quoted.size()), + specs); } }; FMT_END_NAMESPACE #endif FMT_BEGIN_NAMESPACE -FMT_MODULE_EXPORT +FMT_EXPORT template <typename Char> struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {}; FMT_END_NAMESPACE #ifdef __cpp_lib_optional FMT_BEGIN_NAMESPACE -FMT_MODULE_EXPORT +FMT_EXPORT template <typename T, typename Char> struct formatter<std::optional<T>, Char, std::enable_if_t<is_formattable<T, Char>::value>> { @@ -148,22 +196,6 @@ FMT_END_NAMESPACE #ifdef __cpp_lib_variant FMT_BEGIN_NAMESPACE -FMT_MODULE_EXPORT -template <typename Char> struct formatter<std::monostate, Char> { - template <typename ParseContext> - FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { - return ctx.begin(); - } - - template <typename FormatContext> - auto format(const std::monostate&, FormatContext& ctx) const - -> decltype(ctx.out()) { - auto out = ctx.out(); - out = detail::write<Char>(out, "monostate"); - return out; - } -}; - namespace detail { template <typename T> @@ -197,6 +229,7 @@ auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt { } } // namespace detail + template <typename T> struct is_variant_like { static constexpr const bool value = detail::is_variant_like_<T>::value; }; @@ -206,7 +239,21 @@ template <typename T, typename C> struct is_variant_formattable { detail::is_variant_formattable_<T, C>::value; }; -FMT_MODULE_EXPORT +FMT_EXPORT +template <typename Char> struct formatter<std::monostate, Char> { + template <typename ParseContext> + FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template <typename FormatContext> + auto format(const std::monostate&, FormatContext& ctx) const + -> decltype(ctx.out()) { + return detail::write<Char>(ctx.out(), "monostate"); + } +}; + +FMT_EXPORT template <typename Variant, typename Char> struct formatter< Variant, Char, @@ -223,13 +270,14 @@ struct formatter< auto out = ctx.out(); out = detail::write<Char>(out, "variant("); - try { + FMT_TRY { std::visit( [&](const auto& v) { out = detail::write_variant_alternative<Char>(out, v); }, value); - } catch (const std::bad_variant_access&) { + } + FMT_CATCH(const std::bad_variant_access&) { detail::write<Char>(out, "valueless by exception"); } *out++ = ')'; @@ -240,7 +288,7 @@ FMT_END_NAMESPACE #endif // __cpp_lib_variant FMT_BEGIN_NAMESPACE -FMT_MODULE_EXPORT +FMT_EXPORT template <typename Char> struct formatter<std::error_code, Char> { template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { @@ -258,7 +306,7 @@ template <typename Char> struct formatter<std::error_code, Char> { } }; -FMT_MODULE_EXPORT +FMT_EXPORT template <typename T, typename Char> struct formatter< T, Char, @@ -274,7 +322,7 @@ struct formatter< if (it == end || *it == '}') return it; if (*it == 't') { ++it; - with_typename_ = true; + with_typename_ = FMT_USE_TYPEID != 0; } return it; } @@ -287,8 +335,9 @@ struct formatter< if (!with_typename_) return detail::write_bytes(out, string_view(ex.what()), spec); +#if FMT_USE_TYPEID const std::type_info& ti = typeid(ex); -#ifdef FMT_HAS_ABI_CXA_DEMANGLE +# ifdef FMT_HAS_ABI_CXA_DEMANGLE int status = 0; std::size_t size = 0; std::unique_ptr<char, decltype(&std::free)> demangled_name_ptr( @@ -327,23 +376,90 @@ struct formatter< demangled_name_view = string_view(ti.name()); } out = detail::write_bytes(out, demangled_name_view, spec); -#elif FMT_MSC_VERSION +# elif FMT_MSC_VERSION string_view demangled_name_view(ti.name()); if (demangled_name_view.starts_with("class ")) demangled_name_view.remove_prefix(6); else if (demangled_name_view.starts_with("struct ")) demangled_name_view.remove_prefix(7); out = detail::write_bytes(out, demangled_name_view, spec); -#else +# else out = detail::write_bytes(out, string_view(ti.name()), spec); +# endif + *out++ = ':'; + *out++ = ' '; + return detail::write_bytes(out, string_view(ex.what()), spec); #endif - out = detail::write<Char>(out, Char(':')); - out = detail::write<Char>(out, Char(' ')); - out = detail::write_bytes(out, string_view(ex.what()), spec); + } +}; - return out; +namespace detail { + +template <typename T, typename Enable = void> +struct has_flip : std::false_type {}; + +template <typename T> +struct has_flip<T, void_t<decltype(std::declval<T>().flip())>> + : std::true_type {}; + +template <typename T> struct is_bit_reference_like { + static constexpr const bool value = + std::is_convertible<T, bool>::value && + std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value; +}; + +#ifdef _LIBCPP_VERSION + +// Workaround for libc++ incompatibility with C++ standard. +// According to the Standard, `bitset::operator[] const` returns bool. +template <typename C> +struct is_bit_reference_like<std::__bit_const_reference<C>> { + static constexpr const bool value = true; +}; + +#endif + +} // namespace detail + +// We can't use std::vector<bool, Allocator>::reference and +// std::bitset<N>::reference because the compiler can't deduce Allocator and N +// in partial specialization. +FMT_EXPORT +template <typename BitRef, typename Char> +struct formatter<BitRef, Char, + enable_if_t<detail::is_bit_reference_like<BitRef>::value>> + : formatter<bool, Char> { + template <typename FormatContext> + FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter<bool, Char>::format(v, ctx); + } +}; + +FMT_EXPORT +template <typename T, typename Char> +struct formatter<std::atomic<T>, Char, + enable_if_t<is_formattable<T, Char>::value>> + : formatter<T, Char> { + template <typename FormatContext> + auto format(const std::atomic<T>& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter<T, Char>::format(v.load(), ctx); } }; -FMT_END_NAMESPACE +#ifdef __cpp_lib_atomic_flag_test +FMT_EXPORT +template <typename Char> +struct formatter<std::atomic_flag, Char> + : formatter<bool, Char> { + template <typename FormatContext> + auto format(const std::atomic_flag& v, FormatContext& ctx) const + -> decltype(ctx.out()) { + return formatter<bool, Char>::format(v.test(), ctx); + } +}; +#endif // __cpp_lib_atomic_flag_test + +FMT_END_NAMESPACE #endif // FMT_STD_H_ |