Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/boostorg/json
8 : //
9 :
10 : #ifndef BOOST_JSON_DETAIL_DIGEST_HPP
11 : #define BOOST_JSON_DETAIL_DIGEST_HPP
12 :
13 : #include <boost/json/detail/config.hpp>
14 :
15 : #include <algorithm>
16 : #include <iterator>
17 :
18 : namespace boost {
19 : namespace json {
20 : namespace detail {
21 :
22 : // Calculate salted digest of string
23 : template<class ForwardIterator>
24 : std::size_t
25 11262 : digest(ForwardIterator b, ForwardIterator e, std::size_t salt) noexcept
26 : {
27 11262 : std::size_t const len = std::distance(b, e);
28 :
29 : #if BOOST_JSON_ARCH == 64
30 :
31 : using state_type = std::uint64_t;
32 11262 : state_type const m = 0xc6a4a7935bd1e995ULL;
33 11262 : int const r = 47;
34 11262 : state_type hash = salt ^ (len * m);
35 :
36 11262 : constexpr std::size_t N = sizeof(state_type);
37 11262 : e = std::next( b, len & ~std::size_t(N-1) );
38 11292 : for( ; b != e; std::advance(b, N) )
39 : {
40 : state_type num;
41 : #ifdef _MSC_VER
42 : # pragma warning(push)
43 : # pragma warning(disable: 4996)
44 : #endif
45 30 : std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
46 : #ifdef _MSC_VER
47 : # pragma warning(pop)
48 : #endif
49 :
50 30 : num *= m;
51 30 : num ^= num >> r;
52 30 : num *= m;
53 30 : hash ^= num;
54 30 : hash *= m;
55 : }
56 :
57 11262 : switch( len & (N - 1) )
58 : {
59 12 : case 7: hash ^= state_type( *std::next(b, 6) ) << 48; // fall through
60 24 : case 6: hash ^= state_type( *std::next(b, 5) ) << 40; // fall through
61 40 : case 5: hash ^= state_type( *std::next(b, 4) ) << 32; // fall through
62 70 : case 4: hash ^= state_type( *std::next(b, 3) ) << 24; // fall through
63 5502 : case 3: hash ^= state_type( *std::next(b, 2) ) << 16; // fall through
64 12624 : case 2: hash ^= state_type( *std::next(b, 1) ) << 8; // fall through
65 11272 : case 1: hash ^= state_type( *std::next(b, 0) );
66 11256 : hash *= m;
67 : };
68 :
69 11262 : hash ^= hash >> r;
70 11262 : hash *= m;
71 11262 : hash ^= hash >> r;
72 :
73 : #else
74 :
75 : using state_type = std::uint32_t;
76 : state_type const m = 0x5bd1e995;
77 : int const r = 24;
78 : state_type hash = salt ^ len;
79 :
80 : constexpr std::size_t N = sizeof(state_type);
81 : e = std::next( b, len & ~std::size_t(N-1) );
82 : for( ; b != e; std::advance(b, N) )
83 : {
84 : state_type num;
85 : std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
86 :
87 : num *= m;
88 : num ^= num >> r;
89 : num *= m;
90 : hash *= m;
91 : hash ^= num;
92 : }
93 :
94 : switch( len & (N - 1) )
95 : {
96 : case 3: hash ^= state_type( *std::next(b, 2) ) << 16; // fall through
97 : case 2: hash ^= state_type( *std::next(b, 1) ) << 8; // fall through
98 : case 1: hash ^= state_type( *std::next(b, 0) );
99 : hash *= m;
100 : };
101 :
102 : hash ^= hash >> 13;
103 : hash *= m;
104 : hash ^= hash >> 15;
105 :
106 : #endif
107 :
108 11262 : return hash;
109 : }
110 :
111 : } // detail
112 : } // namespace json
113 : } // namespace boost
114 :
115 : #endif
|