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