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