aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/digest/murmur/murmur.h
blob: cbf28864128b422113e9fc0ca65493852261677a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#pragma once

#include <util/system/defaults.h>
#include <util/system/unaligned_mem.h>

/*
 * https://sites.google.com/site/murmurhash/
 */

namespace NMurmurPrivate {
    template <size_t>
    struct TMurmurHash2ATraits;

    template <>
    struct TMurmurHash2ATraits<32> {
        using TValue = ui32;
        static const TValue Multiplier = 0x5bd1e995;
        enum { R1 = 24,
               R2 = 13,
               R3 = 15 };
    };

    template <>
    struct TMurmurHash2ATraits<64> {
        using TValue = ui64;
        static const TValue Multiplier = ULL(0xc6a4a7935bd1e995);
        enum { R1 = 47,
               R2 = 47,
               R3 = 47 };
    };
}

template <class T>
class TMurmurHash2A {
private:
    using TTraits = typename NMurmurPrivate::TMurmurHash2ATraits<8 * sizeof(T)>;
    using TValue = typename TTraits::TValue;

public:
    inline TMurmurHash2A(TValue seed = 0)
        : Hash(seed)
    {
    }

    inline TMurmurHash2A& Update(const void* buf, size_t len) noexcept {
        Size += len;

        MixTail(buf, len);

        while (len >= sizeof(TValue)) {
            Hash = Mix(Hash, ReadUnaligned<TValue>(buf));
            buf = static_cast<const char*>(buf) + sizeof(TValue);
            len -= sizeof(TValue);
        }

        MixTail(buf, len);

        return *this;
    }

    inline TValue Value() const noexcept {
        TValue hash = Mix(Mix(Hash, Tail), (TValue)Size);

        hash ^= hash >> TTraits::R2;
        hash *= TTraits::Multiplier;
        hash ^= hash >> TTraits::R3;

        return hash;
    }

private:
    static inline TValue Mix(TValue h, TValue k) noexcept {
        k *= TTraits::Multiplier;
        k ^= k >> TTraits::R1;
        k *= TTraits::Multiplier;
        h *= TTraits::Multiplier;
        h ^= k;
        return h;
    }

    inline void MixTail(const void*& buf, size_t& len) noexcept {
        while (len && (len < sizeof(TValue) || Count)) {
            Tail |= (TValue) * ((const unsigned char*&)buf)++ << (Count++ * 8);

            --len;

            if (Count == sizeof(TValue)) {
                Hash = Mix(Hash, Tail);
                Tail = 0;
                Count = 0;
            }
        }
    }

private:
    TValue Hash = 0;
    TValue Tail = 0;
    size_t Count = 0;
    size_t Size = 0;
};