1 #pragma once
2
3 #include <cstdint> // uint8_t
4 #include <cstddef> // size_t
5 #include <functional> // hash
6
7 #include <nlohmann/detail/macro_scope.hpp>
8 #include <nlohmann/detail/value_t.hpp>
9
10 namespace nlohmann
11 {
12 namespace detail
13 {
14
15 // boost::hash_combine
combine(std::size_t seed,std::size_t h)16 inline std::size_t combine(std::size_t seed, std::size_t h) noexcept
17 {
18 seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);
19 return seed;
20 }
21
22 /*!
23 @brief hash a JSON value
24
25 The hash function tries to rely on std::hash where possible. Furthermore, the
26 type of the JSON value is taken into account to have different hash values for
27 null, 0, 0U, and false, etc.
28
29 @tparam BasicJsonType basic_json specialization
30 @param j JSON value to hash
31 @return hash value of j
32 */
33 template<typename BasicJsonType>
hash(const BasicJsonType & j)34 std::size_t hash(const BasicJsonType& j)
35 {
36 using string_t = typename BasicJsonType::string_t;
37 using number_integer_t = typename BasicJsonType::number_integer_t;
38 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
39 using number_float_t = typename BasicJsonType::number_float_t;
40
41 const auto type = static_cast<std::size_t>(j.type());
42 switch (j.type())
43 {
44 case BasicJsonType::value_t::null:
45 case BasicJsonType::value_t::discarded:
46 {
47 return combine(type, 0);
48 }
49
50 case BasicJsonType::value_t::object:
51 {
52 auto seed = combine(type, j.size());
53 for (const auto& element : j.items())
54 {
55 const auto h = std::hash<string_t> {}(element.key());
56 seed = combine(seed, h);
57 seed = combine(seed, hash(element.value()));
58 }
59 return seed;
60 }
61
62 case BasicJsonType::value_t::array:
63 {
64 auto seed = combine(type, j.size());
65 for (const auto& element : j)
66 {
67 seed = combine(seed, hash(element));
68 }
69 return seed;
70 }
71
72 case BasicJsonType::value_t::string:
73 {
74 const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>());
75 return combine(type, h);
76 }
77
78 case BasicJsonType::value_t::boolean:
79 {
80 const auto h = std::hash<bool> {}(j.template get<bool>());
81 return combine(type, h);
82 }
83
84 case BasicJsonType::value_t::number_integer:
85 {
86 const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>());
87 return combine(type, h);
88 }
89
90 case BasicJsonType::value_t::number_unsigned:
91 {
92 const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>());
93 return combine(type, h);
94 }
95
96 case BasicJsonType::value_t::number_float:
97 {
98 const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>());
99 return combine(type, h);
100 }
101
102 case BasicJsonType::value_t::binary:
103 {
104 auto seed = combine(type, j.get_binary().size());
105 const auto h = std::hash<bool> {}(j.get_binary().has_subtype());
106 seed = combine(seed, h);
107 seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype()));
108 for (const auto byte : j.get_binary())
109 {
110 seed = combine(seed, std::hash<std::uint8_t> {}(byte));
111 }
112 return seed;
113 }
114
115 default: // LCOV_EXCL_LINE
116 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
117 return 0; // LCOV_EXCL_LINE
118 }
119 }
120
121 } // namespace detail
122 } // namespace nlohmann
123