From 12b5fff0e99fb64df5f751e91bc01d562403401b Mon Sep 17 00:00:00 2001 From: Yedidya Feldblum Date: Wed, 26 Jul 2017 11:39:53 -0700 Subject: [PATCH] Outline throw statements in dynamic Summary: [Folly] Outline `throw` statements in `dynamic`. There is no need for them to be inline - definitionally, they are always cold. Reviewed By: WillerZ Differential Revision: D5497457 fbshipit-source-id: 7b649c59b5b2609f838eb10e9329468d1bd1d558 --- folly/dynamic-inl.h | 37 ++++++++++++++++---------- folly/dynamic.cpp | 64 +++++++++++++++++++++++++++++---------------- 2 files changed, 65 insertions(+), 36 deletions(-) diff --git a/folly/dynamic-inl.h b/folly/dynamic-inl.h index 7db61c02..ee6a850e 100644 --- a/folly/dynamic-inl.h +++ b/folly/dynamic-inl.h @@ -78,11 +78,20 @@ namespace folly { struct TypeError : std::runtime_error { explicit TypeError(const std::string& expected, dynamic::Type actual); - explicit TypeError(const std::string& expected, - dynamic::Type actual1, dynamic::Type actual2); + explicit TypeError( + const std::string& expected, + dynamic::Type actual1, + dynamic::Type actual2); ~TypeError() override; }; +[[noreturn]] void throwTypeError_( + std::string const& expected, + dynamic::Type actual); +[[noreturn]] void throwTypeError_( + std::string const& expected, + dynamic::Type actual1, + dynamic::Type actual2); ////////////////////////////////////////////////////////////////////// @@ -102,7 +111,7 @@ namespace detail { template class Op> dynamic numericOp(dynamic const& a, dynamic const& b) { if (!a.isNumber() || !b.isNumber()) { - throw TypeError("numeric", a.type(), b.type()); + throwTypeError_("numeric", a.type(), b.type()); } if (a.type() != b.type()) { auto& integ = a.isInt() ? a : b; @@ -517,13 +526,13 @@ inline dynamic& dynamic::operator/=(dynamic const& o) { return *this; } -#define FB_DYNAMIC_INTEGER_OP(op) \ - inline dynamic& dynamic::operator op(dynamic const& o) { \ - if (!isInt() || !o.isInt()) { \ - throw TypeError("int64", type(), o.type()); \ - } \ - *getAddress() op o.asInt(); \ - return *this; \ +#define FB_DYNAMIC_INTEGER_OP(op) \ + inline dynamic& dynamic::operator op(dynamic const& o) { \ + if (!isInt() || !o.isInt()) { \ + throwTypeError_("int64", type(), o.type()); \ + } \ + *getAddress() op o.asInt(); \ + return *this; \ } FB_DYNAMIC_INTEGER_OP(%=) @@ -606,7 +615,7 @@ template inline void dynamic::insert(K&& key, V&& val) { inline void dynamic::update(const dynamic& mergeObj) { if (!isObject() || !mergeObj.isObject()) { - throw TypeError("object", type(), mergeObj.type()); + throwTypeError_("object", type(), mergeObj.type()); } for (const auto& pair : mergeObj.items()) { @@ -616,7 +625,7 @@ inline void dynamic::update(const dynamic& mergeObj) { inline void dynamic::update_missing(const dynamic& mergeObj1) { if (!isObject() || !mergeObj1.isObject()) { - throw TypeError("object", type(), mergeObj1.type()); + throwTypeError_("object", type(), mergeObj1.type()); } // Only add if not already there @@ -735,7 +744,7 @@ T dynamic::asImpl() const { case STRING: return to(*get_nothrow()); default: - throw TypeError("int/double/bool/string", type()); + throwTypeError_("int/double/bool/string", type()); } } @@ -804,7 +813,7 @@ T& dynamic::get() { if (auto* p = get_nothrow()) { return *p; } - throw TypeError(TypeInfo::name, type()); + throwTypeError_(TypeInfo::name, type()); } template diff --git a/folly/dynamic.cpp b/folly/dynamic.cpp index 8ef7d08e..08e97472 100644 --- a/folly/dynamic.cpp +++ b/folly/dynamic.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -44,21 +45,36 @@ const char* dynamic::typeName() const { } TypeError::TypeError(const std::string& expected, dynamic::Type actual) - : std::runtime_error(to("TypeError: expected dynamic " - "type `", expected, '\'', ", but had type `", - dynamic::typeName(actual), '\'')) -{} - -TypeError::TypeError(const std::string& expected, - dynamic::Type actual1, dynamic::Type actual2) - : std::runtime_error(to("TypeError: expected dynamic " - "types `", expected, '\'', ", but had types `", - dynamic::typeName(actual1), "' and `", dynamic::typeName(actual2), - '\'')) -{} + : std::runtime_error(sformat( + "TypeError: expected dynamic type `{}', but had type `{}'", + expected, + dynamic::typeName(actual))) {} + +TypeError::TypeError( + const std::string& expected, + dynamic::Type actual1, + dynamic::Type actual2) + : std::runtime_error(sformat( + "TypeError: expected dynamic types `{}, but had types `{}' and `{}'", + expected, + dynamic::typeName(actual1), + dynamic::typeName(actual2))) {} TypeError::~TypeError() = default; +[[noreturn]] void throwTypeError_( + std::string const& expected, + dynamic::Type actual) { + throw TypeError(expected, actual); +} + +[[noreturn]] void throwTypeError_( + std::string const& expected, + dynamic::Type actual1, + dynamic::Type actual2) { + throw TypeError(expected, actual1, actual2); +} + // This is a higher-order preprocessor macro to aid going from runtime // types to the compile time type system. #define FB_DYNAMIC_APPLY(type, apply) \ @@ -93,7 +109,7 @@ TypeError::~TypeError() = default; bool dynamic::operator<(dynamic const& o) const { if (UNLIKELY(type_ == OBJECT || o.type_ == OBJECT)) { - throw TypeError("object", type_); + throwTypeError_("object", type_); } if (type_ != o.type_) { return type_ < o.type_; @@ -156,7 +172,7 @@ dynamic& dynamic::operator=(dynamic&& o) noexcept { dynamic& dynamic::operator[](dynamic const& k) & { if (!isObject() && !isArray()) { - throw TypeError("object/array", type()); + throwTypeError_("object/array", type()); } if (isArray()) { return at(k); @@ -203,7 +219,7 @@ dynamic dynamic::getDefault(const dynamic& k, dynamic&& v) && { const dynamic* dynamic::get_ptr(dynamic const& idx) const& { if (auto* parray = get_nothrow()) { if (!idx.isInt()) { - throw TypeError("int64", idx.type()); + throwTypeError_("int64", idx.type()); } if (idx < 0 || idx >= parray->size()) { return nullptr; @@ -216,14 +232,19 @@ const dynamic* dynamic::get_ptr(dynamic const& idx) const& { } return &it->second; } else { - throw TypeError("object/array", type()); + throwTypeError_("object/array", type()); } } +[[noreturn]] static void throwOutOfRangeAtMissingKey(dynamic const& idx) { + auto msg = sformat("couldn't find key {} in dynamic object", idx.asString()); + std::__throw_out_of_range(msg.c_str()); +} + dynamic const& dynamic::at(dynamic const& idx) const& { if (auto* parray = get_nothrow()) { if (!idx.isInt()) { - throw TypeError("int64", idx.type()); + throwTypeError_("int64", idx.type()); } if (idx < 0 || idx >= parray->size()) { std::__throw_out_of_range("out of range in dynamic array"); @@ -232,12 +253,11 @@ dynamic const& dynamic::at(dynamic const& idx) const& { } else if (auto* pobject = get_nothrow()) { auto it = pobject->find(idx); if (it == pobject->end()) { - throw std::out_of_range(to( - "couldn't find key ", idx.asString(), " in dynamic object")); + throwOutOfRangeAtMissingKey(idx); } return it->second; } else { - throw TypeError("object/array", type()); + throwTypeError_("object/array", type()); } } @@ -251,7 +271,7 @@ std::size_t dynamic::size() const { if (auto* str = get_nothrow()) { return str->size(); } - throw TypeError("array/object", type()); + throwTypeError_("array/object", type()); } dynamic::iterator dynamic::erase(const_iterator first, const_iterator last) { @@ -266,7 +286,7 @@ std::size_t dynamic::hash() const { case OBJECT: case ARRAY: case NULLT: - throw TypeError("not null/object/array", type()); + throwTypeError_("not null/object/array", type()); case INT64: return std::hash()(getInt()); case DOUBLE: -- 2.34.1