/*
- * Copyright 2015 Facebook, Inc.
+ * Copyright 2016 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
dynamic val_;
};
+inline void dynamic::array(EmptyArrayTag) {}
+
+template <class... Args>
+inline dynamic dynamic::array(Args&& ...args) {
+ return dynamic(std::initializer_list<dynamic>{std::forward<Args>(args)...},
+ PrivateTag());
+}
+
// This looks like a case for perfect forwarding, but our use of
// std::initializer_list for constructing dynamic arrays makes it less
// functional than doing this manually.
+
+// TODO(ott, 10300209): When the initializer_list constructor is gone,
+// simplify this.
inline dynamic::ObjectMaker dynamic::object() { return ObjectMaker(); }
inline dynamic::ObjectMaker dynamic::object(dynamic&& a, dynamic&& b) {
return ObjectMaker(std::move(a), std::move(b));
//////////////////////////////////////////////////////////////////////
+inline dynamic::dynamic(void (*)(EmptyArrayTag))
+ : type_(ARRAY)
+{
+ new (&u_.array) Array();
+}
+
inline dynamic::dynamic(ObjectMaker (*)())
: type_(OBJECT)
{
}
inline dynamic::dynamic(std::initializer_list<dynamic> il)
+ : dynamic(std::move(il), PrivateTag()) {
+}
+
+inline dynamic::dynamic(std::initializer_list<dynamic> il, PrivateTag)
: type_(ARRAY)
{
new (&u_.array) Array(il.begin(), il.end());
}
+inline dynamic& dynamic::operator=(std::initializer_list<dynamic> il) {
+ (*this) = dynamic(il, PrivateTag());
+ return *this;
+}
+
inline dynamic::dynamic(ObjectMaker&& maker)
: type_(OBJECT)
{
rv.first->second = std::forward<V>(val);
}
+inline void dynamic::update(const dynamic& mergeObj) {
+ if (!isObject() || !mergeObj.isObject()) {
+ throw TypeError("object", type(), mergeObj.type());
+ }
+
+ for (const auto& pair : mergeObj.items()) {
+ (*this)[pair.first] = pair.second;
+ }
+}
+
+inline void dynamic::update_missing(const dynamic& mergeObj1) {
+ if (!isObject() || !mergeObj1.isObject()) {
+ throw TypeError("object", type(), mergeObj1.type());
+ }
+
+ // Only add if not already there
+ for (const auto& pair : mergeObj1.items()) {
+ if ((*this).find(pair.first) == (*this).items().end()) {
+ (*this)[pair.first] = pair.second;
+ }
+ }
+}
+
+inline dynamic dynamic::merge(
+ const dynamic& mergeObj1,
+ const dynamic& mergeObj2) {
+
+ // No checks on type needed here because they are done in update_missing
+ // Note that we do update_missing here instead of update() because
+ // it will prevent the extra writes that would occur with update()
+ auto ret = mergeObj2;
+ ret.update_missing(mergeObj1);
+ return ret;
+}
+
inline std::size_t dynamic::erase(dynamic const& key) {
auto& obj = get<ObjectImpl>();
return obj.erase(key);
}
inline void dynamic::resize(std::size_t sz, dynamic const& c) {
- auto& array = get<Array>();
- array.resize(sz, c);
+ auto& arr = get<Array>();
+ arr.resize(sz, c);
}
inline void dynamic::push_back(dynamic const& v) {
- auto& array = get<Array>();
- array.push_back(v);
+ auto& arr = get<Array>();
+ arr.push_back(v);
}
inline void dynamic::push_back(dynamic&& v) {
- auto& array = get<Array>();
- array.push_back(std::move(v));
+ auto& arr = get<Array>();
+ arr.push_back(std::move(v));
}
inline void dynamic::pop_back() {
- auto& array = get<Array>();
- array.pop_back();
+ auto& arr = get<Array>();
+ arr.pop_back();
}
//////////////////////////////////////////////////////////////////////
-template<class T> struct dynamic::TypeInfo {
- static char const name[];
- static Type const type;
-};
-
-#define FB_DEC_TYPE(T) \
- template<> char const dynamic::TypeInfo<T>::name[]; \
- template<> dynamic::Type const dynamic::TypeInfo<T>::type
+#define FOLLY_DYNAMIC_DEC_TYPEINFO(T, str, val) \
+ template <> struct dynamic::TypeInfo<T> { \
+ static constexpr const char* name = str; \
+ static constexpr dynamic::Type type = val; \
+ }; \
+ //
-FB_DEC_TYPE(void*);
-FB_DEC_TYPE(bool);
-FB_DEC_TYPE(fbstring);
-FB_DEC_TYPE(dynamic::Array);
-FB_DEC_TYPE(double);
-FB_DEC_TYPE(int64_t);
-FB_DEC_TYPE(dynamic::ObjectImpl);
+FOLLY_DYNAMIC_DEC_TYPEINFO(void*, "null", dynamic::NULLT)
+FOLLY_DYNAMIC_DEC_TYPEINFO(bool, "boolean", dynamic::BOOL)
+FOLLY_DYNAMIC_DEC_TYPEINFO(fbstring, "string", dynamic::STRING)
+FOLLY_DYNAMIC_DEC_TYPEINFO(dynamic::Array, "array", dynamic::ARRAY)
+FOLLY_DYNAMIC_DEC_TYPEINFO(double, "double", dynamic::DOUBLE)
+FOLLY_DYNAMIC_DEC_TYPEINFO(int64_t, "int64", dynamic::INT64)
+FOLLY_DYNAMIC_DEC_TYPEINFO(dynamic::ObjectImpl, "object", dynamic::OBJECT)
-#undef FB_DEC_TYPE
+#undef FOLLY_DYNAMIC_DEC_TYPEINFO
template<class T>
T dynamic::asImpl() const {
out << t;
}
};
+// Otherwise, null, being (void*)0, would print as 0.
+template <>
+struct dynamic::PrintImpl<void*> {
+ static void print(dynamic const& /* d */,
+ std::ostream& out,
+ void* const& nul) {
+ DCHECK_EQ((void*)0, nul);
+ out << "null";
+ }
+};
template<>
struct dynamic::PrintImpl<dynamic::ObjectImpl> {
static void print(dynamic const& d,