1 /*
2  * Copyright (C) 2018-2021 Intel Corporation
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  */
7 
8 #pragma once
9 #include "shared/source/helpers/aligned_memory.h"
10 
11 #include <cstdint>
12 
13 namespace NEO {
14 // clang-format off
15 #define HASH_JENKINS_MIX(a,b,c) \
16 { \
17     a -= b; a -= c; a ^= (c>>13); \
18     b -= c; b -= a; b ^= (a<<8);  \
19     c -= a; c -= b; c ^= (b>>13); \
20     a -= b; a -= c; a ^= (c>>12); \
21     b -= c; b -= a; b ^= (a<<16); \
22     c -= a; c -= b; c ^= (b>>5);  \
23     a -= b; a -= c; a ^= (c>>3);  \
24     b -= c; b -= a; b ^= (a<<10); \
25     c -= a; c -= b; c ^= (b>>15); \
26 }
27 // clang-format on
28 class Hash {
29   public:
Hash()30     Hash() {
31         reset();
32     };
33 
getValue(const char * data,size_t size)34     uint32_t getValue(const char *data, size_t size) {
35         uint32_t value = 0;
36         switch (size) {
37         case 3:
38             value = static_cast<uint32_t>(*reinterpret_cast<const unsigned char *>(data++));
39             value <<= 8;
40             [[fallthrough]];
41         case 2:
42             value |= static_cast<uint32_t>(*reinterpret_cast<const unsigned char *>(data++));
43             value <<= 8;
44             [[fallthrough]];
45         case 1:
46             value |= static_cast<uint32_t>(*reinterpret_cast<const unsigned char *>(data++));
47             value <<= 8;
48         }
49         return value;
50     }
51 
update(const char * buff,size_t size)52     void update(const char *buff, size_t size) {
53         if (buff == nullptr)
54             return;
55 
56         if ((reinterpret_cast<uintptr_t>(buff) & 0x3) != 0) {
57             const unsigned char *tmp = (const unsigned char *)buff;
58 
59             while (size >= sizeof(uint32_t)) {
60                 uint32_t value = (uint32_t)tmp[0] + (((uint32_t)tmp[1]) << 8) + ((uint32_t)tmp[2] << 16) + ((uint32_t)tmp[3] << 24);
61                 a ^= value;
62                 HASH_JENKINS_MIX(a, hi, lo);
63                 size -= sizeof(uint32_t);
64                 tmp += sizeof(uint32_t);
65             }
66             if (size > 0) {
67                 uint32_t value = getValue((char *)tmp, size);
68                 a ^= value;
69                 HASH_JENKINS_MIX(a, hi, lo);
70             }
71         } else {
72             const uint32_t *tmp = reinterpret_cast<const uint32_t *>(buff);
73 
74             while (size >= sizeof(*tmp)) {
75                 a ^= *(tmp++);
76                 HASH_JENKINS_MIX(a, hi, lo);
77                 size -= sizeof(*tmp);
78             }
79 
80             if (size > 0) {
81                 uint32_t value = getValue((char *)tmp, size);
82                 a ^= value;
83                 HASH_JENKINS_MIX(a, hi, lo);
84             }
85         }
86     }
87 
finish()88     uint64_t finish() {
89         return (((uint64_t)hi) << 32) | lo;
90     }
91 
reset()92     void reset() {
93         a = 0x428a2f98;
94         hi = 0x71374491;
95         lo = 0xb5c0fbcf;
96     }
97 
hash(const char * buff,size_t size)98     static uint64_t hash(const char *buff, size_t size) {
99         Hash hash;
100         hash.update(buff, size);
101         return hash.finish();
102     }
103 
104   protected:
105     uint32_t a, hi, lo;
106 };
107 
108 template <typename T>
hashPtrToU32(const T * src)109 uint32_t hashPtrToU32(const T *src) {
110     auto asInt = reinterpret_cast<uintptr_t>(src);
111     constexpr auto m = sizeof(uintptr_t) / 8;
112     asInt = asInt ^ ((asInt & ~(m - 1)) >> (m * 32));
113 
114     return static_cast<uint32_t>(asInt);
115 }
116 } // namespace NEO
117