]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/BrotliCompress/enc/hash.h
BaseTools: Update Brotli Compress to the latest one 1.0.6
[mirror_edk2.git] / BaseTools / Source / C / BrotliCompress / enc / hash.h
index 6756e68c3774c587171d338947b3d1f21da33127..9225d127ac583794d71c9c38dc6fda07055df19a 100644 (file)
 \r
 #include "../common/constants.h"\r
 #include "../common/dictionary.h"\r
-#include "../common/types.h"\r
-#include "./dictionary_hash.h"\r
+#include "../common/platform.h"\r
+#include <brotli/types.h>\r
+#include "./encoder_dict.h"\r
 #include "./fast_log.h"\r
 #include "./find_match_length.h"\r
 #include "./memory.h"\r
-#include "./port.h"\r
 #include "./quality.h"\r
 #include "./static_dict.h"\r
 \r
 extern "C" {\r
 #endif\r
 \r
-#define MAX_TREE_SEARCH_DEPTH 64\r
-#define MAX_TREE_COMP_LENGTH 128\r
-#define score_t size_t\r
+/* Pointer to hasher data.\r
+ *\r
+ * Excluding initialization and destruction, hasher can be passed as\r
+ * HasherHandle by value.\r
+ *\r
+ * Typically hasher data consists of 3 sections:\r
+ * * HasherCommon structure\r
+ * * private structured hasher data, depending on hasher type\r
+ * * private dynamic hasher data, depending on hasher type and parameters\r
+ *\r
+ * Using "define" instead of "typedef", because on MSVC __restrict does not work\r
+ * on typedef pointer types. */\r
+#define HasherHandle uint8_t*\r
+\r
+typedef struct {\r
+  BrotliHasherParams params;\r
+\r
+  /* False if hasher needs to be "prepared" before use. */\r
+  BROTLI_BOOL is_prepared_;\r
+\r
+  size_t dict_num_lookups;\r
+  size_t dict_num_matches;\r
+} HasherCommon;\r
+\r
+static BROTLI_INLINE HasherCommon* GetHasherCommon(HasherHandle handle) {\r
+  return (HasherCommon*)handle;\r
+}\r
 \r
-static const uint32_t kDistanceCacheIndex[] = {\r
-  0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,\r
-};\r
-static const int kDistanceCacheOffset[] = {\r
-  0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3\r
-};\r
+#define score_t size_t\r
 \r
 static const uint32_t kCutoffTransformsCount = 10;\r
-static const uint8_t kCutoffTransforms[] = {\r
-  0, 12, 27, 23, 42, 63, 56, 48, 59, 64\r
-};\r
+/*   0,  12,   27,    23,    42,    63,    56,    48,    59,    64 */\r
+/* 0+0, 4+8, 8+19, 12+11, 16+26, 20+43, 24+32, 28+20, 32+27, 36+28 */\r
+static const uint64_t kCutoffTransforms =\r
+    BROTLI_MAKE_UINT64_T(0x071B520A, 0xDA2D3200);\r
 \r
 typedef struct HasherSearchResult {\r
   size_t len;\r
-  size_t len_x_code; /* == len ^ len_code */\r
   size_t distance;\r
   score_t score;\r
+  int len_code_delta; /* == len_code - len */\r
 } HasherSearchResult;\r
 \r
-typedef struct DictionarySearchStatictics {\r
-  size_t num_lookups;\r
-  size_t num_matches;\r
-} DictionarySearchStatictics;\r
-\r
 /* kHashMul32 multiplier has these properties:\r
    * The multiplier must be odd. Otherwise we may lose the highest bit.\r
-   * No long streaks of 1s or 0s.\r
+   * No long streaks of ones or zeros.\r
    * There is no effort to ensure that it is a prime, the oddity is enough\r
      for this use.\r
    * The number has been tuned heuristically against compression benchmarks. */\r
-static const uint32_t kHashMul32 = 0x1e35a7bd;\r
+static const uint32_t kHashMul32 = 0x1E35A7BD;\r
+static const uint64_t kHashMul64 = BROTLI_MAKE_UINT64_T(0x1E35A7BD, 0x1E35A7BD);\r
+static const uint64_t kHashMul64Long =\r
+    BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);\r
 \r
 static BROTLI_INLINE uint32_t Hash14(const uint8_t* data) {\r
-  uint32_t h = BROTLI_UNALIGNED_LOAD32(data) * kHashMul32;\r
+  uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;\r
   /* The higher bits contain more mixture from the multiplication,\r
      so we take our results from there. */\r
   return h >> (32 - 14);\r
 }\r
 \r
