Extract Hash14/15 to hash_base

PiperOrigin-RevId: 790706104
diff --git a/c/enc/compress_fragment.c b/c/enc/compress_fragment.c
index 13890ea..7600fc5 100644
--- a/c/enc/compress_fragment.c
+++ b/c/enc/compress_fragment.c
@@ -23,6 +23,7 @@
 #include "entropy_encode.h"
 #include "fast_log.h"
 #include "find_match_length.h"
+#include "hash_base.h"
 #include "write_bits.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
@@ -31,14 +32,6 @@
 
 #define MAX_DISTANCE (long)BROTLI_MAX_BACKWARD_LIMIT(18)
 
-/* kHashMul32 multiplier has these properties:
-   * The multiplier must be odd. Otherwise we may lose the highest bit.
-   * No long streaks of ones or zeros.
-   * There is no effort to ensure that it is a prime, the oddity is enough
-     for this use.
-   * The number has been tuned heuristically against compression benchmarks. */
-static const uint32_t kHashMul32 = 0x1E35A7BD;
-
 static BROTLI_INLINE uint32_t Hash(const uint8_t* p, size_t shift) {
   const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(p) << 24) * kHashMul32;
   return (uint32_t)(h >> shift);
diff --git a/c/enc/compress_fragment_two_pass.c b/c/enc/compress_fragment_two_pass.c
index a762679..cca4a19 100644
--- a/c/enc/compress_fragment_two_pass.c
+++ b/c/enc/compress_fragment_two_pass.c
@@ -23,6 +23,7 @@
 #include "entropy_encode.h"
 #include "fast_log.h"
 #include "find_match_length.h"
+#include "hash_base.h"
 #include "write_bits.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
@@ -31,14 +32,6 @@
 
 #define MAX_DISTANCE (long)BROTLI_MAX_BACKWARD_LIMIT(18)
 
-/* kHashMul32 multiplier has these properties:
-   * The multiplier must be odd. Otherwise we may lose the highest bit.
-   * No long streaks of ones or zeros.
-   * There is no effort to ensure that it is a prime, the oddity is enough
-     for this use.
-   * The number has been tuned heuristically against compression benchmarks. */
-static const uint32_t kHashMul32 = 0x1E35A7BD;
-
 static BROTLI_INLINE uint32_t Hash(const uint8_t* p,
     size_t shift, size_t length) {
   const uint64_t h =
diff --git a/c/enc/hash.h b/c/enc/hash.h
index f210246..6462263 100644
--- a/c/enc/hash.h
+++ b/c/enc/hash.h
@@ -22,6 +22,7 @@
 #include "encoder_dict.h"
 #include "fast_log.h"
 #include "find_match_length.h"
+#include "hash_base.h"
 #include "matching_tag_mask.h"
 #include "memory.h"
 #include "quality.h"
@@ -72,23 +73,6 @@
   int len_code_delta; /* == len_code - len */
 } HasherSearchResult;
 
