1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H 11 #define _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H 12 13 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 14 # pragma GCC system_header 15 #endif 16 17 #include <__availability> 18 #include <__chrono/statically_widen.h> 19 #include <__concepts/same_as.h> 20 #include <__config> 21 #include <__format/concepts.h> 22 #include <__format/formatter.h> 23 #include <__format/range_formatter.h> 24 #include <__ranges/concepts.h> 25 #include <__type_traits/remove_cvref.h> 26 #include <__utility/pair.h> 27 #include <string_view> 28 #include <tuple> 29 30 _LIBCPP_BEGIN_NAMESPACE_STD 31 32 #if _LIBCPP_STD_VER > 20 33 34 template <class _Rp, class _CharT> 35 concept __const_formattable_range = 36 ranges::input_range<const _Rp> && formattable<ranges::range_reference_t<const _Rp>, _CharT>; 37 38 template <class _Rp, class _CharT> 39 using __fmt_maybe_const = conditional_t<__const_formattable_range<_Rp, _CharT>, const _Rp, _Rp>; 40 41 _LIBCPP_DIAGNOSTIC_PUSH 42 _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wshadow") 43 _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshadow") 44 // This shadows map, set, and string. 45 enum class range_format { disabled, map, set, sequence, string, debug_string }; 46 _LIBCPP_DIAGNOSTIC_POP 47 48 // There is no definition of this struct, it's purely intended to be used to 49 // generate diagnostics. 50 template <class _Rp> 51 struct _LIBCPP_TEMPLATE_VIS __instantiated_the_primary_template_of_format_kind; 52 53 template <class _Rp> 54 constexpr range_format format_kind = [] { 55 // [format.range.fmtkind]/1 56 // A program that instantiates the primary template of format_kind is ill-formed. 57 static_assert(sizeof(_Rp) != sizeof(_Rp), "create a template specialization of format_kind for your type"); 58 return range_format::disabled; 59 }(); 60 61 template <ranges::input_range _Rp> 62 requires same_as<_Rp, remove_cvref_t<_Rp>> 63 inline constexpr range_format format_kind<_Rp> = [] { 64 // [format.range.fmtkind]/2 65 66 // 2.1 If same_as<remove_cvref_t<ranges::range_reference_t<R>>, R> is true, 67 // Otherwise format_kind<R> is range_format::disabled. 68 if constexpr (same_as<remove_cvref_t<ranges::range_reference_t<_Rp>>, _Rp>) 69 return range_format::disabled; 70 // 2.2 Otherwise, if the qualified-id R::key_type is valid and denotes a type: 71 else if constexpr (requires { typename _Rp::key_type; }) { 72 // 2.2.1 If the qualified-id R::mapped_type is valid and denotes a type ... 73 if constexpr (requires { typename _Rp::mapped_type; } && 74 // 2.2.1 ... If either U is a specialization of pair or U is a specialization 75 // of tuple and tuple_size_v<U> == 2 76 __fmt_pair_like<remove_cvref_t<ranges::range_reference_t<_Rp>>>) 77 return range_format::map; 78 else 79 // 2.2.2 Otherwise format_kind<R> is range_format::set. 80 return range_format::set; 81 } else 82 // 2.3 Otherwise, format_kind<R> is range_format::sequence. 83 return range_format::sequence; 84 }(); 85 86 // This is a non-standard work-around to fix instantiation of 87 // formatter<const _CharT[N], _CharT> 88 // const _CharT[N] satisfies the ranges::input_range concept. 89 // remove_cvref_t<const _CharT[N]> is _CharT[N] so it does not satisfy the 90 // requirement of the above specialization. Instead it will instantiate the 91 // primary template, which is ill-formed. 92 // 93 // An alternative solution is to remove the offending formatter. 94 // 95 // https://godbolt.org/z/bqjhhaexx 96 // 97 // The removal is proposed in LWG3833, but use the work-around until the issue 98 // has been adopted. 99 // TODO FMT Implement LWG3833. 100 template <class _CharT, size_t N> 101 inline constexpr range_format format_kind<const _CharT[N]> = range_format::disabled; 102 103 template <range_format _Kp, ranges::input_range _Rp, class _CharT> 104 struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __range_default_formatter; 105 106 // Required specializations 107 108 template <ranges::input_range _Rp, class _CharT> 109 struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __range_default_formatter<range_format::sequence, _Rp, _CharT> { 110 private: 111 using __maybe_const_r = __fmt_maybe_const<_Rp, _CharT>; 112 range_formatter<remove_cvref_t<ranges::range_reference_t<__maybe_const_r>>, _CharT> __underlying_; 113 114 public: 115 _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) { 116 __underlying_.set_separator(__separator); 117 } 118 _LIBCPP_HIDE_FROM_ABI constexpr void 119 set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) { 120 __underlying_.set_brackets(__opening_bracket, __closing_bracket); 121 } 122 123 template <class _ParseContext> 124 _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 125 return __underlying_.parse(__ctx); 126 } 127 128 template <class FormatContext> 129 _LIBCPP_HIDE_FROM_ABI typename FormatContext::iterator format(__maybe_const_r& __range, FormatContext& __ctx) const { 130 return __underlying_.format(__range, __ctx); 131 } 132 }; 133 134 template <ranges::input_range _Rp, class _CharT> 135 struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __range_default_formatter<range_format::map, _Rp, _CharT> { 136 private: 137 using __maybe_const_map = __fmt_maybe_const<_Rp, _CharT>; 138 using __element_type = remove_cvref_t<ranges::range_reference_t<__maybe_const_map>>; 139 range_formatter<__element_type, _CharT> __underlying_; 140 141 public: 142 _LIBCPP_HIDE_FROM_ABI constexpr __range_default_formatter() 143 requires(__fmt_pair_like<__element_type>) 144 { 145 __underlying_.set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}")); 146 __underlying_.underlying().set_brackets({}, {}); 147 __underlying_.underlying().set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": ")); 148 } 149 150 template <class _ParseContext> 151 _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 152 return __underlying_.parse(__ctx); 153 } 154 155 template <class _FormatContext> 156 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator 157 format(__maybe_const_map& __range, _FormatContext& __ctx) const { 158 return __underlying_.format(__range, __ctx); 159 } 160 }; 161 162 template <ranges::input_range _Rp, class _CharT> 163 struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __range_default_formatter<range_format::set, _Rp, _CharT> { 164 private: 165 using __maybe_const_set = __fmt_maybe_const<_Rp, _CharT>; 166 using __element_type = remove_cvref_t<ranges::range_reference_t<__maybe_const_set>>; 167 range_formatter<__element_type, _CharT> __underlying_; 168 169 public: 170 _LIBCPP_HIDE_FROM_ABI constexpr __range_default_formatter() { 171 __underlying_.set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}")); 172 } 173 174 template <class _ParseContext> 175 _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 176 return __underlying_.parse(__ctx); 177 } 178 179 template <class _FormatContext> 180 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator 181 format(__maybe_const_set& __range, _FormatContext& __ctx) const { 182 return __underlying_.format(__range, __ctx); 183 } 184 }; 185 186 template <range_format _Kp, ranges::input_range _Rp, class _CharT> 187 requires(_Kp == range_format::string || _Kp == range_format::debug_string) 188 struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT __range_default_formatter<_Kp, _Rp, _CharT> { 189 __range_default_formatter() = delete; // TODO FMT Implement 190 }; 191 192 template <ranges::input_range _Rp, class _CharT> 193 requires(format_kind<_Rp> != range_format::disabled && formattable<ranges::range_reference_t<_Rp>, _CharT>) 194 struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<_Rp, _CharT> 195 : __range_default_formatter<format_kind<_Rp>, _Rp, _CharT> {}; 196 197 #endif //_LIBCPP_STD_VER > 20 198 199 _LIBCPP_END_NAMESPACE_STD 200 201 #endif // _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H 202