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 <__algorithm/ranges_copy.h> 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 <__iterator/back_insert_iterator.h> 25 #include <__ranges/concepts.h> 26 #include <__ranges/data.h> 27 #include <__ranges/from_range.h> 28 #include <__ranges/size.h> 29 #include <__type_traits/conditional.h> 30 #include <__type_traits/remove_cvref.h> 31 #include <__utility/pair.h> 32 #include <string_view> 33 34 _LIBCPP_BEGIN_NAMESPACE_STD 35 36 #if _LIBCPP_STD_VER >= 23 37 38 template <class _Rp, class _CharT> 39 concept __const_formattable_range = 40 ranges::input_range<const _Rp> && formattable<ranges::range_reference_t<const _Rp>, _CharT>; 41 42 template <class _Rp, class _CharT> 43 using __fmt_maybe_const = conditional_t<__const_formattable_range<_Rp, _CharT>, const _Rp, _Rp>; 44 45 _LIBCPP_DIAGNOSTIC_PUSH 46 _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wshadow") 47 _LIBCPP_GCC_DIAGNOSTIC_IGNORED("-Wshadow") 48 // This shadows map, set, and string. 49 enum class range_format { disabled, map, set, sequence, string, debug_string }; 50 _LIBCPP_DIAGNOSTIC_POP 51 52 // There is no definition of this struct, it's purely intended to be used to 53 // generate diagnostics. 54 template <class _Rp> 55 struct _LIBCPP_TEMPLATE_VIS __instantiated_the_primary_template_of_format_kind; 56 57 template <class _Rp> 58 constexpr range_format format_kind = [] { 59 // [format.range.fmtkind]/1 60 // A program that instantiates the primary template of format_kind is ill-formed. 61 static_assert(sizeof(_Rp) != sizeof(_Rp), "create a template specialization of format_kind for your type"); 62 return range_format::disabled; 63 }(); 64 65 template <ranges::input_range _Rp> 66 requires same_as<_Rp, remove_cvref_t<_Rp>> 67 inline constexpr range_format format_kind<_Rp> = [] { 68 // [format.range.fmtkind]/2 69 70 // 2.1 If same_as<remove_cvref_t<ranges::range_reference_t<R>>, R> is true, 71 // Otherwise format_kind<R> is range_format::disabled. 72 if constexpr (same_as<remove_cvref_t<ranges::range_reference_t<_Rp>>, _Rp>) 73 return range_format::disabled; 74 // 2.2 Otherwise, if the qualified-id R::key_type is valid and denotes a type: 75 else if constexpr (requires { typename _Rp::key_type; }) { 76 // 2.2.1 If the qualified-id R::mapped_type is valid and denotes a type ... 77 if constexpr (requires { typename _Rp::mapped_type; } && 78 // 2.2.1 ... If either U is a specialization of pair or U is a specialization 79 // of tuple and tuple_size_v<U> == 2 80 __fmt_pair_like<remove_cvref_t<ranges::range_reference_t<_Rp>>>) 81 return range_format::map; 82 else 83 // 2.2.2 Otherwise format_kind<R> is range_format::set. 84 return range_format::set; 85 } else 86 // 2.3 Otherwise, format_kind<R> is range_format::sequence. 87 return range_format::sequence; 88 }(); 89 90 template <range_format _Kp, ranges::input_range _Rp, class _CharT> 91 struct _LIBCPP_TEMPLATE_VIS __range_default_formatter; 92 93 // Required specializations 94 95 template <ranges::input_range _Rp, class _CharT> 96 struct _LIBCPP_TEMPLATE_VIS __range_default_formatter<range_format::sequence, _Rp, _CharT> { 97 private: 98 using __maybe_const_r = __fmt_maybe_const<_Rp, _CharT>; 99 range_formatter<remove_cvref_t<ranges::range_reference_t<__maybe_const_r>>, _CharT> __underlying_; 100 101 public: 102 _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept { 103 __underlying_.set_separator(__separator); 104 } 105 _LIBCPP_HIDE_FROM_ABI constexpr void 106 set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept { 107 __underlying_.set_brackets(__opening_bracket, __closing_bracket); 108 } 109 110 template <class _ParseContext> 111 _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 112 return __underlying_.parse(__ctx); 113 } 114 115 template <class _FormatContext> 116 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator 117 format(__maybe_const_r& __range, _FormatContext& __ctx) const { 118 return __underlying_.format(__range, __ctx); 119 } 120 }; 121 122 template <ranges::input_range _Rp, class _CharT> 123 struct _LIBCPP_TEMPLATE_VIS __range_default_formatter<range_format::map, _Rp, _CharT> { 124 private: 125 using __maybe_const_map = __fmt_maybe_const<_Rp, _CharT>; 126 using __element_type = remove_cvref_t<ranges::range_reference_t<__maybe_const_map>>; 127 range_formatter<__element_type, _CharT> __underlying_; 128 129 public: 130 _LIBCPP_HIDE_FROM_ABI constexpr __range_default_formatter() 131 requires(__fmt_pair_like<__element_type>) 132 { 133 __underlying_.set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}")); 134 __underlying_.underlying().set_brackets({}, {}); 135 __underlying_.underlying().set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": ")); 136 } 137 138 template <class _ParseContext> 139 _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 140 return __underlying_.parse(__ctx); 141 } 142 143 template <class _FormatContext> 144 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator 145 format(__maybe_const_map& __range, _FormatContext& __ctx) const { 146 return __underlying_.format(__range, __ctx); 147 } 148 }; 149 150 template <ranges::input_range _Rp, class _CharT> 151 struct _LIBCPP_TEMPLATE_VIS __range_default_formatter<range_format::set, _Rp, _CharT> { 152 private: 153 using __maybe_const_set = __fmt_maybe_const<_Rp, _CharT>; 154 using __element_type = remove_cvref_t<ranges::range_reference_t<__maybe_const_set>>; 155 range_formatter<__element_type, _CharT> __underlying_; 156 157 public: 158 _LIBCPP_HIDE_FROM_ABI constexpr __range_default_formatter() { 159 __underlying_.set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}")); 160 } 161 162 template <class _ParseContext> 163 _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 164 return __underlying_.parse(__ctx); 165 } 166 167 template <class _FormatContext> 168 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator 169 format(__maybe_const_set& __range, _FormatContext& __ctx) const { 170 return __underlying_.format(__range, __ctx); 171 } 172 }; 173 174 template <range_format _Kp, ranges::input_range _Rp, class _CharT> 175 requires(_Kp == range_format::string || _Kp == range_format::debug_string) 176 struct _LIBCPP_TEMPLATE_VIS __range_default_formatter<_Kp, _Rp, _CharT> { 177 private: 178 // This deviates from the Standard, there the exposition only type is 179 // formatter<basic_string<charT>, charT> underlying_; 180 // Using a string_view allows the format function to avoid a copy of the 181 // input range when it is a contigious range. 182 formatter<basic_string_view<_CharT>, _CharT> __underlying_; 183 184 public: 185 template <class _ParseContext> 186 _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) { 187 typename _ParseContext::iterator __i = __underlying_.parse(__ctx); 188 if constexpr (_Kp == range_format::debug_string) 189 __underlying_.set_debug_format(); 190 return __i; 191 } 192 193 template <class _FormatContext> 194 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator 195 format(conditional_t<ranges::input_range<const _Rp>, const _Rp&, _Rp&> __range, _FormatContext& __ctx) const { 196 // When the range is contiguous use a basic_string_view instead to avoid a 197 // copy of the underlying data. The basic_string_view formatter 198 // specialization is the "basic" string formatter in libc++. 199 if constexpr (ranges::contiguous_range<_Rp> && std::ranges::sized_range<_Rp>) 200 return __underlying_.format(basic_string_view<_CharT>{ranges::data(__range), ranges::size(__range)}, __ctx); 201 else 202 return __underlying_.format(basic_string<_CharT>{from_range, __range}, __ctx); 203 } 204 }; 205 206 template <ranges::input_range _Rp, class _CharT> 207 requires(format_kind<_Rp> != range_format::disabled && formattable<ranges::range_reference_t<_Rp>, _CharT>) 208 struct _LIBCPP_TEMPLATE_VIS formatter<_Rp, _CharT> : __range_default_formatter<format_kind<_Rp>, _Rp, _CharT> {}; 209 210 #endif //_LIBCPP_STD_VER >= 23 211 212 _LIBCPP_END_NAMESPACE_STD 213 214 #endif // _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H 215