-/* kHashMul32 multiplier has these properties:
-   * The multiplier must be odd. Otherwise we may lose the highest bit.
-   * No long streaks of ones or zeros.
-   * There is no effort to ensure that it is a prime, the oddity is enough
-     for this use.
-   * The number has been tuned heuristically against compression benchmarks. */
-static const uint32_t kHashMul32 = 0x1E35A7BD;
-static const uint64_t kHashMul64 =
-    BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);
-
-static BROTLI_INLINE uint32_t Hash14(const uint8_t* data) {
-  uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
-  /* The higher bits contain more mixture from the multiplication,
-     so we take our results from there. */
-  return h >> (32 - 14);
-}
-
 static BROTLI_INLINE void PrepareDistanceCache(
     int* BROTLI_RESTRICT distance_cache, const int num_distances) {
   if (num_distances > 4) {
diff --git a/c/enc/hash_base.h b/c/enc/hash_base.h
new file mode 100644
index 0000000..f10201d
--- /dev/null
+++ b/c/enc/hash_base.h
@@ -0,0 +1,40 @@
+/* Copyright 2025 Google Inc. All Rights Reserved.
+
+   Distributed under MIT license.
+   See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
+*/
+
+/* Basic common hash functions / constants. */
+
+#ifndef THIRD_PARTY_BROTLI_ENC_HASH_BASE_H_
+#define THIRD_PARTY_BROTLI_ENC_HASH_BASE_H_
+
+#include <brotli/types.h>
+
+#include "../common/platform.h"
+
+/* kHashMul32 multiplier has these properties:
+   * The multiplier must be odd. Otherwise we may lose the highest bit.
+   * No long streaks of ones or zeros.
+   * There is no effort to ensure that it is a prime, the oddity is enough
+     for this use.
+   * The number has been tuned heuristically against compression benchmarks. */
+static const uint32_t kHashMul32 = 0x1E35A7BD;
+static const uint64_t kHashMul64 =
+    BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);
+
+static BROTLI_INLINE uint32_t Hash14(const uint8_t* data) {
+  uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
+  /* The higher bits contain more mixture from the multiplication,
+     so we take our results from there. */
+  return h >> (32 - 14);
+}
+
+static BROTLI_INLINE uint32_t Hash15(const uint8_t* data) {
+  uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
+  /* The higher bits contain more mixture from the multiplication,
+     so we take our results from there. */
+  return h >> (32 - 15);
+}
+
+#endif  // THIRD_PARTY_BROTLI_ENC_HASH_BASE_H_
diff --git a/c/enc/static_dict.c b/c/enc/static_dict.c
index 291d283..1504430 100644
--- a/c/enc/static_dict.c
+++ b/c/enc/static_dict.c
@@ -6,23 +6,19 @@
 
 #include "static_dict.h"
 
+#include <brotli/types.h>
+
 #include "../common/dictionary.h"
 #include "../common/platform.h"
 #include "../common/transform.h"
 #include "encoder_dict.h"
 #include "find_match_length.h"
+#include "hash_base.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
 
-static BROTLI_INLINE uint32_t Hash(const uint8_t* data) {
-  uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kDictHashMul32;
-  /* The higher bits contain more mixture from the multiplication,
-     so we take our results from there. */
-  return h >> (32 - kDictNumBits);
-}
-
 static BROTLI_INLINE void AddMatch(size_t distance, size_t len, size_t len_code,
                                    uint32_t* matches) {
   uint32_t match = (uint32_t)((distance << 5) + len_code);
@@ -96,7 +92,7 @@
   }
 #endif  /* BROTLI_EXPERIMENTAL */
   {
-    size_t offset = dictionary->buckets[Hash(data)];
+    size_t offset = dictionary->buckets[Hash15(data)];
     BROTLI_BOOL end = !offset;
     while (!end) {
       DictWord w = dictionary->dict_words[offset++];
@@ -341,7 +337,7 @@
   /* Transforms with prefixes " " and "." */
   if (max_length >= 5 && (data[0] == ' ' || data[0] == '.')) {
     BROTLI_BOOL is_space = TO_BROTLI_BOOL(data[0] == ' ');
-    size_t offset = dictionary->buckets[Hash(&data[1])];
+    size_t offset = dictionary->buckets[Hash15(&data[1])];
     BROTLI_BOOL end = !offset;
     while (!end) {
       DictWord w = dictionary->dict_words[offset++];
@@ -436,7 +432,7 @@
     if ((data[1] == ' ' &&
          (data[0] == 'e' || data[0] == 's' || data[0] == ',')) ||
         (data[0] == 0xC2 && data[1] == 0xA0)) {
-      size_t offset = dictionary->buckets[Hash(&data[2])];
+      size_t offset = dictionary->buckets[Hash15(&data[2])];
       BROTLI_BOOL end = !offset;
       while (!end) {
         DictWord w = dictionary->dict_words[offset++];
@@ -465,7 +461,7 @@
          data[3] == 'e' && data[4] == ' ') ||
         (data[0] == '.' && data[1] == 'c' && data[2] == 'o' &&
          data[3] == 'm' && data[4] == '/')) {
-      size_t offset = dictionary->buckets[Hash(&data[5])];
+      size_t offset = dictionary->buckets[Hash15(&data[5])];
       BROTLI_BOOL end = !offset;
       while (!end) {
         DictWord w = dictionary->dict_words[offset++];
diff --git a/c/enc/static_dict_lut.h b/c/enc/static_dict_lut.h
index a465ffd..0e4243c 100644
--- a/c/enc/static_dict_lut.h
+++ b/c/enc/static_dict_lut.h
@@ -23,9 +23,6 @@
 } DictWord;
 
 /* GENERATED CODE START */
-static const int kDictNumBits = 15;
-static const uint32_t kDictHashMul32 = 0x1E35A7BD;
-
 static const uint16_t kStaticDictionaryBuckets[32768] = {
 1,0,0,0,0,0,0,0,0,3,6,0,0,0,0,0,20,0,0,0,21,0,22,0,0,0,0,0,0,0,0,23,0,0,25,0,29,
 0,53,0,0,0,0,0,0,55,0,0,0,0,0,0,61,76,0,0,0,94,0,0,0,0,0,0,96,0,97,0,98,0,0,0,0,