|
18 | 18 | #include <tuple> |
19 | 19 | #include <type_traits> |
20 | 20 | #include <utility> |
| 21 | +#include <version> |
21 | 22 |
|
22 | 23 | #if __STDC_HOSTED__ |
23 | 24 | #include <atomic> |
24 | | -#if __has_include(<format>) |
| 25 | + |
| 26 | +// LLVM libc++ 17 has usable <format> despite lacking __cpp_lib_format until 19. |
| 27 | +#if __cpp_lib_format >= 201907L || _LIBCPP_VERSION >= 170000 |
25 | 28 | #include <format> |
26 | | -#endif // __has_include(<format>) |
27 | | -#if __cpp_lib_format >= 201907L || \ |
28 | | - (defined(_LIBCPP_VERSION) && _LIBCPP_VERSION >= 170000) |
29 | 29 | #define PRO4D_HAS_FORMAT |
30 | 30 | #endif // __cpp_lib_format || _LIBCPP_VERSION >= 170000 |
31 | 31 | #endif // __STDC_HOSTED__ |
@@ -714,9 +714,6 @@ struct facade_conv_traits_impl { |
714 | 714 | template <class P> |
715 | 715 | static constexpr bool conv_applicable_ptr = |
716 | 716 | (conv_traits<Cs, F>::template applicable_ptr<P> && ...); |
717 | | - template <bool IsDirect, class D, class O> |
718 | | - static constexpr bool is_invocable = |
719 | | - std::is_base_of_v<invocation_meta<F, IsDirect, D, O>, conv_meta>; |
720 | 717 | }; |
721 | 718 | template <class F, class... Rs> |
722 | 719 | struct facade_refl_traits_impl { |
@@ -2148,6 +2145,11 @@ class bad_proxy_cast : public std::bad_cast { |
2148 | 2145 |
|
2149 | 2146 | namespace details { |
2150 | 2147 |
|
| 2148 | +template <template <class...> class TT, class... Ctx> |
| 2149 | +struct enabled_t {}; |
| 2150 | +template <class T, template <class...> class TT, class... Ctx> |
| 2151 | +concept enabled_for = std::is_base_of_v<enabled_t<TT, Ctx...>, T>; |
| 2152 | + |
2151 | 2153 | struct view_conversion_dispatch : cast_dispatch_base<false, true> { |
2152 | 2154 | template <class T> |
2153 | 2155 | PRO4D_STATIC_CALL(auto, T& value) noexcept |
@@ -2179,47 +2181,74 @@ struct weak_conversion_dispatch : cast_dispatch_base<false, true> { |
2179 | 2181 | template <class F> |
2180 | 2182 | using weak_conversion_overload = weak_proxy<F>() const noexcept; |
2181 | 2183 |
|
| 2184 | +template <template <class...> class Formatter, |
| 2185 | + template <class...> class StringView, |
| 2186 | + template <class...> class ParseContext, |
| 2187 | + template <class...> class FormatContext> |
| 2188 | +struct format_traits { |
| 2189 | + template <class CharT> |
| 2190 | + using overload = typename FormatContext<CharT>::iterator( |
| 2191 | + StringView<CharT> spec, FormatContext<CharT>& fc) const; |
| 2192 | + |
| 2193 | + struct dispatch { |
| 2194 | + template <class T, class CharT> |
| 2195 | + PRO4D_STATIC_CALL(auto, const T& self, StringView<CharT> spec, |
| 2196 | + FormatContext<CharT>& fc) |
| 2197 | + requires(std::is_default_constructible_v<Formatter<T, CharT>>) |
| 2198 | + { |
| 2199 | + Formatter<T, CharT> impl; |
| 2200 | + { |
| 2201 | + ParseContext<CharT> pc{spec}; |
| 2202 | + impl.parse(pc); |
| 2203 | + } |
| 2204 | + return impl.format(self, fc); |
| 2205 | + } |
| 2206 | + |
| 2207 | + template <class P, class D, class... Os> |
| 2208 | + struct PRO4D_ENFORCE_EBO accessor : accessor<P, D, Os>... {}; |
| 2209 | + template <class P, class D> |
| 2210 | + struct accessor<P, D, overload<char>> : enabled_t<Formatter, char> {}; |
| 2211 | + template <class P, class D> |
| 2212 | + struct accessor<P, D, overload<wchar_t>> : enabled_t<Formatter, wchar_t> {}; |
| 2213 | + }; |
| 2214 | + |
| 2215 | + template <class CharT> |
| 2216 | + struct formatter { |
| 2217 | + constexpr auto parse(ParseContext<CharT>& pc) { |
| 2218 | + for (auto it = pc.begin(); it != pc.end(); ++it) { |
| 2219 | + if (*it == '}') { |
| 2220 | + spec_ = StringView<CharT>{pc.begin(), it + 1}; |
| 2221 | + return it; |
| 2222 | + } |
| 2223 | + } |
| 2224 | + return pc.end(); |
| 2225 | + } |
| 2226 | + |
| 2227 | + template <class P, class CompatibleFormatContext> |
| 2228 | + auto format(const P& p, CompatibleFormatContext& fc) const -> |
| 2229 | + typename CompatibleFormatContext::iterator { |
| 2230 | + return invoke<dispatch, overload<CharT>>(p, spec_, fc); |
| 2231 | + } |
| 2232 | + |
| 2233 | + private: |
| 2234 | + StringView<CharT> spec_; |
| 2235 | + }; |
| 2236 | +}; |
| 2237 | + |
2182 | 2238 | #ifdef PRO4D_HAS_FORMAT |
2183 | 2239 | template <class CharT> |
2184 | | -struct format_overload_traits; |
| 2240 | +struct std_format_context_traits; |
2185 | 2241 | template <> |
2186 | | -struct format_overload_traits<char> |
2187 | | - : std::type_identity<std::format_context::iterator( |
2188 | | - std::string_view spec, std::format_context& fc) const> {}; |
| 2242 | +struct std_format_context_traits<char> |
| 2243 | + : std::type_identity<std::format_context> {}; |
2189 | 2244 | template <> |
2190 | | -struct format_overload_traits<wchar_t> |
2191 | | - : std::type_identity<std::wformat_context::iterator( |
2192 | | - std::wstring_view spec, std::wformat_context& fc) const> {}; |
| 2245 | +struct std_format_context_traits<wchar_t> |
| 2246 | + : std::type_identity<std::wformat_context> {}; |
2193 | 2247 | template <class CharT> |
2194 | | -using format_overload_t = typename format_overload_traits<CharT>::type; |
2195 | | - |
2196 | | -struct format_dispatch { |
2197 | | - // Note: This function requires std::formatter<T, CharT> to be well-formed. |
2198 | | - // However, the standard did not provide such facility before C++23. In the |
2199 | | - // "required" clause of this function, std::formattable (C++23) is preferred |
2200 | | - // when available. Otherwise, when building with C++20, we simply check |
2201 | | - // whether std::formatter<T, CharT> is a disabled specialization of |
2202 | | - // std::formatter by std::is_default_constructible_v as per |
2203 | | - // [format.formatter.spec]. |
2204 | | - template <class T, class CharT, class OutIt> |
2205 | | - PRO4D_STATIC_CALL(OutIt, const T& self, std::basic_string_view<CharT> spec, |
2206 | | - std::basic_format_context<OutIt, CharT>& fc) |
2207 | | - requires( |
2208 | | -#if __cpp_lib_format_ranges >= 202207L |
2209 | | - std::formattable<T, CharT> |
2210 | | -#else |
2211 | | - std::is_default_constructible_v<std::formatter<T, CharT>> |
2212 | | -#endif // __cpp_lib_format_ranges >= 202207L |
2213 | | - ) |
2214 | | - { |
2215 | | - std::formatter<T, CharT> impl; |
2216 | | - { |
2217 | | - std::basic_format_parse_context<CharT> pc{spec}; |
2218 | | - impl.parse(pc); |
2219 | | - } |
2220 | | - return impl.format(self, fc); |
2221 | | - } |
2222 | | -}; |
| 2248 | +using std_format_context = typename std_format_context_traits<CharT>::type; |
| 2249 | +struct std_format_traits |
| 2250 | + : format_traits<std::formatter, std::basic_string_view, |
| 2251 | + std::basic_format_parse_context, std_format_context> {}; |
2223 | 2252 | #endif // PRO4D_HAS_FORMAT |
2224 | 2253 |
|
2225 | 2254 | #if __cpp_rtti >= 199711L |
@@ -2329,14 +2358,14 @@ namespace skills { |
2329 | 2358 |
|
2330 | 2359 | #ifdef PRO4D_HAS_FORMAT |
2331 | 2360 | template <class FB> |
2332 | | -using format = |
2333 | | - typename FB::template add_convention<details::format_dispatch, |
2334 | | - details::format_overload_t<char>>; |
| 2361 | +using format = typename FB::template add_convention< |
| 2362 | + details::std_format_traits::dispatch, |
| 2363 | + details::std_format_traits::overload<char>>; |
2335 | 2364 |
|
2336 | 2365 | template <class FB> |
2337 | | -using wformat = |
2338 | | - typename FB::template add_convention<details::format_dispatch, |
2339 | | - details::format_overload_t<wchar_t>>; |
| 2366 | +using wformat = typename FB::template add_convention< |
| 2367 | + details::std_format_traits::dispatch, |
| 2368 | + details::std_format_traits::overload<wchar_t>>; |
2340 | 2369 | #endif // PRO4D_HAS_FORMAT |
2341 | 2370 |
|
2342 | 2371 | #if __cpp_rtti >= 199711L |
@@ -2676,31 +2705,10 @@ struct weak_dispatch : D { |
2676 | 2705 | #ifdef PRO4D_HAS_FORMAT |
2677 | 2706 | namespace std { |
2678 | 2707 |
|
2679 | | -template <pro::v4::facade F, class CharT> |
2680 | | - requires(pro::v4::details::facade_traits<F>::template is_invocable< |
2681 | | - false, pro::v4::details::format_dispatch, |
2682 | | - pro::v4::details::format_overload_t<CharT>>) |
2683 | | -struct formatter<pro::v4::proxy_indirect_accessor<F>, CharT> { |
2684 | | - constexpr auto parse(basic_format_parse_context<CharT>& pc) { |
2685 | | - for (auto it = pc.begin(); it != pc.end(); ++it) { |
2686 | | - if (*it == '}') { |
2687 | | - spec_ = basic_string_view<CharT>{pc.begin(), it + 1}; |
2688 | | - return it; |
2689 | | - } |
2690 | | - } |
2691 | | - return pc.end(); |
2692 | | - } |
2693 | | - |
2694 | | - template <class OutIt> |
2695 | | - OutIt format(const pro::v4::proxy_indirect_accessor<F>& p, |
2696 | | - basic_format_context<OutIt, CharT>& fc) const { |
2697 | | - return invoke<pro::v4::details::format_dispatch, |
2698 | | - pro::v4::details::format_overload_t<CharT>>(p, spec_, fc); |
2699 | | - } |
2700 | | - |
2701 | | -private: |
2702 | | - basic_string_view<CharT> spec_; |
2703 | | -}; |
| 2708 | +template <class T, class CharT> |
| 2709 | + requires(pro::v4::details::enabled_for<T, std::formatter, CharT>) |
| 2710 | +struct formatter<T, CharT> |
| 2711 | + : pro::v4::details::std_format_traits::formatter<CharT> {}; |
2704 | 2712 |
|
2705 | 2713 | } // namespace std |
2706 | 2714 | #endif // PRO4D_HAS_FORMAT |
|
0 commit comments