1 | /* |
2 | * Copyright (c) Facebook, Inc. and its affiliates. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | #define FOLLY_FORMAT_H_ |
19 | |
20 | #include <cstdio> |
21 | #include <ios> |
22 | #include <stdexcept> |
23 | #include <tuple> |
24 | #include <type_traits> |
25 | |
26 | #include <folly/CPortability.h> |
27 | #include <folly/Conv.h> |
28 | #include <folly/FormatArg.h> |
29 | #include <folly/Range.h> |
30 | #include <folly/String.h> |
31 | #include <folly/Traits.h> |
32 | |
33 | // Ignore shadowing warnings within this file, so includers can use -Wshadow. |
34 | FOLLY_PUSH_WARNING |
35 | FOLLY_GNU_DISABLE_WARNING("-Wshadow" ) |
36 | |
37 | namespace folly { |
38 | |
39 | // forward declarations |
40 | template <bool containerMode, class... Args> |
41 | class Formatter; |
42 | template <class... Args> |
43 | Formatter<false, Args...> format(StringPiece fmt, Args&&... args); |
44 | template <class C> |
45 | Formatter<true, C> vformat(StringPiece fmt, C&& container); |
46 | template <class T, class Enable = void> |
47 | class FormatValue; |
48 | |
49 | // meta-attribute to identify formatters in this sea of template weirdness |
50 | namespace detail { |
51 | class FormatterTag {}; |
52 | } // namespace detail |
53 | |
54 | /** |
55 | * Formatter class. |
56 | * |
57 | * Note that this class is tricky, as it keeps *references* to its lvalue |
58 | * arguments (while it takes ownership of the temporaries), and it doesn't |
59 | * copy the passed-in format string. Thankfully, you can't use this |
60 | * directly, you have to use format(...) below. |
61 | */ |
62 | |
63 | /* BaseFormatter class. |
64 | * Overridable behaviours: |
65 | * You may override the actual formatting of positional parameters in |
66 | * `doFormatArg`. The Formatter class provides the default implementation. |
67 | * |
68 | * You may also override `doFormat` and `getSizeArg`. These override points were |
69 | * added to permit static analysis of format strings, when it is inconvenient |
70 | * or impossible to instantiate a BaseFormatter with the correct storage |
71 | */ |
72 | template <class Derived, bool containerMode, class... Args> |
73 | class BaseFormatter { |
74 | public: |
75 | /** |
76 | * Append to output. out(StringPiece sp) may be called (more than once) |
77 | */ |
78 | template <class Output> |
79 | void operator()(Output& out) const; |
80 | |
81 | /** |
82 | * Append to a string. |
83 | */ |
84 | template <class Str> |
85 | typename std::enable_if<IsSomeString<Str>::value>::type appendTo( |
86 | Str& str) const { |
87 | auto appender = [&str](StringPiece s) { str.append(s.data(), s.size()); }; |
88 | (*this)(appender); |
89 | } |
90 | |
91 | /** |
92 | * Conversion to string |
93 | */ |
94 | std::string str() const { |
95 | std::string s; |
96 | appendTo(s); |
97 | return s; |
98 | } |
99 | |
100 | /** |
101 | * Conversion to fbstring |
102 | */ |
103 | fbstring fbstr() const { |
104 | fbstring s; |
105 | appendTo(s); |
106 | return s; |
107 | } |
108 | |
109 | /** |
110 | * Metadata to identify generated children of BaseFormatter |
111 | */ |
112 | typedef detail::FormatterTag IsFormatter; |
113 | typedef BaseFormatter BaseType; |
114 | |
115 | private: |
116 | typedef std::tuple<Args...> ValueTuple; |
117 | static constexpr size_t valueCount = std::tuple_size<ValueTuple>::value; |
118 | |
119 | Derived const& asDerived() const { |
120 | return *static_cast<const Derived*>(this); |
121 | } |
122 | |
123 | template <size_t K, class Callback> |
124 | typename std::enable_if<K == valueCount>::type |
125 | doFormatFrom(size_t i, FormatArg& arg, Callback& /*cb*/) const { |
126 | arg.error("argument index out of range, max=" , i); |
127 | } |
128 | |
129 | template <size_t K, class Callback> |
130 | typename std::enable_if<(K < valueCount)>::type |
131 | doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const { |
132 | if (i == K) { |
133 | asDerived().template doFormatArg<K>(arg, cb); |
134 | } else { |
135 | doFormatFrom<K + 1>(i, arg, cb); |
136 | } |
137 | } |
138 | |
139 | template <class Callback> |
140 | void doFormat(size_t i, FormatArg& arg, Callback& cb) const { |
141 | return doFormatFrom<0>(i, arg, cb); |
142 | } |
143 | |
144 | template <size_t K> |
145 | typename std::enable_if<K == valueCount, int>::type getSizeArgFrom( |
146 | size_t i, |
147 | const FormatArg& arg) const { |
148 | arg.error("argument index out of range, max=" , i); |
149 | } |
150 | |
151 | template <class T> |
152 | typename std::enable_if< |
153 | std::is_integral<T>::value && !std::is_same<T, bool>::value, |
154 | int>::type |
155 | getValue(const FormatValue<T>& format, const FormatArg&) const { |
156 | return static_cast<int>(format.getValue()); |
157 | } |
158 | |
159 | template <class T> |
160 | typename std::enable_if< |
161 | !std::is_integral<T>::value || std::is_same<T, bool>::value, |
162 | int>::type |
163 | getValue(const FormatValue<T>&, const FormatArg& arg) const { |
164 | arg.error("dynamic field width argument must be integral" ); |
165 | } |
166 | |
167 | template <size_t K> |
168 | typename std::enable_if < |
169 | K<valueCount, int>::type getSizeArgFrom(size_t i, const FormatArg& arg) |
170 | const { |
171 | if (i == K) { |
172 | return getValue(getFormatValue<K>(), arg); |
173 | } |
174 | return getSizeArgFrom<K + 1>(i, arg); |
175 | } |
176 | |
177 | int getSizeArg(size_t i, const FormatArg& arg) const { |
178 | return getSizeArgFrom<0>(i, arg); |
179 | } |
180 | |
181 | StringPiece str_; |
182 | |
183 | protected: |
184 | explicit BaseFormatter(StringPiece str, Args&&... args); |
185 | |
186 | // Not copyable |
187 | BaseFormatter(const BaseFormatter&) = delete; |
188 | BaseFormatter& operator=(const BaseFormatter&) = delete; |
189 | |
190 | // Movable, but the move constructor and assignment operator are private, |
191 | // for the exclusive use of format() (below). This way, you can't create |
192 | // a Formatter object, but can handle references to it (for streaming, |
193 | // conversion to string, etc) -- which is good, as Formatter objects are |
194 | // dangerous (they may hold references). |
195 | BaseFormatter(BaseFormatter&&) = default; |
196 | BaseFormatter& operator=(BaseFormatter&&) = default; |
197 | |
198 | template <size_t K> |
199 | using ArgType = typename std::tuple_element<K, ValueTuple>::type; |
200 | |
201 | template <size_t K> |
202 | FormatValue<typename std::decay<ArgType<K>>::type> getFormatValue() const { |
203 | return FormatValue<typename std::decay<ArgType<K>>::type>( |
204 | std::get<K>(values_)); |
205 | } |
206 | |
207 | ValueTuple values_; |
208 | }; |
209 | |
210 | template <bool containerMode, class... Args> |
211 | class Formatter : public BaseFormatter< |
212 | Formatter<containerMode, Args...>, |
213 | containerMode, |
214 | Args...> { |
215 | private: |
216 | explicit Formatter(StringPiece& str, Args&&... args) |
217 | : BaseFormatter< |
218 | Formatter<containerMode, Args...>, |
219 | containerMode, |
220 | Args...>(str, std::forward<Args>(args)...) { |
221 | static_assert( |
222 | !containerMode || sizeof...(Args) == 1, |
223 | "Exactly one argument required in container mode" ); |
224 | } |
225 | |
226 | template <size_t K, class Callback> |
227 | void doFormatArg(FormatArg& arg, Callback& cb) const { |
228 | this->template getFormatValue<K>().format(arg, cb); |
229 | } |
230 | |
231 | friend class BaseFormatter< |
232 | Formatter<containerMode, Args...>, |
233 | containerMode, |
234 | Args...>; |
235 | |
236 | template <class... A> |
237 | friend Formatter<false, A...> format(StringPiece fmt, A&&... arg); |
238 | template <class C> |
239 | friend Formatter<true, C> vformat(StringPiece fmt, C&& container); |
240 | }; |
241 | |
242 | /** |
243 | * Formatter objects can be written to streams. |
244 | */ |
245 | template <class C, bool containerMode, class... Args> |
246 | std::ostream& operator<<( |
247 | std::basic_ostream<C>& out, |
248 | const Formatter<containerMode, Args...>& formatter) { |
249 | auto writer = [&out](StringPiece sp) { |
250 | out.write(sp.data(), std::streamsize(sp.size())); |
251 | }; |
252 | formatter(writer); |
253 | return out; |
254 | } |
255 | |
256 | /** |
257 | * Formatter objects can be written to stdio FILEs. |
258 | */ |
259 | template <class Derived, bool containerMode, class... Args> |
260 | void writeTo( |
261 | FILE* fp, |
262 | const BaseFormatter<Derived, containerMode, Args...>& formatter); |
263 | |
264 | /** |
265 | * Create a formatter object. |
266 | * |
267 | * std::string formatted = format("{} {}", 23, 42).str(); |
268 | * LOG(INFO) << format("{} {}", 23, 42); |
269 | * writeTo(stdout, format("{} {}", 23, 42)); |
270 | */ |
271 | template <class... Args> |
272 | Formatter<false, Args...> format(StringPiece fmt, Args&&... args) { |
273 | return Formatter<false, Args...>(fmt, std::forward<Args>(args)...); |
274 | } |
275 | |
276 | /** |
277 | * Like format(), but immediately returns the formatted string instead of an |
278 | * intermediate format object. |
279 | */ |
280 | template <class... Args> |
281 | inline std::string sformat(StringPiece fmt, Args&&... args) { |
282 | return format(fmt, std::forward<Args>(args)...).str(); |
283 | } |
284 | |
285 | /** |
286 | * Create a formatter object that takes one argument (of container type) |
287 | * and uses that container to get argument values from. |
288 | * |
289 | * std::map<string, string> map { {"hello", "world"}, {"answer", "42"} }; |
290 | * |
291 | * The following are equivalent: |
292 | * format("{0[hello]} {0[answer]}", map); |
293 | * |
294 | * vformat("{hello} {answer}", map); |
295 | * |
296 | * but the latter is cleaner. |
297 | */ |
298 | template <class Container> |
299 | Formatter<true, Container> vformat(StringPiece fmt, Container&& container) { |
300 | return Formatter<true, Container>(fmt, std::forward<Container>(container)); |
301 | } |
302 | |
303 | /** |
304 | * Like vformat(), but immediately returns the formatted string instead of an |
305 | * intermediate format object. |
306 | */ |
307 | template <class Container> |
308 | inline std::string svformat(StringPiece fmt, Container&& container) { |
309 | return vformat(fmt, std::forward<Container>(container)).str(); |
310 | } |
311 | |
312 | /** |
313 | * Exception class thrown when a format key is not found in the given |
314 | * associative container keyed by strings. We inherit std::out_of_range for |
315 | * compatibility with callers that expect exception to be thrown directly |
316 | * by std::map or std::unordered_map. |
317 | * |
318 | * Having the key be at the end of the message string, we can access it by |
319 | * simply adding its offset to what(). Not storing separate std::string key |
320 | * makes the exception type small and noexcept-copyable like std::out_of_range, |
321 | * and therefore able to fit in-situ in exception_wrapper. |
322 | */ |
323 | class FOLLY_EXPORT FormatKeyNotFoundException : public std::out_of_range { |
324 | public: |
325 | explicit FormatKeyNotFoundException(StringPiece key); |
326 | |
327 | char const* key() const noexcept { |
328 | return what() + kMessagePrefix.size(); |
329 | } |
330 | |
331 | private: |
332 | static constexpr StringPiece const kMessagePrefix = "format key not found: " ; |
333 | }; |
334 | |
335 | /** |
336 | * Wrap a sequence or associative container so that out-of-range lookups |
337 | * return a default value rather than throwing an exception. |
338 | * |
339 | * Usage: |
340 | * format("[no_such_key"], defaulted(map, 42)) -> 42 |
341 | */ |
342 | namespace detail { |
343 | template <class Container, class Value> |
344 | struct DefaultValueWrapper { |
345 | DefaultValueWrapper(const Container& container, const Value& defaultValue) |
346 | : container(container), defaultValue(defaultValue) {} |
347 | |
348 | const Container& container; |
349 | const Value& defaultValue; |
350 | }; |
351 | } // namespace detail |
352 | |
353 | template <class Container, class Value> |
354 | detail::DefaultValueWrapper<Container, Value> defaulted( |
355 | const Container& c, |
356 | const Value& v) { |
357 | return detail::DefaultValueWrapper<Container, Value>(c, v); |
358 | } |
359 | |
360 | /** |
361 | * Append formatted output to a string. |
362 | * |
363 | * std::string foo; |
364 | * format(&foo, "{} {}", 42, 23); |
365 | * |
366 | * Shortcut for toAppend(format(...), &foo); |
367 | */ |
368 | template <class Str, class... Args> |
369 | typename std::enable_if<IsSomeString<Str>::value>::type |
370 | format(Str* out, StringPiece fmt, Args&&... args) { |
371 | format(fmt, std::forward<Args>(args)...).appendTo(*out); |
372 | } |
373 | |
374 | /** |
375 | * Append vformatted output to a string. |
376 | */ |
377 | template <class Str, class Container> |
378 | typename std::enable_if<IsSomeString<Str>::value>::type |
379 | vformat(Str* out, StringPiece fmt, Container&& container) { |
380 | vformat(fmt, std::forward<Container>(container)).appendTo(*out); |
381 | } |
382 | |
383 | /** |
384 | * Utilities for all format value specializations. |
385 | */ |
386 | namespace format_value { |
387 | |
388 | /** |
389 | * Format a string in "val", obeying appropriate alignment, padding, width, |
390 | * and precision. Treats Align::DEFAULT as Align::LEFT, and |
391 | * Align::PAD_AFTER_SIGN as Align::RIGHT; use formatNumber for |
392 | * number-specific formatting. |
393 | */ |
394 | template <class FormatCallback> |
395 | void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb); |
396 | |
397 | /** |
398 | * Format a number in "val"; the first prefixLen characters form the prefix |
399 | * (sign, "0x" base prefix, etc) which must be left-aligned if the alignment |
400 | * is Align::PAD_AFTER_SIGN. Treats Align::DEFAULT as Align::LEFT. Ignores |
401 | * arg.precision, as that has a different meaning for numbers (not "maximum |
402 | * field width") |
403 | */ |
404 | template <class FormatCallback> |
405 | void formatNumber( |
406 | StringPiece val, |
407 | int prefixLen, |
408 | FormatArg& arg, |
409 | FormatCallback& cb); |
410 | |
411 | /** |
412 | * Format a Formatter object recursively. Behaves just like |
413 | * formatString(fmt.str(), arg, cb); but avoids creating a temporary |
414 | * string if possible. |
415 | */ |
416 | template < |
417 | class FormatCallback, |
418 | class Derived, |
419 | bool containerMode, |
420 | class... Args> |
421 | void formatFormatter( |
422 | const BaseFormatter<Derived, containerMode, Args...>& formatter, |
423 | FormatArg& arg, |
424 | FormatCallback& cb); |
425 | |
426 | } // namespace format_value |
427 | |
428 | /* |
429 | * Specialize folly::FormatValue for your type. |
430 | * |
431 | * FormatValue<T> is constructed with a (reference-collapsed) T&&, which is |
432 | * guaranteed to stay alive until the FormatValue object is destroyed, so you |
433 | * may keep a reference (or pointer) to it instead of making a copy. |
434 | * |
435 | * You must define |
436 | * template <class Callback> |
437 | * void format(FormatArg& arg, Callback& cb) const; |
438 | * with the following semantics: format the value using the given argument. |
439 | * |
440 | * arg is given by non-const reference for convenience -- it won't be reused, |
441 | * so feel free to modify it in place if necessary. (For example, wrap an |
442 | * existing conversion but change the default, or remove the "key" when |
443 | * extracting an element from a container) |
444 | * |
445 | * Call the callback to append data to the output. You may call the callback |
446 | * as many times as you'd like (or not at all, if you want to output an |
447 | * empty string) |
448 | */ |
449 | |
450 | namespace detail { |
451 | |
452 | template <class T, class Enable = void> |
453 | struct IsFormatter : public std::false_type {}; |
454 | |
455 | template <class T> |
456 | struct IsFormatter< |
457 | T, |
458 | typename std::enable_if< |
459 | std::is_same<typename T::IsFormatter, detail::FormatterTag>::value>:: |
460 | type> : public std::true_type {}; |
461 | } // namespace detail |
462 | |
463 | // Deprecated API. formatChecked() et. al. now behave identically to their |
464 | // non-Checked counterparts. |
465 | template <class... Args> |
466 | Formatter<false, Args...> formatChecked(StringPiece fmt, Args&&... args) { |
467 | return format(fmt, std::forward<Args>(args)...); |
468 | } |
469 | template <class... Args> |
470 | inline std::string sformatChecked(StringPiece fmt, Args&&... args) { |
471 | return formatChecked(fmt, std::forward<Args>(args)...).str(); |
472 | } |
473 | template <class Container> |
474 | Formatter<true, Container> vformatChecked( |
475 | StringPiece fmt, |
476 | Container&& container) { |
477 | return vformat(fmt, std::forward<Container>(container)); |
478 | } |
479 | template <class Container> |
480 | inline std::string svformatChecked(StringPiece fmt, Container&& container) { |
481 | return vformatChecked(fmt, std::forward<Container>(container)).str(); |
482 | } |
483 | template <class Str, class... Args> |
484 | typename std::enable_if<IsSomeString<Str>::value>::type |
485 | formatChecked(Str* out, StringPiece fmt, Args&&... args) { |
486 | formatChecked(fmt, std::forward<Args>(args)...).appendTo(*out); |
487 | } |
488 | template <class Str, class Container> |
489 | typename std::enable_if<IsSomeString<Str>::value>::type |
490 | vformatChecked(Str* out, StringPiece fmt, Container&& container) { |
491 | vformatChecked(fmt, std::forward<Container>(container)).appendTo(*out); |
492 | } |
493 | |
494 | } // namespace folly |
495 | |
496 | #include <folly/Format-inl.h> |
497 | |
498 | FOLLY_POP_WARNING |
499 | |