diff --git a/include/boost/json/detail/digest.hpp b/include/boost/json/detail/digest.hpp index 2d9465c00..3fb8a70d7 100644 --- a/include/boost/json/detail/digest.hpp +++ b/include/boost/json/detail/digest.hpp @@ -10,6 +10,10 @@ #ifndef BOOST_JSON_DETAIL_DIGEST_HPP #define BOOST_JSON_DETAIL_DIGEST_HPP +#include +#include +#include + namespace boost { namespace json { namespace detail { @@ -23,18 +27,78 @@ digest( std::size_t salt) noexcept { #if BOOST_JSON_ARCH == 64 - std::uint64_t const prime = 0x100000001B3ULL; - std::uint64_t hash = 0xcbf29ce484222325ULL; + using hash_t = std::uint64_t; + hash_t const prime = 0x100000001B3ULL; + hash_t hash = 0xcbf29ce484222325ULL; +#else + using hash_t = std::uint32_t; + hash_t const prime = 0x01000193UL; + hash_t hash = 0x811C9DC5UL; +#endif + hash += salt; + + constexpr std::size_t step = sizeof(hash_t); + std::size_t n = std::distance(b, e); + + std::array temp; + hash_t batch; + while( n >= step ) + { + std::copy_n(b, step, temp.data()); + + std::memcpy(&batch, temp.data(), step); + hash = (batch ^ hash) * prime; + + std::advance(b, step); + n -= step; + } + + temp.fill(0); + std::copy_n(b, n, temp.data()); + + std::memcpy(&batch, temp.data(), step); + hash = (batch ^ hash) * prime; + + return hash; +} + +// Calculate salted digest of string +template<> +inline +std::size_t +digest( + char const* b, + char const* e, + std::size_t salt) noexcept +{ +#if BOOST_JSON_ARCH == 64 + using hash_t = std::uint64_t; + hash_t const prime = 0x100000001B3ULL; + hash_t hash = 0xcbf29ce484222325ULL; #else - std::uint32_t const prime = 0x01000193UL; - std::uint32_t hash = 0x811C9DC5UL; + using hash_t = std::uint32_t; + hash_t const prime = 0x01000193UL; + hash_t hash = 0x811C9DC5UL; #endif hash += salt; - for(; b != e; ++b) - hash = (*b ^ hash) * prime; + + constexpr std::size_t step = sizeof(hash_t); + + hash_t batch; + for( ; (e - b) >= static_cast(step); b += step ) + { + std::memcpy(&batch, b, step); + hash = (batch ^ hash) * prime; + } + + batch = 0; + std::memcpy(&batch, b, e - b); + hash = (batch ^ hash) * prime; + return hash; } + } // detail } // namespace json } // namespace boost