1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/boostorg/json
7  
// Official repository: https://github.com/boostorg/json
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_JSON_DETAIL_DIGEST_HPP
10  
#ifndef BOOST_JSON_DETAIL_DIGEST_HPP
11  
#define BOOST_JSON_DETAIL_DIGEST_HPP
11  
#define BOOST_JSON_DETAIL_DIGEST_HPP
12  

12  

13  
#include <boost/json/detail/config.hpp>
13  
#include <boost/json/detail/config.hpp>
14  

14  

15  
#include <algorithm>
15  
#include <algorithm>
16  
#include <iterator>
16  
#include <iterator>
17  

17  

18  
namespace boost {
18  
namespace boost {
19  
namespace json {
19  
namespace json {
20  
namespace detail {
20  
namespace detail {
21  

21  

22  
// Calculate salted digest of string
22  
// Calculate salted digest of string
23  
template<class ForwardIterator>
23  
template<class ForwardIterator>
24  
std::size_t
24  
std::size_t
25  
digest(ForwardIterator b, ForwardIterator e, std::size_t salt) noexcept
25  
digest(ForwardIterator b, ForwardIterator e, std::size_t salt) noexcept
26  
{
26  
{
27  
    std::size_t const len = std::distance(b, e);
27  
    std::size_t const len = std::distance(b, e);
28  

28  

29  
#if BOOST_JSON_ARCH == 64
29  
#if BOOST_JSON_ARCH == 64
30  

30  

31  
    using state_type = std::uint64_t;
31  
    using state_type = std::uint64_t;
32  
    state_type const m = 0xc6a4a7935bd1e995ULL;
32  
    state_type const m = 0xc6a4a7935bd1e995ULL;
33  
    int const r = 47;
33  
    int const r = 47;
34  
    state_type hash = salt ^ (len * m);
34  
    state_type hash = salt ^ (len * m);
35  

35  

36  
    constexpr std::size_t N = sizeof(state_type);
36  
    constexpr std::size_t N = sizeof(state_type);
37  
    e = std::next( b, len & ~std::size_t(N-1) );
37  
    e = std::next( b, len & ~std::size_t(N-1) );
38  
    for( ; b != e; std::advance(b, N) )
38  
    for( ; b != e; std::advance(b, N) )
39  
    {
39  
    {
40  
        state_type num;
40  
        state_type num;
41  
#ifdef _MSC_VER
41  
#ifdef _MSC_VER
42  
# pragma warning(push)
42  
# pragma warning(push)
43  
# pragma warning(disable: 4996)
43  
# pragma warning(disable: 4996)
44  
#endif
44  
#endif
45  
        std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
45  
        std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
46  
#ifdef _MSC_VER
46  
#ifdef _MSC_VER
47  
# pragma warning(pop)
47  
# pragma warning(pop)
48  
#endif
48  
#endif
49  

49  

50  
        num *= m;
50  
        num *= m;
51  
        num ^= num >> r;
51  
        num ^= num >> r;
52  
        num *= m;
52  
        num *= m;
53  
        hash ^= num;
53  
        hash ^= num;
54  
        hash *= m;
54  
        hash *= m;
55  
    }
55  
    }
56  

56  

57  
    switch( len & (N - 1) )
57  
    switch( len & (N - 1) )
58  
    {
58  
    {
59  
    case 7: hash ^= state_type( *std::next(b, 6) ) << 48; // fall through
59  
    case 7: hash ^= state_type( *std::next(b, 6) ) << 48; // fall through
60  
    case 6: hash ^= state_type( *std::next(b, 5) ) << 40; // fall through
60  
    case 6: hash ^= state_type( *std::next(b, 5) ) << 40; // fall through
61  
    case 5: hash ^= state_type( *std::next(b, 4) ) << 32; // fall through
61  
    case 5: hash ^= state_type( *std::next(b, 4) ) << 32; // fall through
62  
    case 4: hash ^= state_type( *std::next(b, 3) ) << 24; // fall through
62  
    case 4: hash ^= state_type( *std::next(b, 3) ) << 24; // fall through
63  
    case 3: hash ^= state_type( *std::next(b, 2) ) << 16; // fall through
63  
    case 3: hash ^= state_type( *std::next(b, 2) ) << 16; // fall through
64  
    case 2: hash ^= state_type( *std::next(b, 1) ) << 8;  // fall through
64  
    case 2: hash ^= state_type( *std::next(b, 1) ) << 8;  // fall through
65  
    case 1: hash ^= state_type( *std::next(b, 0) );
65  
    case 1: hash ^= state_type( *std::next(b, 0) );
66  
            hash *= m;
66  
            hash *= m;
67  
    };
67  
    };
68  

68  

69  
    hash ^= hash >> r;
69  
    hash ^= hash >> r;
70  
    hash *= m;
70  
    hash *= m;
71  
    hash ^= hash >> r;
71  
    hash ^= hash >> r;
72  

72  

73  
#else
73  
#else
74  

74  

75  
    using state_type = std::uint32_t;
75  
    using state_type = std::uint32_t;
76  
    state_type const m = 0x5bd1e995;
76  
    state_type const m = 0x5bd1e995;
77  
    int const r = 24;
77  
    int const r = 24;
78  
    state_type hash = salt ^ len;
78  
    state_type hash = salt ^ len;
79  

79  

80  
    constexpr std::size_t N = sizeof(state_type);
80  
    constexpr std::size_t N = sizeof(state_type);
81  
    e = std::next( b, len & ~std::size_t(N-1) );
81  
    e = std::next( b, len & ~std::size_t(N-1) );
82  
    for( ; b != e; std::advance(b, N) )
82  
    for( ; b != e; std::advance(b, N) )
83  
    {
83  
    {
84  
        state_type num;
84  
        state_type num;
85  
        std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
85  
        std::copy_n( b, N, reinterpret_cast<unsigned char*>(&num) );
86  

86  

87  
        num *= m;
87  
        num *= m;
88  
        num ^= num >> r;
88  
        num ^= num >> r;
89  
        num *= m;
89  
        num *= m;
90  
        hash *= m;
90  
        hash *= m;
91  
        hash ^= num;
91  
        hash ^= num;
92  
    }
92  
    }
93  

93  

94  
    switch( len & (N - 1) )
94  
    switch( len & (N - 1) )
95  
    {
95  
    {
96  
    case 3: hash ^= state_type( *std::next(b, 2) ) << 16; // fall through
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
97  
    case 2: hash ^= state_type( *std::next(b, 1) ) << 8;  // fall through
98  
    case 1: hash ^= state_type( *std::next(b, 0) );
98  
    case 1: hash ^= state_type( *std::next(b, 0) );
99  
            hash *= m;
99  
            hash *= m;
100  
    };
100  
    };
101  

101  

102  
    hash ^= hash >> 13;
102  
    hash ^= hash >> 13;
103  
    hash *= m;
103  
    hash *= m;
104  
    hash ^= hash >> 15;
104  
    hash ^= hash >> 15;
105  

105  

106  
#endif
106  
#endif
107  

107  

108  
    return hash;
108  
    return hash;
109  
}
109  
}
110  

110  

111  
} // detail
111  
} // detail
112  
} // namespace json
112  
} // namespace json
113  
} // namespace boost
113  
} // namespace boost
114  

114  

115  
#endif
115  
#endif