1/* NOLINT(build/header_guard) */
2/* Copyright 2018 Google Inc. All Rights Reserved.
3
4 Distributed under MIT license.
5 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
6*/
7
8/* template parameters: FN, HASHER_A, HASHER_B */
9
10/* Composite hasher: This hasher allows to combine two other hashers, HASHER_A
11 and HASHER_B. */
12
13#define HashComposite HASHER()
14
15#define FN_A(X) EXPAND_CAT(X, HASHER_A)
16#define FN_B(X) EXPAND_CAT(X, HASHER_B)
17
18static BROTLI_INLINE size_t FN(HashTypeLength)(void) {
19 size_t a = FN_A(HashTypeLength)();
20 size_t b = FN_B(HashTypeLength)();
21 return a > b ? a : b;
22}
23
24static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
25 size_t a = FN_A(StoreLookahead)();
26 size_t b = FN_B(StoreLookahead)();
27 return a > b ? a : b;
28}
29
30typedef struct HashComposite {
31 HasherHandle ha;
32 HasherHandle hb;
33 const BrotliEncoderParams* params;
34} HashComposite;
35
36static BROTLI_INLINE HashComposite* FN(Self)(HasherHandle handle) {
37 return (HashComposite*)&(GetHasherCommon(handle)[1]);
38}
39
40static void FN(Initialize)(
41 HasherHandle handle, const BrotliEncoderParams* params) {
42 HashComposite* self = FN(Self)(handle);
43 self->ha = 0;
44 self->hb = 0;
45 self->params = params;
46 /* TODO: Initialize of the hashers is defered to Prepare (and params
47 remembered here) because we don't get the one_shot and input_size params
48 here that are needed to know the memory size of them. Instead provide
49 those params to all hashers FN(Initialize) */
50}
51
52static void FN(Prepare)(HasherHandle handle, BROTLI_BOOL one_shot,
53 size_t input_size, const uint8_t* data) {
54 HashComposite* self = FN(Self)(handle);
55 if (!self->ha) {
56 HasherCommon* common_a;
57 HasherCommon* common_b;
58
59 self->ha = handle + sizeof(HasherCommon) + sizeof(HashComposite);
60 common_a = (HasherCommon*)self->ha;
61 common_a->params = self->params->hasher;
62 common_a->is_prepared_ = BROTLI_FALSE;
63 common_a->dict_num_lookups = 0;
64 common_a->dict_num_matches = 0;
65 FN_A(Initialize)(self->ha, self->params);
66
67 self->hb = self->ha + sizeof(HasherCommon) + FN_A(HashMemAllocInBytes)(
68 self->params, one_shot, input_size);
69 common_b = (HasherCommon*)self->hb;
70 common_b->params = self->params->hasher;
71 common_b->is_prepared_ = BROTLI_FALSE;
72 common_b->dict_num_lookups = 0;
73 common_b->dict_num_matches = 0;
74 FN_B(Initialize)(self->hb, self->params);
75 }
76 FN_A(Prepare)(self->ha, one_shot, input_size, data);
77 FN_B(Prepare)(self->hb, one_shot, input_size, data);
78}
79
80static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
81 const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
82 size_t input_size) {
83 return sizeof(HashComposite) + 2 * sizeof(HasherCommon) +
84 FN_A(HashMemAllocInBytes)(params, one_shot, input_size) +
85 FN_B(HashMemAllocInBytes)(params, one_shot, input_size);
86}
87
88static BROTLI_INLINE void FN(Store)(HasherHandle BROTLI_RESTRICT handle,
89 const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
90 HashComposite* self = FN(Self)(handle);
91 FN_A(Store)(self->ha, data, mask, ix);
92 FN_B(Store)(self->hb, data, mask, ix);
93}
94
95static BROTLI_INLINE void FN(StoreRange)(HasherHandle handle,
96 const uint8_t* data, const size_t mask, const size_t ix_start,
97 const size_t ix_end) {
98 HashComposite* self = FN(Self)(handle);
99 FN_A(StoreRange)(self->ha, data, mask, ix_start, ix_end);
100 FN_B(StoreRange)(self->hb, data, mask, ix_start, ix_end);
101}
102
103static BROTLI_INLINE void FN(StitchToPreviousBlock)(HasherHandle handle,
104 size_t num_bytes, size_t position, const uint8_t* ringbuffer,
105 size_t ring_buffer_mask) {
106 HashComposite* self = FN(Self)(handle);
107 FN_A(StitchToPreviousBlock)(self->ha, num_bytes, position, ringbuffer,
108 ring_buffer_mask);
109 FN_B(StitchToPreviousBlock)(self->hb, num_bytes, position, ringbuffer,
110 ring_buffer_mask);
111}
112
113static BROTLI_INLINE void FN(PrepareDistanceCache)(
114 HasherHandle handle, int* BROTLI_RESTRICT distance_cache) {
115 HashComposite* self = FN(Self)(handle);
116 FN_A(PrepareDistanceCache)(self->ha, distance_cache);
117 FN_B(PrepareDistanceCache)(self->hb, distance_cache);
118}
119
120static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
121 const BrotliEncoderDictionary* dictionary,
122 const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
123 const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
124 const size_t max_length, const size_t max_backward,
125 const size_t gap, const size_t max_distance,
126 HasherSearchResult* BROTLI_RESTRICT out) {
127 HashComposite* self = FN(Self)(handle);
128 FN_A(FindLongestMatch)(self->ha, dictionary, data, ring_buffer_mask,
129 distance_cache, cur_ix, max_length, max_backward, gap,
130 max_distance, out);
131 FN_B(FindLongestMatch)(self->hb, dictionary, data, ring_buffer_mask,
132 distance_cache, cur_ix, max_length, max_backward, gap,
133 max_distance, out);
134}
135
136#undef HashComposite
137