mirror of https://github.com/PurpleI2P/i2pd.git
I2P: End-to-End encrypted and anonymous Internet
https://i2pd.website/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
122 lines
3.6 KiB
122 lines
3.6 KiB
#pragma once |
|
|
|
#include <cstdint> // uint8_t |
|
#include <cstddef> // size_t |
|
#include <functional> // hash |
|
|
|
#include <nlohmann/detail/macro_scope.hpp> |
|
#include <nlohmann/detail/value_t.hpp> |
|
|
|
namespace nlohmann |
|
{ |
|
namespace detail |
|
{ |
|
|
|
// boost::hash_combine |
|
inline std::size_t combine(std::size_t seed, std::size_t h) noexcept |
|
{ |
|
seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U); |
|
return seed; |
|
} |
|
|
|
/*! |
|
@brief hash a JSON value |
|
|
|
The hash function tries to rely on std::hash where possible. Furthermore, the |
|
type of the JSON value is taken into account to have different hash values for |
|
null, 0, 0U, and false, etc. |
|
|
|
@tparam BasicJsonType basic_json specialization |
|
@param j JSON value to hash |
|
@return hash value of j |
|
*/ |
|
template<typename BasicJsonType> |
|
std::size_t hash(const BasicJsonType& j) |
|
{ |
|
using string_t = typename BasicJsonType::string_t; |
|
using number_integer_t = typename BasicJsonType::number_integer_t; |
|
using number_unsigned_t = typename BasicJsonType::number_unsigned_t; |
|
using number_float_t = typename BasicJsonType::number_float_t; |
|
|
|
const auto type = static_cast<std::size_t>(j.type()); |
|
switch (j.type()) |
|
{ |
|
case BasicJsonType::value_t::null: |
|
case BasicJsonType::value_t::discarded: |
|
{ |
|
return combine(type, 0); |
|
} |
|
|
|
case BasicJsonType::value_t::object: |
|
{ |
|
auto seed = combine(type, j.size()); |
|
for (const auto& element : j.items()) |
|
{ |
|
const auto h = std::hash<string_t> {}(element.key()); |
|
seed = combine(seed, h); |
|
seed = combine(seed, hash(element.value())); |
|
} |
|
return seed; |
|
} |
|
|
|
case BasicJsonType::value_t::array: |
|
{ |
|
auto seed = combine(type, j.size()); |
|
for (const auto& element : j) |
|
{ |
|
seed = combine(seed, hash(element)); |
|
} |
|
return seed; |
|
} |
|
|
|
case BasicJsonType::value_t::string: |
|
{ |
|
const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>()); |
|
return combine(type, h); |
|
} |
|
|
|
case BasicJsonType::value_t::boolean: |
|
{ |
|
const auto h = std::hash<bool> {}(j.template get<bool>()); |
|
return combine(type, h); |
|
} |
|
|
|
case BasicJsonType::value_t::number_integer: |
|
{ |
|
const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>()); |
|
return combine(type, h); |
|
} |
|
|
|
case BasicJsonType::value_t::number_unsigned: |
|
{ |
|
const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>()); |
|
return combine(type, h); |
|
} |
|
|
|
case BasicJsonType::value_t::number_float: |
|
{ |
|
const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>()); |
|
return combine(type, h); |
|
} |
|
|
|
case BasicJsonType::value_t::binary: |
|
{ |
|
auto seed = combine(type, j.get_binary().size()); |
|
const auto h = std::hash<bool> {}(j.get_binary().has_subtype()); |
|
seed = combine(seed, h); |
|
seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype())); |
|
for (const auto byte : j.get_binary()) |
|
{ |
|
seed = combine(seed, std::hash<std::uint8_t> {}(byte)); |
|
} |
|
return seed; |
|
} |
|
|
|
default: // LCOV_EXCL_LINE |
|
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE |
|
return 0; // LCOV_EXCL_LINE |
|
} |
|
} |
|
|
|
} // namespace detail |
|
} // namespace nlohmann
|
|
|