⚡ hash function without allocation
This commit is contained in:
parent
1a521cbd36
commit
5b229f4cce
3 changed files with 191 additions and 6 deletions
93
include/nlohmann/detail/hash.hpp
Normal file
93
include/nlohmann/detail/hash.hpp
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional> // hash
|
||||||
|
|
||||||
|
namespace nlohmann
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
std::size_t combine(std::size_t seed, std::size_t h)
|
||||||
|
{
|
||||||
|
seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
std::size_t hash(const BasicJsonType& j)
|
||||||
|
{
|
||||||
|
switch (j.type())
|
||||||
|
{
|
||||||
|
case BasicJsonType::value_t::null:
|
||||||
|
case BasicJsonType::discarded:
|
||||||
|
return combine(static_cast<std::size_t>(j.type()), 0);
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::object:
|
||||||
|
{
|
||||||
|
auto seed = combine(static_cast<std::size_t>(j.type()), j.size());
|
||||||
|
for (const auto& element : j.items())
|
||||||
|
{
|
||||||
|
const auto h = std::hash<typename BasicJsonType::string_t> {}(element.key());
|
||||||
|
seed = combine(seed, h);
|
||||||
|
seed = combine(seed, hash(element.value()));
|
||||||
|
}
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::array:
|
||||||
|
{
|
||||||
|
auto seed = combine(static_cast<std::size_t>(j.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<typename BasicJsonType::string_t> {}(j.template get_ref<const typename BasicJsonType::string_t&>());
|
||||||
|
return combine(static_cast<std::size_t>(j.type()), h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::boolean:
|
||||||
|
{
|
||||||
|
const auto h = std::hash<bool> {}(j.template get<bool>());
|
||||||
|
return combine(static_cast<std::size_t>(j.type()), h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::number_integer:
|
||||||
|
{
|
||||||
|
const auto h = std::hash<typename BasicJsonType::number_integer_t> {}(j.template get<typename BasicJsonType::number_integer_t>());
|
||||||
|
return combine(static_cast<std::size_t>(j.type()), h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case nlohmann::detail::value_t::number_unsigned:
|
||||||
|
{
|
||||||
|
const auto h = std::hash<typename BasicJsonType::number_unsigned_t> {}(j.template get<typename BasicJsonType::number_unsigned_t>());
|
||||||
|
return combine(static_cast<std::size_t>(j.type()), h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case nlohmann::detail::value_t::number_float:
|
||||||
|
{
|
||||||
|
const auto h = std::hash<typename BasicJsonType::number_float_t> {}(j.template get<typename BasicJsonType::number_float_t>());
|
||||||
|
return combine(static_cast<std::size_t>(j.type()), h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case nlohmann::detail::value_t::binary:
|
||||||
|
{
|
||||||
|
auto seed = combine(static_cast<std::size_t>(j.type()), j.get_binary().size());
|
||||||
|
seed = combine(seed, j.get_binary().subtype());
|
||||||
|
for (const auto byte : j.get_binary())
|
||||||
|
{
|
||||||
|
seed = combine(seed, std::hash<std::uint8_t> {}(byte));
|
||||||
|
}
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace nlohmann
|
|
@ -51,6 +51,7 @@ SOFTWARE.
|
||||||
#include <nlohmann/detail/conversions/from_json.hpp>
|
#include <nlohmann/detail/conversions/from_json.hpp>
|
||||||
#include <nlohmann/detail/conversions/to_json.hpp>
|
#include <nlohmann/detail/conversions/to_json.hpp>
|
||||||
#include <nlohmann/detail/exceptions.hpp>
|
#include <nlohmann/detail/exceptions.hpp>
|
||||||
|
#include <nlohmann/detail/hash.hpp>
|
||||||
#include <nlohmann/detail/input/binary_reader.hpp>
|
#include <nlohmann/detail/input/binary_reader.hpp>
|
||||||
#include <nlohmann/detail/input/input_adapters.hpp>
|
#include <nlohmann/detail/input/input_adapters.hpp>
|
||||||
#include <nlohmann/detail/input/lexer.hpp>
|
#include <nlohmann/detail/input/lexer.hpp>
|
||||||
|
@ -8698,9 +8699,7 @@ struct hash<nlohmann::json>
|
||||||
*/
|
*/
|
||||||
std::size_t operator()(const nlohmann::json& j) const
|
std::size_t operator()(const nlohmann::json& j) const
|
||||||
{
|
{
|
||||||
// a naive hashing via the string representation
|
return nlohmann::detail::hash(j);
|
||||||
const auto& h = hash<nlohmann::json::string_t>();
|
|
||||||
return h(j.dump());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4442,6 +4442,101 @@ class byte_container_with_subtype : public BinaryType
|
||||||
|
|
||||||
// #include <nlohmann/detail/exceptions.hpp>
|
// #include <nlohmann/detail/exceptions.hpp>
|
||||||
|
|
||||||
|
// #include <nlohmann/detail/hash.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
#include <functional> // hash
|
||||||
|
|
||||||
|
namespace nlohmann
|
||||||
|
{
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
|
||||||
|
std::size_t combine(std::size_t seed, std::size_t h)
|
||||||
|
{
|
||||||
|
seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BasicJsonType>
|
||||||
|
std::size_t hash(const BasicJsonType& j)
|
||||||
|
{
|
||||||
|
switch (j.type())
|
||||||
|
{
|
||||||
|
case BasicJsonType::value_t::null:
|
||||||
|
case BasicJsonType::discarded:
|
||||||
|
return combine(static_cast<std::size_t>(j.type()), 0);
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::object:
|
||||||
|
{
|
||||||
|
auto seed = combine(static_cast<std::size_t>(j.type()), j.size());
|
||||||
|
for (const auto& element : j.items())
|
||||||
|
{
|
||||||
|
const auto h = std::hash<typename BasicJsonType::string_t> {}(element.key());
|
||||||
|
seed = combine(seed, h);
|
||||||
|
seed = combine(seed, hash(element.value()));
|
||||||
|
}
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::array:
|
||||||
|
{
|
||||||
|
auto seed = combine(static_cast<std::size_t>(j.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<typename BasicJsonType::string_t> {}(j.template get_ref<const typename BasicJsonType::string_t&>());
|
||||||
|
return combine(static_cast<std::size_t>(j.type()), h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::boolean:
|
||||||
|
{
|
||||||
|
const auto h = std::hash<bool> {}(j.template get<bool>());
|
||||||
|
return combine(static_cast<std::size_t>(j.type()), h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case BasicJsonType::value_t::number_integer:
|
||||||
|
{
|
||||||
|
const auto h = std::hash<typename BasicJsonType::number_integer_t> {}(j.template get<typename BasicJsonType::number_integer_t>());
|
||||||
|
return combine(static_cast<std::size_t>(j.type()), h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case nlohmann::detail::value_t::number_unsigned:
|
||||||
|
{
|
||||||
|
const auto h = std::hash<typename BasicJsonType::number_unsigned_t> {}(j.template get<typename BasicJsonType::number_unsigned_t>());
|
||||||
|
return combine(static_cast<std::size_t>(j.type()), h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case nlohmann::detail::value_t::number_float:
|
||||||
|
{
|
||||||
|
const auto h = std::hash<typename BasicJsonType::number_float_t> {}(j.template get<typename BasicJsonType::number_float_t>());
|
||||||
|
return combine(static_cast<std::size_t>(j.type()), h);
|
||||||
|
}
|
||||||
|
|
||||||
|
case nlohmann::detail::value_t::binary:
|
||||||
|
{
|
||||||
|
auto seed = combine(static_cast<std::size_t>(j.type()), j.get_binary().size());
|
||||||
|
seed = combine(seed, j.get_binary().subtype());
|
||||||
|
for (const auto byte : j.get_binary())
|
||||||
|
{
|
||||||
|
seed = combine(seed, std::hash<std::uint8_t> {}(byte));
|
||||||
|
}
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace nlohmann
|
||||||
|
|
||||||
// #include <nlohmann/detail/input/binary_reader.hpp>
|
// #include <nlohmann/detail/input/binary_reader.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
@ -24686,9 +24781,7 @@ struct hash<nlohmann::json>
|
||||||
*/
|
*/
|
||||||
std::size_t operator()(const nlohmann::json& j) const
|
std::size_t operator()(const nlohmann::json& j) const
|
||||||
{
|
{
|
||||||
// a naive hashing via the string representation
|
return nlohmann::detail::hash(j);
|
||||||
const auto& h = hash<nlohmann::json::string_t>();
|
|
||||||
return h(j.dump());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue