File: jody_hash.c

package info (click to toggle)
libjodycode 4.1.2-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 3,676 kB
  • sloc: ansic: 2,820; makefile: 372; sh: 160; xml: 37
file content (130 lines) | stat: -rw-r--r-- 3,805 bytes parent folder | download
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/* Jody Bruchon's fast hashing function
 *
 * This function was written to generate a fast hash that also has a
 * fairly low collision rate. The collision rate is much higher than
 * a secure hash algorithm, but the calculation is drastically simpler
 * and faster.
 *
 * Copyright (C) 2014-2026 by Jody Bruchon <jody@jodybruchon.com>
 * Released under The MIT License
 */

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "jody_hash.h"
#include "jody_hash_simd.h"
#include "likely_unlikely.h"

/* Rolling hash block size (4K by default) */
#ifndef ROLLBSIZE
 #define ROLLBSIZE 4096
#endif
#define ROLLBSIZEW (ROLLBSIZE / sizeof(jodyhash_t))


static const jodyhash_t jh_s_constant = JH_ROR2(JODY_HASH_CONSTANT);

/* Hash a block of arbitrary size; must be divisible by sizeof(jodyhash_t)
 * The first block should pass an initial hash of zero.
 * All blocks after the first should pass hash as the value
 * returned by the last call to this function. This allows hashing
 * of any amount of data. If data is not divisible by the size of
 * jodyhash_t, it is MANDATORY that the caller provide a data buffer
 * which is divisible by sizeof(jodyhash_t). */
extern int jody_block_hash(jodyhash_t *data, jodyhash_t *hash, const size_t count)
{
	jodyhash_t element, element2;
	size_t length = 0;

	/* Don't bother trying to hash a zero-length block */
	if (unlikely(count == 0)) return 0;

#ifndef NO_AVX2
#if defined __GNUC__ || defined __clang__
	__builtin_cpu_init ();
	if (__builtin_cpu_supports ("avx2")) {
#endif /* __GNUC__ || __clang__ */
		if (count >= 32) {
			if (jody_block_hash_avx2(&data, hash, count, &length) != 0) return 1;
			goto skip_sse2;
		} else length = count / sizeof(jodyhash_t);
#if defined __GNUC__ || defined __clang__
	} else length = count / sizeof(jodyhash_t);
#endif
#else
	length = count / sizeof(jodyhash_t);
#endif /* NO_AVX2 */


#ifndef NO_SSE2
#if defined __GNUC__ || defined __clang__
	__builtin_cpu_init ();
	if (__builtin_cpu_supports ("sse2")) {
#endif /* __GNUC__ || __clang__ */
		if (count >= 32) {
			if (jody_block_hash_sse2(&data, hash, count, &length) != 0) return 1;
		}
		else length = count / sizeof(jodyhash_t);
#if defined __GNUC__ || defined __clang__
	} else length = count / sizeof(jodyhash_t);
#endif
#else
	length = count / sizeof(jodyhash_t);
#endif /* NO_SSE2 */

#ifndef NO_AVX2
skip_sse2:
#endif
	/* Hash everything (normal) or remaining small tails (SSE2) */
	for (; length > 0; length--) {
		element = *data;
		element2 = JH_ROR(element);
		element2 ^= jh_s_constant;
		element += JODY_HASH_CONSTANT;
		*hash += element;
		*hash ^= element2;
		*hash = JH_ROL2(*hash);
		*hash += element;
		data++;
	}

	/* Handle data tail (for blocks indivisible by sizeof(jodyhash_t)) */
	length = count & (sizeof(jodyhash_t) - 1);
	if (length) {
		element = *data & tail_mask[length];
		element2 = JH_ROR(element);
		element2 ^= jh_s_constant;
		element += JODY_HASH_CONSTANT;
		*hash += element;
		*hash ^= element2;
		*hash = JH_ROL2(*hash);
		*hash += element2;
	}

	return 0;
}


extern int jody_rolling_block_hash(jodyhash_t *data, jodyhash_t *hash, const size_t count)
{
	jodyhash_t rollhash;
	size_t blocks = (count & ~((uint64_t)ROLLBSIZE - 1)) / ROLLBSIZE;
	for (unsigned int i = 0; i < blocks; i++) {
//fprintf(stderr, "rolling([%u] %p, %016" PRIx64 ", %d)\n", i, (void *)data, *hash, ROLLBSIZE);
		rollhash = 0;
		if (jody_block_hash(data, &rollhash, ROLLBSIZE)) return 1;
		*hash ^= rollhash;
		data += ROLLBSIZEW;
	}
	/* Hash the last block */
	blocks = count - (blocks * ROLLBSIZE);
	if (blocks > 0) {
//fprintf(stderr, "rolltail(%p, %016" PRIx64 ", %d)\n", (void *)data, *hash, ROLLBSIZE);
		rollhash = 0;
		if (jody_block_hash(data, &rollhash, blocks)) return 1;
		*hash ^= rollhash;
	}
	return 0;
}