X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2FFormat.h;h=2c5f2fc3c32342f931f82339bb173c15c21621b1;hb=HEAD;hp=8986c4cac847e077a26341027770b549688ade6b;hpb=115059030653fe6f73e351073097ba1e06507f21;p=folly.git diff --git a/folly/Format.h b/folly/Format.h index 8986c4ca..2c5f2fc3 100644 --- a/folly/Format.h +++ b/folly/Format.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 Facebook, Inc. + * Copyright 2012-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,9 +18,11 @@ #define FOLLY_FORMAT_H_ #include +#include #include #include +#include #include #include #include @@ -28,8 +30,8 @@ #include // Ignore shadowing warnings within this file, so includers can use -Wshadow. -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wshadow" +FOLLY_PUSH_WARNING +FOLLY_GCC_DISABLE_WARNING("-Wshadow") namespace folly { @@ -46,14 +48,15 @@ class FormatValue; // meta-attribute to identify formatters in this sea of template weirdness namespace detail { class FormatterTag {}; -}; +} // namespace detail /** * Formatter class. * - * Note that this class is tricky, as it keeps *references* to its arguments - * (and doesn't copy the passed-in format string). Thankfully, you can't use - * this directly, you have to use format(...) below. + * Note that this class is tricky, as it keeps *references* to its lvalue + * arguments (while it takes ownership of the temporaries), and it doesn't + * copy the passed-in format string. Thankfully, you can't use this + * directly, you have to use format(...) below. */ /* BaseFormatter class. @@ -103,14 +106,13 @@ class BaseFormatter { } /** - * metadata to identify generated children of BaseFormatter + * Metadata to identify generated children of BaseFormatter */ typedef detail::FormatterTag IsFormatter; typedef BaseFormatter BaseType; private: - typedef std::tuple::type>...> - ValueTuple; + typedef std::tuple ValueTuple; static constexpr size_t valueCount = std::tuple_size::value; Derived const& asDerived() const { @@ -166,7 +168,7 @@ class BaseFormatter { K::type getSizeArgFrom(size_t i, const FormatArg& arg) const { if (i == K) { - return getValue(std::get(values_), arg); + return getValue(getFormatValue(), arg); } return getSizeArgFrom(i, arg); } @@ -188,10 +190,19 @@ class BaseFormatter { // for the exclusive use of format() (below). This way, you can't create // a Formatter object, but can handle references to it (for streaming, // conversion to string, etc) -- which is good, as Formatter objects are - // dangerous (they hold references, possibly to temporaries) + // dangerous (they may hold references). BaseFormatter(BaseFormatter&&) = default; BaseFormatter& operator=(BaseFormatter&&) = default; + template + using ArgType = typename std::tuple_element::type; + + template + FormatValue>::type> getFormatValue() const { + return FormatValue>::type>( + std::get(values_)); + } + ValueTuple values_; }; @@ -213,7 +224,7 @@ class Formatter : public BaseFormatter< template void doFormatArg(FormatArg& arg, Callback& cb) const { - std::get(this->values_).format(arg, cb); + this->template getFormatValue().format(arg, cb); } friend class BaseFormatter< @@ -297,6 +308,33 @@ inline std::string svformat(StringPiece fmt, Container&& container) { return vformat(fmt, std::forward(container)).str(); } +/** + * Exception class thrown when a format key is not found in the given + * associative container keyed by strings. We inherit std::out_of_range for + * compatibility with callers that expect exception to be thrown directly + * by std::map or std::unordered_map. + * + * Having the key be at the end of the message string, we can access it by + * simply adding its offset to what(). Not storing separate std::string key + * makes the exception type small and noexcept-copyable like std::out_of_range, + * and therefore able to fit in-situ in exception_wrapper. + */ +class FOLLY_EXPORT FormatKeyNotFoundException : public std::out_of_range { + public: + explicit FormatKeyNotFoundException(StringPiece key); + + char const* key() const noexcept { + return what() + kMessagePrefix.size(); + } + + private: + static constexpr StringPiece const kMessagePrefix = "format key not found: "; +}; + +namespace detail { +[[noreturn]] void throwFormatKeyNotFoundException(StringPiece key); +} // namespace detail + /** * Wrap a sequence or associative container so that out-of-range lookups * return a default value rather than throwing an exception. @@ -313,7 +351,7 @@ struct DefaultValueWrapper { const Container& container; const Value& defaultValue; }; -} // namespace +} // namespace detail template detail::DefaultValueWrapper defaulted( @@ -423,7 +461,7 @@ struct IsFormatter< typename std::enable_if< std::is_same::value>:: type> : public std::true_type {}; -} // folly::detail +} // namespace detail // Deprecated API. formatChecked() et. al. now behave identically to their // non-Checked counterparts. @@ -460,4 +498,4 @@ vformatChecked(Str* out, StringPiece fmt, Container&& container) { #include -#pragma GCC diagnostic pop +FOLLY_POP_WARNING