~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/lib/xxhash.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * xxHash - Extremely Fast Hash algorithm
  3  * Copyright (C) 2012-2016, Yann Collet.
  4  *
  5  * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
  6  *
  7  * Redistribution and use in source and binary forms, with or without
  8  * modification, are permitted provided that the following conditions are
  9  * met:
 10  *
 11  *   * Redistributions of source code must retain the above copyright
 12  *     notice, this list of conditions and the following disclaimer.
 13  *   * Redistributions in binary form must reproduce the above
 14  *     copyright notice, this list of conditions and the following disclaimer
 15  *     in the documentation and/or other materials provided with the
 16  *     distribution.
 17  *
 18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 29  *
 30  * This program is free software; you can redistribute it and/or modify it under
 31  * the terms of the GNU General Public License version 2 as published by the
 32  * Free Software Foundation. This program is dual-licensed; you may select
 33  * either version 2 of the GNU General Public License ("GPL") or BSD license
 34  * ("BSD").
 35  *
 36  * You can contact the author at:
 37  * - xxHash homepage: https://cyan4973.github.io/xxHash/
 38  * - xxHash source repository: https://github.com/Cyan4973/xxHash
 39  */
 40 
 41 #include <asm/unaligned.h>
 42 #include <linux/errno.h>
 43 #include <linux/compiler.h>
 44 #include <linux/kernel.h>
 45 #include <linux/module.h>
 46 #include <linux/string.h>
 47 #include <linux/xxhash.h>
 48 
 49 /*-*************************************
 50  * Macros
 51  **************************************/
 52 #define xxh_rotl32(x, r) ((x << r) | (x >> (32 - r)))
 53 #define xxh_rotl64(x, r) ((x << r) | (x >> (64 - r)))
 54 
 55 #ifdef __LITTLE_ENDIAN
 56 # define XXH_CPU_LITTLE_ENDIAN 1
 57 #else
 58 # define XXH_CPU_LITTLE_ENDIAN 0
 59 #endif
 60 
 61 /*-*************************************
 62  * Constants
 63  **************************************/
 64 static const uint32_t PRIME32_1 = 2654435761U;
 65 static const uint32_t PRIME32_2 = 2246822519U;
 66 static const uint32_t PRIME32_3 = 3266489917U;
 67 static const uint32_t PRIME32_4 =  668265263U;
 68 static const uint32_t PRIME32_5 =  374761393U;
 69 
 70 static const uint64_t PRIME64_1 = 11400714785074694791ULL;
 71 static const uint64_t PRIME64_2 = 14029467366897019727ULL;
 72 static const uint64_t PRIME64_3 =  1609587929392839161ULL;
 73 static const uint64_t PRIME64_4 =  9650029242287828579ULL;
 74 static const uint64_t PRIME64_5 =  2870177450012600261ULL;
 75 
 76 /*-**************************
 77  *  Utils
 78  ***************************/
 79 void xxh32_copy_state(struct xxh32_state *dst, const struct xxh32_state *src)
 80 {
 81         memcpy(dst, src, sizeof(*dst));
 82 }
 83 EXPORT_SYMBOL(xxh32_copy_state);
 84 
 85 void xxh64_copy_state(struct xxh64_state *dst, const struct xxh64_state *src)
 86 {
 87         memcpy(dst, src, sizeof(*dst));
 88 }
 89 EXPORT_SYMBOL(xxh64_copy_state);
 90 
 91 /*-***************************
 92  * Simple Hash Functions
 93  ****************************/
 94 static uint32_t xxh32_round(uint32_t seed, const uint32_t input)
 95 {
 96         seed += input * PRIME32_2;
 97         seed = xxh_rotl32(seed, 13);
 98         seed *= PRIME32_1;
 99         return seed;
100 }
101 
102 uint32_t xxh32(const void *input, const size_t len, const uint32_t seed)
103 {
104         const uint8_t *p = (const uint8_t *)input;
105         const uint8_t *b_end = p + len;
106         uint32_t h32;
107 
108         if (len >= 16) {
109                 const uint8_t *const limit = b_end - 16;
110                 uint32_t v1 = seed + PRIME32_1 + PRIME32_2;
111                 uint32_t v2 = seed + PRIME32_2;
112                 uint32_t v3 = seed + 0;
113                 uint32_t v4 = seed - PRIME32_1;
114 
115                 do {
116                         v1 = xxh32_round(v1, get_unaligned_le32(p));
117                         p += 4;
118                         v2 = xxh32_round(v2, get_unaligned_le32(p));
119                         p += 4;
120                         v3 = xxh32_round(v3, get_unaligned_le32(p));
121                         p += 4;
122                         v4 = xxh32_round(v4, get_unaligned_le32(p));
123                         p += 4;
124                 } while (p <= limit);
125 
126                 h32 = xxh_rotl32(v1, 1) + xxh_rotl32(v2, 7) +
127                         xxh_rotl32(v3, 12) + xxh_rotl32(v4, 18);
128         } else {
129                 h32 = seed + PRIME32_5;
130         }
131 
132         h32 += (uint32_t)len;
133 
134         while (p + 4 <= b_end) {
135                 h32 += get_unaligned_le32(p) * PRIME32_3;
136                 h32 = xxh_rotl32(h32, 17) * PRIME32_4;
137                 p += 4;
138         }
139 
140         while (p < b_end) {
141                 h32 += (*p) * PRIME32_5;
142                 h32 = xxh_rotl32(h32, 11) * PRIME32_1;
143                 p++;
144         }
145 
146         h32 ^= h32 >> 15;
147         h32 *= PRIME32_2;
148         h32 ^= h32 >> 13;
149         h32 *= PRIME32_3;
150         h32 ^= h32 >> 16;
151 
152         return h32;
153 }
154 EXPORT_SYMBOL(xxh32);
155 
156 static uint64_t xxh64_round(uint64_t acc, const uint64_t input)
157 {
158         acc += input * PRIME64_2;
159         acc = xxh_rotl64(acc, 31);
160         acc *= PRIME64_1;
161         return acc;
162 }
163 
164 static uint64_t xxh64_merge_round(uint64_t acc, uint64_t val)
165 {
166         val = xxh64_round(0, val);
167         acc ^= val;
168         acc = acc * PRIME64_1 + PRIME64_4;
169         return acc;
170 }
171 
172 uint64_t xxh64(const void *input, const size_t len, const uint64_t seed)
173 {
174         const uint8_t *p = (const uint8_t *)input;
175         const uint8_t *const b_end = p + len;
176         uint64_t h64;
177 
178         if (len >= 32) {
179                 const uint8_t *const limit = b_end - 32;
180                 uint64_t v1 = seed + PRIME64_1 + PRIME64_2;
181                 uint64_t v2 = seed + PRIME64_2;
182                 uint64_t v3 = seed + 0;
183                 uint64_t v4 = seed - PRIME64_1;
184 
185                 do {
186                         v1 = xxh64_round(v1, get_unaligned_le64(p));
187                         p += 8;
188                         v2 = xxh64_round(v2, get_unaligned_le64(p));
189                         p += 8;
190                         v3 = xxh64_round(v3, get_unaligned_le64(p));
191                         p += 8;
192                         v4 = xxh64_round(v4, get_unaligned_le64(p));
193                         p += 8;
194                 } while (p <= limit);
195 
196                 h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
197                         xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
198                 h64 = xxh64_merge_round(h64, v1);
199                 h64 = xxh64_merge_round(h64, v2);
200                 h64 = xxh64_merge_round(h64, v3);
201                 h64 = xxh64_merge_round(h64, v4);
202 
203         } else {
204                 h64  = seed + PRIME64_5;
205         }
206 
207         h64 += (uint64_t)len;
208 
209         while (p + 8 <= b_end) {
210                 const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
211 
212                 h64 ^= k1;
213                 h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
214                 p += 8;
215         }
216 
217         if (p + 4 <= b_end) {
218                 h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
219                 h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
220                 p += 4;
221         }
222 
223         while (p < b_end) {
224                 h64 ^= (*p) * PRIME64_5;
225                 h64 = xxh_rotl64(h64, 11) * PRIME64_1;
226                 p++;
227         }
228 
229         h64 ^= h64 >> 33;
230         h64 *= PRIME64_2;
231         h64 ^= h64 >> 29;
232         h64 *= PRIME64_3;
233         h64 ^= h64 >> 32;
234 
235         return h64;
236 }
237 EXPORT_SYMBOL(xxh64);
238 
239 /*-**************************************************
240  * Advanced Hash Functions
241  ***************************************************/
242 void xxh32_reset(struct xxh32_state *statePtr, const uint32_t seed)
243 {
244         /* use a local state for memcpy() to avoid strict-aliasing warnings */
245         struct xxh32_state state;
246 
247         memset(&state, 0, sizeof(state));
248         state.v1 = seed + PRIME32_1 + PRIME32_2;
249         state.v2 = seed + PRIME32_2;
250         state.v3 = seed + 0;
251         state.v4 = seed - PRIME32_1;
252         memcpy(statePtr, &state, sizeof(state));
253 }
254 EXPORT_SYMBOL(xxh32_reset);
255 
256 void xxh64_reset(struct xxh64_state *statePtr, const uint64_t seed)
257 {
258         /* use a local state for memcpy() to avoid strict-aliasing warnings */
259         struct xxh64_state state;
260 
261         memset(&state, 0, sizeof(state));
262         state.v1 = seed + PRIME64_1 + PRIME64_2;
263         state.v2 = seed + PRIME64_2;
264         state.v3 = seed + 0;
265         state.v4 = seed - PRIME64_1;
266         memcpy(statePtr, &state, sizeof(state));
267 }
268 EXPORT_SYMBOL(xxh64_reset);
269 
270 int xxh32_update(struct xxh32_state *state, const void *input, const size_t len)
271 {
272         const uint8_t *p = (const uint8_t *)input;
273         const uint8_t *const b_end = p + len;
274 
275         if (input == NULL)
276                 return -EINVAL;
277 
278         state->total_len_32 += (uint32_t)len;
279         state->large_len |= (len >= 16) | (state->total_len_32 >= 16);
280 
281         if (state->memsize + len < 16) { /* fill in tmp buffer */
282                 memcpy((uint8_t *)(state->mem32) + state->memsize, input, len);
283                 state->memsize += (uint32_t)len;
284                 return 0;
285         }
286 
287         if (state->memsize) { /* some data left from previous update */
288                 const uint32_t *p32 = state->mem32;
289 
290                 memcpy((uint8_t *)(state->mem32) + state->memsize, input,
291                         16 - state->memsize);
292 
293                 state->v1 = xxh32_round(state->v1, get_unaligned_le32(p32));
294                 p32++;
295                 state->v2 = xxh32_round(state->v2, get_unaligned_le32(p32));
296                 p32++;
297                 state->v3 = xxh32_round(state->v3, get_unaligned_le32(p32));
298                 p32++;
299                 state->v4 = xxh32_round(state->v4, get_unaligned_le32(p32));
300                 p32++;
301 
302                 p += 16-state->memsize;
303                 state->memsize = 0;
304         }
305 
306         if (p <= b_end - 16) {
307                 const uint8_t *const limit = b_end - 16;
308                 uint32_t v1 = state->v1;
309                 uint32_t v2 = state->v2;
310                 uint32_t v3 = state->v3;
311                 uint32_t v4 = state->v4;
312 
313                 do {
314                         v1 = xxh32_round(v1, get_unaligned_le32(p));
315                         p += 4;
316                         v2 = xxh32_round(v2, get_unaligned_le32(p));
317                         p += 4;
318                         v3 = xxh32_round(v3, get_unaligned_le32(p));
319                         p += 4;
320                         v4 = xxh32_round(v4, get_unaligned_le32(p));
321                         p += 4;
322                 } while (p <= limit);
323 
324                 state->v1 = v1;
325                 state->v2 = v2;
326                 state->v3 = v3;
327                 state->v4 = v4;
328         }
329 
330         if (p < b_end) {
331                 memcpy(state->mem32, p, (size_t)(b_end-p));
332                 state->memsize = (uint32_t)(b_end-p);
333         }
334 
335         return 0;
336 }
337 EXPORT_SYMBOL(xxh32_update);
338 
339 uint32_t xxh32_digest(const struct xxh32_state *state)
340 {
341         const uint8_t *p = (const uint8_t *)state->mem32;
342         const uint8_t *const b_end = (const uint8_t *)(state->mem32) +
343                 state->memsize;
344         uint32_t h32;
345 
346         if (state->large_len) {
347                 h32 = xxh_rotl32(state->v1, 1) + xxh_rotl32(state->v2, 7) +
348                         xxh_rotl32(state->v3, 12) + xxh_rotl32(state->v4, 18);
349         } else {
350                 h32 = state->v3 /* == seed */ + PRIME32_5;
351         }
352 
353         h32 += state->total_len_32;
354 
355         while (p + 4 <= b_end) {
356                 h32 += get_unaligned_le32(p) * PRIME32_3;
357                 h32 = xxh_rotl32(h32, 17) * PRIME32_4;
358                 p += 4;
359         }
360 
361         while (p < b_end) {
362                 h32 += (*p) * PRIME32_5;
363                 h32 = xxh_rotl32(h32, 11) * PRIME32_1;
364                 p++;
365         }
366 
367         h32 ^= h32 >> 15;
368         h32 *= PRIME32_2;
369         h32 ^= h32 >> 13;
370         h32 *= PRIME32_3;
371         h32 ^= h32 >> 16;
372 
373         return h32;
374 }
375 EXPORT_SYMBOL(xxh32_digest);
376 
377 int xxh64_update(struct xxh64_state *state, const void *input, const size_t len)
378 {
379         const uint8_t *p = (const uint8_t *)input;
380         const uint8_t *const b_end = p + len;
381 
382         if (input == NULL)
383                 return -EINVAL;
384 
385         state->total_len += len;
386 
387         if (state->memsize + len < 32) { /* fill in tmp buffer */
388                 memcpy(((uint8_t *)state->mem64) + state->memsize, input, len);
389                 state->memsize += (uint32_t)len;
390                 return 0;
391         }
392 
393         if (state->memsize) { /* tmp buffer is full */
394                 uint64_t *p64 = state->mem64;
395 
396                 memcpy(((uint8_t *)p64) + state->memsize, input,
397                         32 - state->memsize);
398 
399                 state->v1 = xxh64_round(state->v1, get_unaligned_le64(p64));
400                 p64++;
401                 state->v2 = xxh64_round(state->v2, get_unaligned_le64(p64));
402                 p64++;
403                 state->v3 = xxh64_round(state->v3, get_unaligned_le64(p64));
404                 p64++;
405                 state->v4 = xxh64_round(state->v4, get_unaligned_le64(p64));
406 
407                 p += 32 - state->memsize;
408                 state->memsize = 0;
409         }
410 
411         if (p + 32 <= b_end) {
412                 const uint8_t *const limit = b_end - 32;
413                 uint64_t v1 = state->v1;
414                 uint64_t v2 = state->v2;
415                 uint64_t v3 = state->v3;
416                 uint64_t v4 = state->v4;
417 
418                 do {
419                         v1 = xxh64_round(v1, get_unaligned_le64(p));
420                         p += 8;
421                         v2 = xxh64_round(v2, get_unaligned_le64(p));
422                         p += 8;
423                         v3 = xxh64_round(v3, get_unaligned_le64(p));
424                         p += 8;
425                         v4 = xxh64_round(v4, get_unaligned_le64(p));
426                         p += 8;
427                 } while (p <= limit);
428 
429                 state->v1 = v1;
430                 state->v2 = v2;
431                 state->v3 = v3;
432                 state->v4 = v4;
433         }
434 
435         if (p < b_end) {
436                 memcpy(state->mem64, p, (size_t)(b_end-p));
437                 state->memsize = (uint32_t)(b_end - p);
438         }
439 
440         return 0;
441 }
442 EXPORT_SYMBOL(xxh64_update);
443 
444 uint64_t xxh64_digest(const struct xxh64_state *state)
445 {
446         const uint8_t *p = (const uint8_t *)state->mem64;
447         const uint8_t *const b_end = (const uint8_t *)state->mem64 +
448                 state->memsize;
449         uint64_t h64;
450 
451         if (state->total_len >= 32) {
452                 const uint64_t v1 = state->v1;
453                 const uint64_t v2 = state->v2;
454                 const uint64_t v3 = state->v3;
455                 const uint64_t v4 = state->v4;
456 
457                 h64 = xxh_rotl64(v1, 1) + xxh_rotl64(v2, 7) +
458                         xxh_rotl64(v3, 12) + xxh_rotl64(v4, 18);
459                 h64 = xxh64_merge_round(h64, v1);
460                 h64 = xxh64_merge_round(h64, v2);
461                 h64 = xxh64_merge_round(h64, v3);
462                 h64 = xxh64_merge_round(h64, v4);
463         } else {
464                 h64  = state->v3 + PRIME64_5;
465         }
466 
467         h64 += (uint64_t)state->total_len;
468 
469         while (p + 8 <= b_end) {
470                 const uint64_t k1 = xxh64_round(0, get_unaligned_le64(p));
471 
472                 h64 ^= k1;
473                 h64 = xxh_rotl64(h64, 27) * PRIME64_1 + PRIME64_4;
474                 p += 8;
475         }
476 
477         if (p + 4 <= b_end) {
478                 h64 ^= (uint64_t)(get_unaligned_le32(p)) * PRIME64_1;
479                 h64 = xxh_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
480                 p += 4;
481         }
482 
483         while (p < b_end) {
484                 h64 ^= (*p) * PRIME64_5;
485                 h64 = xxh_rotl64(h64, 11) * PRIME64_1;
486                 p++;
487         }
488 
489         h64 ^= h64 >> 33;
490         h64 *= PRIME64_2;
491         h64 ^= h64 >> 29;
492         h64 *= PRIME64_3;
493         h64 ^= h64 >> 32;
494 
495         return h64;
496 }
497 EXPORT_SYMBOL(xxh64_digest);
498 
499 MODULE_LICENSE("Dual BSD/GPL");
500 MODULE_DESCRIPTION("xxHash");
501 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php