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