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