126fa459cSmrg/* NOLINT(build/header_guard) */ 226fa459cSmrg/* Copyright 2010 Google Inc. All Rights Reserved. 326fa459cSmrg 426fa459cSmrg Distributed under MIT license. 526fa459cSmrg See file LICENSE for detail or copy at https://opensource.org/licenses/MIT 626fa459cSmrg*/ 726fa459cSmrg 826fa459cSmrg/* template parameters: FN */ 926fa459cSmrg 1026fa459cSmrg/* A (forgetful) hash table to the data seen by the compressor, to 1126fa459cSmrg help create backward references to previous data. 1226fa459cSmrg 1326fa459cSmrg This is a hash map of fixed size (bucket_size_) to a ring buffer of 1426fa459cSmrg fixed size (block_size_). The ring buffer contains the last block_size_ 1526fa459cSmrg index positions of the given hash key in the compressed data. */ 1626fa459cSmrg 1726fa459cSmrg#define HashLongestMatch HASHER() 1826fa459cSmrg 1926fa459cSmrgstatic BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; } 2026fa459cSmrgstatic BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; } 2126fa459cSmrg 2226fa459cSmrg/* HashBytes is the function that chooses the bucket to place the address in. */ 2326fa459cSmrgstatic BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data, 2426fa459cSmrg const uint64_t mask, 2526fa459cSmrg const int shift) { 2626fa459cSmrg const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(data) & mask) * kHashMul64Long; 2726fa459cSmrg /* The higher bits contain more mixture from the multiplication, 2826fa459cSmrg so we take our results from there. */ 2926fa459cSmrg return (uint32_t)(h >> shift); 3026fa459cSmrg} 3126fa459cSmrg 3226fa459cSmrgtypedef struct HashLongestMatch { 3326fa459cSmrg /* Number of hash buckets. */ 3426fa459cSmrg size_t bucket_size_; 3526fa459cSmrg /* Only block_size_ newest backward references are kept, 3626fa459cSmrg and the older are forgotten. */ 3726fa459cSmrg size_t block_size_; 3826fa459cSmrg /* Left-shift for computing hash bucket index from hash value. */ 3926fa459cSmrg int hash_shift_; 4026fa459cSmrg /* Mask for selecting the next 4-8 bytes of input */ 4126fa459cSmrg uint64_t hash_mask_; 4226fa459cSmrg /* Mask for accessing entries in a block (in a ring-buffer manner). */ 4326fa459cSmrg uint32_t block_mask_; 4426fa459cSmrg 4526fa459cSmrg int block_bits_; 4626fa459cSmrg int num_last_distances_to_check_; 4726fa459cSmrg 4826fa459cSmrg /* Shortcuts. */ 4926fa459cSmrg HasherCommon* common_; 5026fa459cSmrg 5126fa459cSmrg /* --- Dynamic size members --- */ 5226fa459cSmrg 5326fa459cSmrg /* Number of entries in a particular bucket. */ 5426fa459cSmrg uint16_t* num_; /* uint16_t[bucket_size]; */ 5526fa459cSmrg 5626fa459cSmrg /* Buckets containing block_size_ of backward references. */ 5726fa459cSmrg uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */ 5826fa459cSmrg} HashLongestMatch; 5926fa459cSmrg 6026fa459cSmrgstatic void FN(Initialize)( 6126fa459cSmrg HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self, 6226fa459cSmrg const BrotliEncoderParams* params) { 6326fa459cSmrg self->common_ = common; 6426fa459cSmrg 6526fa459cSmrg BROTLI_UNUSED(params); 6626fa459cSmrg self->hash_shift_ = 64 - common->params.bucket_bits; 6726fa459cSmrg self->hash_mask_ = (~((uint64_t)0U)) >> (64 - 8 * common->params.hash_len); 6826fa459cSmrg self->bucket_size_ = (size_t)1 << common->params.bucket_bits; 6926fa459cSmrg self->block_bits_ = common->params.block_bits; 7026fa459cSmrg self->block_size_ = (size_t)1 << common->params.block_bits; 7126fa459cSmrg self->block_mask_ = (uint32_t)(self->block_size_ - 1); 7226fa459cSmrg self->num_last_distances_to_check_ = 7326fa459cSmrg common->params.num_last_distances_to_check; 7426fa459cSmrg self->num_ = (uint16_t*)common->extra; 7526fa459cSmrg self->buckets_ = (uint32_t*)&self->num_[self->bucket_size_]; 7626fa459cSmrg} 7726fa459cSmrg 7826fa459cSmrgstatic void FN(Prepare)( 7926fa459cSmrg HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, 8026fa459cSmrg size_t input_size, const uint8_t* BROTLI_RESTRICT data) { 8126fa459cSmrg uint16_t* BROTLI_RESTRICT num = self->num_; 8226fa459cSmrg /* Partial preparation is 100 times slower (per socket). */ 8326fa459cSmrg size_t partial_prepare_threshold = self->bucket_size_ >> 6; 8426fa459cSmrg if (one_shot && input_size <= partial_prepare_threshold) { 8526fa459cSmrg size_t i; 8626fa459cSmrg for (i = 0; i < input_size; ++i) { 8726fa459cSmrg const uint32_t key = FN(HashBytes)(&data[i], self->hash_mask_, 8826fa459cSmrg self->hash_shift_); 8926fa459cSmrg num[key] = 0; 9026fa459cSmrg } 9126fa459cSmrg } else { 9226fa459cSmrg memset(num, 0, self->bucket_size_ * sizeof(num[0])); 9326fa459cSmrg } 9426fa459cSmrg} 9526fa459cSmrg 9626fa459cSmrgstatic BROTLI_INLINE size_t FN(HashMemAllocInBytes)( 9726fa459cSmrg const BrotliEncoderParams* params, BROTLI_BOOL one_shot, 9826fa459cSmrg size_t input_size) { 9926fa459cSmrg size_t bucket_size = (size_t)1 << params->hasher.bucket_bits; 10026fa459cSmrg size_t block_size = (size_t)1 << params->hasher.block_bits; 10126fa459cSmrg BROTLI_UNUSED(one_shot); 10226fa459cSmrg BROTLI_UNUSED(input_size); 10326fa459cSmrg return sizeof(uint16_t) * bucket_size + 10426fa459cSmrg sizeof(uint32_t) * bucket_size * block_size; 10526fa459cSmrg} 10626fa459cSmrg 10726fa459cSmrg/* Look at 4 bytes at &data[ix & mask]. 10826fa459cSmrg Compute a hash from these, and store the value of ix at that position. */ 10926fa459cSmrgstatic BROTLI_INLINE void FN(Store)( 11026fa459cSmrg HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, 11126fa459cSmrg const size_t mask, const size_t ix) { 11226fa459cSmrg uint16_t* BROTLI_RESTRICT num = self->num_; 11326fa459cSmrg uint32_t* BROTLI_RESTRICT buckets = self->buckets_; 11426fa459cSmrg const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_mask_, 11526fa459cSmrg self->hash_shift_); 11626fa459cSmrg const size_t minor_ix = num[key] & self->block_mask_; 11726fa459cSmrg const size_t offset = minor_ix + (key << self->block_bits_); 11826fa459cSmrg ++num[key]; 11926fa459cSmrg buckets[offset] = (uint32_t)ix; 12026fa459cSmrg} 12126fa459cSmrg 12226fa459cSmrgstatic BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self, 12326fa459cSmrg const uint8_t* BROTLI_RESTRICT data, const size_t mask, 12426fa459cSmrg const size_t ix_start, const size_t ix_end) { 12526fa459cSmrg size_t i; 12626fa459cSmrg for (i = ix_start; i < ix_end; ++i) { 12726fa459cSmrg FN(Store)(self, data, mask, i); 12826fa459cSmrg } 12926fa459cSmrg} 13026fa459cSmrg 13126fa459cSmrgstatic BROTLI_INLINE void FN(StitchToPreviousBlock)( 13226fa459cSmrg HashLongestMatch* BROTLI_RESTRICT self, 13326fa459cSmrg size_t num_bytes, size_t position, const uint8_t* ringbuffer, 13426fa459cSmrg size_t ringbuffer_mask) { 13526fa459cSmrg if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) { 13626fa459cSmrg /* Prepare the hashes for three last bytes of the last write. 13726fa459cSmrg These could not be calculated before, since they require knowledge 13826fa459cSmrg of both the previous and the current block. */ 13926fa459cSmrg FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3); 14026fa459cSmrg FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2); 14126fa459cSmrg FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1); 14226fa459cSmrg } 14326fa459cSmrg} 14426fa459cSmrg 14526fa459cSmrgstatic BROTLI_INLINE void FN(PrepareDistanceCache)( 14626fa459cSmrg HashLongestMatch* BROTLI_RESTRICT self, 14726fa459cSmrg int* BROTLI_RESTRICT distance_cache) { 14826fa459cSmrg PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_); 14926fa459cSmrg} 15026fa459cSmrg 15126fa459cSmrg/* Find a longest backward match of &data[cur_ix] up to the length of 15226fa459cSmrg max_length and stores the position cur_ix in the hash table. 15326fa459cSmrg 15426fa459cSmrg REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache 15526fa459cSmrg values; if this method is invoked repeatedly with the same distance 15626fa459cSmrg cache values, it is enough to invoke FN(PrepareDistanceCache) once. 15726fa459cSmrg 15826fa459cSmrg Does not look for matches longer than max_length. 15926fa459cSmrg Does not look for matches further away than max_backward. 16026fa459cSmrg Writes the best match into |out|. 16126fa459cSmrg |out|->score is updated only if a better match is found. */ 16226fa459cSmrgstatic BROTLI_INLINE void FN(FindLongestMatch)( 16326fa459cSmrg HashLongestMatch* BROTLI_RESTRICT self, 16426fa459cSmrg const BrotliEncoderDictionary* dictionary, 16526fa459cSmrg const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, 16626fa459cSmrg const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix, 16726fa459cSmrg const size_t max_length, const size_t max_backward, 16826fa459cSmrg const size_t dictionary_distance, const size_t max_distance, 16926fa459cSmrg HasherSearchResult* BROTLI_RESTRICT out) { 17026fa459cSmrg uint16_t* BROTLI_RESTRICT num = self->num_; 17126fa459cSmrg uint32_t* BROTLI_RESTRICT buckets = self->buckets_; 17226fa459cSmrg const size_t cur_ix_masked = cur_ix & ring_buffer_mask; 17326fa459cSmrg /* Don't accept a short copy from far away. */ 17426fa459cSmrg score_t min_score = out->score; 17526fa459cSmrg score_t best_score = out->score; 17626fa459cSmrg size_t best_len = out->len; 17726fa459cSmrg size_t i; 17826fa459cSmrg out->len = 0; 17926fa459cSmrg out->len_code_delta = 0; 18026fa459cSmrg /* Try last distance first. */ 18126fa459cSmrg for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) { 18226fa459cSmrg const size_t backward = (size_t)distance_cache[i]; 18326fa459cSmrg size_t prev_ix = (size_t)(cur_ix - backward); 18426fa459cSmrg if (prev_ix >= cur_ix) { 18526fa459cSmrg continue; 18626fa459cSmrg } 18726fa459cSmrg if (BROTLI_PREDICT_FALSE(backward > max_backward)) { 18826fa459cSmrg continue; 18926fa459cSmrg } 19026fa459cSmrg prev_ix &= ring_buffer_mask; 19126fa459cSmrg 19226fa459cSmrg if (cur_ix_masked + best_len > ring_buffer_mask || 19326fa459cSmrg prev_ix + best_len > ring_buffer_mask || 19426fa459cSmrg data[cur_ix_masked + best_len] != data[prev_ix + best_len]) { 19526fa459cSmrg continue; 19626fa459cSmrg } 19726fa459cSmrg { 19826fa459cSmrg const size_t len = FindMatchLengthWithLimit(&data[prev_ix], 19926fa459cSmrg &data[cur_ix_masked], 20026fa459cSmrg max_length); 20126fa459cSmrg if (len >= 3 || (len == 2 && i < 2)) { 20226fa459cSmrg /* Comparing for >= 2 does not change the semantics, but just saves for 20326fa459cSmrg a few unnecessary binary logarithms in backward reference score, 20426fa459cSmrg since we are not interested in such short matches. */ 20526fa459cSmrg score_t score = BackwardReferenceScoreUsingLastDistance(len); 20626fa459cSmrg if (best_score < score) { 20726fa459cSmrg if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i); 20826fa459cSmrg if (best_score < score) { 20926fa459cSmrg best_score = score; 21026fa459cSmrg best_len = len; 21126fa459cSmrg out->len = best_len; 21226fa459cSmrg out->distance = backward; 21326fa459cSmrg out->score = best_score; 21426fa459cSmrg } 21526fa459cSmrg } 21626fa459cSmrg } 21726fa459cSmrg } 21826fa459cSmrg } 21926fa459cSmrg { 22026fa459cSmrg const uint32_t key = FN(HashBytes)( 22126fa459cSmrg &data[cur_ix_masked], self->hash_mask_, self->hash_shift_); 22226fa459cSmrg uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_]; 22326fa459cSmrg const size_t down = 22426fa459cSmrg (num[key] > self->block_size_) ? 22526fa459cSmrg (num[key] - self->block_size_) : 0u; 22626fa459cSmrg for (i = num[key]; i > down;) { 22726fa459cSmrg size_t prev_ix = bucket[--i & self->block_mask_]; 22826fa459cSmrg const size_t backward = cur_ix - prev_ix; 22926fa459cSmrg if (BROTLI_PREDICT_FALSE(backward > max_backward)) { 23026fa459cSmrg break; 23126fa459cSmrg } 23226fa459cSmrg prev_ix &= ring_buffer_mask; 23326fa459cSmrg if (cur_ix_masked + best_len > ring_buffer_mask || 23426fa459cSmrg prev_ix + best_len > ring_buffer_mask || 23526fa459cSmrg data[cur_ix_masked + best_len] != data[prev_ix + best_len]) { 23626fa459cSmrg continue; 23726fa459cSmrg } 23826fa459cSmrg { 23926fa459cSmrg const size_t len = FindMatchLengthWithLimit(&data[prev_ix], 24026fa459cSmrg &data[cur_ix_masked], 24126fa459cSmrg max_length); 24226fa459cSmrg if (len >= 4) { 24326fa459cSmrg /* Comparing for >= 3 does not change the semantics, but just saves 24426fa459cSmrg for a few unnecessary binary logarithms in backward reference 24526fa459cSmrg score, since we are not interested in such short matches. */ 24626fa459cSmrg score_t score = BackwardReferenceScore(len, backward); 24726fa459cSmrg if (best_score < score) { 24826fa459cSmrg best_score = score; 24926fa459cSmrg best_len = len; 25026fa459cSmrg out->len = best_len; 25126fa459cSmrg out->distance = backward; 25226fa459cSmrg out->score = best_score; 25326fa459cSmrg } 25426fa459cSmrg } 25526fa459cSmrg } 25626fa459cSmrg } 25726fa459cSmrg bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix; 25826fa459cSmrg ++num[key]; 25926fa459cSmrg } 26026fa459cSmrg if (min_score == out->score) { 26126fa459cSmrg SearchInStaticDictionary(dictionary, 26226fa459cSmrg self->common_, &data[cur_ix_masked], max_length, dictionary_distance, 26326fa459cSmrg max_distance, out, BROTLI_FALSE); 26426fa459cSmrg } 26526fa459cSmrg} 26626fa459cSmrg 26726fa459cSmrg#undef HashLongestMatch 268