Improve the DelayedDestruction smart pointer
[folly.git] / folly / dynamic.cpp
index 63b737558a0e21897d75d6d79a9d282a1e5e4356..725cf56ad1bb0beaf90a2d38b8e24346d110af6a 100644 (file)
@@ -20,19 +20,20 @@ namespace folly {
 
 //////////////////////////////////////////////////////////////////////
 
-#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_);
@@ -52,7 +53,7 @@ TypeError::TypeError(const std::string& expected,
       '\''))
 {}
 
-TypeError::~TypeError() {}
+TypeError::~TypeError() = default;
 
 // This is a higher-order preprocessor macro to aid going from runtime
 // types to the compile time type system.
@@ -100,27 +101,39 @@ bool dynamic::operator==(dynamic const& o) const {
 
 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());
   }
@@ -132,28 +145,46 @@ dynamic& dynamic::operator[](dynamic const& k) {
   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()];
@@ -168,12 +199,12 @@ const dynamic* dynamic::get_ptr(dynamic const& idx) const {
   }
 }
 
-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()];