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