Commit 12b5fff0 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

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
parent 4fbcb4b8
...@@ -78,11 +78,20 @@ namespace folly { ...@@ -78,11 +78,20 @@ namespace folly {
struct TypeError : std::runtime_error { struct TypeError : std::runtime_error {
explicit TypeError(const std::string& expected, dynamic::Type actual); explicit TypeError(const std::string& expected, dynamic::Type actual);
explicit TypeError(const std::string& expected, explicit TypeError(
dynamic::Type actual1, dynamic::Type actual2); const std::string& expected,
dynamic::Type actual1,
dynamic::Type actual2);
~TypeError() override; ~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 { ...@@ -102,7 +111,7 @@ namespace detail {
template<template<class> class Op> template<template<class> class Op>
dynamic numericOp(dynamic const& a, dynamic const& b) { dynamic numericOp(dynamic const& a, dynamic const& b) {
if (!a.isNumber() || !b.isNumber()) { if (!a.isNumber() || !b.isNumber()) {
throw TypeError("numeric", a.type(), b.type()); throwTypeError_("numeric", a.type(), b.type());
} }
if (a.type() != b.type()) { if (a.type() != b.type()) {
auto& integ = a.isInt() ? a : b; auto& integ = a.isInt() ? a : b;
...@@ -517,13 +526,13 @@ inline dynamic& dynamic::operator/=(dynamic const& o) { ...@@ -517,13 +526,13 @@ inline dynamic& dynamic::operator/=(dynamic const& o) {
return *this; return *this;
} }
#define FB_DYNAMIC_INTEGER_OP(op) \ #define FB_DYNAMIC_INTEGER_OP(op) \
inline dynamic& dynamic::operator op(dynamic const& o) { \ inline dynamic& dynamic::operator op(dynamic const& o) { \
if (!isInt() || !o.isInt()) { \ if (!isInt() || !o.isInt()) { \
throw TypeError("int64", type(), o.type()); \ throwTypeError_("int64", type(), o.type()); \
} \ } \
*getAddress<int64_t>() op o.asInt(); \ *getAddress<int64_t>() op o.asInt(); \
return *this; \ return *this; \
} }
FB_DYNAMIC_INTEGER_OP(%=) FB_DYNAMIC_INTEGER_OP(%=)
...@@ -606,7 +615,7 @@ template<class K, class V> inline void dynamic::insert(K&& key, V&& val) { ...@@ -606,7 +615,7 @@ template<class K, class V> inline void dynamic::insert(K&& key, V&& val) {
inline void dynamic::update(const dynamic& mergeObj) { inline void dynamic::update(const dynamic& mergeObj) {
if (!isObject() || !mergeObj.isObject()) { if (!isObject() || !mergeObj.isObject()) {
throw TypeError("object", type(), mergeObj.type()); throwTypeError_("object", type(), mergeObj.type());
} }
for (const auto& pair : mergeObj.items()) { for (const auto& pair : mergeObj.items()) {
...@@ -616,7 +625,7 @@ inline void dynamic::update(const dynamic& mergeObj) { ...@@ -616,7 +625,7 @@ inline void dynamic::update(const dynamic& mergeObj) {
inline void dynamic::update_missing(const dynamic& mergeObj1) { inline void dynamic::update_missing(const dynamic& mergeObj1) {
if (!isObject() || !mergeObj1.isObject()) { if (!isObject() || !mergeObj1.isObject()) {
throw TypeError("object", type(), mergeObj1.type()); throwTypeError_("object", type(), mergeObj1.type());
} }
// Only add if not already there // Only add if not already there
...@@ -735,7 +744,7 @@ T dynamic::asImpl() const { ...@@ -735,7 +744,7 @@ T dynamic::asImpl() const {
case STRING: case STRING:
return to<T>(*get_nothrow<std::string>()); return to<T>(*get_nothrow<std::string>());
default: default:
throw TypeError("int/double/bool/string", type()); throwTypeError_("int/double/bool/string", type());
} }
} }
...@@ -804,7 +813,7 @@ T& dynamic::get() { ...@@ -804,7 +813,7 @@ T& dynamic::get() {
if (auto* p = get_nothrow<T>()) { if (auto* p = get_nothrow<T>()) {
return *p; return *p;
} }
throw TypeError(TypeInfo<T>::name, type()); throwTypeError_(TypeInfo<T>::name, type());
} }
template<class T> template<class T>
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <folly/dynamic.h> #include <folly/dynamic.h>
#include <folly/Assume.h> #include <folly/Assume.h>
#include <folly/Format.h>
#include <folly/Hash.h> #include <folly/Hash.h>
#include <folly/portability/BitsFunctexcept.h> #include <folly/portability/BitsFunctexcept.h>
...@@ -44,21 +45,36 @@ const char* dynamic::typeName() const { ...@@ -44,21 +45,36 @@ const char* dynamic::typeName() const {
} }
TypeError::TypeError(const std::string& expected, dynamic::Type actual) TypeError::TypeError(const std::string& expected, dynamic::Type actual)
: std::runtime_error(to<std::string>("TypeError: expected dynamic " : std::runtime_error(sformat(
"type `", expected, '\'', ", but had type `", "TypeError: expected dynamic type `{}', but had type `{}'",
dynamic::typeName(actual), '\'')) expected,
{} dynamic::typeName(actual))) {}
TypeError::TypeError(const std::string& expected, TypeError::TypeError(
dynamic::Type actual1, dynamic::Type actual2) const std::string& expected,
: std::runtime_error(to<std::string>("TypeError: expected dynamic " dynamic::Type actual1,
"types `", expected, '\'', ", but had types `", dynamic::Type actual2)
dynamic::typeName(actual1), "' and `", dynamic::typeName(actual2), : std::runtime_error(sformat(
'\'')) "TypeError: expected dynamic types `{}, but had types `{}' and `{}'",
{} expected,
dynamic::typeName(actual1),
dynamic::typeName(actual2))) {}
TypeError::~TypeError() = default; 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 // This is a higher-order preprocessor macro to aid going from runtime
// types to the compile time type system. // types to the compile time type system.
#define FB_DYNAMIC_APPLY(type, apply) \ #define FB_DYNAMIC_APPLY(type, apply) \
...@@ -93,7 +109,7 @@ TypeError::~TypeError() = default; ...@@ -93,7 +109,7 @@ TypeError::~TypeError() = default;
bool dynamic::operator<(dynamic const& o) const { bool dynamic::operator<(dynamic const& o) const {
if (UNLIKELY(type_ == OBJECT || o.type_ == OBJECT)) { if (UNLIKELY(type_ == OBJECT || o.type_ == OBJECT)) {
throw TypeError("object", type_); throwTypeError_("object", type_);
} }
if (type_ != o.type_) { if (type_ != o.type_) {
return type_ < o.type_; return type_ < o.type_;
...@@ -156,7 +172,7 @@ dynamic& dynamic::operator=(dynamic&& o) noexcept { ...@@ -156,7 +172,7 @@ dynamic& dynamic::operator=(dynamic&& o) noexcept {
dynamic& dynamic::operator[](dynamic const& k) & { dynamic& dynamic::operator[](dynamic const& k) & {
if (!isObject() && !isArray()) { if (!isObject() && !isArray()) {
throw TypeError("object/array", type()); throwTypeError_("object/array", type());
} }
if (isArray()) { if (isArray()) {
return at(k); return at(k);
...@@ -203,7 +219,7 @@ dynamic dynamic::getDefault(const dynamic& k, dynamic&& v) && { ...@@ -203,7 +219,7 @@ dynamic dynamic::getDefault(const dynamic& k, dynamic&& v) && {
const dynamic* dynamic::get_ptr(dynamic const& idx) const& { const dynamic* dynamic::get_ptr(dynamic const& idx) const& {
if (auto* parray = get_nothrow<Array>()) { if (auto* parray = get_nothrow<Array>()) {
if (!idx.isInt()) { if (!idx.isInt()) {
throw TypeError("int64", idx.type()); throwTypeError_("int64", idx.type());
} }
if (idx < 0 || idx >= parray->size()) { if (idx < 0 || idx >= parray->size()) {
return nullptr; return nullptr;
...@@ -216,14 +232,19 @@ const dynamic* dynamic::get_ptr(dynamic const& idx) const& { ...@@ -216,14 +232,19 @@ const dynamic* dynamic::get_ptr(dynamic const& idx) const& {
} }
return &it->second; return &it->second;
} else { } 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& { dynamic const& dynamic::at(dynamic const& idx) const& {
if (auto* parray = get_nothrow<Array>()) { if (auto* parray = get_nothrow<Array>()) {
if (!idx.isInt()) { if (!idx.isInt()) {
throw TypeError("int64", idx.type()); throwTypeError_("int64", idx.type());
} }
if (idx < 0 || idx >= parray->size()) { if (idx < 0 || idx >= parray->size()) {
std::__throw_out_of_range("out of range in dynamic array"); std::__throw_out_of_range("out of range in dynamic array");
...@@ -232,12 +253,11 @@ dynamic const& dynamic::at(dynamic const& idx) const& { ...@@ -232,12 +253,11 @@ dynamic const& dynamic::at(dynamic const& idx) const& {
} else if (auto* pobject = get_nothrow<ObjectImpl>()) { } else if (auto* pobject = get_nothrow<ObjectImpl>()) {
auto it = pobject->find(idx); auto it = pobject->find(idx);
if (it == pobject->end()) { if (it == pobject->end()) {
throw std::out_of_range(to<std::string>( throwOutOfRangeAtMissingKey(idx);
"couldn't find key ", idx.asString(), " in dynamic object"));
} }
return it->second; return it->second;
} else { } else {
throw TypeError("object/array", type()); throwTypeError_("object/array", type());
} }
} }
...@@ -251,7 +271,7 @@ std::size_t dynamic::size() const { ...@@ -251,7 +271,7 @@ std::size_t dynamic::size() const {
if (auto* str = get_nothrow<std::string>()) { if (auto* str = get_nothrow<std::string>()) {
return str->size(); return str->size();
} }
throw TypeError("array/object", type()); throwTypeError_("array/object", type());
} }
dynamic::iterator dynamic::erase(const_iterator first, const_iterator last) { dynamic::iterator dynamic::erase(const_iterator first, const_iterator last) {
...@@ -266,7 +286,7 @@ std::size_t dynamic::hash() const { ...@@ -266,7 +286,7 @@ std::size_t dynamic::hash() const {
case OBJECT: case OBJECT:
case ARRAY: case ARRAY:
case NULLT: case NULLT:
throw TypeError("not null/object/array", type()); throwTypeError_("not null/object/array", type());
case INT64: case INT64:
return std::hash<int64_t>()(getInt()); return std::hash<int64_t>()(getInt());
case DOUBLE: case DOUBLE:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment