proxygen
Format.h
Go to the documentation of this file.
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.
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>
47 
48 // meta-attribute to identify formatters in this sea of template weirdness
49 namespace detail {
50 class FormatterTag {};
51 } // namespace detail
52 
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>
73  public:
77  template <class Output>
78  void operator()(Output& out) const;
79 
83  template <class Str>
85  Str& str) const {
86  auto appender = [&str](StringPiece s) { str.append(s.data(), s.size()); };
87  (*this)(appender);
88  }
89 
93  std::string str() const {
94  std::string s;
95  appendTo(s);
96  return s;
97  }
98 
102  fbstring fbstr() const {
103  fbstring s;
104  appendTo(s);
105  return s;
106  }
107 
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>
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>
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>
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<
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<
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 {
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 
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 
258 template <class Derived, bool containerMode, class... Args>
259 void writeTo(
260  FILE* fp,
262 
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 
279 template <class... Args>
280 inline std::string sformat(StringPiece fmt, Args&&... args) {
281  return format(fmt, std::forward<Args>(args)...).str();
282 }
283 
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 
306 template <class Container>
307 inline std::string svformat(StringPiece fmt, Container&& container) {
308  return vformat(fmt, std::forward<Container>(container)).str();
309 }
310 
322 class FOLLY_EXPORT FormatKeyNotFoundException : public std::out_of_range {
323  public:
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 
341 namespace detail {
342 template <class Container, class Value>
344  DefaultValueWrapper(const Container& container, const Value& defaultValue)
345  : container(container), defaultValue(defaultValue) {}
346 
347  const Container& container;
349 };
350 } // namespace detail
351 
352 template <class Container, class Value>
354  const Container& c,
355  const Value& v) {
357 }
358 
367 template <class Str, class... Args>
369 format(Str* out, StringPiece fmt, Args&&... args) {
370  format(fmt, std::forward<Args>(args)...).appendTo(*out);
371 }
372 
376 template <class Str, class Container>
378 vformat(Str* out, StringPiece fmt, Container&& container) {
379  vformat(fmt, std::forward<Container>(container)).appendTo(*out);
380 }
381 
385 namespace format_value {
386 
393 template <class FormatCallback>
394 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb);
395 
403 template <class FormatCallback>
404 void formatNumber(
405  StringPiece val,
406  int prefixLen,
407  FormatArg& arg,
408  FormatCallback& cb);
409 
415 template <
416  class FormatCallback,
417  class Derived,
418  bool containerMode,
419  class... Args>
420 void formatFormatter(
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>
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>
484 formatChecked(Str* out, StringPiece fmt, Args&&... args) {
485  formatChecked(fmt, std::forward<Args>(args)...).appendTo(*out);
486 }
487 template <class Str, class Container>
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 
#define T(v)
Definition: http_parser.c:233
#define FOLLY_GNU_DISABLE_WARNING(warningName)
Definition: Portability.h:180
#define FOLLY_POP_WARNING
Definition: Portability.h:179
auto v
std::unique_ptr< int > A
detail::FormatterTag IsFormatter
Definition: Format.h:111
#define FOLLY_PUSH_WARNING
Definition: Portability.h:178
std::string svformatChecked(StringPiece fmt, Container &&container)
Definition: Format.h:479
std::string sformat(StringPiece fmt, Args &&...args)
Definition: Format.h:280
std::enable_if< IsSomeString< Str >::value >::type appendTo(Str &str) const
Definition: Format.h:84
PskType type
std::enable_if< IsSomeString< Str >::value >::type vformatChecked(Str *out, StringPiece fmt, Container &&container)
Definition: Format.h:489
std::enable_if< IsSomeString< Str >::value >::type vformat(Str *out, StringPiece fmt, Container &&container)
Definition: Format.h:378
STL namespace.
double val
Definition: String.cpp:273
std::enable_if< !std::is_integral< T >::value||std::is_same< T, bool >::value, int >::type getValue(const FormatValue< T > &, const FormatArg &arg) const
Definition: Format.h:162
std::enable_if< IsSomeString< Str >::value >::type formatChecked(Str *out, StringPiece fmt, Args &&...args)
Definition: Format.h:484
std::enable_if< std::is_integral< T >::value &&!std::is_same< T, bool >::value, int >::type getValue(const FormatValue< T > &format, const FormatArg &) const
Definition: Format.h:154
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
#define FOLLY_EXPORT
Definition: CPortability.h:133
Derived const & asDerived() const
Definition: Format.h:118
requires E e noexcept(noexcept(s.error(std::move(e))))
void formatString(StringPiece val, FormatArg &arg, FormatCallback &cb)
Definition: Format-inl.h:298
void writeTo(FILE *fp, const BaseFormatter< Derived, containerMode, Args... > &formatter)
Definition: Format-inl.h:283
Formatter(StringPiece &str, Args &&...args)
Definition: Format.h:215
detail::DefaultValueWrapper< Container, Value > defaulted(const Container &c, const Value &v)
Definition: Format.h:353
std::ostream & operator<<(std::ostream &out, const Formatter< containerMode, Args... > &formatter)
Definition: Format.h:245
std::enable_if<(K< valueCount)>::type doFormatFrom(size_t i, FormatArg &arg, Callback &cb) const
Definition: Format.h:130
bool_constant< true > true_type
Definition: gtest-port.h:2210
std::string sformatChecked(StringPiece fmt, Args &&...args)
Definition: Format.h:469
fbstring fbstr() const
Definition: Format.h:102
std::tuple< Args... > ValueTuple
Definition: Format.h:115
bool Value(const T &value, M matcher)
void formatFormatter(const BaseFormatter< Derived, containerMode, Args... > &formatter, FormatArg &arg, FormatCallback &cb)
Definition: Format-inl.h:380
std::enable_if< K==valueCount, int >::type getSizeArgFrom(size_t i, const FormatArg &arg) const
Definition: Format.h:144
std::enable_if< K==valueCount >::type doFormatFrom(size_t i, FormatArg &arg, Callback &) const
Definition: Format.h:124
Append appendTo(Collection &collection)
Definition: Base.h:824
#define C(name, bit)
Definition: CpuId.h:204
static const char *const value
Definition: Conv.cpp:50
DefaultValueWrapper(const Container &container, const Value &defaultValue)
Definition: Format.h:344
std::enable_if< IsSomeString< Str >::value >::type format(Str *out, StringPiece fmt, Args &&...args)
Definition: Format.h:369
void error(Args &&...args) const
Definition: FormatArg.h:217
BaseFormatter BaseType
Definition: Format.h:112
std::string svformat(StringPiece fmt, Container &&container)
Definition: Format.h:307
const char * string
Definition: Conv.cpp:212
static set< string > s
const
Definition: upload.py:398
bool_constant< false > false_type
Definition: gtest-port.h:2209
std::string str() const
Definition: Format.h:93
char const * key() const noexcept
Definition: Format.h:326
char c
void doFormatArg(FormatArg &arg, Callback &cb) const
Definition: Format.h:226
void doFormat(size_t i, FormatArg &arg, Callback &cb) const
Definition: Format.h:139
GMockOutputTest ExpectedCall FILE
const Container & container
Definition: Format.h:347
void formatNumber(StringPiece val, int prefixLen, FormatArg &arg, FormatCallback &cb)
Definition: Format-inl.h:357