-#define BROTLI_LITERAL_BYTE_SCORE 540\r
-#define BROTLI_DISTANCE_BIT_PENALTY 120\r
+static BROTLI_INLINE void PrepareDistanceCache(\r
+    int* BROTLI_RESTRICT distance_cache, const int num_distances) {\r
+  if (num_distances > 4) {\r
+    int last_distance = distance_cache[0];\r
+    distance_cache[4] = last_distance - 1;\r
+    distance_cache[5] = last_distance + 1;\r
+    distance_cache[6] = last_distance - 2;\r
+    distance_cache[7] = last_distance + 2;\r
+    distance_cache[8] = last_distance - 3;\r
+    distance_cache[9] = last_distance + 3;\r
+    if (num_distances > 10) {\r
+      int next_last_distance = distance_cache[1];\r
+      distance_cache[10] = next_last_distance - 1;\r
+      distance_cache[11] = next_last_distance + 1;\r
+      distance_cache[12] = next_last_distance - 2;\r
+      distance_cache[13] = next_last_distance + 2;\r
+      distance_cache[14] = next_last_distance - 3;\r
+      distance_cache[15] = next_last_distance + 3;\r
+    }\r
+  }\r
+}\r
+\r
+#define BROTLI_LITERAL_BYTE_SCORE 135\r
+#define BROTLI_DISTANCE_BIT_PENALTY 30\r
 /* Score must be positive after applying maximal penalty. */\r
 #define BROTLI_SCORE_BASE (BROTLI_DISTANCE_BIT_PENALTY * 8 * sizeof(size_t))\r
 \r
@@ -97,97 +137,83 @@ static BROTLI_INLINE score_t BackwardReferenceScore(
       BROTLI_DISTANCE_BIT_PENALTY * Log2FloorNonZero(backward_reference_offset);\r
 }\r
 \r
-static const score_t kDistanceShortCodeCost[BROTLI_NUM_DISTANCE_SHORT_CODES] = {\r
-  /* Repeat last */\r
-  BROTLI_SCORE_BASE +  60,\r
-  /* 2nd, 3rd, 4th last */\r
-  BROTLI_SCORE_BASE -  95,\r
-  BROTLI_SCORE_BASE - 117,\r
-  BROTLI_SCORE_BASE - 127,\r
-  /* Last with offset */\r
-  BROTLI_SCORE_BASE -  93,\r
-  BROTLI_SCORE_BASE -  93,\r
-  BROTLI_SCORE_BASE -  96,\r
-  BROTLI_SCORE_BASE -  96,\r
-  BROTLI_SCORE_BASE -  99,\r
-  BROTLI_SCORE_BASE -  99,\r
-  /* 2nd last with offset */\r
-  BROTLI_SCORE_BASE - 105,\r
-  BROTLI_SCORE_BASE - 105,\r
-  BROTLI_SCORE_BASE - 115,\r
-  BROTLI_SCORE_BASE - 115,\r
-  BROTLI_SCORE_BASE - 125,\r
-  BROTLI_SCORE_BASE - 125\r
-};\r
-\r
 static BROTLI_INLINE score_t BackwardReferenceScoreUsingLastDistance(\r
-    size_t copy_length, size_t distance_short_code) {\r
+    size_t copy_length) {\r
   return BROTLI_LITERAL_BYTE_SCORE * (score_t)copy_length +\r
-      kDistanceShortCodeCost[distance_short_code];\r
+      BROTLI_SCORE_BASE + 15;\r
 }\r
 \r
