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