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 <__config>
20#include <__format/concepts.h>
21#include <__format/fmt_pair_like.h>
22#include <__format/formatter.h>
23#include <__format/range_format.h>
24#include <__format/range_formatter.h>
25#include <__iterator/back_insert_iterator.h>
26#include <__ranges/concepts.h>
27#include <__ranges/data.h>
28#include <__ranges/from_range.h>
29#include <__ranges/size.h>
30#include <__type_traits/conditional.h>
31#include <__type_traits/remove_cvref.h>
32#include <__utility/pair.h>
33#include <string_view>
34
35_LIBCPP_BEGIN_NAMESPACE_STD
36
37#if _LIBCPP_STD_VER >= 23
38
39template <class _Rp, class _CharT>
40concept __const_formattable_range =
41 ranges::input_range<const _Rp> && formattable<ranges::range_reference_t<const _Rp>, _CharT>;
42
43template <class _Rp, class _CharT>
44using __fmt_maybe_const _LIBCPP_NODEBUG = conditional_t<__const_formattable_range<_Rp, _CharT>, const _Rp, _Rp>;
45
46// There is no definition of this struct, it's purely intended to be used to
47// generate diagnostics.
48template <class _Rp>
49struct __instantiated_the_primary_template_of_format_kind;
50
51template <range_format _Kp, ranges::input_range _Rp, class _CharT>
52struct __range_default_formatter;
53
54// Required specializations
55
56template <ranges::input_range _Rp, class _CharT>
57struct __range_default_formatter<range_format::sequence, _Rp, _CharT> {
58private:
59 using __maybe_const_r _LIBCPP_NODEBUG = __fmt_maybe_const<_Rp, _CharT>;
60 range_formatter<remove_cvref_t<ranges::range_reference_t<__maybe_const_r>>, _CharT> __underlying_;
61
62public:
63 _LIBCPP_HIDE_FROM_ABI constexpr void set_separator(basic_string_view<_CharT> __separator) noexcept {
64 __underlying_.set_separator(__separator);
65 }
66 _LIBCPP_HIDE_FROM_ABI constexpr void
67 set_brackets(basic_string_view<_CharT> __opening_bracket, basic_string_view<_CharT> __closing_bracket) noexcept {
68 __underlying_.set_brackets(__opening_bracket, __closing_bracket);
69 }
70
71 template <class _ParseContext>
72 _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
73 return __underlying_.parse(__ctx);
74 }
75
76 template <class _FormatContext>
77 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
78 format(__maybe_const_r& __range, _FormatContext& __ctx) const {
79 return __underlying_.format(__range, __ctx);
80 }
81};
82
83template <ranges::input_range _Rp, class _CharT>
84struct __range_default_formatter<range_format::map, _Rp, _CharT> {
85private:
86 using __maybe_const_map _LIBCPP_NODEBUG = __fmt_maybe_const<_Rp, _CharT>;
87 using __element_type _LIBCPP_NODEBUG = remove_cvref_t<ranges::range_reference_t<__maybe_const_map>>;
88 range_formatter<__element_type, _CharT> __underlying_;
89
90public:
91 _LIBCPP_HIDE_FROM_ABI constexpr __range_default_formatter()
92 requires(__fmt_pair_like<__element_type>)
93 {
94 __underlying_.set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}"));
95 __underlying_.underlying().set_brackets({}, {});
96 __underlying_.underlying().set_separator(_LIBCPP_STATICALLY_WIDEN(_CharT, ": "));
97 }
98
99 template <class _ParseContext>
100 _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
101 return __underlying_.parse(__ctx);
102 }
103
104 template <class _FormatContext>
105 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
106 format(__maybe_const_map& __range, _FormatContext& __ctx) const {
107 return __underlying_.format(__range, __ctx);
108 }
109};
110
111template <ranges::input_range _Rp, class _CharT>
112struct __range_default_formatter<range_format::set, _Rp, _CharT> {
113private:
114 using __maybe_const_set _LIBCPP_NODEBUG = __fmt_maybe_const<_Rp, _CharT>;
115 using __element_type _LIBCPP_NODEBUG = remove_cvref_t<ranges::range_reference_t<__maybe_const_set>>;
116 range_formatter<__element_type, _CharT> __underlying_;
117
118public:
119 _LIBCPP_HIDE_FROM_ABI constexpr __range_default_formatter() {
120 __underlying_.set_brackets(_LIBCPP_STATICALLY_WIDEN(_CharT, "{"), _LIBCPP_STATICALLY_WIDEN(_CharT, "}"));
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
130 format(__maybe_const_set& __range, _FormatContext& __ctx) const {
131 return __underlying_.format(__range, __ctx);
132 }
133};
134
135template <range_format _Kp, ranges::input_range _Rp, class _CharT>
136 requires(_Kp == range_format::string || _Kp == range_format::debug_string)
137struct __range_default_formatter<_Kp, _Rp, _CharT> {
138private:
139 // This deviates from the Standard, there the exposition only type is
140 // formatter<basic_string<charT>, charT> underlying_;
141 // Using a string_view allows the format function to avoid a copy of the
142 // input range when it is a contigious range.
143 formatter<basic_string_view<_CharT>, _CharT> __underlying_;
144
145public:
146 template <class _ParseContext>
147 _LIBCPP_HIDE_FROM_ABI constexpr typename _ParseContext::iterator parse(_ParseContext& __ctx) {
148 typename _ParseContext::iterator __i = __underlying_.parse(__ctx);
149 if constexpr (_Kp == range_format::debug_string)
150 __underlying_.set_debug_format();
151 return __i;
152 }
153
154 template <class _FormatContext>
155 _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator
156 format(conditional_t<ranges::input_range<const _Rp>, const _Rp&, _Rp&> __range, _FormatContext& __ctx) const {
157 // When the range is contiguous use a basic_string_view instead to avoid a
158 // copy of the underlying data. The basic_string_view formatter
159 // specialization is the "basic" string formatter in libc++.
160 if constexpr (ranges::contiguous_range<_Rp> && std::ranges::sized_range<_Rp>)
161 return __underlying_.format(basic_string_view<_CharT>{ranges::data(__range), ranges::size(__range)}, __ctx);
162 else
163 return __underlying_.format(basic_string<_CharT>{from_range, __range}, __ctx);
164 }
165};
166
167template <ranges::input_range _Rp, class _CharT>
168 requires(format_kind<_Rp> != range_format::disabled && formattable<ranges::range_reference_t<_Rp>, _CharT>)
169struct formatter<_Rp, _CharT> : __range_default_formatter<format_kind<_Rp>, _Rp, _CharT> {};
170
171#endif // _LIBCPP_STD_VER >= 23
172
173_LIBCPP_END_NAMESPACE_STD
174
175#endif // _LIBCPP___FORMAT_RANGE_DEFAULT_FORMATTER_H