2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H
11 #define _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H
13 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
14 # pragma GCC system_header
17 #include <__algorithm/ranges_copy.h>
18 #include <__chrono/statically_widen.h>
19 #include <__concepts/same_as.h>
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>
34 _LIBCPP_BEGIN_NAMESPACE_STD
36 #if _LIBCPP_STD_VER >= 23
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
>;
42 template <class _Rp
, class _CharT
>
43 using __fmt_maybe_const
= conditional_t
<__const_formattable_range
<_Rp
, _CharT
>, const _Rp
, _Rp
>;
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
52 // There is no definition of this struct, it's purely intended to be used to
53 // generate diagnostics.
55 struct _LIBCPP_TEMPLATE_VIS __instantiated_the_primary_template_of_format_kind
;
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
;
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
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
;
83 // 2.2.2 Otherwise format_kind<R> is range_format::set.
84 return range_format::set
;
86 // 2.3 Otherwise, format_kind<R> is range_format::sequence.
87 return range_format::sequence
;
90 template <range_format _Kp
, ranges::input_range _Rp
, class _CharT
>
91 struct _LIBCPP_TEMPLATE_VIS __range_default_formatter
;
93 // Required specializations
95 template <ranges::input_range _Rp
, class _CharT
>
96 struct _LIBCPP_TEMPLATE_VIS __range_default_formatter
<range_format::sequence
, _Rp
, _CharT
> {
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_
;
102 _LIBCPP_HIDE_FROM_ABI
constexpr void set_separator(basic_string_view
<_CharT
> __separator
) noexcept
{
103 __underlying_
.set_separator(__separator
);
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
);
110 template <class _ParseContext
>
111 _LIBCPP_HIDE_FROM_ABI
constexpr typename
_ParseContext::iterator
parse(_ParseContext
& __ctx
) {
112 return __underlying_
.parse(__ctx
);
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
);
122 template <ranges::input_range _Rp
, class _CharT
>
123 struct _LIBCPP_TEMPLATE_VIS __range_default_formatter
<range_format::map
, _Rp
, _CharT
> {
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_
;
130 _LIBCPP_HIDE_FROM_ABI
constexpr __range_default_formatter()
131 requires(__fmt_pair_like
<__element_type
>)
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
, ": "));
138 template <class _ParseContext
>
139 _LIBCPP_HIDE_FROM_ABI
constexpr typename
_ParseContext::iterator
parse(_ParseContext
& __ctx
) {
140 return __underlying_
.parse(__ctx
);
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
);
150 template <ranges::input_range _Rp
, class _CharT
>
151 struct _LIBCPP_TEMPLATE_VIS __range_default_formatter
<range_format::set
, _Rp
, _CharT
> {
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_
;
158 _LIBCPP_HIDE_FROM_ABI
constexpr __range_default_formatter() {
159 __underlying_
.set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT
, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT
, "}"));
162 template <class _ParseContext
>
163 _LIBCPP_HIDE_FROM_ABI
constexpr typename
_ParseContext::iterator
parse(_ParseContext
& __ctx
) {
164 return __underlying_
.parse(__ctx
);
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
);
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
> {
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_
;
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();
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
);
202 return __underlying_
.format(basic_string
<_CharT
>{from_range
, __range
}, __ctx
);
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
> {};
210 #endif //_LIBCPP_STD_VER >= 23
212 _LIBCPP_END_NAMESPACE_STD
214 #endif // _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H