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