-static BROTLI_INLINE void DictionarySearchStaticticsReset(\r
-    DictionarySearchStatictics* self) {\r
-  self->num_lookups = 0;\r
-  self->num_matches = 0;\r
+static BROTLI_INLINE score_t BackwardReferencePenaltyUsingLastDistance(\r
+    size_t distance_short_code) {\r
+  return (score_t)39 + ((0x1CA10 >> (distance_short_code & 0xE)) & 0xE);\r
 }\r
 \r
 static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(\r
-    size_t item, const uint8_t* data, size_t max_length, size_t max_backward,\r
+    const BrotliEncoderDictionary* dictionary, size_t item, const uint8_t* data,\r
+    size_t max_length, size_t max_backward, size_t max_distance,\r
     HasherSearchResult* out) {\r
   size_t len;\r
-  size_t dist;\r
+  size_t word_idx;\r
   size_t offset;\r
   size_t matchlen;\r
   size_t backward;\r
   score_t score;\r
-  len = item & 31;\r
-  dist = item >> 5;\r
-  offset = kBrotliDictionaryOffsetsByLength[len] + len * dist;\r
+  len = item & 0x1F;\r
+  word_idx = item >> 5;\r
+  offset = dictionary->words->offsets_by_length[len] + len * word_idx;\r
   if (len > max_length) {\r
     return BROTLI_FALSE;\r
   }\r
 \r
-  matchlen = FindMatchLengthWithLimit(data, &kBrotliDictionary[offset], len);\r
-  if (matchlen + kCutoffTransformsCount <= len || matchlen == 0) {\r
+  matchlen =\r
+      FindMatchLengthWithLimit(data, &dictionary->words->data[offset], len);\r
+  if (matchlen + dictionary->cutoffTransformsCount <= len || matchlen == 0) {\r
     return BROTLI_FALSE;\r
   }\r
   {\r
-    size_t transform_id = kCutoffTransforms[len - matchlen];\r
-    backward = max_backward + dist + 1 +\r
-        (transform_id << kBrotliDictionarySizeBitsByLength[len]);\r
+    size_t cut = len - matchlen;\r
+    size_t transform_id = (cut << 2) +\r
+        (size_t)((dictionary->cutoffTransforms >> (cut * 6)) & 0x3F);\r
+    backward = max_backward + 1 + word_idx +\r
+        (transform_id << dictionary->words->size_bits_by_length[len]);\r
+  }\r
+  if (backward > max_distance) {\r
+    return BROTLI_FALSE;\r
   }\r
   score = BackwardReferenceScore(matchlen, backward);\r
   if (score < out->score) {\r
     return BROTLI_FALSE;\r
   }\r
   out->len = matchlen;\r
-  out->len_x_code = len ^ matchlen;\r
+  out->len_code_delta = (int)len - (int)matchlen;\r
   out->distance = backward;\r
   out->score = score;\r
   return BROTLI_TRUE;\r
 }\r
 \r
-static BROTLI_INLINE BROTLI_BOOL SearchInStaticDictionary(\r
-    DictionarySearchStatictics* self, const uint8_t* data, size_t max_length,\r
-    size_t max_backward, HasherSearchResult* out, BROTLI_BOOL shallow) {\r
+static BROTLI_INLINE void SearchInStaticDictionary(\r
+    const BrotliEncoderDictionary* dictionary,\r
+    HasherHandle handle, const uint8_t* data, size_t max_length,\r
+    size_t max_backward, size_t max_distance,\r
+    HasherSearchResult* out, BROTLI_BOOL shallow) {\r
   size_t key;\r
   size_t i;\r
-  BROTLI_BOOL is_match_found = BROTLI_FALSE;\r
-  if (self->num_matches < (self->num_lookups >> 7)) {\r
-    return BROTLI_FALSE;\r
+  HasherCommon* self = GetHasherCommon(handle);\r
+  if (self->dict_num_matches < (self->dict_num_lookups >> 7)) {\r
+    return;\r
   }\r
   key = Hash14(data) << 1;\r
-  for (i = 0; i < (shallow ? 1 : 2); ++i, ++key) {\r
-    size_t item = kStaticDictionaryHash[key];\r
-    self->num_lookups++;\r
-    if (item != 0 &&\r
-        TestStaticDictionaryItem(item, data, max_length, max_backward, out)) {\r
-      self->num_matches++;\r
-      is_match_found = BROTLI_TRUE;\r
+  for (i = 0; i < (shallow ? 1u : 2u); ++i, ++key) {\r
+    size_t item = dictionary->hash_table[key];\r
+    self->dict_num_lookups++;\r
+    if (item != 0) {\r
+      BROTLI_BOOL item_matches = TestStaticDictionaryItem(\r
+          dictionary, item, data, max_length, max_backward, max_distance, out);\r
+      if (item_matches) {\r
+        self->dict_num_matches++;\r
+      }\r
     }\r
   }\r
-  return is_match_found;\r
 }\r
 \r
 typedef struct BackwardMatch {\r
@@ -221,320 +247,26 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
 #define CAT(a, b) a ## b\r
 #define FN(X) EXPAND_CAT(X, HASHER())\r
 \r
-#define MAX_NUM_MATCHES_H10 (64 + MAX_TREE_SEARCH_DEPTH)\r
-\r
 #define HASHER() H10\r
-#define HashToBinaryTree HASHER()\r
-\r
 #define BUCKET_BITS 17\r
-#define BUCKET_SIZE (1 << BUCKET_BITS)\r
-\r
-static size_t FN(HashTypeLength)(void) { return 4; }\r
-static size_t FN(StoreLookahead)(void) { return MAX_TREE_COMP_LENGTH; }\r
-\r
-static uint32_t FN(HashBytes)(const uint8_t *data) {\r
-  uint32_t h = BROTLI_UNALIGNED_LOAD32(data) * kHashMul32;\r
-  /* The higher bits contain more mixture from the multiplication,\r
-     so we take our results from there. */\r
-  return h >> (32 - BUCKET_BITS);\r
-}\r
-\r
-/* A (forgetful) hash table where each hash bucket contains a binary tree of\r
-   sequences whose first 4 bytes share the same hash code.\r
-   Each sequence is MAX_TREE_COMP_LENGTH long and is identified by its starting\r
-   position in the input data. The binary tree is sorted by the lexicographic\r
-   order of the sequences, and it is also a max-heap with respect to the\r
-   starting positions. */\r
-typedef struct HashToBinaryTree {\r
-  /* The window size minus 1 */\r
-  size_t window_mask_;\r
-\r
-  /* Hash table that maps the 4-byte hashes of the sequence to the last\r
-     position where this hash was found, which is the root of the binary\r
-     tree of sequences that share this hash bucket. */\r
-  uint32_t buckets_[BUCKET_SIZE];\r
-\r
-  /* The union of the binary trees of each hash bucket. The root of the tree\r
-     corresponding to a hash is a sequence starting at buckets_[hash] and\r
-     the left and right children of a sequence starting at pos are\r
-     forest_[2 * pos] and forest_[2 * pos + 1]. */\r
-  uint32_t* forest_;\r
-\r
-  /* A position used to mark a non-existent sequence, i.e. a tree is empty if\r
-     its root is at invalid_pos_ and a node is a leaf if both its children\r
-     are at invalid_pos_. */\r
-  uint32_t invalid_pos_;\r
-\r
-  size_t forest_size_;\r
-  BROTLI_BOOL is_dirty_;\r
-} HashToBinaryTree;\r
-\r
-static void FN(Reset)(HashToBinaryTree* self) {\r
-  self->is_dirty_ = BROTLI_TRUE;\r
-}\r
-\r
-static void FN(Initialize)(HashToBinaryTree* self) {\r
-  self->forest_ = NULL;\r
-  self->forest_size_ = 0;\r
-  FN(Reset)(self);\r
-}\r
-\r
-static void FN(Cleanup)(MemoryManager* m, HashToBinaryTree* self) {\r
-  BROTLI_FREE(m, self->forest_);\r
-}\r
-\r
-static void FN(Init)(\r
-    MemoryManager* m, HashToBinaryTree* self, const uint8_t* data,\r
-    const BrotliEncoderParams* params, size_t position, size_t bytes,\r
-    BROTLI_BOOL is_last) {\r
-  if (self->is_dirty_) {\r
-    uint32_t invalid_pos;\r
-    size_t num_nodes;\r
-    uint32_t i;\r
-    BROTLI_UNUSED(data);\r
-    self->window_mask_ = (1u << params->lgwin) - 1u;\r
-    invalid_pos = (uint32_t)(0 - self->window_mask_);\r
-    self->invalid_pos_ = invalid_pos;\r
-    for (i = 0; i < BUCKET_SIZE; i++) {\r
-      self->buckets_[i] = invalid_pos;\r
-    }\r
-    num_nodes = (position == 0 && is_last) ? bytes : self->window_mask_ + 1;\r
-    if (num_nodes > self->forest_size_) {\r
-      BROTLI_FREE(m, self->forest_);\r
-      self->forest_ = BROTLI_ALLOC(m, uint32_t, 2 * num_nodes);\r
-      if (BROTLI_IS_OOM(m)) return;\r
-      self->forest_size_ = num_nodes;\r
-    }\r
-    self->is_dirty_ = BROTLI_FALSE;\r
-  }\r
-}\r
-\r
-static BROTLI_INLINE size_t FN(LeftChildIndex)(HashToBinaryTree* self,\r
-    const size_t pos) {\r
-  return 2 * (pos & self->window_mask_);\r
-}\r
-\r
-static BROTLI_INLINE size_t FN(RightChildIndex)(HashToBinaryTree* self,\r
-    const size_t pos) {\r
-  return 2 * (pos & self->window_mask_) + 1;\r
-}\r
-\r
-/* Stores the hash of the next 4 bytes and in a single tree-traversal, the\r
-   hash bucket's binary tree is searched for matches and is re-rooted at the\r
-   current position.\r
-\r
-   If less than MAX_TREE_COMP_LENGTH data is available, the hash bucket of the\r
-   current position is searched for matches, but the state of the hash table\r
-   is not changed, since we can not know the final sorting order of the\r
-   current (incomplete) sequence.\r
-\r
-   This function must be called with increasing cur_ix positions. */\r
-static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(\r
-    HashToBinaryTree* self, const uint8_t* const BROTLI_RESTRICT data,\r
-    const size_t cur_ix, const size_t ring_buffer_mask, const size_t max_length,\r
-    const size_t max_backward, size_t* const BROTLI_RESTRICT best_len,\r
-    BackwardMatch* BROTLI_RESTRICT matches) {\r
-  const size_t cur_ix_masked = cur_ix & ring_buffer_mask;\r
-  const size_t max_comp_len =\r
-      BROTLI_MIN(size_t, max_length, MAX_TREE_COMP_LENGTH);\r
-  const BROTLI_BOOL should_reroot_tree =\r
-      TO_BROTLI_BOOL(max_length >= MAX_TREE_COMP_LENGTH);\r
-  const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);\r
-  size_t prev_ix = self->buckets_[key];\r
-  /* The forest index of the rightmost node of the left subtree of the new\r
-     root, updated as we traverse and reroot the tree of the hash bucket. */\r
-  size_t node_left = FN(LeftChildIndex)(self, cur_ix);\r
-  /* The forest index of the leftmost node of the right subtree of the new\r
-     root, updated as we traverse and reroot the tree of the hash bucket. */\r
-  size_t node_right = FN(RightChildIndex)(self, cur_ix);\r
-  /* The match length of the rightmost node of the left subtree of the new\r
-     root, updated as we traverse and reroot the tree of the hash bucket. */\r
-  size_t best_len_left = 0;\r
-  /* The match length of the leftmost node of the right subtree of the new\r
-     root, updated as we traverse and reroot the tree of the hash bucket. */\r
-  size_t best_len_right = 0;\r
-  size_t depth_remaining;\r
-  if (should_reroot_tree) {\r
-    self->buckets_[key] = (uint32_t)cur_ix;\r
-  }\r
-  for (depth_remaining = MAX_TREE_SEARCH_DEPTH; ; --depth_remaining) {\r
-    const size_t backward = cur_ix - prev_ix;\r
-    const size_t prev_ix_masked = prev_ix & ring_buffer_mask;\r
-    if (backward == 0 || backward > max_backward || depth_remaining == 0) {\r
-      if (should_reroot_tree) {\r
-        self->forest_[node_left] = self->invalid_pos_;\r
-        self->forest_[node_right] = self->invalid_pos_;\r
-      }\r
-      break;\r
-    }\r
-    {\r
-      const size_t cur_len = BROTLI_MIN(size_t, best_len_left, best_len_right);\r
-      size_t len;\r
-      assert(cur_len <= MAX_TREE_COMP_LENGTH);\r
-      len = cur_len +\r
-          FindMatchLengthWithLimit(&data[cur_ix_masked + cur_len],\r
-                                   &data[prev_ix_masked + cur_len],\r
-                                   max_length - cur_len);\r
-      assert(0 == memcmp(&data[cur_ix_masked], &data[prev_ix_masked], len));\r
-      if (matches && len > *best_len) {\r
-        *best_len = len;\r
-        InitBackwardMatch(matches++, backward, len);\r
-      }\r
-      if (len >= max_comp_len) {\r
-        if (should_reroot_tree) {\r
-          self->forest_[node_left] =\r
-              self->forest_[FN(LeftChildIndex)(self, prev_ix)];\r
-          self->forest_[node_right] =\r
-              self->forest_[FN(RightChildIndex)(self, prev_ix)];\r
-        }\r
-        break;\r
-      }\r
-      if (data[cur_ix_masked + len] > data[prev_ix_masked + len]) {\r
-        best_len_left = len;\r
-        if (should_reroot_tree) {\r
-          self->forest_[node_left] = (uint32_t)prev_ix;\r
-        }\r
-        node_left = FN(RightChildIndex)(self, prev_ix);\r
-        prev_ix = self->forest_[node_left];\r
-      } else {\r
-        best_len_right = len;\r
-        if (should_reroot_tree) {\r
-          self->forest_[node_right] = (uint32_t)prev_ix;\r
-        }\r
-        node_right = FN(LeftChildIndex)(self, prev_ix);\r
-        prev_ix = self->forest_[node_right];\r
-      }\r
-    }\r
-  }\r
-  return matches;\r
-}\r
-\r
-/* Finds all backward matches of &data[cur_ix & ring_buffer_mask] up to the\r
-   length of max_length and stores the position cur_ix in the hash table.\r
-\r
-   Sets *num_matches to the number of matches found, and stores the found\r
-   matches in matches[0] to matches[*num_matches - 1]. The matches will be\r
-   sorted by strictly increasing length and (non-strictly) increasing\r
-   distance. */\r
-static BROTLI_INLINE size_t FN(FindAllMatches)(HashToBinaryTree* self,\r
-    const uint8_t* data, const size_t ring_buffer_mask, const size_t cur_ix,\r
-    const size_t max_length, const size_t max_backward,\r
-    const BrotliEncoderParams* params, BackwardMatch* matches) {\r
-  BackwardMatch* const orig_matches = matches;\r
-  const size_t cur_ix_masked = cur_ix & ring_buffer_mask;\r
-  size_t best_len = 1;\r
-  const size_t short_match_max_backward =\r
-      params->quality != HQ_ZOPFLIFICATION_QUALITY ? 16 : 64;\r
-  size_t stop = cur_ix - short_match_max_backward;\r
-  uint32_t dict_matches[BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1];\r
-  size_t i;\r
-  if (cur_ix < short_match_max_backward) { stop = 0; }\r
-  for (i = cur_ix - 1; i > stop && best_len <= 2; --i) {\r
-    size_t prev_ix = i;\r
-    const size_t backward = cur_ix - prev_ix;\r
-    if (PREDICT_FALSE(backward > max_backward)) {\r
-      break;\r
-    }\r
-    prev_ix &= ring_buffer_mask;\r
-    if (data[cur_ix_masked] != data[prev_ix] ||\r
-        data[cur_ix_masked + 1] != data[prev_ix + 1]) {\r
-      continue;\r
-    }\r
-    {\r
-      const size_t len =\r
-          FindMatchLengthWithLimit(&data[prev_ix], &data[cur_ix_masked],\r
-                                   max_length);\r
-      if (len > best_len) {\r
-        best_len = len;\r
-        InitBackwardMatch(matches++, backward, len);\r
-      }\r
-    }\r
-  }\r
-  if (best_len < max_length) {\r
-    matches = FN(StoreAndFindMatches)(self, data, cur_ix, ring_buffer_mask,\r
-        max_length, max_backward, &best_len, matches);\r
-  }\r
-  for (i = 0; i <= BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN; ++i) {\r
-    dict_matches[i] = kInvalidMatch;\r
-  }\r
-  {\r
-    size_t minlen = BROTLI_MAX(size_t, 4, best_len + 1);\r
-    if (BrotliFindAllStaticDictionaryMatches(&data[cur_ix_masked], minlen,\r
-                                             max_length, &dict_matches[0])) {\r
-      size_t maxlen = BROTLI_MIN(\r
-          size_t, BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN, max_length);\r
-      size_t l;\r
-      for (l = minlen; l <= maxlen; ++l) {\r
-        uint32_t dict_id = dict_matches[l];\r
-        if (dict_id < kInvalidMatch) {\r
-          InitDictionaryBackwardMatch(matches++,\r
-              max_backward + (dict_id >> 5) + 1, l, dict_id & 31);\r
-        }\r
-      }\r
-    }\r
-  }\r
-  return (size_t)(matches - orig_matches);\r
-}\r
-\r
-/* Stores the hash of the next 4 bytes and re-roots the binary tree at the\r
-   current sequence, without returning any matches.\r
-   REQUIRES: ix + MAX_TREE_COMP_LENGTH <= end-of-current-block */\r
-static BROTLI_INLINE void FN(Store)(HashToBinaryTree* self, const uint8_t *data,\r
-    const size_t mask, const size_t ix) {\r
-  /* Maximum distance is window size - 16, see section 9.1. of the spec. */\r
-  const size_t max_backward = self->window_mask_ - 15;\r
-  FN(StoreAndFindMatches)(self, data, ix, mask, MAX_TREE_COMP_LENGTH,\r
-      max_backward, NULL, NULL);\r
-}\r
-\r
-static BROTLI_INLINE void FN(StoreRange)(HashToBinaryTree* self,\r
-    const uint8_t *data, const size_t mask, const size_t ix_start,\r
-    const size_t ix_end) {\r
-  size_t i = ix_start + 63 <= ix_end ? ix_end - 63 : ix_start;\r
-  for (; i < ix_end; ++i) {\r
-    FN(Store)(self, data, mask, i);\r
-  }\r
-}\r
-\r
-static BROTLI_INLINE void FN(StitchToPreviousBlock)(HashToBinaryTree* self,\r
-    size_t num_bytes, size_t position, const uint8_t* ringbuffer,\r
-    size_t ringbuffer_mask) {\r
-  if (num_bytes >= FN(HashTypeLength)() - 1 &&\r
-      position >= MAX_TREE_COMP_LENGTH) {\r
-    /* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher.\r
-       These could not be calculated before, since they require knowledge\r
-       of both the previous and the current block. */\r
-    const size_t i_start = position - MAX_TREE_COMP_LENGTH + 1;\r
-    const size_t i_end = BROTLI_MIN(size_t, position, i_start + num_bytes);\r
-    size_t i;\r
-    for (i = i_start; i < i_end; ++i) {\r
-      /* Maximum distance is window size - 16, see section 9.1. of the spec.\r
-         Furthermore, we have to make sure that we don't look further back\r
-         from the start of the next block than the window size, otherwise we\r
-         could access already overwritten areas of the ringbuffer. */\r
-      const size_t max_backward =\r
-          self->window_mask_ - BROTLI_MAX(size_t, 15, position - i);\r
-      /* We know that i + MAX_TREE_COMP_LENGTH <= position + num_bytes, i.e. the\r
-         end of the current block and that we have at least\r
-         MAX_TREE_COMP_LENGTH tail in the ringbuffer. */\r
-      FN(StoreAndFindMatches)(self, ringbuffer, i, ringbuffer_mask,\r
-          MAX_TREE_COMP_LENGTH, max_backward, NULL, NULL);\r
-    }\r
-  }\r
-}\r
-\r
-#undef BUCKET_SIZE\r
+#define MAX_TREE_SEARCH_DEPTH 64\r
+#define MAX_TREE_COMP_LENGTH 128\r
+#include "./hash_to_binary_tree_inc.h"  /* NOLINT(build/include) */\r
+#undef MAX_TREE_SEARCH_DEPTH\r
+#undef MAX_TREE_COMP_LENGTH\r
 #undef BUCKET_BITS\r
-\r
 #undef HASHER\r
+/* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */\r
+#define MAX_NUM_MATCHES_H10 128\r
 \r
 /* For BUCKET_SWEEP == 1, enabling the dictionary lookup makes compression\r
    a little faster (0.5% - 1%) and it compresses 0.15% better on small text\r
-   and html inputs. */\r
+   and HTML inputs. */\r
 \r
 #define HASHER() H2\r
 #define BUCKET_BITS 16\r
 #define BUCKET_SWEEP 1\r
+#define HASH_LEN 5\r
 #define USE_DICTIONARY 1\r
 #include "./hash_longest_match_quickly_inc.h"  /* NOLINT(build/include) */\r
 #undef BUCKET_SWEEP\r
@@ -556,48 +288,17 @@ static BROTLI_INLINE void FN(StitchToPreviousBlock)(HashToBinaryTree* self,
 #define USE_DICTIONARY 1\r
 #include "./hash_longest_match_quickly_inc.h"  /* NOLINT(build/include) */\r
 #undef USE_DICTIONARY\r
+#undef HASH_LEN\r
 #undef BUCKET_SWEEP\r
 #undef BUCKET_BITS\r
 #undef HASHER\r
 \r
 #define HASHER() H5\r
-#define BUCKET_BITS 14\r
-#define BLOCK_BITS 4\r
-#define NUM_LAST_DISTANCES_TO_CHECK 4\r
 #include "./hash_longest_match_inc.h"  /* NOLINT(build/include) */\r
-#undef BLOCK_BITS\r
 #undef HASHER\r
 \r
 #define HASHER() H6\r
-#define BLOCK_BITS 5\r
-#include "./hash_longest_match_inc.h"  /* NOLINT(build/include) */\r
-#undef NUM_LAST_DISTANCES_TO_CHECK\r
-#undef BLOCK_BITS\r
-#undef BUCKET_BITS\r
-#undef HASHER\r
-\r
-#define HASHER() H7\r
-#define BUCKET_BITS 15\r
-#define BLOCK_BITS 6\r
-#define NUM_LAST_DISTANCES_TO_CHECK 10\r
-#include "./hash_longest_match_inc.h"  /* NOLINT(build/include) */\r
-#undef BLOCK_BITS\r
-#undef HASHER\r
-\r
-#define HASHER() H8\r
-#define BLOCK_BITS 7\r
-#include "./hash_longest_match_inc.h"  /* NOLINT(build/include) */\r
-#undef NUM_LAST_DISTANCES_TO_CHECK\r
-#undef BLOCK_BITS\r
-#undef HASHER\r
-\r
-#define HASHER() H9\r
-#define BLOCK_BITS 8\r
-#define NUM_LAST_DISTANCES_TO_CHECK 16\r
-#include "./hash_longest_match_inc.h"  /* NOLINT(build/include) */\r
-#undef NUM_LAST_DISTANCES_TO_CHECK\r
-#undef BLOCK_BITS\r
-#undef BUCKET_BITS\r
+#include "./hash_longest_match64_inc.h"  /* NOLINT(build/include) */\r
 #undef HASHER\r
 \r
 #define BUCKET_BITS 15\r
@@ -630,86 +331,165 @@ static BROTLI_INLINE void FN(StitchToPreviousBlock)(HashToBinaryTree* self,
 \r
 #undef BUCKET_BITS\r
 \r
+#define HASHER() H54\r
+#define BUCKET_BITS 20\r
+#define BUCKET_SWEEP 4\r
+#define HASH_LEN 7\r
+#define USE_DICTIONARY 0\r
+#include "./hash_longest_match_quickly_inc.h"  /* NOLINT(build/include) */\r
+#undef USE_DICTIONARY\r
+#undef HASH_LEN\r
+#undef BUCKET_SWEEP\r
+#undef BUCKET_BITS\r
+#undef HASHER\r
+\r
+/* fast large window hashers */\r
+\r
+#define HASHER() HROLLING_FAST\r
+#define CHUNKLEN 32\r
+#define JUMP 4\r
+#define NUMBUCKETS 16777216\r
+#define MASK ((NUMBUCKETS * 64) - 1)\r
+#include "./hash_rolling_inc.h"  /* NOLINT(build/include) */\r
+#undef JUMP\r
+#undef HASHER\r
+\r
+\r
+#define HASHER() HROLLING\r
+#define JUMP 1\r
+#include "./hash_rolling_inc.h"  /* NOLINT(build/include) */\r
+#undef MASK\r
+#undef NUMBUCKETS\r
+#undef JUMP\r
+#undef CHUNKLEN\r
+#undef HASHER\r
+\r
+#define HASHER() H35\r
+#define HASHER_A H3\r
+#define HASHER_B HROLLING_FAST\r
+#include "./hash_composite_inc.h"  /* NOLINT(build/include) */\r
+#undef HASHER_A\r
+#undef HASHER_B\r
+#undef HASHER\r
+\r
+#define HASHER() H55\r
+#define HASHER_A H54\r
+#define HASHER_B HROLLING_FAST\r
+#include "./hash_composite_inc.h"  /* NOLINT(build/include) */\r
+#undef HASHER_A\r
+#undef HASHER_B\r
+#undef HASHER\r
+\r
+#define HASHER() H65\r
+#define HASHER_A H6\r
+#define HASHER_B HROLLING\r
+#include "./hash_composite_inc.h"  /* NOLINT(build/include) */\r
+#undef HASHER_A\r
+#undef HASHER_B\r
+#undef HASHER\r
+\r
 #undef FN\r
 #undef CAT\r
 #undef EXPAND_CAT\r
 \r
-#define FOR_GENERIC_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(7) H(8) H(9) \\r
-                               H(40) H(41) H(42)\r
+#define FOR_GENERIC_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)\\r
+                               H(35) H(55) H(65)\r
 #define FOR_ALL_HASHERS(H) FOR_GENERIC_HASHERS(H) H(10)\r
 \r
-typedef struct Hashers {\r
-#define _MEMBER(N) H ## N* h ## N;\r
-  FOR_ALL_HASHERS(_MEMBER)\r
-#undef _MEMBER\r
-} Hashers;\r
-\r
-static BROTLI_INLINE void InitHashers(Hashers* self) {\r
-#define _INIT(N) self->h ## N = 0;\r
-  FOR_ALL_HASHERS(_INIT)\r
-#undef _INIT\r
+static BROTLI_INLINE void DestroyHasher(\r
+    MemoryManager* m, HasherHandle* handle) {\r
+  if (*handle == NULL) return;\r
+  BROTLI_FREE(m, *handle);\r
 }\r
 \r
-static BROTLI_INLINE void DestroyHashers(MemoryManager* m, Hashers* self) {\r
-  if (self->h10) CleanupH10(m, self->h10);\r
-#define _CLEANUP(N) BROTLI_FREE(m, self->h ## N)\r
-  FOR_ALL_HASHERS(_CLEANUP)\r
-#undef _CLEANUP\r
+static BROTLI_INLINE void HasherReset(HasherHandle handle) {\r
+  if (handle == NULL) return;\r
+  GetHasherCommon(handle)->is_prepared_ = BROTLI_FALSE;\r
 }\r
 \r
-static BROTLI_INLINE void HashersReset(Hashers* self, int type) {\r
-  switch (type) {\r
-#define _RESET(N) case N: ResetH ## N(self->h ## N); break;\r
-    FOR_ALL_HASHERS(_RESET)\r
-#undef _RESET\r
-    default: break;\r
+static BROTLI_INLINE size_t HasherSize(const BrotliEncoderParams* params,\r
+    BROTLI_BOOL one_shot, const size_t input_size) {\r
+  size_t result = sizeof(HasherCommon);\r
+  switch (params->hasher.type) {\r
+#define SIZE_(N)                                                         \\r
+    case N:                                                              \\r
+      result += HashMemAllocInBytesH ## N(params, one_shot, input_size); \\r
+      break;\r
+    FOR_ALL_HASHERS(SIZE_)\r
+#undef SIZE_\r
+    default:\r
+      break;\r
   }\r
+  return result;\r
 }\r
 \r
-static BROTLI_INLINE void HashersSetup(\r
-    MemoryManager* m, Hashers* self, int type) {\r
-  switch (type) {\r
-#define _SETUP(N) case N: self->h ## N = BROTLI_ALLOC(m, H ## N, 1); break;\r
-    FOR_ALL_HASHERS(_SETUP)\r
-#undef _SETUP\r
-    default: break;\r
+static BROTLI_INLINE void HasherSetup(MemoryManager* m, HasherHandle* handle,\r
+    BrotliEncoderParams* params, const uint8_t* data, size_t position,\r
+    size_t input_size, BROTLI_BOOL is_last) {\r
+  HasherHandle self = NULL;\r
+  HasherCommon* common = NULL;\r
+  BROTLI_BOOL one_shot = (position == 0 && is_last);\r
+  if (*handle == NULL) {\r
+    size_t alloc_size;\r
+    ChooseHasher(params, &params->hasher);\r
+    alloc_size = HasherSize(params, one_shot, input_size);\r
+    self = BROTLI_ALLOC(m, uint8_t, alloc_size);\r
+    if (BROTLI_IS_OOM(m)) return;\r
+    *handle = self;\r
+    common = GetHasherCommon(self);\r
+    common->params = params->hasher;\r
+    switch (common->params.type) {\r
+#define INITIALIZE_(N)                     \\r
+      case N:                              \\r
+        InitializeH ## N(*handle, params); \\r
+        break;\r
+      FOR_ALL_HASHERS(INITIALIZE_);\r
+#undef INITIALIZE_\r
+      default:\r
+        break;\r
+    }\r
+    HasherReset(*handle);\r
   }\r
-  if (BROTLI_IS_OOM(m)) return;\r
-  if (type == 10) InitializeH10(self->h10);\r
-  HashersReset(self, type);\r
-}\r
 \r
-#define _WARMUP_HASH(N)                                                        \\r
-static BROTLI_INLINE void WarmupHashH ## N(MemoryManager* m,                   \\r
-    const BrotliEncoderParams* params, const size_t size, const uint8_t* dict, \\r
-    H ## N* hasher) {                                                          \\r
-  size_t overlap = (StoreLookaheadH ## N()) - 1;                               \\r
-  size_t i;                                                                    \\r
-  InitH ## N(m, hasher, dict, params, 0, size, BROTLI_FALSE);                  \\r
-  if (BROTLI_IS_OOM(m)) return;                                                \\r
-  for (i = 0; i + overlap < size; i++) {                                       \\r
-    StoreH ## N(hasher, dict, ~(size_t)0, i);                                  \\r
-  }                                                                            \\r
+  self = *handle;\r
+  common = GetHasherCommon(self);\r
+  if (!common->is_prepared_) {\r
+    switch (common->params.type) {\r
+#define PREPARE_(N)                                      \\r
+      case N:                                            \\r
+        PrepareH ## N(self, one_shot, input_size, data); \\r
+        break;\r
+      FOR_ALL_HASHERS(PREPARE_)\r
+#undef PREPARE_\r
+      default: break;\r
+    }\r
+    if (position == 0) {\r
+        common->dict_num_lookups = 0;\r
+        common->dict_num_matches = 0;\r
+    }\r
+    common->is_prepared_ = BROTLI_TRUE;\r
+  }\r
 }\r
-FOR_ALL_HASHERS(_WARMUP_HASH)\r
-#undef _WARMUP_HASH\r
-\r
-/* Custom LZ77 window. */\r
-static BROTLI_INLINE void HashersPrependCustomDictionary(\r
-    MemoryManager* m, Hashers* self, const BrotliEncoderParams* params,\r
-    const size_t size, const uint8_t* dict) {\r
-  int hasher_type = ChooseHasher(params);\r
-  switch (hasher_type) {\r
-#define _PREPEND(N) \\r
-    case N: WarmupHashH ## N(m, params, size, dict, self->h ## N); break;\r
-    FOR_ALL_HASHERS(_PREPEND)\r
-#undef _PREPEND\r
+\r
+static BROTLI_INLINE void InitOrStitchToPreviousBlock(\r
+    MemoryManager* m, HasherHandle* handle, const uint8_t* data, size_t mask,\r
+    BrotliEncoderParams* params, size_t position, size_t input_size,\r
+    BROTLI_BOOL is_last) {\r
+  HasherHandle self;\r
+  HasherSetup(m, handle, params, data, position, input_size, is_last);\r
+  if (BROTLI_IS_OOM(m)) return;\r
+  self = *handle;\r
+  switch (GetHasherCommon(self)->params.type) {\r
+#define INIT_(N)                                                           \\r
+    case N:                                                                \\r
+      StitchToPreviousBlockH ## N(self, input_size, position, data, mask); \\r
+    break;\r
+    FOR_ALL_HASHERS(INIT_)\r
+#undef INIT_\r
     default: break;\r
   }\r
-  if (BROTLI_IS_OOM(m)) return;\r
 }\r
 \r
-\r
 #if defined(__cplusplus) || defined(c_plusplus)\r
 }  /* extern "C" */\r
 #endif\r