diff options
Diffstat (limited to 'xdelta3/xdelta3-hash.h')
-rw-r--r-- | xdelta3/xdelta3-hash.h | 142 |
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" */ |
47 | static 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) */ |
50 | static inline uint32_t | 51 | static 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 | } |
58 | static inline uint32_t | 59 | static inline uint32_t |
59 | xd3_small_cksum_update (uint32_t *state, | 60 | xd3_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 | ||
67 | static inline usize_t | 68 | #if XD3_ENCODER |
69 | inline usize_t | ||
68 | xd3_checksum_hash (const xd3_hash_cfg *cfg, const usize_t cksum) | 70 | xd3_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]) | ||
75 | extern const uint16_t __single_hash32[256]; | ||
76 | |||
77 | inline uint32_t | 75 | inline uint32_t |
78 | xd3_large32_cksum (const uint8_t *seg, const usize_t ln) | 76 | xd3_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 | ||
95 | inline uint32_t | 85 | inline uint32_t |
96 | xd3_large32_cksum_update (uint32_t cksum, | 86 | xd3_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]) | ||
112 | extern const uint32_t __single_hash64[256]; | ||
113 | |||
114 | inline uint64_t | 92 | inline uint64_t |
115 | xd3_large64_cksum (const uint8_t *seg, const usize_t len) | 93 | xd3_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 | ||
132 | inline uint64_t | 102 | inline uint64_t |
133 | xd3_large64_cksum_update (uint64_t cksum, | 103 | xd3_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 | |||
148 | inline usize_t | ||
149 | xd3_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 | |||
161 | inline usize_t | ||
162 | xd3_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 | ||
172 | static usize_t | 109 | static 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 | ||
192 | static void | 129 | int |
193 | xd3_size_hashtable (xd3_stream *stream, | 130 | xd3_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_ */ |