xref: /mOS-networking-stack/core/src/util.c (revision d88f3b1d)
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