summaryrefslogtreecommitdiff
path: root/xdelta3/xdelta3-hash.h
diff options
context:
space:
mode:
Diffstat (limited to 'xdelta3/xdelta3-hash.h')
-rw-r--r--xdelta3/xdelta3-hash.h142
1 files changed, 48 insertions, 94 deletions
diff --git a/xdelta3/xdelta3-hash.h b/xdelta3/xdelta3-hash.h
index fd18099..2919b98 100644
--- a/xdelta3/xdelta3-hash.h
+++ b/xdelta3/xdelta3-hash.h
@@ -41,10 +41,11 @@
41#define UNALIGNED_READ32(dest,src) memcpy((dest), (src), 4); 41#define UNALIGNED_READ32(dest,src) memcpy((dest), (src), 4);
42#endif 42#endif
43 43
44/* This is a good hash multiplier for 32-bit LCGs: see "linear 44/* These are good hash multipliers for 32-bit and 64-bit LCGs: see
45 * congruential generators of different sizes and good lattice 45 * "linear congruential generators of different sizes and good lattice
46 * structure" */ 46 * structure" */
47static const uint32_t hash_multiplier = 1597334677U; 47#define xd3_hash_multiplier32 1597334677U
48#define xd3_hash_multiplier64 1181783497276652981ULL
48 49
49/* TODO: small cksum is hard-coded for 4 bytes (i.e., "look" is unused) */ 50/* TODO: small cksum is hard-coded for 4 bytes (i.e., "look" is unused) */
50static inline uint32_t 51static inline uint32_t
@@ -53,7 +54,7 @@ xd3_scksum (uint32_t *state,
53 const usize_t look) 54 const usize_t look)
54{ 55{
55 UNALIGNED_READ32(state, base); 56 UNALIGNED_READ32(state, base);
56 return (*state) * hash_multiplier; 57 return (*state) * xd3_hash_multiplier32;
57} 58}
58static inline uint32_t 59static inline uint32_t
59xd3_small_cksum_update (uint32_t *state, 60xd3_small_cksum_update (uint32_t *state,
@@ -61,112 +62,48 @@ xd3_small_cksum_update (uint32_t *state,
61 usize_t look) 62 usize_t look)
62{ 63{
63 UNALIGNED_READ32(state, base+1); 64 UNALIGNED_READ32(state, base+1);
64 return (*state) * hash_multiplier; 65 return (*state) * xd3_hash_multiplier32;
65} 66}
66 67
67static inline usize_t 68#if XD3_ENCODER
69inline usize_t
68xd3_checksum_hash (const xd3_hash_cfg *cfg, const usize_t cksum) 70xd3_checksum_hash (const xd3_hash_cfg *cfg, const usize_t cksum)
69{ 71{
70 return (cksum >> cfg->shift) ^ (cksum & cfg->mask); 72 return (cksum >> cfg->shift) ^ (cksum & cfg->mask);
71} 73}
72 74
73#if XD3_ENCODER
74#define PERMUTE32(x) (__single_hash32[x])
75extern const uint16_t __single_hash32[256];
76
77inline uint32_t 75inline uint32_t
78xd3_large32_cksum (const uint8_t *seg, const usize_t ln) 76xd3_large32_cksum (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look)
79{ 77{
80 static const uint32_t kBits = 16; 78 uint32_t h = 0;
81 static const uint32_t kMask = 0xffff; 79 for (usize_t i = 0; i < look; i++) {
82 usize_t i = 0; 80 h += base[i] * cfg->powers[i];
83 uint32_t low = 0; 81 }
84 uint32_t high = 0; 82 return h;
85
86 for (; i < ln; i += 1)
87 {
88 low += PERMUTE32(*seg++);
89 high += low;
90 }
91
92 return ((high & kMask) << kBits) | (low & kMask);
93} 83}
94 84
95inline uint32_t 85inline uint32_t
96xd3_large32_cksum_update (uint32_t cksum, 86xd3_large32_cksum_update (xd3_hash_cfg *cfg, const uint32_t cksum,
97 const uint8_t *base, 87 const uint8_t *base, const usize_t look)
98 usize_t look)
99{ 88{
100 static const uint32_t kBits = 16; 89 return xd3_hash_multiplier32 * cksum - cfg->multiplier * base[0] + base[look];
101 static const uint32_t kMask = 0xffff;
102 uint32_t old_c = PERMUTE32(base[0]);
103 uint32_t new_c = PERMUTE32(base[look]);
104 uint32_t low = ((cksum & kMask) - old_c + new_c) & kMask;
105 uint32_t high = ((cksum >> kBits) - (old_c * look) + low) & kMask;
106 return (high << kBits) | low;
107} 90}
108 91
109#undef PERMUTE32
110
111#define PERMUTE64(x) (__single_hash64[x])
112extern const uint32_t __single_hash64[256];
113
114inline uint64_t 92inline uint64_t
115xd3_large64_cksum (const uint8_t *seg, const usize_t len) 93xd3_large64_cksum (xd3_hash_cfg *cfg, const uint8_t *base, const usize_t look)
116{ 94{
117 static const uint64_t kBits = 32; 95 uint64_t h = 0;
118 static const uint64_t kMask = 0xffffffff; 96 for (usize_t i = 0; i < look; i++) {
119 usize_t i = 0; 97 h += base[i] * cfg->powers[i];
120 uint64_t low = 0; 98 }
121 uint64_t high = 0; 99 return h;
122
123 for (; i < len; i += 1)
124 {
125 low += PERMUTE64(*seg++);
126 high += low;
127 }
128
129 return ((high & kMask) << kBits) | (low & kMask);
130} 100}
131 101
132inline uint64_t 102inline uint64_t
133xd3_large64_cksum_update (uint64_t cksum, 103xd3_large64_cksum_update (xd3_hash_cfg *cfg, const uint64_t cksum,
134 const uint8_t *base, 104 const uint8_t *base, const usize_t look)
135 usize_t look)
136{ 105{
137 static const uint64_t kBits = 32; 106 return xd3_hash_multiplier64 * cksum - cfg->multiplier * base[0] + base[look];
138 static const uint64_t kMask = 0xffffffff;
139 uint64_t old_c = PERMUTE64(base[0]);
140 uint64_t new_c = PERMUTE64(base[look]);
141 uint64_t low = ((cksum & kMask) - old_c + new_c) & kMask;
142 uint64_t high = ((cksum >> kBits) - (old_c * look) + low) & kMask;
143 return (high << kBits) | low;
144}
145
146#undef PERMUTE64
147
148inline usize_t
149xd3_large_cksum (const uint8_t *seg, const usize_t len)
150{
151 if (SIZEOF_USIZE_T == 4)
152 {
153 return xd3_large32_cksum (seg, len);
154 }
155 else
156 {
157 return xd3_large64_cksum (seg, len);
158 }
159}
160
161inline usize_t
162xd3_large_cksum_update (usize_t cksum,
163 const uint8_t *base,
164 usize_t look) {
165#if SIZEOF_USIZE_T == 4
166 return xd3_large32_cksum_update (cksum, base, look);
167#else
168 return xd3_large64_cksum_update (cksum, base, look);
169#endif
170} 107}
171 108
172static usize_t 109static usize_t
@@ -179,9 +116,9 @@ xd3_size_hashtable_bits (usize_t slots)
179 { 116 {
180 if (slots < (1U << i)) 117 if (slots < (1U << i))
181 { 118 {
182 /* TODO: this is compaction=1 in checksum_test.cc and maybe should 119 /* Note: this is the compaction=1 setting measured in
183 * not be fixed at -1. */ 120 * checksum_test */
184 bits = i - 1; 121 bits = i - 1;
185 break; 122 break;
186 } 123 }
187 } 124 }
@@ -189,9 +126,10 @@ xd3_size_hashtable_bits (usize_t slots)
189 return bits; 126 return bits;
190} 127}
191 128
192static void 129int
193xd3_size_hashtable (xd3_stream *stream, 130xd3_size_hashtable (xd3_stream *stream,
194 usize_t slots, 131 usize_t slots,
132 usize_t look,
195 xd3_hash_cfg *cfg) 133 xd3_hash_cfg *cfg)
196{ 134{
197 usize_t bits = xd3_size_hashtable_bits (slots); 135 usize_t bits = xd3_size_hashtable_bits (slots);
@@ -199,7 +137,23 @@ xd3_size_hashtable (xd3_stream *stream,
199 cfg->size = (1U << bits); 137 cfg->size = (1U << bits);
200 cfg->mask = (cfg->size - 1); 138 cfg->mask = (cfg->size - 1);
201 cfg->shift = (SIZEOF_USIZE_T * 8) - bits; 139 cfg->shift = (SIZEOF_USIZE_T * 8) - bits;
140 cfg->look = look;
141
142 if ((cfg->powers =
143 (usize_t*) xd3_alloc0 (stream, look, sizeof (usize_t))) == NULL)
144 {
145 return ENOMEM;
146 }
147
148 cfg->powers[look-1] = 1;
149 for (int i = look-2; i >= 0; i--)
150 {
151 cfg->powers[i] = cfg->powers[i+1] * xd3_hash_multiplier;
152 }
153 cfg->multiplier = cfg->powers[0] * xd3_hash_multiplier;
154
155 return 0;
202} 156}
203 157
204#endif 158#endif /* XD3_ENCODER */
205#endif /* _XDELTA3_HASH_H_ */ 159#endif /* _XDELTA3_HASH_H_ */