Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/other-licenses/snappy/./../../../other-licenses/snappy/src/snappy-internal.h
Warning:line 377, column 5
Value stored to 's2' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_snappy0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/other-licenses/snappy -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/other-licenses/snappy -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D HAVE_ATTRIBUTE_ALWAYS_INLINE=1 -D HAVE_BUILTIN_CTZ=1 -D HAVE_BUILTIN_EXPECT=1 -D HAVE_BUILTIN_PREFETCH=1 -D HAVE_SYS_MMAN_H=1 -D HAVE_SYS_RESOURCE_H=1 -D HAVE_SYS_TIME_H=1 -D HAVE_SYS_UIO_H=1 -D HAVE_UNISTD_H=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/other-licenses/snappy -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/other-licenses/snappy -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -Wno-sign-compare -Wno-unused-function -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-10-17-231001-351276-1 -x c++ Unified_cpp_snappy0.cpp
1// Copyright 2008 Google Inc. All Rights Reserved.
2//
3// Redistribution and use in source and binary forms, with or without
4// modification, are permitted provided that the following conditions are
5// met:
6//
7// * Redistributions of source code must retain the above copyright
8// notice, this list of conditions and the following disclaimer.
9// * Redistributions in binary form must reproduce the above
10// copyright notice, this list of conditions and the following disclaimer
11// in the documentation and/or other materials provided with the
12// distribution.
13// * Neither the name of Google Inc. nor the names of its
14// contributors may be used to endorse or promote products derived from
15// this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28//
29// Internals shared between the Snappy implementation and its unittest.
30
31#ifndef THIRD_PARTY_SNAPPY_SNAPPY_INTERNAL_H_
32#define THIRD_PARTY_SNAPPY_SNAPPY_INTERNAL_H_
33
34#include <utility>
35
36#include "snappy-stubs-internal.h"
37
38#if SNAPPY_HAVE_SSSE3
39// Please do not replace with <x86intrin.h> or with headers that assume more
40// advanced SSE versions without checking with all the OWNERS.
41#include <emmintrin.h>
42#include <tmmintrin.h>
43#endif
44
45#if SNAPPY_HAVE_NEON
46#include <arm_neon.h>
47#endif
48
49#if SNAPPY_RVV_1 || SNAPPY_RVV_0_7
50#define SNAPPY_HAVE_RVV0 1
51#include <riscv_vector.h>
52#else
53#define SNAPPY_HAVE_RVV0 0
54#endif
55
56#if SNAPPY_RVV_1 || SNAPPY_RVV_0_7
57#define VSETVL_E8M2 __riscv_vsetvl_e8m2
58#define VLE8_V_U8M2 __riscv_vle8_v_u8m2
59#define VSE8_V_U8M2 __riscv_vse8_v_u8m2
60#endif
61
62#if SNAPPY_HAVE_SSSE3 || SNAPPY_HAVE_NEON
63#define SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE0 1
64#else
65#define SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE0 0
66#endif
67
68namespace snappy {
69namespace internal {
70
71#if SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE0
72#if SNAPPY_HAVE_SSSE3
73using V128 = __m128i;
74#elif SNAPPY_HAVE_NEON
75using V128 = uint8x16_t;
76#endif
77
78// Load 128 bits of integer data. `src` must be 16-byte aligned.
79inline V128 V128_Load(const V128* src);
80
81// Load 128 bits of integer data. `src` does not need to be aligned.
82inline V128 V128_LoadU(const V128* src);
83
84// Store 128 bits of integer data. `dst` does not need to be aligned.
85inline void V128_StoreU(V128* dst, V128 val);
86
87// Shuffle packed 8-bit integers using a shuffle mask.
88// Each packed integer in the shuffle mask must be in [0,16).
89inline V128 V128_Shuffle(V128 input, V128 shuffle_mask);
90
91// Constructs V128 with 16 chars |c|.
92inline V128 V128_DupChar(char c);
93
94#if SNAPPY_HAVE_SSSE3
95inline V128 V128_Load(const V128* src) { return _mm_load_si128(src); }
96
97inline V128 V128_LoadU(const V128* src) { return _mm_loadu_si128(src); }
98
99inline void V128_StoreU(V128* dst, V128 val) { _mm_storeu_si128(dst, val); }
100
101inline V128 V128_Shuffle(V128 input, V128 shuffle_mask) {
102 return _mm_shuffle_epi8(input, shuffle_mask);
103}
104
105inline V128 V128_DupChar(char c) { return _mm_set1_epi8(c); }
106
107#elif SNAPPY_HAVE_NEON
108inline V128 V128_Load(const V128* src) {
109 return vld1q_u8(reinterpret_cast<const uint8_t*>(src));
110}
111
112inline V128 V128_LoadU(const V128* src) {
113 return vld1q_u8(reinterpret_cast<const uint8_t*>(src));
114}
115
116inline void V128_StoreU(V128* dst, V128 val) {
117 vst1q_u8(reinterpret_cast<uint8_t*>(dst), val);
118}
119
120inline V128 V128_Shuffle(V128 input, V128 shuffle_mask) {
121 assert(vminvq_u8(shuffle_mask) >= 0 && vmaxvq_u8(shuffle_mask) <= 15)(static_cast <bool> (vminvq_u8(shuffle_mask) >= 0 &&
vmaxvq_u8(shuffle_mask) <= 15) ? void (0) : __assert_fail
("vminvq_u8(shuffle_mask) >= 0 && vmaxvq_u8(shuffle_mask) <= 15"
, __builtin_FILE (), __builtin_LINE (), __extension__ __PRETTY_FUNCTION__
))
;
122 return vqtbl1q_u8(input, shuffle_mask);
123}
124
125inline V128 V128_DupChar(char c) { return vdupq_n_u8(c); }
126
127
128#endif
129#endif // SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE
130
131// Working memory performs a single allocation to hold all scratch space
132// required for compression.
133class WorkingMemory {
134 public:
135 explicit WorkingMemory(size_t input_size);
136
137 // Non-allocating: lays out the scratch space in the caller-provided
138 // buffer, which must be at least RequiredSize(input_size) bytes, aligned
139 // at least as strictly as uint16_t, and must outlive "*this".
140 WorkingMemory(size_t input_size, char* buffer);
141 ~WorkingMemory();
142
143 // The buffer size required by the non-allocating constructor above.
144 static size_t RequiredSize(size_t input_size);
145
146 // Allocates and clears a hash table using memory in "*this",
147 // stores the number of buckets in "*table_size" and returns a pointer to
148 // the base of the hash table.
149 uint16_t* GetHashTable(size_t fragment_size, int* table_size) const;
150 char* GetScratchInput() const { return input_; }
151 char* GetScratchOutput() const { return output_; }
152
153 private:
154 char* mem_; // the allocated memory, never nullptr
155 size_t size_; // the size of the allocated memory, never 0
156 bool owns_mem_;
157 uint16_t* table_; // the pointer to the hashtable
158 char* input_; // the pointer to the input scratch buffer
159 char* output_; // the pointer to the output scratch buffer
160
161 // No copying
162 WorkingMemory(const WorkingMemory&);
163 void operator=(const WorkingMemory&);
164};
165
166// Flat array compression that does not emit the "uncompressed length"
167// prefix. Compresses "input" string to the "*op" buffer.
168//
169// REQUIRES: "input_length <= kBlockSize"
170// REQUIRES: "op" points to an array of memory that is at least
171// "MaxCompressedLength(input_length)" in size.
172// REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero.
173// REQUIRES: "table_size" is a power of two
174//
175// Returns an "end" pointer into "op" buffer.
176// "end - op" is the compressed size of "input".
177char* CompressFragment(const char* input,
178 size_t input_length,
179 char* op,
180 uint16_t* table,
181 const int table_size);
182
183// Find the largest n such that
184//
185// s1[0,n-1] == s2[0,n-1]
186// and n <= (s2_limit - s2).
187//
188// Return make_pair(n, n < 8).
189// Does not read *s2_limit or beyond.
190// Does not read *(s1 + (s2_limit - s2)) or beyond.
191// Requires that s2_limit >= s2.
192//
193// In addition populate *data with the next 5 bytes from the end of the match.
194// This is only done if 8 bytes are available (s2_limit - s2 >= 8). The point is
195// that on some arch's this can be done faster in this routine than subsequent
196// loading from s2 + n.
197//
198// Separate implementation for 64-bit, little-endian cpus.
199// riscv and little-endian cpu choose this routinue can be done faster too.
200#if !SNAPPY_IS_BIG_ENDIAN && \
201 (defined(__x86_64__1) || defined(_M_X64) || defined(ARCH_PPC) || \
202 defined(__aarch64__) || (defined(__riscv) && (__riscv_xlen == 64)))
203static inline std::pair<size_t, bool> FindMatchLength(const char* s1,
204 const char* s2,
205 const char* s2_limit,
206 uint64_t* data) {
207 assert(s2_limit >= s2)(static_cast <bool> (s2_limit >= s2) ? void (0) : __assert_fail
("s2_limit >= s2", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
208 size_t matched = 0;
209
210 // This block isn't necessary for correctness; we could just start looping
211 // immediately. As an optimization though, it is useful. It creates some not
212 // uncommon code paths that determine, without extra effort, whether the match
213 // length is less than 8. In short, we are hoping to avoid a conditional
214 // branch, and perhaps get better code layout from the C++ compiler.
215 if (SNAPPY_PREDICT_TRUE(s2 <= s2_limit - 16)(__builtin_expect(!!(s2 <= s2_limit - 16), 1))) {
216 uint64_t a1 = UNALIGNED_LOAD64(s1);
217 uint64_t a2 = UNALIGNED_LOAD64(s2);
218 if (SNAPPY_PREDICT_TRUE(a1 != a2)(__builtin_expect(!!(a1 != a2), 1))) {
219 // This code is critical for performance. The reason is that it determines
220 // how much to advance `ip` (s2). This obviously depends on both the loads
221 // from the `candidate` (s1) and `ip`. Furthermore the next `candidate`
222 // depends on the advanced `ip` calculated here through a load, hash and
223 // new candidate hash lookup (a lot of cycles). This makes s1 (ie.
224 // `candidate`) the variable that limits throughput. This is the reason we
225 // go through hoops to have this function update `data` for the next iter.
226 // The straightforward code would use *data, given by
227 //
228 // *data = UNALIGNED_LOAD64(s2 + matched_bytes) (Latency of 5 cycles),
229 //
230 // as input for the hash table lookup to find next candidate. However
231 // this forces the load on the data dependency chain of s1, because
232 // matched_bytes directly depends on s1. However matched_bytes is 0..7, so
233 // we can also calculate *data by
234 //
235 // *data = AlignRight(UNALIGNED_LOAD64(s2), UNALIGNED_LOAD64(s2 + 8),
236 // matched_bytes);
237 //
238 // The loads do not depend on s1 anymore and are thus off the bottleneck.
239 // The straightforward implementation on x86_64 would be to use
240 //
241 // shrd rax, rdx, cl (cl being matched_bytes * 8)
242 //
243 // unfortunately shrd with a variable shift has a 4 cycle latency. So this
244 // only wins 1 cycle. The BMI2 shrx instruction is a 1 cycle variable
245 // shift instruction but can only shift 64 bits. If we focus on just
246 // obtaining the least significant 4 bytes, we can obtain this by
247 //
248 // *data = ConditionalMove(matched_bytes < 4, UNALIGNED_LOAD64(s2),
249 // UNALIGNED_LOAD64(s2 + 4) >> ((matched_bytes & 3) * 8);
250 //
251 // Writen like above this is not a big win, the conditional move would be
252 // a cmp followed by a cmov (2 cycles) followed by a shift (1 cycle).
253 // However matched_bytes < 4 is equal to
254 // static_cast<uint32_t>(xorval) != 0. Writen that way, the conditional
255 // move (2 cycles) can execute in parallel with FindLSBSetNonZero64
256 // (tzcnt), which takes 3 cycles.
257 uint64_t xorval = a1 ^ a2;
258 int shift = Bits::FindLSBSetNonZero64(xorval);
259 size_t matched_bytes = shift >> 3;
260 uint64_t a3 = UNALIGNED_LOAD64(s2 + 4);
261#ifndef __x86_64__1
262 a2 = static_cast<uint32_t>(xorval) == 0 ? a3 : a2;
263#else
264 // Ideally this would just be
265 //
266 // a2 = static_cast<uint32_t>(xorval) == 0 ? a3 : a2;
267 //
268 // However clang correctly infers that the above statement participates on
269 // a critical data dependency chain and thus, unfortunately, refuses to
270 // use a conditional move (it's tuned to cut data dependencies). In this
271 // case there is a longer parallel chain anyway AND this will be fairly
272 // unpredictable.
273 asm("testl %k2, %k2\n\t"
274 "cmovzq %1, %0\n\t"
275 : "+r"(a2)
276 : "r"(a3), "r"(xorval)
277 : "cc");
278#endif
279 *data = a2 >> (shift & (3 * 8));
280 return std::pair<size_t, bool>(matched_bytes, true);
281 } else {
282 matched = 8;
283 s2 += 8;
284 }
285 }
286 SNAPPY_PREFETCH(s1 + 64)__builtin_prefetch(s1 + 64, 0, 3);
287 SNAPPY_PREFETCH(s2 + 64)__builtin_prefetch(s2 + 64, 0, 3);
288
289 // Find out how long the match is. We loop over the data 64 bits at a
290 // time until we find a 64-bit block that doesn't match; then we find
291 // the first non-matching bit and use that to calculate the total
292 // length of the match.
293 while (SNAPPY_PREDICT_TRUE(s2 <= s2_limit - 16)(__builtin_expect(!!(s2 <= s2_limit - 16), 1))) {
294 uint64_t a1 = UNALIGNED_LOAD64(s1 + matched);
295 uint64_t a2 = UNALIGNED_LOAD64(s2);
296 if (a1 == a2) {
297 s2 += 8;
298 matched += 8;
299 } else {
300 uint64_t xorval = a1 ^ a2;
301 int shift = Bits::FindLSBSetNonZero64(xorval);
302 size_t matched_bytes = shift >> 3;
303 uint64_t a3 = UNALIGNED_LOAD64(s2 + 4);
304#ifndef __x86_64__1
305 a2 = static_cast<uint32_t>(xorval) == 0 ? a3 : a2;
306#else
307 asm("testl %k2, %k2\n\t"
308 "cmovzq %1, %0\n\t"
309 : "+r"(a2)
310 : "r"(a3), "r"(xorval)
311 : "cc");
312#endif
313 *data = a2 >> (shift & (3 * 8));
314 matched += matched_bytes;
315 assert(matched >= 8)(static_cast <bool> (matched >= 8) ? void (0) : __assert_fail
("matched >= 8", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
316 return std::pair<size_t, bool>(matched, false);
317 }
318 }
319 while (SNAPPY_PREDICT_TRUE(s2 < s2_limit)(__builtin_expect(!!(s2 < s2_limit), 1))) {
320 if (s1[matched] == *s2) {
321 ++s2;
322 ++matched;
323 } else {
324 if (s2 <= s2_limit - 8) {
325 *data = UNALIGNED_LOAD64(s2);
326 }
327 return std::pair<size_t, bool>(matched, matched < 8);
328 }
329 }
330 return std::pair<size_t, bool>(matched, matched < 8);
331}
332#else
333static inline std::pair<size_t, bool> FindMatchLength(const char* s1,
334 const char* s2,
335 const char* s2_limit,
336 uint64_t* data) {
337 // Implementation based on the x86-64 version, above.
338 assert(s2_limit >= s2)(static_cast <bool> (s2_limit >= s2) ? void (0) : __assert_fail
("s2_limit >= s2", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
339 int matched = 0;
340
341 while (s2 <= s2_limit - 4 &&
342 UNALIGNED_LOAD32(s2) == UNALIGNED_LOAD32(s1 + matched)) {
343 s2 += 4;
344 matched += 4;
345 }
346 if (LittleEndian::IsLittleEndian() && s2 <= s2_limit - 4) {
347 uint32_t x = UNALIGNED_LOAD32(s2) ^ UNALIGNED_LOAD32(s1 + matched);
348 int matching_bits = Bits::FindLSBSetNonZero(x);
349 matched += matching_bits >> 3;
350 s2 += matching_bits >> 3;
351 } else {
352 while ((s2 < s2_limit) && (s1[matched] == *s2)) {
353 ++s2;
354 ++matched;
355 }
356 }
357 if (s2 <= s2_limit - 8) *data = LittleEndian::Load64(s2);
358 return std::pair<size_t, bool>(matched, matched < 8);
359}
360#endif
361
362static inline size_t FindMatchLengthPlain(const char* s1, const char* s2,
363 const char* s2_limit) {
364 // Implementation based on the x86-64 version, above.
365 assert(s2_limit >= s2)(static_cast <bool> (s2_limit >= s2) ? void (0) : __assert_fail
("s2_limit >= s2", __builtin_FILE (), __builtin_LINE (), __extension__
__PRETTY_FUNCTION__))
;
366 int matched = 0;
367
368 while (s2 <= s2_limit - 8 &&
369 UNALIGNED_LOAD64(s2) == UNALIGNED_LOAD64(s1 + matched)) {
370 s2 += 8;
371 matched += 8;
372 }
373 if (LittleEndian::IsLittleEndian() && s2 <= s2_limit - 8) {
374 uint64_t x = UNALIGNED_LOAD64(s2) ^ UNALIGNED_LOAD64(s1 + matched);
375 int matching_bits = Bits::FindLSBSetNonZero64(x);
376 matched += matching_bits >> 3;
377 s2 += matching_bits >> 3;
Value stored to 's2' is never read
378 } else {
379 while ((s2 < s2_limit) && (s1[matched] == *s2)) {
380 ++s2;
381 ++matched;
382 }
383 }
384 return matched;
385}
386
387// Lookup tables for decompression code. Give --snappy_dump_decompression_table
388// to the unit test to recompute char_table.
389
390enum {
391 LITERAL = 0,
392 COPY_1_BYTE_OFFSET = 1, // 3 bit length + 3 bits of offset in opcode
393 COPY_2_BYTE_OFFSET = 2,
394 COPY_4_BYTE_OFFSET = 3
395};
396static const int kMaximumTagLength = 5; // COPY_4_BYTE_OFFSET plus the actual offset.
397
398// Data stored per entry in lookup table:
399// Range Bits-used Description
400// ------------------------------------
401// 1..64 0..7 Literal/copy length encoded in opcode byte
402// 0..7 8..10 Copy offset encoded in opcode byte / 256
403// 0..4 11..13 Extra bytes after opcode
404//
405// We use eight bits for the length even though 7 would have sufficed
406// because of efficiency reasons:
407// (1) Extracting a byte is faster than a bit-field
408// (2) It properly aligns copy offset so we do not need a <<8
409static constexpr uint16_t char_table[256] = {
410 // clang-format off
411 0x0001, 0x0804, 0x1001, 0x2001, 0x0002, 0x0805, 0x1002, 0x2002,
412 0x0003, 0x0806, 0x1003, 0x2003, 0x0004, 0x0807, 0x1004, 0x2004,
413 0x0005, 0x0808, 0x1005, 0x2005, 0x0006, 0x0809, 0x1006, 0x2006,
414 0x0007, 0x080a, 0x1007, 0x2007, 0x0008, 0x080b, 0x1008, 0x2008,
415 0x0009, 0x0904, 0x1009, 0x2009, 0x000a, 0x0905, 0x100a, 0x200a,
416 0x000b, 0x0906, 0x100b, 0x200b, 0x000c, 0x0907, 0x100c, 0x200c,
417 0x000d, 0x0908, 0x100d, 0x200d, 0x000e, 0x0909, 0x100e, 0x200e,
418 0x000f, 0x090a, 0x100f, 0x200f, 0x0010, 0x090b, 0x1010, 0x2010,
419 0x0011, 0x0a04, 0x1011, 0x2011, 0x0012, 0x0a05, 0x1012, 0x2012,
420 0x0013, 0x0a06, 0x1013, 0x2013, 0x0014, 0x0a07, 0x1014, 0x2014,
421 0x0015, 0x0a08, 0x1015, 0x2015, 0x0016, 0x0a09, 0x1016, 0x2016,
422 0x0017, 0x0a0a, 0x1017, 0x2017, 0x0018, 0x0a0b, 0x1018, 0x2018,
423 0x0019, 0x0b04, 0x1019, 0x2019, 0x001a, 0x0b05, 0x101a, 0x201a,
424 0x001b, 0x0b06, 0x101b, 0x201b, 0x001c, 0x0b07, 0x101c, 0x201c,
425 0x001d, 0x0b08, 0x101d, 0x201d, 0x001e, 0x0b09, 0x101e, 0x201e,
426 0x001f, 0x0b0a, 0x101f, 0x201f, 0x0020, 0x0b0b, 0x1020, 0x2020,
427 0x0021, 0x0c04, 0x1021, 0x2021, 0x0022, 0x0c05, 0x1022, 0x2022,
428 0x0023, 0x0c06, 0x1023, 0x2023, 0x0024, 0x0c07, 0x1024, 0x2024,
429 0x0025, 0x0c08, 0x1025, 0x2025, 0x0026, 0x0c09, 0x1026, 0x2026,
430 0x0027, 0x0c0a, 0x1027, 0x2027, 0x0028, 0x0c0b, 0x1028, 0x2028,
431 0x0029, 0x0d04, 0x1029, 0x2029, 0x002a, 0x0d05, 0x102a, 0x202a,
432 0x002b, 0x0d06, 0x102b, 0x202b, 0x002c, 0x0d07, 0x102c, 0x202c,
433 0x002d, 0x0d08, 0x102d, 0x202d, 0x002e, 0x0d09, 0x102e, 0x202e,
434 0x002f, 0x0d0a, 0x102f, 0x202f, 0x0030, 0x0d0b, 0x1030, 0x2030,
435 0x0031, 0x0e04, 0x1031, 0x2031, 0x0032, 0x0e05, 0x1032, 0x2032,
436 0x0033, 0x0e06, 0x1033, 0x2033, 0x0034, 0x0e07, 0x1034, 0x2034,
437 0x0035, 0x0e08, 0x1035, 0x2035, 0x0036, 0x0e09, 0x1036, 0x2036,
438 0x0037, 0x0e0a, 0x1037, 0x2037, 0x0038, 0x0e0b, 0x1038, 0x2038,
439 0x0039, 0x0f04, 0x1039, 0x2039, 0x003a, 0x0f05, 0x103a, 0x203a,
440 0x003b, 0x0f06, 0x103b, 0x203b, 0x003c, 0x0f07, 0x103c, 0x203c,
441 0x0801, 0x0f08, 0x103d, 0x203d, 0x1001, 0x0f09, 0x103e, 0x203e,
442 0x1801, 0x0f0a, 0x103f, 0x203f, 0x2001, 0x0f0b, 0x1040, 0x2040,
443 // clang-format on
444};
445
446} // end namespace internal
447} // end namespace snappy
448
449#endif // THIRD_PARTY_SNAPPY_SNAPPY_INTERNAL_H_