//////////////////////////////////////////////////////////////////////
-#define DEF_TYPE(T, str, typen) \
- template<> char const dynamic::TypeInfo<T>::name[] = str; \
- template<> dynamic::Type const dynamic::TypeInfo<T>::type = typen
+#define FOLLY_DYNAMIC_DEF_TYPEINFO(T) \
+ constexpr const char* dynamic::TypeInfo<T>::name; \
+ constexpr dynamic::Type dynamic::TypeInfo<T>::type; \
+ //
-DEF_TYPE(void*, "null", dynamic::NULLT);
-DEF_TYPE(bool, "boolean", dynamic::BOOL);
-DEF_TYPE(fbstring, "string", dynamic::STRING);
-DEF_TYPE(dynamic::Array, "array", dynamic::ARRAY);
-DEF_TYPE(double, "double", dynamic::DOUBLE);
-DEF_TYPE(int64_t, "int64", dynamic::INT64);
-DEF_TYPE(dynamic::ObjectImpl, "object", dynamic::OBJECT);
+FOLLY_DYNAMIC_DEF_TYPEINFO(void*)
+FOLLY_DYNAMIC_DEF_TYPEINFO(bool)
+FOLLY_DYNAMIC_DEF_TYPEINFO(fbstring)
+FOLLY_DYNAMIC_DEF_TYPEINFO(dynamic::Array)
+FOLLY_DYNAMIC_DEF_TYPEINFO(double)
+FOLLY_DYNAMIC_DEF_TYPEINFO(int64_t)
+FOLLY_DYNAMIC_DEF_TYPEINFO(dynamic::ObjectImpl)
-#undef DEF_TYPE
+#undef FOLLY_DYNAMIC_DEF_TYPEINFO
const char* dynamic::typeName() const {
return typeName(type_);
'\''))
{}
-TypeError::~TypeError() {}
+TypeError::~TypeError() = default;
// This is a higher-order preprocessor macro to aid going from runtime
// types to the compile time type system.
dynamic& dynamic::operator=(dynamic const& o) {
if (&o != this) {
- destroy();
+ if (type_ == o.type_) {
+#define FB_X(T) *getAddress<T>() = *o.getAddress<T>()
+ FB_DYNAMIC_APPLY(type_, FB_X);
+#undef FB_X
+ } else {
+ destroy();
#define FB_X(T) new (getAddress<T>()) T(*o.getAddress<T>())
- FB_DYNAMIC_APPLY(o.type_, FB_X);
+ FB_DYNAMIC_APPLY(o.type_, FB_X);
#undef FB_X
- type_ = o.type_;
+ type_ = o.type_;
+ }
}
return *this;
}
dynamic& dynamic::operator=(dynamic&& o) noexcept {
if (&o != this) {
- destroy();
+ if (type_ == o.type_) {
+#define FB_X(T) *getAddress<T>() = std::move(*o.getAddress<T>())
+ FB_DYNAMIC_APPLY(type_, FB_X);
+#undef FB_X
+ } else {
+ destroy();
#define FB_X(T) new (getAddress<T>()) T(std::move(*o.getAddress<T>()))
- FB_DYNAMIC_APPLY(o.type_, FB_X);
+ FB_DYNAMIC_APPLY(o.type_, FB_X);
#undef FB_X
- type_ = o.type_;
+ type_ = o.type_;
+ }
}
return *this;
}
-dynamic& dynamic::operator[](dynamic const& k) {
+dynamic& dynamic::operator[](dynamic const& k) & {
if (!isObject() && !isArray()) {
throw TypeError("object/array", type());
}
return ret.first->second;
}
-dynamic dynamic::getDefault(const dynamic& k, const dynamic& v) const {
+dynamic dynamic::getDefault(const dynamic& k, const dynamic& v) const& {
auto& obj = get<ObjectImpl>();
auto it = obj.find(k);
return it == obj.end() ? v : it->second;
}
-dynamic&& dynamic::getDefault(const dynamic& k, dynamic&& v) const {
+dynamic dynamic::getDefault(const dynamic& k, dynamic&& v) const& {
auto& obj = get<ObjectImpl>();
auto it = obj.find(k);
- if (it != obj.end()) {
- v = it->second;
+ // Avoid clang bug with ternary
+ if (it == obj.end()) {
+ return std::move(v);
+ } else {
+ return it->second;
}
+}
- return std::move(v);
+dynamic dynamic::getDefault(const dynamic& k, const dynamic& v) && {
+ auto& obj = get<ObjectImpl>();
+ auto it = obj.find(k);
+ // Avoid clang bug with ternary
+ if (it == obj.end()) {
+ return v;
+ } else {
+ return std::move(it->second);
+ }
+}
+
+dynamic dynamic::getDefault(const dynamic& k, dynamic&& v) && {
+ auto& obj = get<ObjectImpl>();
+ auto it = obj.find(k);
+ return std::move(it == obj.end() ? v : it->second);
}
-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 (!idx.isInt()) {
throw TypeError("int64", idx.type());
}
- if (idx >= parray->size()) {
+ if (idx < 0 || idx >= parray->size()) {
return nullptr;
}
return &(*parray)[idx.asInt()];
}
}
-dynamic const& dynamic::at(dynamic const& idx) const {
+dynamic const& dynamic::at(dynamic const& idx) const& {
if (auto* parray = get_nothrow<Array>()) {
if (!idx.isInt()) {
throw TypeError("int64", idx.type());
}
- if (idx >= parray->size()) {
+ if (idx < 0 || idx >= parray->size()) {
throw std::out_of_range("out of range in dynamic array");
}
return (*parray)[idx.asInt()];