]> git.proxmox.com Git - ceph.git/blob - ceph/src/fmt/include/fmt/ranges.h
import 15.2.0 Octopus source
[ceph.git] / ceph / src / fmt / include / fmt / ranges.h
1 // Formatting library for C++ - experimental range support
2 //
3 // Copyright (c) 2012 - present, Victor Zverovich
4 // All rights reserved.
5 //
6 // For the license information refer to format.h.
7 //
8 // Copyright (c) 2018 - present, Remotion (Igor Schulz)
9 // All Rights Reserved
10 // {fmt} support for ranges, containers and types tuple interface.
11
12 #ifndef FMT_RANGES_H_
13 #define FMT_RANGES_H_
14
15 #include <type_traits>
16 #include "format.h"
17
18 // output only up to N items from the range.
19 #ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
20 # define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
21 #endif
22
23 FMT_BEGIN_NAMESPACE
24
25 template <typename Char> struct formatting_base {
26 template <typename ParseContext>
27 FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
28 return ctx.begin();
29 }
30 };
31
32 template <typename Char, typename Enable = void>
33 struct formatting_range : formatting_base<Char> {
34 static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =
35 FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the
36 // range.
37 Char prefix;
38 Char delimiter;
39 Char postfix;
40 formatting_range() : prefix('{'), delimiter(','), postfix('}') {}
41 static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
42 static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
43 };
44
45 template <typename Char, typename Enable = void>
46 struct formatting_tuple : formatting_base<Char> {
47 Char prefix;
48 Char delimiter;
49 Char postfix;
50 formatting_tuple() : prefix('('), delimiter(','), postfix(')') {}
51 static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
52 static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
53 };
54
55 namespace internal {
56
57 template <typename RangeT, typename OutputIterator>
58 OutputIterator copy(const RangeT& range, OutputIterator out) {
59 for (auto it = range.begin(), end = range.end(); it != end; ++it)
60 *out++ = *it;
61 return out;
62 }
63
64 template <typename OutputIterator>
65 OutputIterator copy(const char* str, OutputIterator out) {
66 while (*str) *out++ = *str++;
67 return out;
68 }
69
70 template <typename OutputIterator>
71 OutputIterator copy(char ch, OutputIterator out) {
72 *out++ = ch;
73 return out;
74 }
75
76 /// Return true value if T has std::string interface, like std::string_view.
77 template <typename T> class is_like_std_string {
78 template <typename U>
79 static auto check(U* p)
80 -> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
81 template <typename> static void check(...);
82
83 public:
84 static FMT_CONSTEXPR_DECL const bool value =
85 !std::is_void<decltype(check<T>(FMT_NULL))>::value;
86 };
87
88 template <typename Char>
89 struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {};
90
91 template <typename... Ts> struct conditional_helper {};
92
93 template <typename T, typename _ = void> struct is_range_ : std::false_type {};
94
95 #if !FMT_MSC_VER || FMT_MSC_VER > 1800
96 template <typename T>
97 struct is_range_<
98 T, typename std::conditional<
99 false,
100 conditional_helper<decltype(internal::declval<T>().begin()),
101 decltype(internal::declval<T>().end())>,
102 void>::type> : std::true_type {};
103 #endif
104
105 /// tuple_size and tuple_element check.
106 template <typename T> class is_tuple_like_ {
107 template <typename U>
108 static auto check(U* p) -> decltype(
109 std::tuple_size<U>::value,
110 (void)internal::declval<typename std::tuple_element<0, U>::type>(),
111 int());
112 template <typename> static void check(...);
113
114 public:
115 static FMT_CONSTEXPR_DECL const bool value =
116 !std::is_void<decltype(check<T>(FMT_NULL))>::value;
117 };
118
119 // Check for integer_sequence
120 #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
121 template <typename T, T... N>
122 using integer_sequence = std::integer_sequence<T, N...>;
123 template <std::size_t... N> using index_sequence = std::index_sequence<N...>;
124 template <std::size_t N>
125 using make_index_sequence = std::make_index_sequence<N>;
126 #else
127 template <typename T, T... N> struct integer_sequence {
128 typedef T value_type;
129
130 static FMT_CONSTEXPR std::size_t size() { return sizeof...(N); }
131 };
132
133 template <std::size_t... N>
134 using index_sequence = integer_sequence<std::size_t, N...>;
135
136 template <typename T, std::size_t N, T... Ns>
137 struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
138 template <typename T, T... Ns>
139 struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
140
141 template <std::size_t N>
142 using make_index_sequence = make_integer_sequence<std::size_t, N>;
143 #endif
144
145 template <class Tuple, class F, size_t... Is>
146 void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT {
147 using std::get;
148 // using free function get<I>(T) now.
149 const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
150 (void)_; // blocks warnings
151 }
152
153 template <class T>
154 FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(
155 T const&) {
156 return {};
157 }
158
159 template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
160 const auto indexes = get_indexes(tup);
161 for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
162 }
163
164 template <typename Arg, FMT_ENABLE_IF(!is_like_std_string<
165 typename std::decay<Arg>::type>::value)>
166 FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
167 return add_space ? " {}" : "{}";
168 }
169
170 template <typename Arg, FMT_ENABLE_IF(is_like_std_string<
171 typename std::decay<Arg>::type>::value)>
172 FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
173 return add_space ? " \"{}\"" : "\"{}\"";
174 }
175
176 FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) {
177 return add_space ? " \"{}\"" : "\"{}\"";
178 }
179 FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) {
180 return add_space ? L" \"{}\"" : L"\"{}\"";
181 }
182
183 FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
184 return add_space ? " '{}'" : "'{}'";
185 }
186 FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
187 return add_space ? L" '{}'" : L"'{}'";
188 }
189
190 } // namespace internal
191
192 template <typename T> struct is_tuple_like {
193 static FMT_CONSTEXPR_DECL const bool value =
194 internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
195 };
196
197 template <typename TupleT, typename Char>
198 struct formatter<
199 TupleT, Char,
200 typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> {
201 private:
202 // C++11 generic lambda for format()
203 template <typename FormatContext> struct format_each {
204 template <typename T> void operator()(const T& v) {
205 if (i > 0) {
206 if (formatting.add_prepostfix_space) {
207 *out++ = ' ';
208 }
209 out = internal::copy(formatting.delimiter, out);
210 }
211 out = format_to(out,
212 internal::format_str_quoted(
213 (formatting.add_delimiter_spaces && i > 0), v),
214 v);
215 ++i;
216 }
217
218 formatting_tuple<Char>& formatting;
219 std::size_t& i;
220 typename std::add_lvalue_reference<decltype(
221 std::declval<FormatContext>().out())>::type out;
222 };
223
224 public:
225 formatting_tuple<Char> formatting;
226
227 template <typename ParseContext>
228 FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
229 return formatting.parse(ctx);
230 }
231
232 template <typename FormatContext = format_context>
233 auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
234 auto out = ctx.out();
235 std::size_t i = 0;
236 internal::copy(formatting.prefix, out);
237
238 internal::for_each(values, format_each<FormatContext>{formatting, i, out});
239 if (formatting.add_prepostfix_space) {
240 *out++ = ' ';
241 }
242 internal::copy(formatting.postfix, out);
243
244 return ctx.out();
245 }
246 };
247
248 template <typename T> struct is_range {
249 static FMT_CONSTEXPR_DECL const bool value =
250 internal::is_range_<T>::value && !internal::is_like_std_string<T>::value;
251 };
252
253 template <typename RangeT, typename Char>
254 struct formatter<RangeT, Char,
255 typename std::enable_if<fmt::is_range<RangeT>::value>::type> {
256 formatting_range<Char> formatting;
257
258 template <typename ParseContext>
259 FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
260 return formatting.parse(ctx);
261 }
262
263 template <typename FormatContext>
264 typename FormatContext::iterator format(const RangeT& values,
265 FormatContext& ctx) {
266 auto out = internal::copy(formatting.prefix, ctx.out());
267 std::size_t i = 0;
268 for (auto it = values.begin(), end = values.end(); it != end; ++it) {
269 if (i > 0) {
270 if (formatting.add_prepostfix_space) *out++ = ' ';
271 out = internal::copy(formatting.delimiter, out);
272 }
273 out = format_to(out,
274 internal::format_str_quoted(
275 (formatting.add_delimiter_spaces && i > 0), *it),
276 *it);
277 if (++i > formatting.range_length_limit) {
278 out = format_to(out, " ... <other elements>");
279 break;
280 }
281 }
282 if (formatting.add_prepostfix_space) *out++ = ' ';
283 return internal::copy(formatting.postfix, out);
284 }
285 };
286
287 FMT_END_NAMESPACE
288
289 #endif // FMT_RANGES_H_