xref: /aosp_15_r20/external/fmtlib/include/fmt/ranges.h (revision 5c90c05cd622c0a81b57953a4d343e0e489f2e08)
1*5c90c05cSAndroid Build Coastguard Worker // Formatting library for C++ - range and tuple support
2*5c90c05cSAndroid Build Coastguard Worker //
3*5c90c05cSAndroid Build Coastguard Worker // Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
4*5c90c05cSAndroid Build Coastguard Worker // All rights reserved.
5*5c90c05cSAndroid Build Coastguard Worker //
6*5c90c05cSAndroid Build Coastguard Worker // For the license information refer to format.h.
7*5c90c05cSAndroid Build Coastguard Worker 
8*5c90c05cSAndroid Build Coastguard Worker #ifndef FMT_RANGES_H_
9*5c90c05cSAndroid Build Coastguard Worker #define FMT_RANGES_H_
10*5c90c05cSAndroid Build Coastguard Worker 
11*5c90c05cSAndroid Build Coastguard Worker #ifndef FMT_MODULE
12*5c90c05cSAndroid Build Coastguard Worker #  include <initializer_list>
13*5c90c05cSAndroid Build Coastguard Worker #  include <iterator>
14*5c90c05cSAndroid Build Coastguard Worker #  include <string>
15*5c90c05cSAndroid Build Coastguard Worker #  include <tuple>
16*5c90c05cSAndroid Build Coastguard Worker #  include <type_traits>
17*5c90c05cSAndroid Build Coastguard Worker #  include <utility>
18*5c90c05cSAndroid Build Coastguard Worker #endif
19*5c90c05cSAndroid Build Coastguard Worker 
20*5c90c05cSAndroid Build Coastguard Worker #include "format.h"
21*5c90c05cSAndroid Build Coastguard Worker 
22*5c90c05cSAndroid Build Coastguard Worker FMT_BEGIN_NAMESPACE
23*5c90c05cSAndroid Build Coastguard Worker 
24*5c90c05cSAndroid Build Coastguard Worker FMT_EXPORT
25*5c90c05cSAndroid Build Coastguard Worker enum class range_format { disabled, map, set, sequence, string, debug_string };
26*5c90c05cSAndroid Build Coastguard Worker 
27*5c90c05cSAndroid Build Coastguard Worker namespace detail {
28*5c90c05cSAndroid Build Coastguard Worker 
29*5c90c05cSAndroid Build Coastguard Worker template <typename T> class is_map {
30*5c90c05cSAndroid Build Coastguard Worker   template <typename U> static auto check(U*) -> typename U::mapped_type;
31*5c90c05cSAndroid Build Coastguard Worker   template <typename> static void check(...);
32*5c90c05cSAndroid Build Coastguard Worker 
33*5c90c05cSAndroid Build Coastguard Worker  public:
34*5c90c05cSAndroid Build Coastguard Worker   static constexpr const bool value =
35*5c90c05cSAndroid Build Coastguard Worker       !std::is_void<decltype(check<T>(nullptr))>::value;
36*5c90c05cSAndroid Build Coastguard Worker };
37*5c90c05cSAndroid Build Coastguard Worker 
38*5c90c05cSAndroid Build Coastguard Worker template <typename T> class is_set {
39*5c90c05cSAndroid Build Coastguard Worker   template <typename U> static auto check(U*) -> typename U::key_type;
40*5c90c05cSAndroid Build Coastguard Worker   template <typename> static void check(...);
41*5c90c05cSAndroid Build Coastguard Worker 
42*5c90c05cSAndroid Build Coastguard Worker  public:
43*5c90c05cSAndroid Build Coastguard Worker   static constexpr const bool value =
44*5c90c05cSAndroid Build Coastguard Worker       !std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
45*5c90c05cSAndroid Build Coastguard Worker };
46*5c90c05cSAndroid Build Coastguard Worker 
47*5c90c05cSAndroid Build Coastguard Worker // C array overload
48*5c90c05cSAndroid Build Coastguard Worker template <typename T, std::size_t N>
49*5c90c05cSAndroid Build Coastguard Worker auto range_begin(const T (&arr)[N]) -> const T* {
50*5c90c05cSAndroid Build Coastguard Worker   return arr;
51*5c90c05cSAndroid Build Coastguard Worker }
52*5c90c05cSAndroid Build Coastguard Worker template <typename T, std::size_t N>
53*5c90c05cSAndroid Build Coastguard Worker auto range_end(const T (&arr)[N]) -> const T* {
54*5c90c05cSAndroid Build Coastguard Worker   return arr + N;
55*5c90c05cSAndroid Build Coastguard Worker }
56*5c90c05cSAndroid Build Coastguard Worker 
57*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename Enable = void>
58*5c90c05cSAndroid Build Coastguard Worker struct has_member_fn_begin_end_t : std::false_type {};
59*5c90c05cSAndroid Build Coastguard Worker 
60*5c90c05cSAndroid Build Coastguard Worker template <typename T>
61*5c90c05cSAndroid Build Coastguard Worker struct has_member_fn_begin_end_t<T, void_t<decltype(*std::declval<T>().begin()),
62*5c90c05cSAndroid Build Coastguard Worker                                            decltype(std::declval<T>().end())>>
63*5c90c05cSAndroid Build Coastguard Worker     : std::true_type {};
64*5c90c05cSAndroid Build Coastguard Worker 
65*5c90c05cSAndroid Build Coastguard Worker // Member function overloads.
66*5c90c05cSAndroid Build Coastguard Worker template <typename T>
67*5c90c05cSAndroid Build Coastguard Worker auto range_begin(T&& rng) -> decltype(static_cast<T&&>(rng).begin()) {
68*5c90c05cSAndroid Build Coastguard Worker   return static_cast<T&&>(rng).begin();
69*5c90c05cSAndroid Build Coastguard Worker }
70*5c90c05cSAndroid Build Coastguard Worker template <typename T>
71*5c90c05cSAndroid Build Coastguard Worker auto range_end(T&& rng) -> decltype(static_cast<T&&>(rng).end()) {
72*5c90c05cSAndroid Build Coastguard Worker   return static_cast<T&&>(rng).end();
73*5c90c05cSAndroid Build Coastguard Worker }
74*5c90c05cSAndroid Build Coastguard Worker 
75*5c90c05cSAndroid Build Coastguard Worker // ADL overloads. Only participate in overload resolution if member functions
76*5c90c05cSAndroid Build Coastguard Worker // are not found.
77*5c90c05cSAndroid Build Coastguard Worker template <typename T>
78*5c90c05cSAndroid Build Coastguard Worker auto range_begin(T&& rng)
79*5c90c05cSAndroid Build Coastguard Worker     -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
80*5c90c05cSAndroid Build Coastguard Worker                    decltype(begin(static_cast<T&&>(rng)))> {
81*5c90c05cSAndroid Build Coastguard Worker   return begin(static_cast<T&&>(rng));
82*5c90c05cSAndroid Build Coastguard Worker }
83*5c90c05cSAndroid Build Coastguard Worker template <typename T>
84*5c90c05cSAndroid Build Coastguard Worker auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
85*5c90c05cSAndroid Build Coastguard Worker                                        decltype(end(static_cast<T&&>(rng)))> {
86*5c90c05cSAndroid Build Coastguard Worker   return end(static_cast<T&&>(rng));
87*5c90c05cSAndroid Build Coastguard Worker }
88*5c90c05cSAndroid Build Coastguard Worker 
89*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename Enable = void>
90*5c90c05cSAndroid Build Coastguard Worker struct has_const_begin_end : std::false_type {};
91*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename Enable = void>
92*5c90c05cSAndroid Build Coastguard Worker struct has_mutable_begin_end : std::false_type {};
93*5c90c05cSAndroid Build Coastguard Worker 
94*5c90c05cSAndroid Build Coastguard Worker template <typename T>
95*5c90c05cSAndroid Build Coastguard Worker struct has_const_begin_end<
96*5c90c05cSAndroid Build Coastguard Worker     T, void_t<decltype(*detail::range_begin(
97*5c90c05cSAndroid Build Coastguard Worker                   std::declval<const remove_cvref_t<T>&>())),
98*5c90c05cSAndroid Build Coastguard Worker               decltype(detail::range_end(
99*5c90c05cSAndroid Build Coastguard Worker                   std::declval<const remove_cvref_t<T>&>()))>>
100*5c90c05cSAndroid Build Coastguard Worker     : std::true_type {};
101*5c90c05cSAndroid Build Coastguard Worker 
102*5c90c05cSAndroid Build Coastguard Worker template <typename T>
103*5c90c05cSAndroid Build Coastguard Worker struct has_mutable_begin_end<
104*5c90c05cSAndroid Build Coastguard Worker     T, void_t<decltype(*detail::range_begin(std::declval<T&>())),
105*5c90c05cSAndroid Build Coastguard Worker               decltype(detail::range_end(std::declval<T&>())),
106*5c90c05cSAndroid Build Coastguard Worker               // the extra int here is because older versions of MSVC don't
107*5c90c05cSAndroid Build Coastguard Worker               // SFINAE properly unless there are distinct types
108*5c90c05cSAndroid Build Coastguard Worker               int>> : std::true_type {};
109*5c90c05cSAndroid Build Coastguard Worker 
110*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename _ = void> struct is_range_ : std::false_type {};
111*5c90c05cSAndroid Build Coastguard Worker template <typename T>
112*5c90c05cSAndroid Build Coastguard Worker struct is_range_<T, void>
113*5c90c05cSAndroid Build Coastguard Worker     : std::integral_constant<bool, (has_const_begin_end<T>::value ||
114*5c90c05cSAndroid Build Coastguard Worker                                     has_mutable_begin_end<T>::value)> {};
115*5c90c05cSAndroid Build Coastguard Worker 
116*5c90c05cSAndroid Build Coastguard Worker // tuple_size and tuple_element check.
117*5c90c05cSAndroid Build Coastguard Worker template <typename T> class is_tuple_like_ {
118*5c90c05cSAndroid Build Coastguard Worker   template <typename U, typename V = typename std::remove_cv<U>::type>
119*5c90c05cSAndroid Build Coastguard Worker   static auto check(U* p) -> decltype(std::tuple_size<V>::value, 0);
120*5c90c05cSAndroid Build Coastguard Worker   template <typename> static void check(...);
121*5c90c05cSAndroid Build Coastguard Worker 
122*5c90c05cSAndroid Build Coastguard Worker  public:
123*5c90c05cSAndroid Build Coastguard Worker   static constexpr const bool value =
124*5c90c05cSAndroid Build Coastguard Worker       !std::is_void<decltype(check<T>(nullptr))>::value;
125*5c90c05cSAndroid Build Coastguard Worker };
126*5c90c05cSAndroid Build Coastguard Worker 
127*5c90c05cSAndroid Build Coastguard Worker // Check for integer_sequence
128*5c90c05cSAndroid Build Coastguard Worker #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
129*5c90c05cSAndroid Build Coastguard Worker template <typename T, T... N>
130*5c90c05cSAndroid Build Coastguard Worker using integer_sequence = std::integer_sequence<T, N...>;
131*5c90c05cSAndroid Build Coastguard Worker template <size_t... N> using index_sequence = std::index_sequence<N...>;
132*5c90c05cSAndroid Build Coastguard Worker template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
133*5c90c05cSAndroid Build Coastguard Worker #else
134*5c90c05cSAndroid Build Coastguard Worker template <typename T, T... N> struct integer_sequence {
135*5c90c05cSAndroid Build Coastguard Worker   using value_type = T;
136*5c90c05cSAndroid Build Coastguard Worker 
137*5c90c05cSAndroid Build Coastguard Worker   static FMT_CONSTEXPR auto size() -> size_t { return sizeof...(N); }
138*5c90c05cSAndroid Build Coastguard Worker };
139*5c90c05cSAndroid Build Coastguard Worker 
140*5c90c05cSAndroid Build Coastguard Worker template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
141*5c90c05cSAndroid Build Coastguard Worker 
142*5c90c05cSAndroid Build Coastguard Worker template <typename T, size_t N, T... Ns>
143*5c90c05cSAndroid Build Coastguard Worker struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
144*5c90c05cSAndroid Build Coastguard Worker template <typename T, T... Ns>
145*5c90c05cSAndroid Build Coastguard Worker struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
146*5c90c05cSAndroid Build Coastguard Worker 
147*5c90c05cSAndroid Build Coastguard Worker template <size_t N>
148*5c90c05cSAndroid Build Coastguard Worker using make_index_sequence = make_integer_sequence<size_t, N>;
149*5c90c05cSAndroid Build Coastguard Worker #endif
150*5c90c05cSAndroid Build Coastguard Worker 
151*5c90c05cSAndroid Build Coastguard Worker template <typename T>
152*5c90c05cSAndroid Build Coastguard Worker using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
153*5c90c05cSAndroid Build Coastguard Worker 
154*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename C, bool = is_tuple_like_<T>::value>
155*5c90c05cSAndroid Build Coastguard Worker class is_tuple_formattable_ {
156*5c90c05cSAndroid Build Coastguard Worker  public:
157*5c90c05cSAndroid Build Coastguard Worker   static constexpr const bool value = false;
158*5c90c05cSAndroid Build Coastguard Worker };
159*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
160*5c90c05cSAndroid Build Coastguard Worker   template <size_t... Is>
161*5c90c05cSAndroid Build Coastguard Worker   static auto all_true(index_sequence<Is...>,
162*5c90c05cSAndroid Build Coastguard Worker                        integer_sequence<bool, (Is >= 0)...>) -> std::true_type;
163*5c90c05cSAndroid Build Coastguard Worker   static auto all_true(...) -> std::false_type;
164*5c90c05cSAndroid Build Coastguard Worker 
165*5c90c05cSAndroid Build Coastguard Worker   template <size_t... Is>
166*5c90c05cSAndroid Build Coastguard Worker   static auto check(index_sequence<Is...>) -> decltype(all_true(
167*5c90c05cSAndroid Build Coastguard Worker       index_sequence<Is...>{},
168*5c90c05cSAndroid Build Coastguard Worker       integer_sequence<bool,
169*5c90c05cSAndroid Build Coastguard Worker                        (is_formattable<typename std::tuple_element<Is, T>::type,
170*5c90c05cSAndroid Build Coastguard Worker                                        C>::value)...>{}));
171*5c90c05cSAndroid Build Coastguard Worker 
172*5c90c05cSAndroid Build Coastguard Worker  public:
173*5c90c05cSAndroid Build Coastguard Worker   static constexpr const bool value =
174*5c90c05cSAndroid Build Coastguard Worker       decltype(check(tuple_index_sequence<T>{}))::value;
175*5c90c05cSAndroid Build Coastguard Worker };
176*5c90c05cSAndroid Build Coastguard Worker 
177*5c90c05cSAndroid Build Coastguard Worker template <typename Tuple, typename F, size_t... Is>
178*5c90c05cSAndroid Build Coastguard Worker FMT_CONSTEXPR void for_each(index_sequence<Is...>, Tuple&& t, F&& f) {
179*5c90c05cSAndroid Build Coastguard Worker   using std::get;
180*5c90c05cSAndroid Build Coastguard Worker   // Using a free function get<Is>(Tuple) now.
181*5c90c05cSAndroid Build Coastguard Worker   const int unused[] = {0, ((void)f(get<Is>(t)), 0)...};
182*5c90c05cSAndroid Build Coastguard Worker   ignore_unused(unused);
183*5c90c05cSAndroid Build Coastguard Worker }
184*5c90c05cSAndroid Build Coastguard Worker 
185*5c90c05cSAndroid Build Coastguard Worker template <typename Tuple, typename F>
186*5c90c05cSAndroid Build Coastguard Worker FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) {
187*5c90c05cSAndroid Build Coastguard Worker   for_each(tuple_index_sequence<remove_cvref_t<Tuple>>(),
188*5c90c05cSAndroid Build Coastguard Worker            std::forward<Tuple>(t), std::forward<F>(f));
189*5c90c05cSAndroid Build Coastguard Worker }
190*5c90c05cSAndroid Build Coastguard Worker 
191*5c90c05cSAndroid Build Coastguard Worker template <typename Tuple1, typename Tuple2, typename F, size_t... Is>
192*5c90c05cSAndroid Build Coastguard Worker void for_each2(index_sequence<Is...>, Tuple1&& t1, Tuple2&& t2, F&& f) {
193*5c90c05cSAndroid Build Coastguard Worker   using std::get;
194*5c90c05cSAndroid Build Coastguard Worker   const int unused[] = {0, ((void)f(get<Is>(t1), get<Is>(t2)), 0)...};
195*5c90c05cSAndroid Build Coastguard Worker   ignore_unused(unused);
196*5c90c05cSAndroid Build Coastguard Worker }
197*5c90c05cSAndroid Build Coastguard Worker 
198*5c90c05cSAndroid Build Coastguard Worker template <typename Tuple1, typename Tuple2, typename F>
199*5c90c05cSAndroid Build Coastguard Worker void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) {
200*5c90c05cSAndroid Build Coastguard Worker   for_each2(tuple_index_sequence<remove_cvref_t<Tuple1>>(),
201*5c90c05cSAndroid Build Coastguard Worker             std::forward<Tuple1>(t1), std::forward<Tuple2>(t2),
202*5c90c05cSAndroid Build Coastguard Worker             std::forward<F>(f));
203*5c90c05cSAndroid Build Coastguard Worker }
204*5c90c05cSAndroid Build Coastguard Worker 
205*5c90c05cSAndroid Build Coastguard Worker namespace tuple {
206*5c90c05cSAndroid Build Coastguard Worker // Workaround a bug in MSVC 2019 (v140).
207*5c90c05cSAndroid Build Coastguard Worker template <typename Char, typename... T>
208*5c90c05cSAndroid Build Coastguard Worker using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>;
209*5c90c05cSAndroid Build Coastguard Worker 
210*5c90c05cSAndroid Build Coastguard Worker using std::get;
211*5c90c05cSAndroid Build Coastguard Worker template <typename Tuple, typename Char, std::size_t... Is>
212*5c90c05cSAndroid Build Coastguard Worker auto get_formatters(index_sequence<Is...>)
213*5c90c05cSAndroid Build Coastguard Worker     -> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>;
214*5c90c05cSAndroid Build Coastguard Worker }  // namespace tuple
215*5c90c05cSAndroid Build Coastguard Worker 
216*5c90c05cSAndroid Build Coastguard Worker #if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
217*5c90c05cSAndroid Build Coastguard Worker // Older MSVC doesn't get the reference type correctly for arrays.
218*5c90c05cSAndroid Build Coastguard Worker template <typename R> struct range_reference_type_impl {
219*5c90c05cSAndroid Build Coastguard Worker   using type = decltype(*detail::range_begin(std::declval<R&>()));
220*5c90c05cSAndroid Build Coastguard Worker };
221*5c90c05cSAndroid Build Coastguard Worker 
222*5c90c05cSAndroid Build Coastguard Worker template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
223*5c90c05cSAndroid Build Coastguard Worker   using type = T&;
224*5c90c05cSAndroid Build Coastguard Worker };
225*5c90c05cSAndroid Build Coastguard Worker 
226*5c90c05cSAndroid Build Coastguard Worker template <typename T>
227*5c90c05cSAndroid Build Coastguard Worker using range_reference_type = typename range_reference_type_impl<T>::type;
228*5c90c05cSAndroid Build Coastguard Worker #else
229*5c90c05cSAndroid Build Coastguard Worker template <typename Range>
230*5c90c05cSAndroid Build Coastguard Worker using range_reference_type =
231*5c90c05cSAndroid Build Coastguard Worker     decltype(*detail::range_begin(std::declval<Range&>()));
232*5c90c05cSAndroid Build Coastguard Worker #endif
233*5c90c05cSAndroid Build Coastguard Worker 
234*5c90c05cSAndroid Build Coastguard Worker // We don't use the Range's value_type for anything, but we do need the Range's
235*5c90c05cSAndroid Build Coastguard Worker // reference type, with cv-ref stripped.
236*5c90c05cSAndroid Build Coastguard Worker template <typename Range>
237*5c90c05cSAndroid Build Coastguard Worker using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
238*5c90c05cSAndroid Build Coastguard Worker 
239*5c90c05cSAndroid Build Coastguard Worker template <typename Formatter>
240*5c90c05cSAndroid Build Coastguard Worker FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set)
241*5c90c05cSAndroid Build Coastguard Worker     -> decltype(f.set_debug_format(set)) {
242*5c90c05cSAndroid Build Coastguard Worker   f.set_debug_format(set);
243*5c90c05cSAndroid Build Coastguard Worker }
244*5c90c05cSAndroid Build Coastguard Worker template <typename Formatter>
245*5c90c05cSAndroid Build Coastguard Worker FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {}
246*5c90c05cSAndroid Build Coastguard Worker 
247*5c90c05cSAndroid Build Coastguard Worker template <typename T>
248*5c90c05cSAndroid Build Coastguard Worker struct range_format_kind_
249*5c90c05cSAndroid Build Coastguard Worker     : std::integral_constant<range_format,
250*5c90c05cSAndroid Build Coastguard Worker                              std::is_same<uncvref_type<T>, T>::value
251*5c90c05cSAndroid Build Coastguard Worker                                  ? range_format::disabled
252*5c90c05cSAndroid Build Coastguard Worker                              : is_map<T>::value ? range_format::map
253*5c90c05cSAndroid Build Coastguard Worker                              : is_set<T>::value ? range_format::set
254*5c90c05cSAndroid Build Coastguard Worker                                                 : range_format::sequence> {};
255*5c90c05cSAndroid Build Coastguard Worker 
256*5c90c05cSAndroid Build Coastguard Worker template <range_format K>
257*5c90c05cSAndroid Build Coastguard Worker using range_format_constant = std::integral_constant<range_format, K>;
258*5c90c05cSAndroid Build Coastguard Worker 
259*5c90c05cSAndroid Build Coastguard Worker // These are not generic lambdas for compatibility with C++11.
260*5c90c05cSAndroid Build Coastguard Worker template <typename Char> struct parse_empty_specs {
261*5c90c05cSAndroid Build Coastguard Worker   template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) {
262*5c90c05cSAndroid Build Coastguard Worker     f.parse(ctx);
263*5c90c05cSAndroid Build Coastguard Worker     detail::maybe_set_debug_format(f, true);
264*5c90c05cSAndroid Build Coastguard Worker   }
265*5c90c05cSAndroid Build Coastguard Worker   parse_context<Char>& ctx;
266*5c90c05cSAndroid Build Coastguard Worker };
267*5c90c05cSAndroid Build Coastguard Worker template <typename FormatContext> struct format_tuple_element {
268*5c90c05cSAndroid Build Coastguard Worker   using char_type = typename FormatContext::char_type;
269*5c90c05cSAndroid Build Coastguard Worker 
270*5c90c05cSAndroid Build Coastguard Worker   template <typename T>
271*5c90c05cSAndroid Build Coastguard Worker   void operator()(const formatter<T, char_type>& f, const T& v) {
272*5c90c05cSAndroid Build Coastguard Worker     if (i > 0) ctx.advance_to(detail::copy<char_type>(separator, ctx.out()));
273*5c90c05cSAndroid Build Coastguard Worker     ctx.advance_to(f.format(v, ctx));
274*5c90c05cSAndroid Build Coastguard Worker     ++i;
275*5c90c05cSAndroid Build Coastguard Worker   }
276*5c90c05cSAndroid Build Coastguard Worker 
277*5c90c05cSAndroid Build Coastguard Worker   int i;
278*5c90c05cSAndroid Build Coastguard Worker   FormatContext& ctx;
279*5c90c05cSAndroid Build Coastguard Worker   basic_string_view<char_type> separator;
280*5c90c05cSAndroid Build Coastguard Worker };
281*5c90c05cSAndroid Build Coastguard Worker 
282*5c90c05cSAndroid Build Coastguard Worker }  // namespace detail
283*5c90c05cSAndroid Build Coastguard Worker 
284*5c90c05cSAndroid Build Coastguard Worker template <typename T> struct is_tuple_like {
285*5c90c05cSAndroid Build Coastguard Worker   static constexpr const bool value =
286*5c90c05cSAndroid Build Coastguard Worker       detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
287*5c90c05cSAndroid Build Coastguard Worker };
288*5c90c05cSAndroid Build Coastguard Worker 
289*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename C> struct is_tuple_formattable {
290*5c90c05cSAndroid Build Coastguard Worker   static constexpr const bool value =
291*5c90c05cSAndroid Build Coastguard Worker       detail::is_tuple_formattable_<T, C>::value;
292*5c90c05cSAndroid Build Coastguard Worker };
293*5c90c05cSAndroid Build Coastguard Worker 
294*5c90c05cSAndroid Build Coastguard Worker template <typename Tuple, typename Char>
295*5c90c05cSAndroid Build Coastguard Worker struct formatter<Tuple, Char,
296*5c90c05cSAndroid Build Coastguard Worker                  enable_if_t<fmt::is_tuple_like<Tuple>::value &&
297*5c90c05cSAndroid Build Coastguard Worker                              fmt::is_tuple_formattable<Tuple, Char>::value>> {
298*5c90c05cSAndroid Build Coastguard Worker  private:
299*5c90c05cSAndroid Build Coastguard Worker   decltype(detail::tuple::get_formatters<Tuple, Char>(
300*5c90c05cSAndroid Build Coastguard Worker       detail::tuple_index_sequence<Tuple>())) formatters_;
301*5c90c05cSAndroid Build Coastguard Worker 
302*5c90c05cSAndroid Build Coastguard Worker   basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
303*5c90c05cSAndroid Build Coastguard Worker   basic_string_view<Char> opening_bracket_ =
304*5c90c05cSAndroid Build Coastguard Worker       detail::string_literal<Char, '('>{};
305*5c90c05cSAndroid Build Coastguard Worker   basic_string_view<Char> closing_bracket_ =
306*5c90c05cSAndroid Build Coastguard Worker       detail::string_literal<Char, ')'>{};
307*5c90c05cSAndroid Build Coastguard Worker 
308*5c90c05cSAndroid Build Coastguard Worker  public:
309*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR formatter() {}
310*5c90c05cSAndroid Build Coastguard Worker 
311*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
312*5c90c05cSAndroid Build Coastguard Worker     separator_ = sep;
313*5c90c05cSAndroid Build Coastguard Worker   }
314*5c90c05cSAndroid Build Coastguard Worker 
315*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
316*5c90c05cSAndroid Build Coastguard Worker                                   basic_string_view<Char> close) {
317*5c90c05cSAndroid Build Coastguard Worker     opening_bracket_ = open;
318*5c90c05cSAndroid Build Coastguard Worker     closing_bracket_ = close;
319*5c90c05cSAndroid Build Coastguard Worker   }
320*5c90c05cSAndroid Build Coastguard Worker 
321*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
322*5c90c05cSAndroid Build Coastguard Worker     auto it = ctx.begin();
323*5c90c05cSAndroid Build Coastguard Worker     auto end = ctx.end();
324*5c90c05cSAndroid Build Coastguard Worker     if (it != end && detail::to_ascii(*it) == 'n') {
325*5c90c05cSAndroid Build Coastguard Worker       ++it;
326*5c90c05cSAndroid Build Coastguard Worker       set_brackets({}, {});
327*5c90c05cSAndroid Build Coastguard Worker       set_separator({});
328*5c90c05cSAndroid Build Coastguard Worker     }
329*5c90c05cSAndroid Build Coastguard Worker     if (it != end && *it != '}') report_error("invalid format specifier");
330*5c90c05cSAndroid Build Coastguard Worker     ctx.advance_to(it);
331*5c90c05cSAndroid Build Coastguard Worker     detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx});
332*5c90c05cSAndroid Build Coastguard Worker     return it;
333*5c90c05cSAndroid Build Coastguard Worker   }
334*5c90c05cSAndroid Build Coastguard Worker 
335*5c90c05cSAndroid Build Coastguard Worker   template <typename FormatContext>
336*5c90c05cSAndroid Build Coastguard Worker   auto format(const Tuple& value, FormatContext& ctx) const
337*5c90c05cSAndroid Build Coastguard Worker       -> decltype(ctx.out()) {
338*5c90c05cSAndroid Build Coastguard Worker     ctx.advance_to(detail::copy<Char>(opening_bracket_, ctx.out()));
339*5c90c05cSAndroid Build Coastguard Worker     detail::for_each2(
340*5c90c05cSAndroid Build Coastguard Worker         formatters_, value,
341*5c90c05cSAndroid Build Coastguard Worker         detail::format_tuple_element<FormatContext>{0, ctx, separator_});
342*5c90c05cSAndroid Build Coastguard Worker     return detail::copy<Char>(closing_bracket_, ctx.out());
343*5c90c05cSAndroid Build Coastguard Worker   }
344*5c90c05cSAndroid Build Coastguard Worker };
345*5c90c05cSAndroid Build Coastguard Worker 
346*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename Char> struct is_range {
347*5c90c05cSAndroid Build Coastguard Worker   static constexpr const bool value =
348*5c90c05cSAndroid Build Coastguard Worker       detail::is_range_<T>::value && !detail::has_to_string_view<T>::value;
349*5c90c05cSAndroid Build Coastguard Worker };
350*5c90c05cSAndroid Build Coastguard Worker 
351*5c90c05cSAndroid Build Coastguard Worker namespace detail {
352*5c90c05cSAndroid Build Coastguard Worker 
353*5c90c05cSAndroid Build Coastguard Worker template <typename Char, typename Element>
354*5c90c05cSAndroid Build Coastguard Worker using range_formatter_type = formatter<remove_cvref_t<Element>, Char>;
355*5c90c05cSAndroid Build Coastguard Worker 
356*5c90c05cSAndroid Build Coastguard Worker template <typename R>
357*5c90c05cSAndroid Build Coastguard Worker using maybe_const_range =
358*5c90c05cSAndroid Build Coastguard Worker     conditional_t<has_const_begin_end<R>::value, const R, R>;
359*5c90c05cSAndroid Build Coastguard Worker 
360*5c90c05cSAndroid Build Coastguard Worker // Workaround a bug in MSVC 2015 and earlier.
361*5c90c05cSAndroid Build Coastguard Worker #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
362*5c90c05cSAndroid Build Coastguard Worker template <typename R, typename Char>
363*5c90c05cSAndroid Build Coastguard Worker struct is_formattable_delayed
364*5c90c05cSAndroid Build Coastguard Worker     : is_formattable<uncvref_type<maybe_const_range<R>>, Char> {};
365*5c90c05cSAndroid Build Coastguard Worker #endif
366*5c90c05cSAndroid Build Coastguard Worker }  // namespace detail
367*5c90c05cSAndroid Build Coastguard Worker 
368*5c90c05cSAndroid Build Coastguard Worker template <typename...> struct conjunction : std::true_type {};
369*5c90c05cSAndroid Build Coastguard Worker template <typename P> struct conjunction<P> : P {};
370*5c90c05cSAndroid Build Coastguard Worker template <typename P1, typename... Pn>
371*5c90c05cSAndroid Build Coastguard Worker struct conjunction<P1, Pn...>
372*5c90c05cSAndroid Build Coastguard Worker     : conditional_t<bool(P1::value), conjunction<Pn...>, P1> {};
373*5c90c05cSAndroid Build Coastguard Worker 
374*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename Char, typename Enable = void>
375*5c90c05cSAndroid Build Coastguard Worker struct range_formatter;
376*5c90c05cSAndroid Build Coastguard Worker 
377*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename Char>
378*5c90c05cSAndroid Build Coastguard Worker struct range_formatter<
379*5c90c05cSAndroid Build Coastguard Worker     T, Char,
380*5c90c05cSAndroid Build Coastguard Worker     enable_if_t<conjunction<std::is_same<T, remove_cvref_t<T>>,
381*5c90c05cSAndroid Build Coastguard Worker                             is_formattable<T, Char>>::value>> {
382*5c90c05cSAndroid Build Coastguard Worker  private:
383*5c90c05cSAndroid Build Coastguard Worker   detail::range_formatter_type<Char, T> underlying_;
384*5c90c05cSAndroid Build Coastguard Worker   basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
385*5c90c05cSAndroid Build Coastguard Worker   basic_string_view<Char> opening_bracket_ =
386*5c90c05cSAndroid Build Coastguard Worker       detail::string_literal<Char, '['>{};
387*5c90c05cSAndroid Build Coastguard Worker   basic_string_view<Char> closing_bracket_ =
388*5c90c05cSAndroid Build Coastguard Worker       detail::string_literal<Char, ']'>{};
389*5c90c05cSAndroid Build Coastguard Worker   bool is_debug = false;
390*5c90c05cSAndroid Build Coastguard Worker 
391*5c90c05cSAndroid Build Coastguard Worker   template <typename Output, typename It, typename Sentinel, typename U = T,
392*5c90c05cSAndroid Build Coastguard Worker             FMT_ENABLE_IF(std::is_same<U, Char>::value)>
393*5c90c05cSAndroid Build Coastguard Worker   auto write_debug_string(Output& out, It it, Sentinel end) const -> Output {
394*5c90c05cSAndroid Build Coastguard Worker     auto buf = basic_memory_buffer<Char>();
395*5c90c05cSAndroid Build Coastguard Worker     for (; it != end; ++it) buf.push_back(*it);
396*5c90c05cSAndroid Build Coastguard Worker     auto specs = format_specs();
397*5c90c05cSAndroid Build Coastguard Worker     specs.set_type(presentation_type::debug);
398*5c90c05cSAndroid Build Coastguard Worker     return detail::write<Char>(
399*5c90c05cSAndroid Build Coastguard Worker         out, basic_string_view<Char>(buf.data(), buf.size()), specs);
400*5c90c05cSAndroid Build Coastguard Worker   }
401*5c90c05cSAndroid Build Coastguard Worker 
402*5c90c05cSAndroid Build Coastguard Worker   template <typename Output, typename It, typename Sentinel, typename U = T,
403*5c90c05cSAndroid Build Coastguard Worker             FMT_ENABLE_IF(!std::is_same<U, Char>::value)>
404*5c90c05cSAndroid Build Coastguard Worker   auto write_debug_string(Output& out, It, Sentinel) const -> Output {
405*5c90c05cSAndroid Build Coastguard Worker     return out;
406*5c90c05cSAndroid Build Coastguard Worker   }
407*5c90c05cSAndroid Build Coastguard Worker 
408*5c90c05cSAndroid Build Coastguard Worker  public:
409*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR range_formatter() {}
410*5c90c05cSAndroid Build Coastguard Worker 
411*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& {
412*5c90c05cSAndroid Build Coastguard Worker     return underlying_;
413*5c90c05cSAndroid Build Coastguard Worker   }
414*5c90c05cSAndroid Build Coastguard Worker 
415*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
416*5c90c05cSAndroid Build Coastguard Worker     separator_ = sep;
417*5c90c05cSAndroid Build Coastguard Worker   }
418*5c90c05cSAndroid Build Coastguard Worker 
419*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
420*5c90c05cSAndroid Build Coastguard Worker                                   basic_string_view<Char> close) {
421*5c90c05cSAndroid Build Coastguard Worker     opening_bracket_ = open;
422*5c90c05cSAndroid Build Coastguard Worker     closing_bracket_ = close;
423*5c90c05cSAndroid Build Coastguard Worker   }
424*5c90c05cSAndroid Build Coastguard Worker 
425*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
426*5c90c05cSAndroid Build Coastguard Worker     auto it = ctx.begin();
427*5c90c05cSAndroid Build Coastguard Worker     auto end = ctx.end();
428*5c90c05cSAndroid Build Coastguard Worker     detail::maybe_set_debug_format(underlying_, true);
429*5c90c05cSAndroid Build Coastguard Worker     if (it == end) return underlying_.parse(ctx);
430*5c90c05cSAndroid Build Coastguard Worker 
431*5c90c05cSAndroid Build Coastguard Worker     switch (detail::to_ascii(*it)) {
432*5c90c05cSAndroid Build Coastguard Worker     case 'n':
433*5c90c05cSAndroid Build Coastguard Worker       set_brackets({}, {});
434*5c90c05cSAndroid Build Coastguard Worker       ++it;
435*5c90c05cSAndroid Build Coastguard Worker       break;
436*5c90c05cSAndroid Build Coastguard Worker     case '?':
437*5c90c05cSAndroid Build Coastguard Worker       is_debug = true;
438*5c90c05cSAndroid Build Coastguard Worker       set_brackets({}, {});
439*5c90c05cSAndroid Build Coastguard Worker       ++it;
440*5c90c05cSAndroid Build Coastguard Worker       if (it == end || *it != 's') report_error("invalid format specifier");
441*5c90c05cSAndroid Build Coastguard Worker       FMT_FALLTHROUGH;
442*5c90c05cSAndroid Build Coastguard Worker     case 's':
443*5c90c05cSAndroid Build Coastguard Worker       if (!std::is_same<T, Char>::value)
444*5c90c05cSAndroid Build Coastguard Worker         report_error("invalid format specifier");
445*5c90c05cSAndroid Build Coastguard Worker       if (!is_debug) {
446*5c90c05cSAndroid Build Coastguard Worker         set_brackets(detail::string_literal<Char, '"'>{},
447*5c90c05cSAndroid Build Coastguard Worker                      detail::string_literal<Char, '"'>{});
448*5c90c05cSAndroid Build Coastguard Worker         set_separator({});
449*5c90c05cSAndroid Build Coastguard Worker         detail::maybe_set_debug_format(underlying_, false);
450*5c90c05cSAndroid Build Coastguard Worker       }
451*5c90c05cSAndroid Build Coastguard Worker       ++it;
452*5c90c05cSAndroid Build Coastguard Worker       return it;
453*5c90c05cSAndroid Build Coastguard Worker     }
454*5c90c05cSAndroid Build Coastguard Worker 
455*5c90c05cSAndroid Build Coastguard Worker     if (it != end && *it != '}') {
456*5c90c05cSAndroid Build Coastguard Worker       if (*it != ':') report_error("invalid format specifier");
457*5c90c05cSAndroid Build Coastguard Worker       detail::maybe_set_debug_format(underlying_, false);
458*5c90c05cSAndroid Build Coastguard Worker       ++it;
459*5c90c05cSAndroid Build Coastguard Worker     }
460*5c90c05cSAndroid Build Coastguard Worker 
461*5c90c05cSAndroid Build Coastguard Worker     ctx.advance_to(it);
462*5c90c05cSAndroid Build Coastguard Worker     return underlying_.parse(ctx);
463*5c90c05cSAndroid Build Coastguard Worker   }
464*5c90c05cSAndroid Build Coastguard Worker 
465*5c90c05cSAndroid Build Coastguard Worker   template <typename R, typename FormatContext>
466*5c90c05cSAndroid Build Coastguard Worker   auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
467*5c90c05cSAndroid Build Coastguard Worker     auto out = ctx.out();
468*5c90c05cSAndroid Build Coastguard Worker     auto it = detail::range_begin(range);
469*5c90c05cSAndroid Build Coastguard Worker     auto end = detail::range_end(range);
470*5c90c05cSAndroid Build Coastguard Worker     if (is_debug) return write_debug_string(out, std::move(it), end);
471*5c90c05cSAndroid Build Coastguard Worker 
472*5c90c05cSAndroid Build Coastguard Worker     out = detail::copy<Char>(opening_bracket_, out);
473*5c90c05cSAndroid Build Coastguard Worker     int i = 0;
474*5c90c05cSAndroid Build Coastguard Worker     for (; it != end; ++it) {
475*5c90c05cSAndroid Build Coastguard Worker       if (i > 0) out = detail::copy<Char>(separator_, out);
476*5c90c05cSAndroid Build Coastguard Worker       ctx.advance_to(out);
477*5c90c05cSAndroid Build Coastguard Worker       auto&& item = *it;  // Need an lvalue
478*5c90c05cSAndroid Build Coastguard Worker       out = underlying_.format(item, ctx);
479*5c90c05cSAndroid Build Coastguard Worker       ++i;
480*5c90c05cSAndroid Build Coastguard Worker     }
481*5c90c05cSAndroid Build Coastguard Worker     out = detail::copy<Char>(closing_bracket_, out);
482*5c90c05cSAndroid Build Coastguard Worker     return out;
483*5c90c05cSAndroid Build Coastguard Worker   }
484*5c90c05cSAndroid Build Coastguard Worker };
485*5c90c05cSAndroid Build Coastguard Worker 
486*5c90c05cSAndroid Build Coastguard Worker FMT_EXPORT
487*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename Char, typename Enable = void>
488*5c90c05cSAndroid Build Coastguard Worker struct range_format_kind
489*5c90c05cSAndroid Build Coastguard Worker     : conditional_t<
490*5c90c05cSAndroid Build Coastguard Worker           is_range<T, Char>::value, detail::range_format_kind_<T>,
491*5c90c05cSAndroid Build Coastguard Worker           std::integral_constant<range_format, range_format::disabled>> {};
492*5c90c05cSAndroid Build Coastguard Worker 
493*5c90c05cSAndroid Build Coastguard Worker template <typename R, typename Char>
494*5c90c05cSAndroid Build Coastguard Worker struct formatter<
495*5c90c05cSAndroid Build Coastguard Worker     R, Char,
496*5c90c05cSAndroid Build Coastguard Worker     enable_if_t<conjunction<
497*5c90c05cSAndroid Build Coastguard Worker         bool_constant<
498*5c90c05cSAndroid Build Coastguard Worker             range_format_kind<R, Char>::value != range_format::disabled &&
499*5c90c05cSAndroid Build Coastguard Worker             range_format_kind<R, Char>::value != range_format::map &&
500*5c90c05cSAndroid Build Coastguard Worker             range_format_kind<R, Char>::value != range_format::string &&
501*5c90c05cSAndroid Build Coastguard Worker             range_format_kind<R, Char>::value != range_format::debug_string>
502*5c90c05cSAndroid Build Coastguard Worker // Workaround a bug in MSVC 2015 and earlier.
503*5c90c05cSAndroid Build Coastguard Worker #if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
504*5c90c05cSAndroid Build Coastguard Worker         ,
505*5c90c05cSAndroid Build Coastguard Worker         detail::is_formattable_delayed<R, Char>
506*5c90c05cSAndroid Build Coastguard Worker #endif
507*5c90c05cSAndroid Build Coastguard Worker         >::value>> {
508*5c90c05cSAndroid Build Coastguard Worker  private:
509*5c90c05cSAndroid Build Coastguard Worker   using range_type = detail::maybe_const_range<R>;
510*5c90c05cSAndroid Build Coastguard Worker   range_formatter<detail::uncvref_type<range_type>, Char> range_formatter_;
511*5c90c05cSAndroid Build Coastguard Worker 
512*5c90c05cSAndroid Build Coastguard Worker  public:
513*5c90c05cSAndroid Build Coastguard Worker   using nonlocking = void;
514*5c90c05cSAndroid Build Coastguard Worker 
515*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR formatter() {
516*5c90c05cSAndroid Build Coastguard Worker     if (detail::const_check(range_format_kind<R, Char>::value !=
517*5c90c05cSAndroid Build Coastguard Worker                             range_format::set))
518*5c90c05cSAndroid Build Coastguard Worker       return;
519*5c90c05cSAndroid Build Coastguard Worker     range_formatter_.set_brackets(detail::string_literal<Char, '{'>{},
520*5c90c05cSAndroid Build Coastguard Worker                                   detail::string_literal<Char, '}'>{});
521*5c90c05cSAndroid Build Coastguard Worker   }
522*5c90c05cSAndroid Build Coastguard Worker 
523*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
524*5c90c05cSAndroid Build Coastguard Worker     return range_formatter_.parse(ctx);
525*5c90c05cSAndroid Build Coastguard Worker   }
526*5c90c05cSAndroid Build Coastguard Worker 
527*5c90c05cSAndroid Build Coastguard Worker   template <typename FormatContext>
528*5c90c05cSAndroid Build Coastguard Worker   auto format(range_type& range, FormatContext& ctx) const
529*5c90c05cSAndroid Build Coastguard Worker       -> decltype(ctx.out()) {
530*5c90c05cSAndroid Build Coastguard Worker     return range_formatter_.format(range, ctx);
531*5c90c05cSAndroid Build Coastguard Worker   }
532*5c90c05cSAndroid Build Coastguard Worker };
533*5c90c05cSAndroid Build Coastguard Worker 
534*5c90c05cSAndroid Build Coastguard Worker // A map formatter.
535*5c90c05cSAndroid Build Coastguard Worker template <typename R, typename Char>
536*5c90c05cSAndroid Build Coastguard Worker struct formatter<
537*5c90c05cSAndroid Build Coastguard Worker     R, Char,
538*5c90c05cSAndroid Build Coastguard Worker     enable_if_t<range_format_kind<R, Char>::value == range_format::map>> {
539*5c90c05cSAndroid Build Coastguard Worker  private:
540*5c90c05cSAndroid Build Coastguard Worker   using map_type = detail::maybe_const_range<R>;
541*5c90c05cSAndroid Build Coastguard Worker   using element_type = detail::uncvref_type<map_type>;
542*5c90c05cSAndroid Build Coastguard Worker 
543*5c90c05cSAndroid Build Coastguard Worker   decltype(detail::tuple::get_formatters<element_type, Char>(
544*5c90c05cSAndroid Build Coastguard Worker       detail::tuple_index_sequence<element_type>())) formatters_;
545*5c90c05cSAndroid Build Coastguard Worker   bool no_delimiters_ = false;
546*5c90c05cSAndroid Build Coastguard Worker 
547*5c90c05cSAndroid Build Coastguard Worker  public:
548*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR formatter() {}
549*5c90c05cSAndroid Build Coastguard Worker 
550*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
551*5c90c05cSAndroid Build Coastguard Worker     auto it = ctx.begin();
552*5c90c05cSAndroid Build Coastguard Worker     auto end = ctx.end();
553*5c90c05cSAndroid Build Coastguard Worker     if (it != end) {
554*5c90c05cSAndroid Build Coastguard Worker       if (detail::to_ascii(*it) == 'n') {
555*5c90c05cSAndroid Build Coastguard Worker         no_delimiters_ = true;
556*5c90c05cSAndroid Build Coastguard Worker         ++it;
557*5c90c05cSAndroid Build Coastguard Worker       }
558*5c90c05cSAndroid Build Coastguard Worker       if (it != end && *it != '}') {
559*5c90c05cSAndroid Build Coastguard Worker         if (*it != ':') report_error("invalid format specifier");
560*5c90c05cSAndroid Build Coastguard Worker         ++it;
561*5c90c05cSAndroid Build Coastguard Worker       }
562*5c90c05cSAndroid Build Coastguard Worker       ctx.advance_to(it);
563*5c90c05cSAndroid Build Coastguard Worker     }
564*5c90c05cSAndroid Build Coastguard Worker     detail::for_each(formatters_, detail::parse_empty_specs<Char>{ctx});
565*5c90c05cSAndroid Build Coastguard Worker     return it;
566*5c90c05cSAndroid Build Coastguard Worker   }
567*5c90c05cSAndroid Build Coastguard Worker 
568*5c90c05cSAndroid Build Coastguard Worker   template <typename FormatContext>
569*5c90c05cSAndroid Build Coastguard Worker   auto format(map_type& map, FormatContext& ctx) const -> decltype(ctx.out()) {
570*5c90c05cSAndroid Build Coastguard Worker     auto out = ctx.out();
571*5c90c05cSAndroid Build Coastguard Worker     basic_string_view<Char> open = detail::string_literal<Char, '{'>{};
572*5c90c05cSAndroid Build Coastguard Worker     if (!no_delimiters_) out = detail::copy<Char>(open, out);
573*5c90c05cSAndroid Build Coastguard Worker     int i = 0;
574*5c90c05cSAndroid Build Coastguard Worker     basic_string_view<Char> sep = detail::string_literal<Char, ',', ' '>{};
575*5c90c05cSAndroid Build Coastguard Worker     for (auto&& value : map) {
576*5c90c05cSAndroid Build Coastguard Worker       if (i > 0) out = detail::copy<Char>(sep, out);
577*5c90c05cSAndroid Build Coastguard Worker       ctx.advance_to(out);
578*5c90c05cSAndroid Build Coastguard Worker       detail::for_each2(formatters_, value,
579*5c90c05cSAndroid Build Coastguard Worker                         detail::format_tuple_element<FormatContext>{
580*5c90c05cSAndroid Build Coastguard Worker                             0, ctx, detail::string_literal<Char, ':', ' '>{}});
581*5c90c05cSAndroid Build Coastguard Worker       ++i;
582*5c90c05cSAndroid Build Coastguard Worker     }
583*5c90c05cSAndroid Build Coastguard Worker     basic_string_view<Char> close = detail::string_literal<Char, '}'>{};
584*5c90c05cSAndroid Build Coastguard Worker     if (!no_delimiters_) out = detail::copy<Char>(close, out);
585*5c90c05cSAndroid Build Coastguard Worker     return out;
586*5c90c05cSAndroid Build Coastguard Worker   }
587*5c90c05cSAndroid Build Coastguard Worker };
588*5c90c05cSAndroid Build Coastguard Worker 
589*5c90c05cSAndroid Build Coastguard Worker // A (debug_)string formatter.
590*5c90c05cSAndroid Build Coastguard Worker template <typename R, typename Char>
591*5c90c05cSAndroid Build Coastguard Worker struct formatter<
592*5c90c05cSAndroid Build Coastguard Worker     R, Char,
593*5c90c05cSAndroid Build Coastguard Worker     enable_if_t<range_format_kind<R, Char>::value == range_format::string ||
594*5c90c05cSAndroid Build Coastguard Worker                 range_format_kind<R, Char>::value ==
595*5c90c05cSAndroid Build Coastguard Worker                     range_format::debug_string>> {
596*5c90c05cSAndroid Build Coastguard Worker  private:
597*5c90c05cSAndroid Build Coastguard Worker   using range_type = detail::maybe_const_range<R>;
598*5c90c05cSAndroid Build Coastguard Worker   using string_type =
599*5c90c05cSAndroid Build Coastguard Worker       conditional_t<std::is_constructible<
600*5c90c05cSAndroid Build Coastguard Worker                         detail::std_string_view<Char>,
601*5c90c05cSAndroid Build Coastguard Worker                         decltype(detail::range_begin(std::declval<R>())),
602*5c90c05cSAndroid Build Coastguard Worker                         decltype(detail::range_end(std::declval<R>()))>::value,
603*5c90c05cSAndroid Build Coastguard Worker                     detail::std_string_view<Char>, std::basic_string<Char>>;
604*5c90c05cSAndroid Build Coastguard Worker 
605*5c90c05cSAndroid Build Coastguard Worker   formatter<string_type, Char> underlying_;
606*5c90c05cSAndroid Build Coastguard Worker 
607*5c90c05cSAndroid Build Coastguard Worker  public:
608*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
609*5c90c05cSAndroid Build Coastguard Worker     return underlying_.parse(ctx);
610*5c90c05cSAndroid Build Coastguard Worker   }
611*5c90c05cSAndroid Build Coastguard Worker 
612*5c90c05cSAndroid Build Coastguard Worker   template <typename FormatContext>
613*5c90c05cSAndroid Build Coastguard Worker   auto format(range_type& range, FormatContext& ctx) const
614*5c90c05cSAndroid Build Coastguard Worker       -> decltype(ctx.out()) {
615*5c90c05cSAndroid Build Coastguard Worker     auto out = ctx.out();
616*5c90c05cSAndroid Build Coastguard Worker     if (detail::const_check(range_format_kind<R, Char>::value ==
617*5c90c05cSAndroid Build Coastguard Worker                             range_format::debug_string))
618*5c90c05cSAndroid Build Coastguard Worker       *out++ = '"';
619*5c90c05cSAndroid Build Coastguard Worker     out = underlying_.format(
620*5c90c05cSAndroid Build Coastguard Worker         string_type{detail::range_begin(range), detail::range_end(range)}, ctx);
621*5c90c05cSAndroid Build Coastguard Worker     if (detail::const_check(range_format_kind<R, Char>::value ==
622*5c90c05cSAndroid Build Coastguard Worker                             range_format::debug_string))
623*5c90c05cSAndroid Build Coastguard Worker       *out++ = '"';
624*5c90c05cSAndroid Build Coastguard Worker     return out;
625*5c90c05cSAndroid Build Coastguard Worker   }
626*5c90c05cSAndroid Build Coastguard Worker };
627*5c90c05cSAndroid Build Coastguard Worker 
628*5c90c05cSAndroid Build Coastguard Worker template <typename It, typename Sentinel, typename Char = char>
629*5c90c05cSAndroid Build Coastguard Worker struct join_view : detail::view {
630*5c90c05cSAndroid Build Coastguard Worker   It begin;
631*5c90c05cSAndroid Build Coastguard Worker   Sentinel end;
632*5c90c05cSAndroid Build Coastguard Worker   basic_string_view<Char> sep;
633*5c90c05cSAndroid Build Coastguard Worker 
634*5c90c05cSAndroid Build Coastguard Worker   join_view(It b, Sentinel e, basic_string_view<Char> s)
635*5c90c05cSAndroid Build Coastguard Worker       : begin(std::move(b)), end(e), sep(s) {}
636*5c90c05cSAndroid Build Coastguard Worker };
637*5c90c05cSAndroid Build Coastguard Worker 
638*5c90c05cSAndroid Build Coastguard Worker template <typename It, typename Sentinel, typename Char>
639*5c90c05cSAndroid Build Coastguard Worker struct formatter<join_view<It, Sentinel, Char>, Char> {
640*5c90c05cSAndroid Build Coastguard Worker  private:
641*5c90c05cSAndroid Build Coastguard Worker   using value_type =
642*5c90c05cSAndroid Build Coastguard Worker #ifdef __cpp_lib_ranges
643*5c90c05cSAndroid Build Coastguard Worker       std::iter_value_t<It>;
644*5c90c05cSAndroid Build Coastguard Worker #else
645*5c90c05cSAndroid Build Coastguard Worker       typename std::iterator_traits<It>::value_type;
646*5c90c05cSAndroid Build Coastguard Worker #endif
647*5c90c05cSAndroid Build Coastguard Worker   formatter<remove_cvref_t<value_type>, Char> value_formatter_;
648*5c90c05cSAndroid Build Coastguard Worker 
649*5c90c05cSAndroid Build Coastguard Worker   using view_ref = conditional_t<std::is_copy_constructible<It>::value,
650*5c90c05cSAndroid Build Coastguard Worker                                  const join_view<It, Sentinel, Char>&,
651*5c90c05cSAndroid Build Coastguard Worker                                  join_view<It, Sentinel, Char>&&>;
652*5c90c05cSAndroid Build Coastguard Worker 
653*5c90c05cSAndroid Build Coastguard Worker  public:
654*5c90c05cSAndroid Build Coastguard Worker   using nonlocking = void;
655*5c90c05cSAndroid Build Coastguard Worker 
656*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
657*5c90c05cSAndroid Build Coastguard Worker     return value_formatter_.parse(ctx);
658*5c90c05cSAndroid Build Coastguard Worker   }
659*5c90c05cSAndroid Build Coastguard Worker 
660*5c90c05cSAndroid Build Coastguard Worker   template <typename FormatContext>
661*5c90c05cSAndroid Build Coastguard Worker   auto format(view_ref& value, FormatContext& ctx) const
662*5c90c05cSAndroid Build Coastguard Worker       -> decltype(ctx.out()) {
663*5c90c05cSAndroid Build Coastguard Worker     auto it = std::forward<view_ref>(value).begin;
664*5c90c05cSAndroid Build Coastguard Worker     auto out = ctx.out();
665*5c90c05cSAndroid Build Coastguard Worker     if (it == value.end) return out;
666*5c90c05cSAndroid Build Coastguard Worker     out = value_formatter_.format(*it, ctx);
667*5c90c05cSAndroid Build Coastguard Worker     ++it;
668*5c90c05cSAndroid Build Coastguard Worker     while (it != value.end) {
669*5c90c05cSAndroid Build Coastguard Worker       out = detail::copy<Char>(value.sep.begin(), value.sep.end(), out);
670*5c90c05cSAndroid Build Coastguard Worker       ctx.advance_to(out);
671*5c90c05cSAndroid Build Coastguard Worker       out = value_formatter_.format(*it, ctx);
672*5c90c05cSAndroid Build Coastguard Worker       ++it;
673*5c90c05cSAndroid Build Coastguard Worker     }
674*5c90c05cSAndroid Build Coastguard Worker     return out;
675*5c90c05cSAndroid Build Coastguard Worker   }
676*5c90c05cSAndroid Build Coastguard Worker };
677*5c90c05cSAndroid Build Coastguard Worker 
678*5c90c05cSAndroid Build Coastguard Worker /// Returns a view that formats the iterator range `[begin, end)` with elements
679*5c90c05cSAndroid Build Coastguard Worker /// separated by `sep`.
680*5c90c05cSAndroid Build Coastguard Worker template <typename It, typename Sentinel>
681*5c90c05cSAndroid Build Coastguard Worker auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
682*5c90c05cSAndroid Build Coastguard Worker   return {std::move(begin), end, sep};
683*5c90c05cSAndroid Build Coastguard Worker }
684*5c90c05cSAndroid Build Coastguard Worker 
685*5c90c05cSAndroid Build Coastguard Worker /**
686*5c90c05cSAndroid Build Coastguard Worker  * Returns a view that formats `range` with elements separated by `sep`.
687*5c90c05cSAndroid Build Coastguard Worker  *
688*5c90c05cSAndroid Build Coastguard Worker  * **Example**:
689*5c90c05cSAndroid Build Coastguard Worker  *
690*5c90c05cSAndroid Build Coastguard Worker  *     auto v = std::vector<int>{1, 2, 3};
691*5c90c05cSAndroid Build Coastguard Worker  *     fmt::print("{}", fmt::join(v, ", "));
692*5c90c05cSAndroid Build Coastguard Worker  *     // Output: 1, 2, 3
693*5c90c05cSAndroid Build Coastguard Worker  *
694*5c90c05cSAndroid Build Coastguard Worker  * `fmt::join` applies passed format specifiers to the range elements:
695*5c90c05cSAndroid Build Coastguard Worker  *
696*5c90c05cSAndroid Build Coastguard Worker  *     fmt::print("{:02}", fmt::join(v, ", "));
697*5c90c05cSAndroid Build Coastguard Worker  *     // Output: 01, 02, 03
698*5c90c05cSAndroid Build Coastguard Worker  */
699*5c90c05cSAndroid Build Coastguard Worker template <typename Range>
700*5c90c05cSAndroid Build Coastguard Worker auto join(Range&& r, string_view sep)
701*5c90c05cSAndroid Build Coastguard Worker     -> join_view<decltype(detail::range_begin(r)),
702*5c90c05cSAndroid Build Coastguard Worker                  decltype(detail::range_end(r))> {
703*5c90c05cSAndroid Build Coastguard Worker   return {detail::range_begin(r), detail::range_end(r), sep};
704*5c90c05cSAndroid Build Coastguard Worker }
705*5c90c05cSAndroid Build Coastguard Worker 
706*5c90c05cSAndroid Build Coastguard Worker template <typename Char, typename... T> struct tuple_join_view : detail::view {
707*5c90c05cSAndroid Build Coastguard Worker   const std::tuple<T...>& tuple;
708*5c90c05cSAndroid Build Coastguard Worker   basic_string_view<Char> sep;
709*5c90c05cSAndroid Build Coastguard Worker 
710*5c90c05cSAndroid Build Coastguard Worker   tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s)
711*5c90c05cSAndroid Build Coastguard Worker       : tuple(t), sep{s} {}
712*5c90c05cSAndroid Build Coastguard Worker };
713*5c90c05cSAndroid Build Coastguard Worker 
714*5c90c05cSAndroid Build Coastguard Worker // Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
715*5c90c05cSAndroid Build Coastguard Worker // support in tuple_join. It is disabled by default because of issues with
716*5c90c05cSAndroid Build Coastguard Worker // the dynamic width and precision.
717*5c90c05cSAndroid Build Coastguard Worker #ifndef FMT_TUPLE_JOIN_SPECIFIERS
718*5c90c05cSAndroid Build Coastguard Worker #  define FMT_TUPLE_JOIN_SPECIFIERS 0
719*5c90c05cSAndroid Build Coastguard Worker #endif
720*5c90c05cSAndroid Build Coastguard Worker 
721*5c90c05cSAndroid Build Coastguard Worker template <typename Char, typename... T>
722*5c90c05cSAndroid Build Coastguard Worker struct formatter<tuple_join_view<Char, T...>, Char> {
723*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
724*5c90c05cSAndroid Build Coastguard Worker     return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>());
725*5c90c05cSAndroid Build Coastguard Worker   }
726*5c90c05cSAndroid Build Coastguard Worker 
727*5c90c05cSAndroid Build Coastguard Worker   template <typename FormatContext>
728*5c90c05cSAndroid Build Coastguard Worker   auto format(const tuple_join_view<Char, T...>& value,
729*5c90c05cSAndroid Build Coastguard Worker               FormatContext& ctx) const -> typename FormatContext::iterator {
730*5c90c05cSAndroid Build Coastguard Worker     return do_format(value, ctx,
731*5c90c05cSAndroid Build Coastguard Worker                      std::integral_constant<size_t, sizeof...(T)>());
732*5c90c05cSAndroid Build Coastguard Worker   }
733*5c90c05cSAndroid Build Coastguard Worker 
734*5c90c05cSAndroid Build Coastguard Worker  private:
735*5c90c05cSAndroid Build Coastguard Worker   std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_;
736*5c90c05cSAndroid Build Coastguard Worker 
737*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx,
738*5c90c05cSAndroid Build Coastguard Worker                               std::integral_constant<size_t, 0>)
739*5c90c05cSAndroid Build Coastguard Worker       -> const Char* {
740*5c90c05cSAndroid Build Coastguard Worker     return ctx.begin();
741*5c90c05cSAndroid Build Coastguard Worker   }
742*5c90c05cSAndroid Build Coastguard Worker 
743*5c90c05cSAndroid Build Coastguard Worker   template <size_t N>
744*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto do_parse(parse_context<Char>& ctx,
745*5c90c05cSAndroid Build Coastguard Worker                               std::integral_constant<size_t, N>)
746*5c90c05cSAndroid Build Coastguard Worker       -> const Char* {
747*5c90c05cSAndroid Build Coastguard Worker     auto end = ctx.begin();
748*5c90c05cSAndroid Build Coastguard Worker #if FMT_TUPLE_JOIN_SPECIFIERS
749*5c90c05cSAndroid Build Coastguard Worker     end = std::get<sizeof...(T) - N>(formatters_).parse(ctx);
750*5c90c05cSAndroid Build Coastguard Worker     if (N > 1) {
751*5c90c05cSAndroid Build Coastguard Worker       auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
752*5c90c05cSAndroid Build Coastguard Worker       if (end != end1)
753*5c90c05cSAndroid Build Coastguard Worker         report_error("incompatible format specs for tuple elements");
754*5c90c05cSAndroid Build Coastguard Worker     }
755*5c90c05cSAndroid Build Coastguard Worker #endif
756*5c90c05cSAndroid Build Coastguard Worker     return end;
757*5c90c05cSAndroid Build Coastguard Worker   }
758*5c90c05cSAndroid Build Coastguard Worker 
759*5c90c05cSAndroid Build Coastguard Worker   template <typename FormatContext>
760*5c90c05cSAndroid Build Coastguard Worker   auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx,
761*5c90c05cSAndroid Build Coastguard Worker                  std::integral_constant<size_t, 0>) const ->
762*5c90c05cSAndroid Build Coastguard Worker       typename FormatContext::iterator {
763*5c90c05cSAndroid Build Coastguard Worker     return ctx.out();
764*5c90c05cSAndroid Build Coastguard Worker   }
765*5c90c05cSAndroid Build Coastguard Worker 
766*5c90c05cSAndroid Build Coastguard Worker   template <typename FormatContext, size_t N>
767*5c90c05cSAndroid Build Coastguard Worker   auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
768*5c90c05cSAndroid Build Coastguard Worker                  std::integral_constant<size_t, N>) const ->
769*5c90c05cSAndroid Build Coastguard Worker       typename FormatContext::iterator {
770*5c90c05cSAndroid Build Coastguard Worker     auto out = std::get<sizeof...(T) - N>(formatters_)
771*5c90c05cSAndroid Build Coastguard Worker                    .format(std::get<sizeof...(T) - N>(value.tuple), ctx);
772*5c90c05cSAndroid Build Coastguard Worker     if (N <= 1) return out;
773*5c90c05cSAndroid Build Coastguard Worker     out = detail::copy<Char>(value.sep, out);
774*5c90c05cSAndroid Build Coastguard Worker     ctx.advance_to(out);
775*5c90c05cSAndroid Build Coastguard Worker     return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
776*5c90c05cSAndroid Build Coastguard Worker   }
777*5c90c05cSAndroid Build Coastguard Worker };
778*5c90c05cSAndroid Build Coastguard Worker 
779*5c90c05cSAndroid Build Coastguard Worker namespace detail {
780*5c90c05cSAndroid Build Coastguard Worker // Check if T has an interface like a container adaptor (e.g. std::stack,
781*5c90c05cSAndroid Build Coastguard Worker // std::queue, std::priority_queue).
782*5c90c05cSAndroid Build Coastguard Worker template <typename T> class is_container_adaptor_like {
783*5c90c05cSAndroid Build Coastguard Worker   template <typename U> static auto check(U* p) -> typename U::container_type;
784*5c90c05cSAndroid Build Coastguard Worker   template <typename> static void check(...);
785*5c90c05cSAndroid Build Coastguard Worker 
786*5c90c05cSAndroid Build Coastguard Worker  public:
787*5c90c05cSAndroid Build Coastguard Worker   static constexpr const bool value =
788*5c90c05cSAndroid Build Coastguard Worker       !std::is_void<decltype(check<T>(nullptr))>::value;
789*5c90c05cSAndroid Build Coastguard Worker };
790*5c90c05cSAndroid Build Coastguard Worker 
791*5c90c05cSAndroid Build Coastguard Worker template <typename Container> struct all {
792*5c90c05cSAndroid Build Coastguard Worker   const Container& c;
793*5c90c05cSAndroid Build Coastguard Worker   auto begin() const -> typename Container::const_iterator { return c.begin(); }
794*5c90c05cSAndroid Build Coastguard Worker   auto end() const -> typename Container::const_iterator { return c.end(); }
795*5c90c05cSAndroid Build Coastguard Worker };
796*5c90c05cSAndroid Build Coastguard Worker }  // namespace detail
797*5c90c05cSAndroid Build Coastguard Worker 
798*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename Char>
799*5c90c05cSAndroid Build Coastguard Worker struct formatter<
800*5c90c05cSAndroid Build Coastguard Worker     T, Char,
801*5c90c05cSAndroid Build Coastguard Worker     enable_if_t<conjunction<detail::is_container_adaptor_like<T>,
802*5c90c05cSAndroid Build Coastguard Worker                             bool_constant<range_format_kind<T, Char>::value ==
803*5c90c05cSAndroid Build Coastguard Worker                                           range_format::disabled>>::value>>
804*5c90c05cSAndroid Build Coastguard Worker     : formatter<detail::all<typename T::container_type>, Char> {
805*5c90c05cSAndroid Build Coastguard Worker   using all = detail::all<typename T::container_type>;
806*5c90c05cSAndroid Build Coastguard Worker   template <typename FormatContext>
807*5c90c05cSAndroid Build Coastguard Worker   auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) {
808*5c90c05cSAndroid Build Coastguard Worker     struct getter : T {
809*5c90c05cSAndroid Build Coastguard Worker       static auto get(const T& t) -> all {
810*5c90c05cSAndroid Build Coastguard Worker         return {t.*(&getter::c)};  // Access c through the derived class.
811*5c90c05cSAndroid Build Coastguard Worker       }
812*5c90c05cSAndroid Build Coastguard Worker     };
813*5c90c05cSAndroid Build Coastguard Worker     return formatter<all>::format(getter::get(t), ctx);
814*5c90c05cSAndroid Build Coastguard Worker   }
815*5c90c05cSAndroid Build Coastguard Worker };
816*5c90c05cSAndroid Build Coastguard Worker 
817*5c90c05cSAndroid Build Coastguard Worker FMT_BEGIN_EXPORT
818*5c90c05cSAndroid Build Coastguard Worker 
819*5c90c05cSAndroid Build Coastguard Worker /**
820*5c90c05cSAndroid Build Coastguard Worker  * Returns an object that formats `std::tuple` with elements separated by `sep`.
821*5c90c05cSAndroid Build Coastguard Worker  *
822*5c90c05cSAndroid Build Coastguard Worker  * **Example**:
823*5c90c05cSAndroid Build Coastguard Worker  *
824*5c90c05cSAndroid Build Coastguard Worker  *     auto t = std::tuple<int, char>{1, 'a'};
825*5c90c05cSAndroid Build Coastguard Worker  *     fmt::print("{}", fmt::join(t, ", "));
826*5c90c05cSAndroid Build Coastguard Worker  *     // Output: 1, a
827*5c90c05cSAndroid Build Coastguard Worker  */
828*5c90c05cSAndroid Build Coastguard Worker template <typename... T>
829*5c90c05cSAndroid Build Coastguard Worker FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep)
830*5c90c05cSAndroid Build Coastguard Worker     -> tuple_join_view<char, T...> {
831*5c90c05cSAndroid Build Coastguard Worker   return {tuple, sep};
832*5c90c05cSAndroid Build Coastguard Worker }
833*5c90c05cSAndroid Build Coastguard Worker 
834*5c90c05cSAndroid Build Coastguard Worker /**
835*5c90c05cSAndroid Build Coastguard Worker  * Returns an object that formats `std::initializer_list` with elements
836*5c90c05cSAndroid Build Coastguard Worker  * separated by `sep`.
837*5c90c05cSAndroid Build Coastguard Worker  *
838*5c90c05cSAndroid Build Coastguard Worker  * **Example**:
839*5c90c05cSAndroid Build Coastguard Worker  *
840*5c90c05cSAndroid Build Coastguard Worker  *     fmt::print("{}", fmt::join({1, 2, 3}, ", "));
841*5c90c05cSAndroid Build Coastguard Worker  *     // Output: "1, 2, 3"
842*5c90c05cSAndroid Build Coastguard Worker  */
843*5c90c05cSAndroid Build Coastguard Worker template <typename T>
844*5c90c05cSAndroid Build Coastguard Worker auto join(std::initializer_list<T> list, string_view sep)
845*5c90c05cSAndroid Build Coastguard Worker     -> join_view<const T*, const T*> {
846*5c90c05cSAndroid Build Coastguard Worker   return join(std::begin(list), std::end(list), sep);
847*5c90c05cSAndroid Build Coastguard Worker }
848*5c90c05cSAndroid Build Coastguard Worker 
849*5c90c05cSAndroid Build Coastguard Worker FMT_END_EXPORT
850*5c90c05cSAndroid Build Coastguard Worker FMT_END_NAMESPACE
851*5c90c05cSAndroid Build Coastguard Worker 
852*5c90c05cSAndroid Build Coastguard Worker #endif  // FMT_RANGES_H_
853