+dynamic dynamic::getDefault(const dynamic& k, dynamic&& v) const& {
+ auto& obj = get<ObjectImpl>();
+ auto it = obj.find(k);
+ // Avoid clang bug with ternary
+ if (it == obj.end()) {
+ return std::move(v);
+ } else {
+ return it->second;
+ }
+}
+
+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& {
+ if (auto* parray = get_nothrow<Array>()) {
+ if (!idx.isInt()) {
+ throwTypeError_("int64", idx.type());
+ }
+ if (idx < 0 || idx >= parray->size()) {
+ return nullptr;
+ }
+ return &(*parray)[size_t(idx.asInt())];
+ } else if (auto* pobject = get_nothrow<ObjectImpl>()) {
+ auto it = pobject->find(idx);
+ if (it == pobject->end()) {
+ return nullptr;
+ }
+ return &it->second;
+ } else {
+ 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()) {
+ throwTypeError_("int64", idx.type());
+ }
+ if (idx < 0 || idx >= parray->size()) {
+ std::__throw_out_of_range("out of range in dynamic array");
+ }
+ return (*parray)[size_t(idx.asInt())];
+ } else if (auto* pobject = get_nothrow<ObjectImpl>()) {
+ auto it = pobject->find(idx);
+ if (it == pobject->end()) {
+ throwOutOfRangeAtMissingKey(idx);
+ }
+ return it->second;
+ } else {
+ throwTypeError_("object/array", type());
+ }
+}
+
+std::size_t dynamic::size() const {
+ if (auto* ar = get_nothrow<Array>()) {
+ return ar->size();
+ }
+ if (auto* obj = get_nothrow<ObjectImpl>()) {
+ return obj->size();
+ }
+ if (auto* str = get_nothrow<std::string>()) {
+ return str->size();
+ }
+ throwTypeError_("array/object", type());
+}
+
+dynamic::iterator dynamic::erase(const_iterator first, const_iterator last) {
+ auto& arr = get<Array>();
+ return get<Array>().erase(
+ arr.begin() + (first - arr.begin()),
+ arr.begin() + (last - arr.begin()));
+}
+
+std::size_t dynamic::hash() const {
+ switch (type()) {
+ case OBJECT:
+ case ARRAY:
+ case NULLT:
+ throwTypeError_("not null/object/array", type());
+ case INT64:
+ return std::hash<int64_t>()(getInt());
+ case DOUBLE:
+ return std::hash<double>()(getDouble());
+ case BOOL:
+ return std::hash<bool>()(getBool());
+ case STRING: {
+ // keep it compatible with FBString
+ const auto& str = getString();
+ return ::folly::hash::fnv32_buf(str.data(), str.size());
+ }
+ }
+ assume_unreachable();
+}
+
+char const* dynamic::typeName(Type t) {
+#define FB_X(T) return TypeInfo<T>::name
+ FB_DYNAMIC_APPLY(t, FB_X);
+#undef FB_X
+}
+
+void dynamic::destroy() noexcept {
+ // This short-circuit speeds up some microbenchmarks.
+ if (type_ == NULLT) return;
+
+#define FB_X(T) detail::Destroy::destroy(getAddress<T>())
+ FB_DYNAMIC_APPLY(type_, FB_X);
+#undef FB_X
+ type_ = NULLT;
+ u_.nul = nullptr;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+}