• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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