1 /*
2 Borrowed XXH32 and XXH64 implementation from xxHash project
3
4 Added Copyright notice just above the function definition
5
6 TODO 1 : We might wanna implement our version of xxh for copyright reason
7 TODO 2 : We might wanna gather all copyright notice and create a single file.
8 */
9
10
11
12 #include <stdint.h>
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include <mtcp_util.h>
18 #include <limits.h>
19 #include <stdio.h>
20 #include <errno.h>
21 #include <stdlib.h>
22
23 /*-------------------------------------------------------------*/
24 extern int
25 FetchEndianType();
26 /*-------------------------------------------------------------*/
27 static void
BuildKeyCache(uint32_t * cache,int cache_len)28 BuildKeyCache(uint32_t *cache, int cache_len)
29 {
30 #ifndef NBBY
31 #define NBBY 8 /* number of bits per byte */
32 #endif
33
34 /* Both of DPDK and Netmap uses this key for hash calculation.
35 * Do not change any single bit of this key. */
36 static const uint8_t key[] = {
37 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
38 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
39 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
40 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
41 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05
42 };
43
44 uint32_t result = (((uint32_t)key[0]) << 24) |
45 (((uint32_t)key[1]) << 16) |
46 (((uint32_t)key[2]) << 8) | ((uint32_t)key[3]);
47 uint32_t idx = 32;
48 int i;
49
50 for (i = 0; i < cache_len; i++, idx++) {
51 uint8_t shift = (idx % NBBY);
52 uint32_t bit;
53
54 cache[i] = result;
55 bit = ((key[idx/NBBY] << shift) & 0x80) ? 1 : 0;
56 result = ((result << 1) | bit);
57 }
58
59 }
60 /*-------------------------------------------------------------*/
61 uint32_t
GetRSSHash(in_addr_t sip,in_addr_t dip,in_port_t sp,in_port_t dp)62 GetRSSHash(in_addr_t sip, in_addr_t dip, in_port_t sp, in_port_t dp)
63 {
64 #define MSB32 0x80000000
65 #define MSB16 0x8000
66 #define KEY_CACHE_LEN 96
67
68 uint32_t res = 0;
69 int i;
70 static int first = 1;
71 static uint32_t key_cache[KEY_CACHE_LEN] = {0};
72
73 if (first) {
74 BuildKeyCache(key_cache, KEY_CACHE_LEN);
75 first = 0;
76 }
77
78 for (i = 0; i < 32; i++) {
79 if (sip & MSB32)
80 res ^= key_cache[i];
81 sip <<= 1;
82 }
83 for (i = 0; i < 32; i++) {
84 if (dip & MSB32)
85 res ^= key_cache[32+i];
86 dip <<= 1;
87 }
88 for (i = 0; i < 16; i++) {
89 if (sp & MSB16)
90 res ^= key_cache[64+i];
91 sp <<= 1;
92 }
93 for (i = 0; i < 16; i++) {
94 if (dp & MSB16)
95 res ^= key_cache[80+i];
96 dp <<= 1;
97 }
98 return res;
99 }
100 /*-------------------------------------------------------------------*/
101 /* RSS redirection table is in the little endian byte order (intel) */
102 /* */
103 /* idx: 0 1 2 3 | 4 5 6 7 | 8 9 10 11 | 12 13 14 15 | 16 17 18 19 ...*/
104 /* val: 3 2 1 0 | 7 6 5 4 | 11 10 9 8 | 15 14 13 12 | 19 18 17 16 ...*/
105 /* qid = val % num_queues */
106 /*-------------------------------------------------------------------*/
107 /*
108 * ixgbe (e.g., X520) : (Rx queue #) = (7 LS bits of RSS hash) mod N
109 * i40e (e.g., XL710) : (Rx queue #) = (9 LS bits of RSS hash) mod N
110 */
111 /*-------------------------------------------------------------------*/
112 #define RSS_BIT_MASK_IXGBE 0x0000007F
113 #define RSS_BIT_MASK_I40E 0x000001FF
114 int
GetRSSCPUCore(in_addr_t sip,in_addr_t dip,in_port_t sp,in_port_t dp,int num_queues)115 GetRSSCPUCore(in_addr_t sip, in_addr_t dip,
116 in_port_t sp, in_port_t dp, int num_queues)
117 {
118 uint32_t masked;
119 int endian_type = FetchEndianType();
120
121 if (endian_type) {
122 masked = GetRSSHash(sip, dip, sp, dp) & RSS_BIT_MASK_I40E;
123 static const uint32_t off[4] = {3, 1, -1, -3};
124 masked += off[masked & 0x3];
125 }
126 else
127 masked = GetRSSHash(sip, dip, sp, dp) & RSS_BIT_MASK_IXGBE;
128
129 return (masked % num_queues);
130
131 }
132 /*-------------------------------------------------------------*/
133 int
mystrtol(const char * nptr,int base)134 mystrtol(const char *nptr, int base)
135 {
136 int rval;
137 char *endptr;
138
139 errno = 0;
140 rval = strtol(nptr, &endptr, 10);
141 /* check for strtol errors */
142 if ((errno == ERANGE && (rval == LONG_MAX ||
143 rval == LONG_MIN))
144 || (errno != 0 && rval == 0)) {
145 perror("strtol");
146 exit(EXIT_FAILURE);
147 }
148 if (endptr == nptr) {
149 fprintf(stderr, "Parsing strtol error!\n");
150 exit(EXIT_FAILURE);
151 }
152
153 return rval;
154 }
155 /*---------------------------------------------------------------*/
156 int
StrToArgs(char * str,int * argc,char ** argv,int max_argc)157 StrToArgs(char *str, int *argc, char **argv, int max_argc)
158 {
159
160 uint8_t single_quotes;
161 uint8_t double_quotes;
162 uint8_t delim;
163
164 single_quotes = 0;
165 double_quotes = 0;
166 delim = 1;
167
168 *argc = 0;
169
170 int i;
171 int len = strlen(str);
172 for (i = 0; i < len; i++) {
173
174 if (str[i] == '\'') {
175 if (single_quotes)
176 str[i] = '\0';
177 else
178 i++;
179 single_quotes = !single_quotes;
180 goto __non_space;
181 } else if (str[i] == '\"') {
182 if (double_quotes)
183 str[i] = '\0';
184 else
185 i++;
186 double_quotes = !double_quotes;
187 goto __non_space;
188 }
189
190 if (single_quotes || double_quotes)
191 continue;
192
193 if (isspace(str[i])) {
194 delim = 1;
195 str[i] = '\0';
196 continue;
197 }
198 __non_space:
199 if (delim == 1) {
200 delim = 0;
201 argv[(*argc)++] = &str[i];
202 if (*argc > max_argc)
203 break;
204 }
205 }
206
207 argv[*argc] = NULL;
208
209 return 0;
210 }
211
212 /*
213 xxHash - Fast Hash algorithm
214 Copyright (C) 2012-2015, Yann Collet
215
216 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
217
218 Redistribution and use in source and binary forms, with or without
219 modification, are permitted provided that the following conditions are
220 met:
221
222 * Redistributions of source code must retain the above copyright
223 notice, this list of conditions and the following disclaimer.
224 * Redistributions in binary form must reproduce the above
225 copyright notice, this list of conditions and the following disclaimer
226 in the documentation and/or other materials provided with the
227 distribution.
228
229 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
230 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
231 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
232 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
233 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
234 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
235 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
237 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
238 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
239 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
240
241 You can contact the author at :
242 - xxHash source repository : https://github.com/Cyan4973/xxHash
243 */
244
245
246
247
248 /**************************************
249 * Tuning parameters
250 **************************************/
251 /* Unaligned memory access is automatically enabled for "common" CPU, such as x86.
252 * For others CPU, the compiler will be more cautious, and insert extra code to ensure aligned access is respected.
253 * If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance.
254 * You can also enable this parameter if you know your input data will always be aligned (boundaries of 4, for U32).
255 */
256 #if defined(__ARM_FEATURE_UNALIGNED) || defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
257 # define XXH_USE_UNALIGNED_ACCESS 1
258 #endif
259
260 /* XXH_ACCEPT_NULL_INPUT_POINTER :
261 * If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.
262 * When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.
263 * By default, this option is disabled. To enable it, uncomment below define :
264 */
265 /* #define XXH_ACCEPT_NULL_INPUT_POINTER 1 */
266
267 /* XXH_FORCE_NATIVE_FORMAT :
268 * By default, xxHash library provides endian-independant Hash values, based on little-endian convention.
269 * Results are therefore identical for little-endian and big-endian CPU.
270 * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
271 * Should endian-independance be of no importance for your application, you may set the #define below to 1.
272 * It will improve speed for Big-endian CPU.
273 * This option has no impact on Little_Endian CPU.
274 */
275 #define XXH_FORCE_NATIVE_FORMAT 0
276
277
278 /**************************************
279 * Compiler Specific Options
280 ***************************************/
281 #ifdef _MSC_VER /* Visual Studio */
282 # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
283 # define FORCE_INLINE static __forceinline
284 #else
285 # if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
286 # ifdef __GNUC__
287 # define FORCE_INLINE static inline __attribute__((always_inline))
288 # else
289 # define FORCE_INLINE static inline
290 # endif
291 # else
292 # define FORCE_INLINE static
293 # endif /* __STDC_VERSION__ */
294 #endif
295
296
297 /**************************************
298 * Basic Types
299 ***************************************/
300 #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
301 # include <stdint.h>
302 typedef uint8_t BYTE;
303 typedef uint16_t U16;
304 typedef uint32_t U32;
305 typedef int32_t S32;
306 typedef uint64_t U64;
307 #else
308 typedef unsigned char BYTE;
309 typedef unsigned short U16;
310 typedef unsigned int U32;
311 typedef signed int S32;
312 typedef unsigned long long U64;
313 #endif
314
XXH_read32(const void * memPtr)315 static U32 XXH_read32(const void* memPtr)
316 {
317 U32 val32;
318 memcpy(&val32, memPtr, 4);
319 return val32;
320 }
321
XXH_read64(const void * memPtr)322 static U64 XXH_read64(const void* memPtr)
323 {
324 U64 val64;
325 memcpy(&val64, memPtr, 8);
326 return val64;
327 }
328
329
330
331 /******************************************
332 * Compiler-specific Functions and Macros
333 ******************************************/
334 #define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
335
336 /* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
337 #if defined(_MSC_VER)
338 # define XXH_rotl32(x,r) _rotl(x,r)
339 # define XXH_rotl64(x,r) _rotl64(x,r)
340 #else
341 # define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
342 # define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))
343 #endif
344
345 #if defined(_MSC_VER) /* Visual Studio */
346 # define XXH_swap32 _byteswap_ulong
347 # define XXH_swap64 _byteswap_uint64
348 #elif GCC_VERSION >= 403
349 # define XXH_swap32 __builtin_bswap32
350 # define XXH_swap64 __builtin_bswap64
351 #else
XXH_swap32(U32 x)352 static U32 XXH_swap32 (U32 x)
353 {
354 return ((x << 24) & 0xff000000 ) |
355 ((x << 8) & 0x00ff0000 ) |
356 ((x >> 8) & 0x0000ff00 ) |
357 ((x >> 24) & 0x000000ff );
358 }
XXH_swap64(U64 x)359 static U64 XXH_swap64 (U64 x)
360 {
361 return ((x << 56) & 0xff00000000000000ULL) |
362 ((x << 40) & 0x00ff000000000000ULL) |
363 ((x << 24) & 0x0000ff0000000000ULL) |
364 ((x << 8) & 0x000000ff00000000ULL) |
365 ((x >> 8) & 0x00000000ff000000ULL) |
366 ((x >> 24) & 0x0000000000ff0000ULL) |
367 ((x >> 40) & 0x000000000000ff00ULL) |
368 ((x >> 56) & 0x00000000000000ffULL);
369 }
370 #endif
371
372
373 /***************************************
374 * Architecture Macros
375 ***************************************/
376 typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
377 #ifndef XXH_CPU_LITTLE_ENDIAN /* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example using a compiler switch */
378 static const int one = 1;
379 # define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&one))
380 #endif
381
382
383 /*****************************
384 * Memory reads
385 *****************************/
386 typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
387
XXH_readLE32_align(const void * ptr,XXH_endianess endian,XXH_alignment align)388 FORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
389 {
390 if (align==XXH_unaligned)
391 return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));
392 else
393 return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);
394 }
395
XXH_readLE64_align(const void * ptr,XXH_endianess endian,XXH_alignment align)396 FORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)
397 {
398 if (align==XXH_unaligned)
399 return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));
400 else
401 return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);
402 }
403
404 /***************************************
405 * Macros
406 ***************************************/
407 #define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(!!(c)) }; } /* use only *after* variable declarations */
408
409
410 /***************************************
411 * Constants
412 ***************************************/
413 #define PRIME32_1 2654435761U
414 #define PRIME32_2 2246822519U
415 #define PRIME32_3 3266489917U
416 #define PRIME32_4 668265263U
417 #define PRIME32_5 374761393U
418
419 #define PRIME64_1 11400714785074694791ULL
420 #define PRIME64_2 14029467366897019727ULL
421 #define PRIME64_3 1609587929392839161ULL
422 #define PRIME64_4 9650029242287828579ULL
423 #define PRIME64_5 2870177450012600261ULL
424
425
426 /*****************************
427 * Simple Hash Functions
428 *****************************/
XXH32_endian_align(const void * input,size_t len,U32 seed,XXH_endianess endian,XXH_alignment align)429 FORCE_INLINE U32 XXH32_endian_align(const void* input, size_t len, U32 seed, XXH_endianess endian, XXH_alignment align)
430 {
431 const BYTE* p = (const BYTE*)input;
432 const BYTE* bEnd = p + len;
433 U32 h32;
434 #define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)
435
436 #ifdef XXH_ACCEPT_NULL_INPUT_POINTER
437 if (p==NULL)
438 {
439 len=0;
440 bEnd=p=(const BYTE*)(size_t)16;
441 }
442 #endif
443
444 if (len>=16)
445 {
446 const BYTE* const limit = bEnd - 16;
447 U32 v1 = seed + PRIME32_1 + PRIME32_2;
448 U32 v2 = seed + PRIME32_2;
449 U32 v3 = seed + 0;
450 U32 v4 = seed - PRIME32_1;
451
452 do
453 {
454 v1 += XXH_get32bits(p) * PRIME32_2;
455 v1 = XXH_rotl32(v1, 13);
456 v1 *= PRIME32_1;
457 p+=4;
458 v2 += XXH_get32bits(p) * PRIME32_2;
459 v2 = XXH_rotl32(v2, 13);
460 v2 *= PRIME32_1;
461 p+=4;
462 v3 += XXH_get32bits(p) * PRIME32_2;
463 v3 = XXH_rotl32(v3, 13);
464 v3 *= PRIME32_1;
465 p+=4;
466 v4 += XXH_get32bits(p) * PRIME32_2;
467 v4 = XXH_rotl32(v4, 13);
468 v4 *= PRIME32_1;
469 p+=4;
470 }
471 while (p<=limit);
472
473 h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
474 }
475 else
476 {
477 h32 = seed + PRIME32_5;
478 }
479
480 h32 += (U32) len;
481
482 while (p+4<=bEnd)
483 {
484 h32 += XXH_get32bits(p) * PRIME32_3;
485 h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
486 p+=4;
487 }
488
489 while (p<bEnd)
490 {
491 h32 += (*p) * PRIME32_5;
492 h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
493 p++;
494 }
495
496 h32 ^= h32 >> 15;
497 h32 *= PRIME32_2;
498 h32 ^= h32 >> 13;
499 h32 *= PRIME32_3;
500 h32 ^= h32 >> 16;
501
502 return h32;
503 }
504
505
XXH32(const void * input,size_t len,unsigned seed)506 unsigned XXH32 (const void* input, size_t len, unsigned seed)
507 {
508 #if 0
509 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
510 XXH32_state_t state;
511 XXH32_reset(&state, seed);
512 XXH32_update(&state, input, len);
513 return XXH32_digest(&state);
514 #else
515 XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
516
517 # if !defined(XXH_USE_UNALIGNED_ACCESS)
518 if ((((size_t)input) & 3) == 0) /* Input is 4-bytes aligned, leverage the speed benefit */
519 {
520 if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
521 return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
522 else
523 return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
524 }
525 # endif
526
527 if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
528 return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
529 else
530 return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
531 #endif
532 }
533
XXH64_endian_align(const void * input,size_t len,U64 seed,XXH_endianess endian,XXH_alignment align)534 FORCE_INLINE U64 XXH64_endian_align(const void* input, size_t len, U64 seed, XXH_endianess endian, XXH_alignment align)
535 {
536 const BYTE* p = (const BYTE*)input;
537 const BYTE* bEnd = p + len;
538 U64 h64;
539 #define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)
540
541 #ifdef XXH_ACCEPT_NULL_INPUT_POINTER
542 if (p==NULL)
543 {
544 len=0;
545 bEnd=p=(const BYTE*)(size_t)32;
546 }
547 #endif
548
549 if (len>=32)
550 {
551 const BYTE* const limit = bEnd - 32;
552 U64 v1 = seed + PRIME64_1 + PRIME64_2;
553 U64 v2 = seed + PRIME64_2;
554 U64 v3 = seed + 0;
555 U64 v4 = seed - PRIME64_1;
556
557 do
558 {
559 v1 += XXH_get64bits(p) * PRIME64_2;
560 p+=8;
561 v1 = XXH_rotl64(v1, 31);
562 v1 *= PRIME64_1;
563 v2 += XXH_get64bits(p) * PRIME64_2;
564 p+=8;
565 v2 = XXH_rotl64(v2, 31);
566 v2 *= PRIME64_1;
567 v3 += XXH_get64bits(p) * PRIME64_2;
568 p+=8;
569 v3 = XXH_rotl64(v3, 31);
570 v3 *= PRIME64_1;
571 v4 += XXH_get64bits(p) * PRIME64_2;
572 p+=8;
573 v4 = XXH_rotl64(v4, 31);
574 v4 *= PRIME64_1;
575 }
576 while (p<=limit);
577
578 h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);
579
580 v1 *= PRIME64_2;
581 v1 = XXH_rotl64(v1, 31);
582 v1 *= PRIME64_1;
583 h64 ^= v1;
584 h64 = h64 * PRIME64_1 + PRIME64_4;
585
586 v2 *= PRIME64_2;
587 v2 = XXH_rotl64(v2, 31);
588 v2 *= PRIME64_1;
589 h64 ^= v2;
590 h64 = h64 * PRIME64_1 + PRIME64_4;
591
592 v3 *= PRIME64_2;
593 v3 = XXH_rotl64(v3, 31);
594 v3 *= PRIME64_1;
595 h64 ^= v3;
596 h64 = h64 * PRIME64_1 + PRIME64_4;
597
598 v4 *= PRIME64_2;
599 v4 = XXH_rotl64(v4, 31);
600 v4 *= PRIME64_1;
601 h64 ^= v4;
602 h64 = h64 * PRIME64_1 + PRIME64_4;
603 }
604 else
605 {
606 h64 = seed + PRIME64_5;
607 }
608
609 h64 += (U64) len;
610
611 while (p+8<=bEnd)
612 {
613 U64 k1 = XXH_get64bits(p);
614 k1 *= PRIME64_2;
615 k1 = XXH_rotl64(k1,31);
616 k1 *= PRIME64_1;
617 h64 ^= k1;
618 h64 = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4;
619 p+=8;
620 }
621
622 if (p+4<=bEnd)
623 {
624 h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1;
625 h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;
626 p+=4;
627 }
628
629 while (p<bEnd)
630 {
631 h64 ^= (*p) * PRIME64_5;
632 h64 = XXH_rotl64(h64, 11) * PRIME64_1;
633 p++;
634 }
635
636 h64 ^= h64 >> 33;
637 h64 *= PRIME64_2;
638 h64 ^= h64 >> 29;
639 h64 *= PRIME64_3;
640 h64 ^= h64 >> 32;
641
642 return h64;
643 }
644
645
XXH64(const void * input,size_t len,unsigned long long seed)646 unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)
647 {
648 #if 0
649 /* Simple version, good for code maintenance, but unfortunately slow for small inputs */
650 XXH64_state_t state;
651 XXH64_reset(&state, seed);
652 XXH64_update(&state, input, len);
653 return XXH64_digest(&state);
654 #else
655 XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
656
657 # if !defined(XXH_USE_UNALIGNED_ACCESS)
658 if ((((size_t)input) & 7)==0) /* Input is aligned, let's leverage the speed advantage */
659 {
660 if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
661 return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
662 else
663 return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
664 }
665 # endif
666
667 if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
668 return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
669 else
670 return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
671 #endif
672 }
673
674