X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=folly%2Fdynamic-inl.h;h=984b7a4cac9da7aa04c451ca67337673e612c0a5;hb=d1af84b686a8eb9a360c28bedac3cee2a0a3f5f0;hp=204d48f91f7af271f92f58e995a4f6cc2efe8973;hpb=c2c66129648524ddb456fa44b35c1531dd103004;p=folly.git diff --git a/folly/dynamic-inl.h b/folly/dynamic-inl.h index 204d48f9..984b7a4c 100644 --- a/folly/dynamic-inl.h +++ b/folly/dynamic-inl.h @@ -1,5 +1,5 @@ /* - * Copyright 2014 Facebook, Inc. + * Copyright 2017 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,15 +14,14 @@ * limitations under the License. */ -#ifndef FOLLY_DYNAMIC_INL_H_ -#define FOLLY_DYNAMIC_INL_H_ +#pragma once #include #include #include -#include "folly/Likely.h" -#include "folly/Conv.h" -#include "folly/Format.h" +#include +#include +#include ////////////////////////////////////////////////////////////////////// @@ -41,36 +40,45 @@ struct hash< ::folly::dynamic> { // 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) do { \ - switch ((type)) { \ - case NULLT: apply(void*); break; \ - case ARRAY: apply(Array); break; \ - case BOOL: apply(bool); break; \ - case DOUBLE: apply(double); break; \ - case INT64: apply(int64_t); break; \ - case OBJECT: apply(ObjectImpl); break; \ - case STRING: apply(fbstring); break; \ - default: CHECK(0); abort(); \ - } \ -} while (0) +#define FB_DYNAMIC_APPLY(type, apply) \ + do { \ + switch ((type)) { \ + case NULLT: \ + apply(void*); \ + break; \ + case ARRAY: \ + apply(Array); \ + break; \ + case BOOL: \ + apply(bool); \ + break; \ + case DOUBLE: \ + apply(double); \ + break; \ + case INT64: \ + apply(int64_t); \ + break; \ + case OBJECT: \ + apply(ObjectImpl); \ + break; \ + case STRING: \ + apply(std::string); \ + break; \ + default: \ + CHECK(0); \ + abort(); \ + } \ + } while (0) ////////////////////////////////////////////////////////////////////// namespace folly { struct TypeError : std::runtime_error { - explicit TypeError(const std::string& expected, dynamic::Type actual) - : std::runtime_error(to("TypeError: expected dynamic " - "type `", expected, '\'', ", but had type `", - dynamic::typeName(actual), '\'')) - {} + explicit TypeError(const std::string& expected, dynamic::Type actual); explicit TypeError(const std::string& expected, - dynamic::Type actual1, dynamic::Type actual2) - : std::runtime_error(to("TypeError: expected dynamic " - "types `", expected, '\'', ", but had types `", - dynamic::typeName(actual1), "' and `", dynamic::typeName(actual2), - '\'')) - {} + dynamic::Type actual1, dynamic::Type actual2); + ~TypeError(); }; @@ -84,41 +92,6 @@ namespace detail { template static void destroy(T* t) { t->~T(); } }; - /* - * The enable_if junk here is necessary to avoid ambiguous - * conversions relating to bool and double when you implicitly - * convert an int or long to a dynamic. - */ - template struct ConversionHelper; - template - struct ConversionHelper< - T, - typename std::enable_if< - std::is_integral::value && !std::is_same::value - >::type - > { - typedef int64_t type; - }; - template - struct ConversionHelper< - T, - typename std::enable_if< - (!std::is_integral::value || std::is_same::value) && - !std::is_same::value - >::type - > { - typedef T type; - }; - template - struct ConversionHelper< - T, - typename std::enable_if< - std::is_same::value - >::type - > { - typedef void* type; - }; - /* * Helper for implementing numeric conversions in operators on * numbers. Just promotes to double when one of the arguments is @@ -162,12 +135,7 @@ struct dynamic::ObjectMaker { friend struct dynamic; explicit ObjectMaker() : val_(dynamic::object) {} - explicit ObjectMaker(dynamic const& key, dynamic val) - : val_(dynamic::object) - { - val_.insert(key, std::move(val)); - } - explicit ObjectMaker(dynamic&& key, dynamic val) + explicit ObjectMaker(dynamic key, dynamic val) : val_(dynamic::object) { val_.insert(std::move(key), std::move(val)); @@ -180,15 +148,10 @@ struct dynamic::ObjectMaker { ObjectMaker& operator=(ObjectMaker const&) = delete; ObjectMaker& operator=(ObjectMaker&&) = delete; - // These return rvalue-references instead of lvalue-references to allow - // constructs like this to moved instead of copied: + // This returns an rvalue-reference instead of an lvalue-reference + // to allow constructs like this to moved instead of copied: // dynamic a = dynamic::object("a", "b")("c", "d") - ObjectMaker&& operator()(dynamic const& key, dynamic val) { - val_.insert(key, std::move(val)); - return std::move(*this); - } - - ObjectMaker&& operator()(dynamic&& key, dynamic val) { + ObjectMaker&& operator()(dynamic key, dynamic val) { val_.insert(std::move(key), std::move(val)); return std::move(*this); } @@ -197,23 +160,17 @@ private: dynamic val_; }; -// 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. +inline void dynamic::array(EmptyArrayTag) {} + +template +inline dynamic dynamic::array(Args&& ...args) { + return dynamic(Array{std::forward(args)...}); +} + inline dynamic::ObjectMaker dynamic::object() { return ObjectMaker(); } -inline dynamic::ObjectMaker dynamic::object(dynamic&& a, dynamic&& b) { +inline dynamic::ObjectMaker dynamic::object(dynamic a, dynamic b) { return ObjectMaker(std::move(a), std::move(b)); } -inline dynamic::ObjectMaker dynamic::object(dynamic const& a, dynamic&& b) { - return ObjectMaker(a, std::move(b)); -} -inline dynamic::ObjectMaker dynamic::object(dynamic&& a, dynamic const& b) { - return ObjectMaker(std::move(a), b); -} -inline dynamic::ObjectMaker -dynamic::object(dynamic const& a, dynamic const& b) { - return ObjectMaker(a, b); -} ////////////////////////////////////////////////////////////////////// @@ -254,6 +211,16 @@ struct dynamic::const_value_iterator ////////////////////////////////////////////////////////////////////// +inline dynamic::dynamic() : dynamic(nullptr) {} + +inline dynamic::dynamic(std::nullptr_t) : type_(NULLT) {} + +inline dynamic::dynamic(void (*)(EmptyArrayTag)) + : type_(ARRAY) +{ + new (&u_.array) Array(); +} + inline dynamic::dynamic(ObjectMaker (*)()) : type_(OBJECT) { @@ -263,37 +230,19 @@ inline dynamic::dynamic(ObjectMaker (*)()) inline dynamic::dynamic(StringPiece s) : type_(STRING) { - new (&u_.string) fbstring(s.data(), s.size()); + new (&u_.string) std::string(s.data(), s.size()); } inline dynamic::dynamic(char const* s) : type_(STRING) { - new (&u_.string) fbstring(s); -} - -inline dynamic::dynamic(std::string const& s) - : type_(STRING) -{ - new (&u_.string) fbstring(s); -} - -inline dynamic::dynamic(fbstring const& s) - : type_(STRING) -{ - new (&u_.string) fbstring(s); + new (&u_.string) std::string(s); } -inline dynamic::dynamic(fbstring&& s) +inline dynamic::dynamic(std::string s) : type_(STRING) { - new (&u_.string) fbstring(std::move(s)); -} - -inline dynamic::dynamic(std::initializer_list il) - : type_(ARRAY) -{ - new (&u_.array) Array(il.begin(), il.end()); + new (&u_.string) std::string(std::move(s)); } inline dynamic::dynamic(ObjectMaker&& maker) @@ -309,22 +258,40 @@ inline dynamic::dynamic(dynamic const& o) *this = o; } -inline dynamic::dynamic(dynamic&& o) +inline dynamic::dynamic(dynamic&& o) noexcept : type_(NULLT) { *this = std::move(o); } -inline dynamic::~dynamic() { destroy(); } +inline dynamic::~dynamic() noexcept { destroy(); } -template +// Integral types except bool convert to int64_t, float types to double. +template +struct dynamic::NumericTypeHelper< + T, typename std::enable_if::value>::type> { + using type = int64_t; +}; +template <> +struct dynamic::NumericTypeHelper { + using type = bool; +}; +template <> +struct dynamic::NumericTypeHelper { + using type = double; +}; +template <> +struct dynamic::NumericTypeHelper { + using type = double; +}; + +template::type */> dynamic::dynamic(T t) { - typedef typename detail::ConversionHelper::type U; - type_ = TypeInfo::type; - new (getAddress()) U(std::move(t)); + type_ = TypeInfo::type; + new (getAddress()) NumericType(NumericType(t)); } -template +template dynamic::dynamic(Iterator first, Iterator last) : type_(ARRAY) { @@ -374,7 +341,9 @@ inline dynamic::IterableProxy dynamic::items() return &(get()); } -inline bool dynamic::isString() const { return get_nothrow(); } +inline bool dynamic::isString() const { + return get_nothrow(); +} inline bool dynamic::isObject() const { return get_nothrow(); } inline bool dynamic::isBool() const { return get_nothrow(); } inline bool dynamic::isArray() const { return get_nothrow(); } @@ -387,13 +356,49 @@ inline dynamic::Type dynamic::type() const { return type_; } -inline fbstring dynamic::asString() const { return asImpl(); } -inline double dynamic::asDouble() const { return asImpl(); } -inline int64_t dynamic::asInt() const { return asImpl(); } -inline bool dynamic::asBool() const { return asImpl(); } +inline std::string dynamic::asString() const { + return asImpl(); +} +inline double dynamic::asDouble() const { + return asImpl(); +} +inline int64_t dynamic::asInt() const { + return asImpl(); +} +inline bool dynamic::asBool() const { + return asImpl(); +} + +inline const std::string& dynamic::getString() const& { + return get(); +} +inline double dynamic::getDouble() const& { return get(); } +inline int64_t dynamic::getInt() const& { return get(); } +inline bool dynamic::getBool() const& { return get(); } + +inline std::string& dynamic::getString()& { + return get(); +} +inline double& dynamic::getDouble() & { return get(); } +inline int64_t& dynamic::getInt() & { return get(); } +inline bool& dynamic::getBool() & { return get(); } + +inline std::string&& dynamic::getString()&& { + return std::move(get()); +} +inline double dynamic::getDouble() && { return get(); } +inline int64_t dynamic::getInt() && { return get(); } +inline bool dynamic::getBool() && { return get(); } -inline const char* dynamic::data() const { return get().data(); } -inline const char* dynamic::c_str() const { return get().c_str(); } +inline const char* dynamic::data() const& { + return get().data(); +} +inline const char* dynamic::c_str() const& { + return get().c_str(); +} +inline StringPiece dynamic::stringPiece() const { + return get(); +} template struct dynamic::CompareOp { @@ -401,44 +406,15 @@ struct dynamic::CompareOp { }; template<> struct dynamic::CompareOp { - static bool comp(ObjectImpl const& a, ObjectImpl const& b) { + static bool comp(ObjectImpl const&, ObjectImpl const&) { // This code never executes; it is just here for the compiler. return false; } }; -inline bool dynamic::operator<(dynamic const& o) const { - if (UNLIKELY(type_ == OBJECT || o.type_ == OBJECT)) { - throw TypeError("object", type_); - } - if (type_ != o.type_) { - return type_ < o.type_; - } - -#define FB_X(T) return CompareOp::comp(*getAddress(), \ - *o.getAddress()) - FB_DYNAMIC_APPLY(type_, FB_X); -#undef FB_X -} - -inline bool dynamic::operator==(dynamic const& o) const { - if (type() != o.type()) { - if (isNumber() && o.isNumber()) { - auto& integ = isInt() ? *this : o; - auto& doubl = isInt() ? o : *this; - return integ.asInt() == doubl.asDouble(); - } - return false; - } - -#define FB_X(T) return *getAddress() == *o.getAddress(); - FB_DYNAMIC_APPLY(type_, FB_X); -#undef FB_X -} - inline dynamic& dynamic::operator+=(dynamic const& o) { if (type() == STRING && o.type() == STRING) { - *getAddress() += *o.getAddress(); + *getAddress() += *o.getAddress(); return *this; } *this = detail::numericOp(*this, o); @@ -486,113 +462,41 @@ inline dynamic& dynamic::operator--() { return *this; } -inline dynamic& dynamic::operator=(dynamic const& o) { - if (&o != this) { - destroy(); -#define FB_X(T) new (getAddress()) T(*o.getAddress()) - FB_DYNAMIC_APPLY(o.type_, FB_X); -#undef FB_X - type_ = o.type_; - } - return *this; -} - -inline dynamic& dynamic::operator=(dynamic&& o) { - if (&o != this) { - destroy(); -#define FB_X(T) new (getAddress()) T(std::move(*o.getAddress())) - FB_DYNAMIC_APPLY(o.type_, FB_X); -#undef FB_X - type_ = o.type_; - } - return *this; -} - -inline dynamic& dynamic::operator[](dynamic const& k) { - if (!isObject() && !isArray()) { - throw TypeError("object/array", type()); - } - if (isArray()) { - return at(k); - } - auto& obj = get(); - auto ret = obj.insert({k, nullptr}); - return ret.first->second; -} - -inline dynamic const& dynamic::operator[](dynamic const& idx) const { +inline dynamic const& dynamic::operator[](dynamic const& idx) const& { return at(idx); } -inline dynamic dynamic::getDefault(const dynamic& k, const dynamic& v) const { - auto& obj = get(); - auto it = obj.find(k); - return it == obj.end() ? v : it->second; +inline dynamic&& dynamic::operator[](dynamic const& idx) && { + return std::move((*this)[idx]); } -inline dynamic&& dynamic::getDefault(const dynamic& k, dynamic&& v) const { +template inline dynamic& dynamic::setDefault(K&& k, V&& v) { auto& obj = get(); - auto it = obj.find(k); - if (it != obj.end()) { - v = it->second; - } - - return std::move(v); + return obj.insert(std::make_pair(std::forward(k), + std::forward(v))).first->second; } -template inline dynamic& dynamic::setDefault(K&& k, V&& v) { +template inline dynamic& dynamic::setDefault(K&& k, dynamic&& v) { auto& obj = get(); return obj.insert(std::make_pair(std::forward(k), - std::forward(v))).first->second; + std::move(v))).first->second; } -inline dynamic* dynamic::get_ptr(dynamic const& idx) { - return const_cast(const_cast(this)->get_ptr(idx)); +template inline dynamic& dynamic::setDefault(K&& k, const dynamic& v) { + auto& obj = get(); + return obj.insert(std::make_pair(std::forward(k), v)).first->second; } -inline const dynamic* dynamic::get_ptr(dynamic const& idx) const { - if (auto* parray = get_nothrow()) { - if (!idx.isInt()) { - throw TypeError("int64", idx.type()); - } - if (idx >= parray->size()) { - return nullptr; - } - return &(*parray)[idx.asInt()]; - } else if (auto* pobject = get_nothrow()) { - auto it = pobject->find(idx); - if (it == pobject->end()) { - return nullptr; - } - return &it->second; - } else { - throw TypeError("object/array", type()); - } +inline dynamic* dynamic::get_ptr(dynamic const& idx) & { + return const_cast(const_cast(this)->get_ptr(idx)); } -inline dynamic& dynamic::at(dynamic const& idx) { +inline dynamic& dynamic::at(dynamic const& idx) & { return const_cast(const_cast(this)->at(idx)); } -inline dynamic const& dynamic::at(dynamic const& idx) const { - if (auto* parray = get_nothrow()) { - if (!idx.isInt()) { - throw TypeError("int64", idx.type()); - } - if (idx >= parray->size()) { - throw std::out_of_range("out of range in dynamic array"); - } - return (*parray)[idx.asInt()]; - } else if (auto* pobject = get_nothrow()) { - auto it = pobject->find(idx); - if (it == pobject->end()) { - throw std::out_of_range(to( - "couldn't find key ", idx.asString(), " in dynamic object")); - } - return it->second; - } else { - throw TypeError("object/array", type()); - } +inline dynamic&& dynamic::at(dynamic const& idx) && { + return std::move(at(idx)); } inline bool dynamic::empty() const { @@ -602,21 +506,8 @@ inline bool dynamic::empty() const { return !size(); } -inline std::size_t dynamic::size() const { - if (auto* ar = get_nothrow()) { - return ar->size(); - } - if (auto* obj = get_nothrow()) { - return obj->size(); - } - if (auto* str = get_nothrow()) { - return str->size(); - } - throw TypeError("array/object", type()); -} - inline std::size_t dynamic::count(dynamic const& key) const { - return find(key) != items().end(); + return find(key) != items().end() ? 1u : 0u; } inline dynamic::const_item_iterator dynamic::find(dynamic const& key) const { @@ -625,17 +516,45 @@ inline dynamic::const_item_iterator dynamic::find(dynamic const& key) const { template inline void dynamic::insert(K&& key, V&& val) { auto& obj = get(); - auto rv = obj.insert(std::make_pair(std::forward(key), - std::forward(val))); - if (!rv.second) { - // note, the second use of std:forward(val) is only correct - // if the first one did not result in a move. obj[key] = val - // would be preferrable but doesn't compile because dynamic - // is (intentionally) not default constructable - rv.first->second = std::forward(val); + auto rv = obj.insert({ std::forward(key), nullptr }); + rv.first->second = std::forward(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(); return obj.erase(key); @@ -649,14 +568,6 @@ inline dynamic::const_iterator dynamic::erase(const_iterator it) { return get().erase(arr.begin() + (it - arr.begin())); } -inline dynamic::const_iterator -dynamic::erase(const_iterator first, const_iterator last) { - auto& arr = get(); - return get().erase( - arr.begin() + (first - arr.begin()), - arr.begin() + (last - arr.begin())); -} - inline dynamic::const_key_iterator dynamic::erase(const_key_iterator it) { return const_key_iterator(get().erase(it.base())); } @@ -688,64 +599,47 @@ inline dynamic::const_item_iterator dynamic::erase(const_item_iterator first, } inline void dynamic::resize(std::size_t sz, dynamic const& c) { - auto& array = get(); - array.resize(sz, c); + auto& arr = get(); + arr.resize(sz, c); } inline void dynamic::push_back(dynamic const& v) { - auto& array = get(); - array.push_back(v); + auto& arr = get(); + arr.push_back(v); } inline void dynamic::push_back(dynamic&& v) { - auto& array = get(); - array.push_back(std::move(v)); + auto& arr = get(); + arr.push_back(std::move(v)); } inline void dynamic::pop_back() { - auto& array = get(); - array.pop_back(); -} - -inline std::size_t dynamic::hash() const { - switch (type()) { - case OBJECT: - case ARRAY: - case NULLT: - throw TypeError("not null/object/array", type()); - case INT64: - return std::hash()(asInt()); - case DOUBLE: - return std::hash()(asDouble()); - case BOOL: - return std::hash()(asBool()); - case STRING: - return std::hash()(asString()); - default: - CHECK(0); abort(); - } + auto& arr = get(); + arr.pop_back(); } ////////////////////////////////////////////////////////////////////// -template struct dynamic::TypeInfo { - static char const name[]; - static Type const type; -}; +inline dynamic::dynamic(Array&& r) : type_(ARRAY) { + new (&u_.array) Array(std::move(r)); +} -#define FB_DEC_TYPE(T) \ - template<> char const dynamic::TypeInfo::name[]; \ - template<> dynamic::Type const dynamic::TypeInfo::type +#define FOLLY_DYNAMIC_DEC_TYPEINFO(T, str, val) \ + template <> struct dynamic::TypeInfo { \ + 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(std::string, "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 T dynamic::asImpl() const { @@ -753,7 +647,8 @@ T dynamic::asImpl() const { case INT64: return to(*get_nothrow()); case DOUBLE: return to(*get_nothrow()); case BOOL: return to(*get_nothrow()); - case STRING: return to(*get_nothrow()); + case STRING: + return to(*get_nothrow()); default: throw TypeError("int/double/bool/string", type()); } @@ -761,7 +656,7 @@ T dynamic::asImpl() const { // Return a T* to our type, or null if we're not that type. template -T* dynamic::get_nothrow() { +T* dynamic::get_nothrow() & noexcept { if (type_ != TypeInfo::type) { return nullptr; } @@ -769,40 +664,43 @@ T* dynamic::get_nothrow() { } template -T const* dynamic::get_nothrow() const { +T const* dynamic::get_nothrow() const& noexcept { return const_cast(this)->get_nothrow(); } // Return T* for where we can put a T, without type checking. (Memory // might be uninitialized, even.) template -T* dynamic::getAddress() { +T* dynamic::getAddress() noexcept { return GetAddrImpl::get(u_); } template -T const* dynamic::getAddress() const { +T const* dynamic::getAddress() const noexcept { return const_cast(this)->getAddress(); } template struct dynamic::GetAddrImpl {}; template<> struct dynamic::GetAddrImpl { - static void** get(Data& d) { return &d.nul; } + static void** get(Data& d) noexcept { return &d.nul; } }; template<> struct dynamic::GetAddrImpl { - static Array* get(Data& d) { return &d.array; } + static Array* get(Data& d) noexcept { return &d.array; } }; template<> struct dynamic::GetAddrImpl { - static bool* get(Data& d) { return &d.boolean; } + static bool* get(Data& d) noexcept { return &d.boolean; } }; template<> struct dynamic::GetAddrImpl { - static int64_t* get(Data& d) { return &d.integer; } + static int64_t* get(Data& d) noexcept { return &d.integer; } }; template<> struct dynamic::GetAddrImpl { - static double* get(Data& d) { return &d.doubl; } + static double* get(Data& d) noexcept { return &d.doubl; } }; -template<> struct dynamic::GetAddrImpl { - static fbstring* get(Data& d) { return &d.string; } +template <> +struct dynamic::GetAddrImpl { + static std::string* get(Data& d) noexcept { + return &d.string; + } }; template<> struct dynamic::GetAddrImpl { static_assert(sizeof(ObjectImpl) <= sizeof(Data::objectBuffer), @@ -810,7 +708,7 @@ template<> struct dynamic::GetAddrImpl { " amount of space depending on its template parameters. This is " "weird. Make objectBuffer bigger if you want to compile dynamic."); - static ObjectImpl* get(Data& d) { + static ObjectImpl* get(Data& d) noexcept { void* data = &d.objectBuffer; return static_cast(data); } @@ -829,23 +727,6 @@ T const& dynamic::get() const { return const_cast(this)->get(); } -inline char const* dynamic::typeName(Type t) { -#define FB_X(T) return TypeInfo::name - FB_DYNAMIC_APPLY(t, FB_X); -#undef FB_X -} - -inline void dynamic::destroy() { - // This short-circuit speeds up some microbenchmarks. - if (type_ == NULLT) return; - -#define FB_X(T) detail::Destroy::destroy(getAddress()) - FB_DYNAMIC_APPLY(type_, FB_X); -#undef FB_X - type_ = NULLT; - u_.nul = nullptr; -} - ////////////////////////////////////////////////////////////////////// /* @@ -858,6 +739,16 @@ struct dynamic::PrintImpl { out << t; } }; +// Otherwise, null, being (void*)0, would print as 0. +template <> +struct dynamic::PrintImpl { + static void print(dynamic const& /* d */, + std::ostream& out, + void* const& nul) { + DCHECK_EQ((void*)0, nul); + out << "null"; + } +}; template<> struct dynamic::PrintImpl { static void print(dynamic const& d, @@ -907,7 +798,7 @@ class FormatValue { FormatValue(val_.asInt()).format(arg, cb); break; case dynamic::STRING: - FormatValue(val_.asString()).format(arg, cb); + FormatValue(val_.asString()).format(arg, cb); break; case dynamic::DOUBLE: FormatValue(val_.asDouble()).format(arg, cb); @@ -916,7 +807,7 @@ class FormatValue { FormatValue(val_.at(arg.splitIntKey())).format(arg, cb); break; case dynamic::OBJECT: - FormatValue(val_.at(arg.splitKey().toFbstring())).format(arg, cb); + FormatValue(val_.at(arg.splitKey().toString())).format(arg, cb); break; } } @@ -946,7 +837,7 @@ class FormatValue> { case dynamic::ARRAY: { int key = arg.splitIntKey(); - if (key >= 0 && key < c.size()) { + if (key >= 0 && size_t(key) < c.size()) { FormatValue(c.at(key)).format(arg, cb); } else{ FormatValue(val_.defaultValue).format(arg, cb); @@ -973,5 +864,3 @@ class FormatValue> { } // namespaces #undef FB_DYNAMIC_APPLY - -#endif