Commit 41431d75 authored by Xiao Shi's avatar Xiao Shi Committed by Facebook Github Bot

Back out "[folly] use heterogeneous lookup and mutation in folly::dynamic" and...

Back out "[folly] use heterogeneous lookup and mutation in folly::dynamic" and "[folly] use F14NodeMap in folly::dynamic"

Summary:
D8299863 and D8299800

Mostly backing out for xplat autoupdater. The TARGETS / DEFS got scrambled.

Differential Revision: D9139265

fbshipit-source-id: 78b0238370d4de4fdc363d0867dc46de3a572f58
parent 5f195e92
......@@ -23,59 +23,6 @@
#include <folly/Likely.h>
#include <folly/detail/Iterators.h>
namespace folly {
namespace detail {
struct DynamicHasher {
using is_transparent = void;
size_t operator()(dynamic const& d) const {
return d.hash();
}
template <typename T>
std::enable_if_t<std::is_convertible<T, StringPiece>::value, size_t>
operator()(T const& val) const {
// keep consistent with dynamic::hash() for strings
return Hash()(static_cast<StringPiece>(val));
}
};
struct DynamicKeyEqual {
using is_transparent = void;
bool operator()(const dynamic& lhs, const dynamic& rhs) const {
return std::equal_to<dynamic>()(lhs, rhs);
}
// Dynamic objects contains a map<dynamic, dynamic>. At least one of the
// operands should be a dynamic. Hence, an operator() where both operands are
// convertible to StringPiece is unnecessary.
template <typename A, typename B>
std::enable_if_t<
std::is_convertible<A, StringPiece>::value &&
std::is_convertible<B, StringPiece>::value,
bool>
operator()(A const& lhs, B const& rhs) const = delete;
template <typename A>
std::enable_if_t<std::is_convertible<A, StringPiece>::value, bool> operator()(
A const& lhs,
dynamic const& rhs) const {
return FOLLY_LIKELY(rhs.type() == dynamic::Type::STRING) &&
std::equal_to<StringPiece>()(lhs, rhs.stringPiece());
}
template <typename B>
std::enable_if_t<std::is_convertible<B, StringPiece>::value, bool> operator()(
dynamic const& lhs,
B const& rhs) const {
return FOLLY_LIKELY(lhs.type() == dynamic::Type::STRING) &&
std::equal_to<StringPiece>()(lhs.stringPiece(), rhs);
}
};
} // namespace detail
} // namespace folly
//////////////////////////////////////////////////////////////////////
namespace std {
......@@ -194,17 +141,13 @@ dynamic numericOp(dynamic const& a, dynamic const& b) {
/*
* We're doing this instead of a simple member typedef to avoid the
* undefined behavior of parameterizing F14NodeMap<> with an
* undefined behavior of parameterizing std::unordered_map<> with an
* incomplete type.
*
* Note: Later we may add separate order tracking here (a multi-index
* type of thing.)
*/
struct dynamic::ObjectImpl : F14NodeMap<
dynamic,
dynamic,
detail::DynamicHasher,
detail::DynamicKeyEqual> {};
struct dynamic::ObjectImpl : std::unordered_map<dynamic, dynamic> {};
//////////////////////////////////////////////////////////////////////
......@@ -647,43 +590,21 @@ inline dynamic&& dynamic::operator[](dynamic const& idx) && {
return std::move((*this)[idx]);
}
template <typename K>
inline std::enable_if_t<std::is_convertible<K, StringPiece>::value, dynamic&>
dynamic::operator[](K&& k) & {
auto& obj = get<ObjectImpl>();
auto ret = obj.emplace(std::forward<K>(k), nullptr);
return ret.first->second;
}
template <typename K>
inline std::
enable_if_t<std::is_convertible<K, StringPiece>::value, dynamic const&>
dynamic::operator[](K&& k) const& {
return at(std::forward<K>(k));
}
template <typename K>
inline std::enable_if_t<std::is_convertible<K, StringPiece>::value, dynamic&&>
dynamic::operator[](K&& k) && {
return std::move((*this)[std::forward<K>(k)]);
}
template <class K, class V>
inline dynamic& dynamic::setDefault(K&& k, V&& v) {
template <class K, class V> inline dynamic& dynamic::setDefault(K&& k, V&& v) {
auto& obj = get<ObjectImpl>();
return obj.emplace(std::forward<K>(k), std::forward<V>(v)).first->second;
return obj.insert(std::make_pair(std::forward<K>(k),
std::forward<V>(v))).first->second;
}
template <class K>
inline dynamic& dynamic::setDefault(K&& k, dynamic&& v) {
template <class K> inline dynamic& dynamic::setDefault(K&& k, dynamic&& v) {
auto& obj = get<ObjectImpl>();
return obj.emplace(std::forward<K>(k), std::move(v)).first->second;
return obj.insert(std::make_pair(std::forward<K>(k),
std::move(v))).first->second;
}
template <class K>
inline dynamic& dynamic::setDefault(K&& k, const dynamic& v) {
template <class K> inline dynamic& dynamic::setDefault(K&& k, const dynamic& v) {
auto& obj = get<ObjectImpl>();
return obj.emplace(std::forward<K>(k), v).first->second;
return obj.insert(std::make_pair(std::forward<K>(k), v)).first->second;
}
inline dynamic* dynamic::get_ptr(dynamic const& idx) & {
......@@ -703,33 +624,6 @@ inline dynamic&& dynamic::at(dynamic const& idx) && {
return std::move(at(idx));
}
template <typename K>
std::enable_if_t<std::is_convertible<K, StringPiece>::value, dynamic const&>
dynamic::at(K const& idx) const& {
auto* pobject = get_nothrow<ObjectImpl>();
if (!pobject) {
throwTypeError_("object/array", type());
}
auto it = pobject->find(idx);
if (it == pobject->end()) {
throw_exception<std::out_of_range>(
sformat("couldn't find key {} in dynamic object", idx));
}
return it->second;
}
template <typename K>
inline std::enable_if_t<std::is_convertible<K, StringPiece>::value, dynamic&>
dynamic::at(K const& idx) & {
return const_cast<dynamic&>(const_cast<dynamic const*>(this)->at(idx));
}
template <typename K>
inline std::enable_if_t<std::is_convertible<K, StringPiece>::value, dynamic&&>
dynamic::at(K const& idx) && {
return std::move(at(idx));
}
inline bool dynamic::empty() const {
if (isNull()) {
return true;
......@@ -740,11 +634,6 @@ inline bool dynamic::empty() const {
inline std::size_t dynamic::count(dynamic const& key) const {
return find(key) != items().end() ? 1u : 0u;
}
template <typename K>
inline std::enable_if_t<std::is_convertible<K, StringPiece>::value, std::size_t>
dynamic::count(K const& key) const {
return find(key) != items().end() ? 1u : 0u;
}
inline dynamic::const_item_iterator dynamic::find(dynamic const& key) const {
return get<ObjectImpl>().find(key);
......@@ -753,25 +642,10 @@ inline dynamic::item_iterator dynamic::find(dynamic const& key) {
return get<ObjectImpl>().find(key);
}
template <typename K>
inline std::enable_if_t<
std::is_convertible<K, StringPiece>::value,
dynamic::const_item_iterator>
dynamic::find(K const& key) const {
return get<ObjectImpl>().find(key);
}
template <typename K>
inline std::enable_if_t<
std::is_convertible<K, StringPiece>::value,
dynamic::item_iterator>
dynamic::find(K const& key) {
return get<ObjectImpl>().find(key);
}
template <class K, class V>
inline void dynamic::insert(K&& key, V&& val) {
template <class K, class V> inline void dynamic::insert(K&& key, V&& val) {
auto& obj = get<ObjectImpl>();
obj[std::forward<K>(key)] = std::forward<V>(val);
auto rv = obj.insert({ std::forward<K>(key), nullptr });
rv.first->second = std::forward<V>(val);
}
inline void dynamic::update(const dynamic& mergeObj) {
......@@ -836,12 +710,6 @@ inline std::size_t dynamic::erase(dynamic const& key) {
auto& obj = get<ObjectImpl>();
return obj.erase(key);
}
template <typename K>
inline std::enable_if_t<std::is_convertible<K, StringPiece>::value, std::size_t>
dynamic::erase(K&& key) {
auto& obj = get<ObjectImpl>();
return obj.erase(std::forward<K>(key));
}
inline dynamic::iterator dynamic::erase(const_iterator it) {
auto& arr = get<Array>();
......@@ -987,11 +855,10 @@ struct dynamic::GetAddrImpl<std::string> {
}
};
template <> struct dynamic::GetAddrImpl<dynamic::ObjectImpl> {
static_assert(
sizeof(ObjectImpl) <= sizeof(Data::objectBuffer),
"In your implementation, F14NodeMap<> apparently takes different"
" amount of space depending on its template parameters. This is "
"weird. Make objectBuffer bigger if you want to compile dynamic.");
static_assert(sizeof(ObjectImpl) <= sizeof(Data::objectBuffer),
"In your implementation, std::unordered_map<> apparently takes different"
" 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) noexcept {
void* data = &d.objectBuffer;
......
......@@ -188,7 +188,7 @@ dynamic& dynamic::operator[](dynamic const& k) & {
return at(k);
}
auto& obj = get<ObjectImpl>();
auto ret = obj.emplace(k, nullptr);
auto ret = obj.insert({k, nullptr});
return ret.first->second;
}
......@@ -246,6 +246,11 @@ const dynamic* dynamic::get_ptr(dynamic const& idx) const& {
}
}
[[noreturn]] static void throwOutOfRangeAtMissingKey(dynamic const& idx) {
auto msg = sformat("couldn't find key {} in dynamic object", idx.asString());
throw_exception<std::out_of_range>(msg);
}
dynamic const& dynamic::at(dynamic const& idx) const& {
if (auto* parray = get_nothrow<Array>()) {
if (!idx.isInt()) {
......@@ -258,8 +263,7 @@ dynamic const& dynamic::at(dynamic const& idx) const& {
} else if (auto* pobject = get_nothrow<ObjectImpl>()) {
auto it = pobject->find(idx);
if (it == pobject->end()) {
throw_exception<std::out_of_range>(
sformat("couldn't find key {} in dynamic object", idx.asString()));
throwOutOfRangeAtMissingKey(idx);
}
return it->second;
} else {
......@@ -312,7 +316,6 @@ std::size_t dynamic::hash() const {
case BOOL:
return std::hash<bool>()(getBool());
case STRING:
// keep consistent with detail::DynamicHasher
return Hash()(getString());
}
assume_unreachable();
......
......@@ -57,6 +57,7 @@
#include <ostream>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
......@@ -64,7 +65,6 @@
#include <folly/Range.h>
#include <folly/Traits.h>
#include <folly/container/F14Map.h>
#include <folly/json_pointer.h>
namespace folly {
......@@ -379,25 +379,12 @@ struct dynamic : private boost::operators<dynamic> {
const_item_iterator find(dynamic const&) const;
item_iterator find(dynamic const&);
template <typename K>
std::enable_if_t<
std::is_convertible<K, StringPiece>::value,
const_item_iterator>
find(K const&) const;
template <typename K>
std::enable_if_t<std::is_convertible<K, StringPiece>::value, item_iterator>
find(K const&);
/*
* If this is an object, returns whether it contains a field with
* the given name. Otherwise throws TypeError.
*/
std::size_t count(dynamic const&) const;
template <typename K>
std::enable_if_t<std::is_convertible<K, StringPiece>::value, std::size_t>
count(K const&) const;
/*
* For objects or arrays, provides access to sub-fields by index or
* field name.
......@@ -410,16 +397,6 @@ struct dynamic : private boost::operators<dynamic> {
dynamic& at(dynamic const&) &;
dynamic&& at(dynamic const&) &&;
template <typename K>
std::enable_if_t<std::is_convertible<K, StringPiece>::value, dynamic const&>
at(K const&) const&;
template <typename K>
std::enable_if_t<std::is_convertible<K, StringPiece>::value, dynamic&> at(
K const&) &;
template <typename K>
std::enable_if_t<std::is_convertible<K, StringPiece>::value, dynamic&&> at(
K const&) &&;
/*
* Locate element using JSON pointer, per RFC 6901. Returns nullptr if
* element could not be located. Throws if pointer does not match the
......@@ -463,16 +440,6 @@ struct dynamic : private boost::operators<dynamic> {
dynamic const& operator[](dynamic const&) const&;
dynamic&& operator[](dynamic const&) &&;
template <typename K>
std::enable_if_t<std::is_convertible<K, StringPiece>::value, dynamic&>
operator[](K&&) &;
template <typename K>
std::enable_if_t<std::is_convertible<K, StringPiece>::value, dynamic const&>
operator[](K&&) const&;
template <typename K>
std::enable_if_t<std::is_convertible<K, StringPiece>::value, dynamic&&>
operator[](K&&) &&;
/*
* Only defined for objects, throws TypeError otherwise.
*
......@@ -510,8 +477,7 @@ struct dynamic : private boost::operators<dynamic> {
/*
* Inserts the supplied key-value pair to an object, or throws if
* it's not an object. If the key already exists, insert will overwrite the
* value, i.e., similar to insert_or_assign.
* it's not an object.
*
* Invalidates iterators.
*/
......@@ -553,9 +519,6 @@ struct dynamic : private boost::operators<dynamic> {
* Returns the number of elements erased (i.e. 1 or 0).
*/
std::size_t erase(dynamic const& key);
template <typename K>
std::enable_if_t<std::is_convertible<K, StringPiece>::value, std::size_t>
erase(K&&);
/*
* Erase an element from a dynamic object or array, using an
......@@ -645,14 +608,15 @@ struct dynamic : private boost::operators<dynamic> {
/*
* Objects are placement new'd here. We have to use a char buffer
* because we don't know the type here (F14NodeMap<> with
* because we don't know the type here (std::unordered_map<> with
* dynamic would be parameterizing a std:: template with an
* incomplete type right now). (Note that in contrast we know it
* is ok to do this with fbvector because we own it.)
*/
std::aligned_storage<
sizeof(F14NodeMap<int, int>),
alignof(F14NodeMap<int, int>)>::type objectBuffer;
sizeof(std::unordered_map<int,int>),
alignof(std::unordered_map<int,int>)
>::type objectBuffer;
} u_;
};
......
......@@ -33,31 +33,11 @@ TEST(Dynamic, ObjectBasics) {
EXPECT_EQ(obj.at("a"), false);
EXPECT_EQ(obj.size(), 1);
obj.insert("a", true);
dynamic key{"a"};
folly::StringPiece sp{"a"};
std::string s{"a"};
EXPECT_EQ(obj.size(), 1);
EXPECT_EQ(obj.at("a"), true);
EXPECT_EQ(obj.at(sp), true);
EXPECT_EQ(obj.at(key), true);
obj.at(sp) = nullptr;
obj.at("a") = nullptr;
EXPECT_EQ(obj.size(), 1);
EXPECT_TRUE(obj.at(s) == nullptr);
obj["a"] = 12;
EXPECT_EQ(obj[sp], 12);
obj[key] = "foo";
EXPECT_EQ(obj["a"], "foo");
(void)obj["b"];
EXPECT_EQ(obj.size(), 2);
obj.erase("a");
EXPECT_TRUE(obj.find(sp) == obj.items().end());
obj.erase("b");
EXPECT_EQ(obj.size(), 0);
EXPECT_TRUE(obj.at("a") == nullptr);
dynamic newObject = dynamic::object;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment