Commit c391dc14 authored by Paul Jewell's avatar Paul Jewell Committed by Facebook Github Bot

Allowing folly::dynamics of object/array type to be hashed

Summary:
Currently, an error is thrown if a user tries to hash an instance of `folly::dynamic` which is of type `object` or `array`. Primitive underlying types are fine.

There doesn't seem to be a strict reason for this, as objects and arrays are just as hashable as primitive types. Additionally, the inability to hash here causes some unnecessary drawbacks (e.g. interacting with `unordered_map`s).

This diff uses the existing dependency on `folly/hash/Hash.h` to start allowing `folly::dynamic` objects/arrays to be hashed as well.

Reviewed By: ot

Differential Revision: D7219760

fbshipit-source-id: 1dff3f99bdacb66f719c614040cbd668ce51a33e
parent 3b0fb5d6
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
#include <numeric>
#include <folly/dynamic.h> #include <folly/dynamic.h>
#include <folly/Format.h> #include <folly/Format.h>
...@@ -291,10 +293,22 @@ dynamic::iterator dynamic::erase(const_iterator first, const_iterator last) { ...@@ -291,10 +293,22 @@ dynamic::iterator dynamic::erase(const_iterator first, const_iterator last) {
std::size_t dynamic::hash() const { std::size_t dynamic::hash() const {
switch (type()) { switch (type()) {
case NULLT:
return 0xBAAAAAAD;
case OBJECT: case OBJECT:
{
// Accumulate using addition instead of using hash_range (as in the ARRAY
// case), as we need a commutative hash operation since unordered_map's
// iteration order is unspecified.
auto h = std::hash<std::pair<dynamic, dynamic>>{};
return std::accumulate(
items().begin(),
items().end(),
size_t{0x0B1EC7},
[&](auto acc, auto item) { return acc + h(item); });
}
case ARRAY: case ARRAY:
case NULLT: return folly::hash::hash_range(begin(), end());
throwTypeError_("not null/object/array", type());
case INT64: case INT64:
return std::hash<int64_t>()(getInt()); return std::hash<int64_t>()(getInt());
case DOUBLE: case DOUBLE:
......
...@@ -101,8 +101,19 @@ TEST(Dynamic, ObjectBasics) { ...@@ -101,8 +101,19 @@ TEST(Dynamic, ObjectBasics) {
EXPECT_EQ(objInsert.find("1")->second.size(), 1); EXPECT_EQ(objInsert.find("1")->second.size(), 1);
// We don't allow objects as keys in objects. // Looking up objects as keys
EXPECT_ANY_THROW(newObject[d3] = 12); dynamic objDefinedInOneOrder = folly::dynamic::object
("bar", "987")
("baz", folly::dynamic::array(1, 2, 3))
("foo2", folly::dynamic::object("1", "2"));
dynamic sameObjInDifferentOrder = folly::dynamic::object
("bar", "987")
("foo2", folly::dynamic::object("1", "2"))
("baz", folly::dynamic::array(1, 2, 3));
newObject[objDefinedInOneOrder] = 12;
EXPECT_EQ(newObject.at(objDefinedInOneOrder).getInt(), 12);
EXPECT_EQ(newObject.at(sameObjInDifferentOrder).getInt(), 12);
// Merge two objects // Merge two objects
dynamic origMergeObj1 = folly::dynamic::object(); dynamic origMergeObj1 = folly::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