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);
//////////////////////////////////////////////////////////////////////
template<template<class> 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;
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<int64_t>() 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<int64_t>() op o.asInt(); \
+ return *this; \
}
FB_DYNAMIC_INTEGER_OP(%=)
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()) {
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
case STRING:
return to<T>(*get_nothrow<std::string>());
default:
- throw TypeError("int/double/bool/string", type());
+ throwTypeError_("int/double/bool/string", type());
}
}
if (auto* p = get_nothrow<T>()) {
return *p;
}
- throw TypeError(TypeInfo<T>::name, type());
+ throwTypeError_(TypeInfo<T>::name, type());
}
template<class T>
#include <folly/dynamic.h>
#include <folly/Assume.h>
+#include <folly/Format.h>
#include <folly/Hash.h>
#include <folly/portability/BitsFunctexcept.h>
}
TypeError::TypeError(const std::string& expected, dynamic::Type actual)
- : std::runtime_error(to<std::string>("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<std::string>("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) \
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_;
dynamic& dynamic::operator[](dynamic const& k) & {
if (!isObject() && !isArray()) {
- throw TypeError("object/array", type());
+ throwTypeError_("object/array", type());
}
if (isArray()) {
return at(k);
const dynamic* dynamic::get_ptr(dynamic const& idx) const& {
if (auto* parray = get_nothrow<Array>()) {
if (!idx.isInt()) {
- throw TypeError("int64", idx.type());
+ throwTypeError_("int64", idx.type());
}
if (idx < 0 || idx >= parray->size()) {
return nullptr;
}
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<Array>()) {
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");
} else if (auto* pobject = get_nothrow<ObjectImpl>()) {
auto it = pobject->find(idx);
if (it == pobject->end()) {
- throw std::out_of_range(to<std::string>(
- "couldn't find key ", idx.asString(), " in dynamic object"));
+ throwOutOfRangeAtMissingKey(idx);
}
return it->second;
} else {
- throw TypeError("object/array", type());
+ throwTypeError_("object/array", type());
}
}
if (auto* str = get_nothrow<std::string>()) {
return str->size();
}
- throw TypeError("array/object", type());
+ throwTypeError_("array/object", type());
}
dynamic::iterator dynamic::erase(const_iterator first, const_iterator last) {
case OBJECT:
case ARRAY:
case NULLT:
- throw TypeError("not null/object/array", type());
+ throwTypeError_("not null/object/array", type());
case INT64:
return std::hash<int64_t>()(getInt());
case DOUBLE: