Internal changes PiperOrigin-RevId: 621907514
diff --git a/.bazelrc b/.bazelrc index 673b332..3843446 100644 --- a/.bazelrc +++ b/.bazelrc
@@ -1,4 +1,2 @@ # googletest requires C++14 or above build --cxxopt='-std=c++17' -# Enable Bzlmod for every Bazel command -common --enable_bzlmod
diff --git a/.github/workflows/riscv64-qemu-test.yaml b/.github/workflows/riscv64-qemu-test.yaml deleted file mode 100644 index 3b97480..0000000 --- a/.github/workflows/riscv64-qemu-test.yaml +++ /dev/null
@@ -1,43 +0,0 @@ -name: riscv64-qemu-test - -on: [push, pull_request] - -jobs: - test: - runs-on: ubuntu-latest - env: - RISCV_CROSSCOMPILE: "ON" - riscv_gnu_toolchain_download_path: https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2025.07.03/riscv64-glibc-ubuntu-24.04-gcc-nightly-2025.07.03-nightly.tar.xz - RISCV_PATH: /opt/riscv - - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install dependencies - run: | - sudo apt update - sudo apt install -y --no-install-recommends \ - qemu-user qemu-user-static \ - build-essential \ - cmake \ - git - sudo mkdir -p $RISCV_PATH - wget ${riscv_gnu_toolchain_download_path} -O riscv-toolchain.tar.xz - sudo tar -xvf riscv-toolchain.tar.xz -C $RISCV_PATH --strip-components=1 - sudo sed -i "s|libdir='/mnt/riscv/riscv64-unknown-linux-gnu/lib'|libdir='$RISCV_PATH/riscv64-unknown-linux-gnu/lib'|g" $RISCV_PATH/riscv64-unknown-linux-gnu/lib/libatomic.la - - - name: Build and Run Unit Tests - run: | - export PATH=$RISCV_PATH/bin:$PATH - export LD_LIBRARY_PATH="/opt/riscv/lib:$LD_LIBRARY_PATH" - export QEMU_LD_PREFIX=$RISCV_PATH/sysroot - mkdir build && cd build - cmake -DCMAKE_BUILD_TYPE=Release ../ - make -j$(nproc) - make test - - - name: Run Benchmark - run: ./build/snappy_benchmark - working-directory: ./
diff --git a/.gitignore b/.gitignore index 0c8cf0e..826af25 100644 --- a/.gitignore +++ b/.gitignore
@@ -6,5 +6,4 @@ # Build directory. build/ /bazel-* -MODULE.bazel.lock out/
diff --git a/BUILD.bazel b/BUILD.bazel index 49db08e..97c9f3a 100644 --- a/BUILD.bazel +++ b/BUILD.bazel
@@ -26,21 +26,11 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -load("@bazel_skylib//rules:expand_template.bzl", "expand_template") -load("@bazel_skylib//rules:write_file.bzl", "write_file") -load("@rules_cc//cc:cc_library.bzl", "cc_library") -load("@rules_cc//cc:cc_test.bzl", "cc_test") - package(default_visibility = ["//visibility:public"]) licenses(["notice"]) -exports_files([ - "COPYING", - "COPYING.notestdata", -]) - -SNAPPY_VERSION = (1, 2, 2) +SNAPPY_VERSION = (1, 1, 10) config_setting( name = "windows", @@ -50,7 +40,7 @@ cc_library( name = "config", hdrs = ["config.h"], - defines = ["HAVE_CONFIG_H"], + defines = ["HAVE_CONFIG_H"] ) cc_library( @@ -62,10 +52,8 @@ name = "snappy-stubs-internal", srcs = ["snappy-stubs-internal.cc"], hdrs = ["snappy-stubs-internal.h"], - implementation_deps = [ - ":config", - ], deps = [ + ":config", ":snappy-stubs-public", ], ) @@ -82,15 +70,12 @@ "snappy-sinksource.h", ], copts = select({ - ":windows": [], - "//conditions:default": [ - "-Wno-sign-compare", - ], - }), - implementation_deps = [ - ":config", - ], + ":windows": [], + "//conditions:default": [ + "-Wno-sign-compare", + ]}), deps = [ + ":config", ":snappy-stubs-internal", ":snappy-stubs-public", ], @@ -129,7 +114,7 @@ deps = [ ":snappy", ":snappy-test", - "@com_google_benchmark//:benchmark_main", + "//third_party/benchmark:benchmark_main", ], ) @@ -142,15 +127,15 @@ deps = [ ":snappy", ":snappy-test", - "@com_google_googletest//:gtest_main", + "//third_party/googletest:gtest_main", ], ) # Generate a config.h similar to what cmake would produce. -write_file( +genrule( name = "config_h", - out = "config.h", - content = """\ + outs = ["config.h"], + cmd = """cat <<EOF >$@ #define HAVE_STDDEF_H 1 #define HAVE_STDINT_H 1 #ifdef __has_builtin @@ -207,17 +192,19 @@ # define SNAPPY_IS_BIG_ENDIAN 1 # endif #endif -""".splitlines(), +EOF +""", ) -expand_template( +genrule( name = "snappy_stubs_public_h", - out = "snappy-stubs-public.h", - substitutions = { - "${HAVE_SYS_UIO_H_01}": "!_WIN32", - "${PROJECT_VERSION_MAJOR}": str(SNAPPY_VERSION[0]), - "${PROJECT_VERSION_MINOR}": str(SNAPPY_VERSION[1]), - "${PROJECT_VERSION_PATCH}": str(SNAPPY_VERSION[2]), - }, - template = "snappy-stubs-public.h.in", + srcs = ["snappy-stubs-public.h.in"], + outs = ["snappy-stubs-public.h"], + # Assume sys/uio.h is available on non-Windows. + # Set the version numbers. + cmd = ("""sed -e 's/$${HAVE_SYS_UIO_H_01}/!_WIN32/g' \ + -e 's/$${PROJECT_VERSION_MAJOR}/%d/g' \ + -e 's/$${PROJECT_VERSION_MINOR}/%d/g' \ + -e 's/$${PROJECT_VERSION_PATCH}/%d/g' \ + $< >$@""" % SNAPPY_VERSION), )
diff --git a/CMakeLists.txt b/CMakeLists.txt index ac43da3..85afe58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -26,8 +26,8 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -cmake_minimum_required(VERSION 3.10) -project(Snappy VERSION 1.2.2 LANGUAGES C CXX) +cmake_minimum_required(VERSION 3.1) +project(Snappy VERSION 1.1.10 LANGUAGES C CXX) # C++ standard can be overridden when this is used as a sub-project. if(NOT CMAKE_CXX_STANDARD) @@ -38,7 +38,7 @@ endif(NOT CMAKE_CXX_STANDARD) # https://github.com/izenecloud/cmake/blob/master/SetCompilerWarningAll.cmake -if(MSVC) +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") # Use the highest warning level for Visual Studio. set(CMAKE_CXX_WARNING_LEVEL 4) if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") @@ -55,7 +55,7 @@ # Disable RTTI. string(REGEX REPLACE "/GR" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GR-") -else(MSVC) +else(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") # Use -Wall for clang and gcc. if(NOT CMAKE_CXX_FLAGS MATCHES "-Wall") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") @@ -85,7 +85,7 @@ # Disable RTTI. string(REGEX REPLACE "-frtti" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") -endif(MSVC) +endif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") # BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to make # it prominent in the GUI. @@ -155,20 +155,10 @@ return __builtin_expect(0, 1); }" HAVE_BUILTIN_EXPECT) -# Check if the built-in __builtin_ctz (count trailing zeros) is available. -# Require either a non-RISC-V target, or a RISC-V core that implements -# the Zbb bit-manipulation extension where ctz is guaranteed. check_cxx_source_compiles(" -#ifdef __riscv - #ifdef __riscv_zbb - int main() { return __builtin_ctzll(0); } - #else - #error \"ZBB not enabled in current config\" - #endif -#else - int main() { return __builtin_ctzll(0); } -#endif -" HAVE_BUILTIN_CTZ) +int main() { + return __builtin_ctzll(0); +}" HAVE_BUILTIN_CTZ) check_cxx_source_compiles(" int main() { @@ -216,41 +206,13 @@ check_cxx_source_compiles(" #include <arm_neon.h> -#include <stdint.h> int main() { uint8_t val = 3, dup[8]; - uint8x16_t v1 = vld1q_dup_u8(&val); - uint8x16_t v2 = vqtbl1q_u8(v1, v1); - vst1q_u8(dup, v1); - vst1q_u8(dup, v2); + uint8x16_t v = vld1q_dup_u8(&val); + vst1q_u8(dup, v); return 0; }" SNAPPY_HAVE_NEON) -#check RVV 1.0 need __riscv_ prefix -check_cxx_source_compiles(" - #include <riscv_vector.h> - #include <stdint.h> - #include <stddef.h> - int main() { - uint8_t val = 3, dup[8]; - size_t vl = __riscv_vsetvl_e8m1(8); - vuint8m1_t v = __riscv_vmv_v_x_u8m1(val, vl); - return 0; - }" SNAPPY_RVV_1) - - -#check RVV 0.7.1 not __riscv_ prefix -check_cxx_source_compiles(" - #include <riscv_vector.h> - #include <stdint.h> - #include <stddef.h> - int main() { - uint8_t val = 3, dup[8]; - size_t vl = vsetvl_e8m1(8); - vuint8m1_t v = vmv_v_x_u8m1(val, vl); - return 0; - }" SNAPPY_RVV_0_7) - include(CheckSymbolExists) check_symbol_exists("mmap" "sys/mman.h" HAVE_FUNC_MMAP) check_symbol_exists("sysconf" "unistd.h" HAVE_FUNC_SYSCONF) @@ -296,7 +258,9 @@ "snappy-stubs-internal.cc" "snappy.cc" "${PROJECT_BINARY_DIR}/config.h" - PUBLIC + + # Only CMake 3.3+ supports PUBLIC sources in targets exported by "install". + $<$<VERSION_GREATER:CMAKE_VERSION,3.2>:PUBLIC> $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/snappy-c.h> $<INSTALL_INTERFACE:include/snappy-c.h> $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/snappy-sinksource.h> @@ -333,9 +297,6 @@ # Test files include snappy-test.h, HAVE_CONFIG_H must be defined. target_compile_definitions(snappy_test_support PUBLIC -DHAVE_CONFIG_H) - if(BUILD_SHARED_LIBS) - set_target_properties(snappy_test_support PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) - endif(BUILD_SHARED_LIBS) target_link_libraries(snappy_test_support snappy)
diff --git a/COPYING.notestdata b/COPYING.notestdata deleted file mode 100644 index 8d6bd9f..0000000 --- a/COPYING.notestdata +++ /dev/null
@@ -1,28 +0,0 @@ -Copyright 2011, Google Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/MODULE.bazel b/MODULE.bazel deleted file mode 100644 index d283a49..0000000 --- a/MODULE.bazel +++ /dev/null
@@ -1,26 +0,0 @@ -module( - name = "snappy", - version = "1.2.2", - compatibility_level = 1, -) - -bazel_dep(name = "rules_cc", version = "0.2.4") -bazel_dep(name = "bazel_skylib", version = "1.8.2") - -bazel_dep( - name = "googletest", - version = "1.17.0.bcr.2", - dev_dependency = True, - repo_name = "com_google_googletest", -) -bazel_dep( - name = "google_benchmark", - version = "1.9.5", - dev_dependency = True, - repo_name = "com_google_benchmark", -) - -bazel_dep( - name = "platforms", - version = "1.0.0", -)
diff --git a/NEWS b/NEWS index ef935ba..792a578 100644 --- a/NEWS +++ b/NEWS
@@ -1,18 +1,3 @@ -Snappy v1.2.2, Mar 26th 2025: - - * We added a new compression level in v1.2.1 which compresses a bit - denser but slower. Decompression speed should be even faster with it. - - * We fixed a very old issue of data corruption when compressed size - exceeds 4GB. This can happen when you compress data close to 4GB - and it's incompressible, for example, random data. - - * Started to use minimum CMake 3.10 because older ones are not - planned to be supported. - - * Various other small fixes and performance improvements (especially - for clang). - Snappy v1.1.10, Mar 8th 2023: * Performance improvements
diff --git a/README.md b/README.md index 9b4a494..398be7d 100644 --- a/README.md +++ b/README.md
@@ -140,10 +140,10 @@ 1. C++11 2. Clang (gcc and MSVC are best-effort). 3. Low level optimizations (e.g. assembly or equivalent intrinsics) for: - - [x86](https://en.wikipedia.org/wiki/X86) - - [x86-64](https://en.wikipedia.org/wiki/X86-64) - - ARMv7 (32-bit) - - ARMv8 (AArch64) + 1. [x86](https://en.wikipedia.org/wiki/X86) + 2. [x86-64](https://en.wikipedia.org/wiki/X86-64) + 3. ARMv7 (32-bit) + 4. ARMv8 (AArch64) 4. Supports only the Snappy compression scheme as described in [format_description.txt](format_description.txt). 5. CMake for building
diff --git a/WORKSPACE.bzlmod b/WORKSPACE.bzlmod deleted file mode 100644 index e69de29..0000000 --- a/WORKSPACE.bzlmod +++ /dev/null
diff --git a/cmake/config.h.in b/cmake/config.h.in index de80c5f..3510c27 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in
@@ -58,12 +58,6 @@ /* Define to 1 if you target processors with NEON and have <arm_neon.h>. */ #cmakedefine01 SNAPPY_HAVE_NEON -/* Define to 1 if you target processors with RVV1.0 and have <riscv_vector.h>. */ -#cmakedefine01 SNAPPY_RVV_1 - -/* Define to 1 if you target processors with RVV0.7 and have <riscv_vector.h>. */ -#cmakedefine01 SNAPPY_RVV_0_7 - /* Define to 1 if you have <arm_neon.h> and <arm_acle.h> and want to optimize compression speed by using __crc32cw from <arm_acle.h>. */ #cmakedefine01 SNAPPY_HAVE_NEON_CRC32
diff --git a/snappy-internal.h b/snappy-internal.h index 9be0542..ae78247 100644 --- a/snappy-internal.h +++ b/snappy-internal.h
@@ -46,24 +46,7 @@ #include <arm_neon.h> #endif -#if SNAPPY_RVV_1 || SNAPPY_RVV_0_7 -#define SNAPPY_HAVE_RVV 1 -#include <riscv_vector.h> -#else -#define SNAPPY_HAVE_RVV 0 -#endif - -#ifdef SNAPPY_RVV_1 -#define VSETVL_E8M2 __riscv_vsetvl_e8m2 -#define VLE8_V_U8M2 __riscv_vle8_v_u8m2 -#define VSE8_V_U8M2 __riscv_vse8_v_u8m2 -#elif SNAPPY_RVV_0_7 -#define VSETVL_E8M2 vsetvl_e8m2 -#define VLE8_V_U8M2 vle8_v_u8m2 -#define VSE8_V_U8M2 vse8_v_u8m2 -#endif - -#if SNAPPY_HAVE_SSSE3 || SNAPPY_HAVE_NEON +#if SNAPPY_HAVE_SSSE3 || SNAPPY_HAVE_NEON #define SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE 1 #else #define SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE 0 @@ -78,7 +61,7 @@ #elif SNAPPY_HAVE_NEON using V128 = uint8x16_t; #endif - + // Load 128 bits of integer data. `src` must be 16-byte aligned. inline V128 V128_Load(const V128* src); @@ -127,8 +110,6 @@ } inline V128 V128_DupChar(char c) { return vdupq_n_u8(c); } - - #endif #endif // SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE @@ -191,10 +172,9 @@ // loading from s2 + n. // // Separate implementation for 64-bit, little-endian cpus. -// riscv and little-endian cpu choose this routinue can be done faster too. #if !SNAPPY_IS_BIG_ENDIAN && \ (defined(__x86_64__) || defined(_M_X64) || defined(ARCH_PPC) || \ - defined(ARCH_ARM) || (defined(__riscv) && (__riscv_xlen == 64))) + defined(ARCH_ARM)) static inline std::pair<size_t, bool> FindMatchLength(const char* s1, const char* s2, const char* s2_limit,
diff --git a/snappy-stubs-internal.h b/snappy-stubs-internal.h index 10fdbae..526c38b 100644 --- a/snappy-stubs-internal.h +++ b/snappy-stubs-internal.h
@@ -304,8 +304,8 @@ void operator=(const Bits&); }; -// In RISC-V, CLZ is supported by instructions from the ZBB bit-manipulation extension. #if HAVE_BUILTIN_CTZ + inline int Bits::Log2FloorNonZero(uint32_t n) { assert(n != 0); // (31 ^ x) is equivalent to (31 - x) for x in [0, 31]. An easy proof @@ -393,7 +393,6 @@ #endif // End portable versions. -// In RISC-V, CLZ is supported by instructions from the ZBB bit-manipulation extension. #if HAVE_BUILTIN_CTZ inline int Bits::FindLSBSetNonZero64(uint64_t n) {
diff --git a/snappy.cc b/snappy.cc index f62db8d..708c57d 100644 --- a/snappy.cc +++ b/snappy.cc
@@ -74,7 +74,6 @@ #include <cstdint> #include <cstdio> #include <cstring> -#include <functional> #include <memory> #include <string> #include <utility> @@ -281,8 +280,6 @@ // 4, 5, 0, 1, 2, 3, 4, 5, 0, 1}. These byte index sequences are generated by // calling MakePatternMaskBytes(0, 6, index_sequence<16>()) and // MakePatternMaskBytes(16, 6, index_sequence<16>()) respectively. - - template <size_t... indexes> inline constexpr std::array<char, sizeof...(indexes)> MakePatternMaskBytes( int index_offset, int pattern_size, index_sequence<indexes...>) { @@ -300,6 +297,7 @@ MakePatternMaskBytes(index_offset, pattern_sizes_minus_one + 1, make_index_sequence</*indexes=*/sizeof(V128)>())...}; } + // This is an array of shuffle control masks that can be used as the source // operand for PSHUFB to permute the contents of the destination XMM register // into a repeating byte pattern. @@ -330,6 +328,7 @@ return V128_Shuffle(V128_LoadU(reinterpret_cast<const V128*>(src)), generation_mask); } + SNAPPY_ATTRIBUTE_ALWAYS_INLINE static inline std::pair<V128 /* pattern */, V128 /* reshuffle_mask */> LoadPatternAndReshuffleMask(const char* src, const size_t pattern_size) { @@ -345,6 +344,7 @@ pattern_reshuffle_masks[pattern_size - 1].data())); return {pattern, reshuffle_mask}; } + #endif // SNAPPY_HAVE_VECTOR_BYTE_SHUFFLE // Fallback for when we need to copy while extending the pattern, for example @@ -493,6 +493,7 @@ LoadPatternAndReshuffleMask(src, pattern_size); V128 pattern = pattern_and_reshuffle_mask.first; V128 reshuffle_mask = pattern_and_reshuffle_mask.second; + // There is at least one, and at most four 16-byte blocks. Writing four // conditionals instead of a loop allows FDO to layout the code with // respect to the actual probabilities of each length. @@ -519,6 +520,7 @@ LoadPatternAndReshuffleMask(src, pattern_size); V128 pattern = pattern_and_reshuffle_mask.first; V128 reshuffle_mask = pattern_and_reshuffle_mask.second; + // This code path is relatively cold however so we save code size // by avoiding unrolling and vectorizing. // @@ -957,8 +959,6 @@ char* CompressFragmentDoubleHash(const char* input, size_t input_size, char* op, uint16_t* table, const int table_size, uint16_t* table2, const int table_size2) { - (void)table_size2; - assert(table_size == table_size2); // "ip" is the input pointer, and "op" is the output pointer. const char* ip = input; assert(input_size <= kBlockSize); @@ -1224,7 +1224,7 @@ void MemCopy64(char* dst, const void* src, size_t size) { // Always copy this many bytes. If that's below size then copy the full 64. constexpr int kShortMemCopy = 32; - (void)kShortMemCopy; + assert(size <= 64); assert(std::less_equal<const void*>()(static_cast<const char*>(src) + size, dst) || @@ -1243,27 +1243,6 @@ data = _mm256_lddqu_si256(static_cast<const __m256i *>(src) + 1); _mm256_storeu_si256(reinterpret_cast<__m256i *>(dst) + 1, data); } - // RVV acceleration available on RISC-V when compiled with -march=rv64gcv -#elif defined(__riscv) && SNAPPY_HAVE_RVV - // Cast pointers to the type we will operate on. - unsigned char* dst_ptr = reinterpret_cast<unsigned char*>(dst); - const unsigned char* src_ptr = reinterpret_cast<const unsigned char*>(src); - size_t remaining_bytes = size; - // Loop as long as there are bytes remaining to be copied. - while (remaining_bytes > 0) { - // Set vector configuration: e8 (8-bit elements), m2 (LMUL=2). - // Use e8m2 configuration to maximize throughput. - size_t vl = VSETVL_E8M2(remaining_bytes); - // Load data from the current source pointer. - vuint8m2_t vec = VLE8_V_U8M2(src_ptr, vl); - // Store data to the current destination pointer. - VSE8_V_U8M2(dst_ptr, vec, vl); - // Update pointers and the remaining count. - src_ptr += vl; - dst_ptr += vl; - remaining_bytes -= vl; - } - #else std::memmove(dst, src, kShortMemCopy); // Profiling shows that nearly all copies are short. @@ -1363,32 +1342,6 @@ return tag_type; } -SNAPPY_ATTRIBUTE_ALWAYS_INLINE -inline size_t AdvanceToNextTagRVOptimized(const uint8_t** ip_p, size_t* tag) { - const uint8_t*& ip = *ip_p; - // This section is crucial for the throughput of the decompression loop. - // The latency of an iteration is fundamentally constrained by the data chain on ip: - // ip -> c = *tag -> literal_len = c >> 2, tag_type = c & 3 - // -> literal_advance = literal_len + 2, copy_advance = tag_type + 1 - // -> next_ip = ip + literal_advance OR ip + copy_advance (literal vs copy) - // -> *tag = byte at (next_ip - 1); ip = next_ip - // - // Base RISC-V has no x86-style cmov and no AArch64 csinc on the same shape; this - // computes both candidate advances and both load offsets, then selects with - // (is_literal ? ... : ...). With the Zicond extension (czero.eqz / czero.nez), those - // selections typically lower to branchless conditional-zero ops instead of a - // hard-to-predict literal/copy branch, which is why this form tends to win there. - const size_t literal_len = *tag >> 2; - const size_t tag_type = *tag & 3; - const bool is_literal = (tag_type == 0); - const size_t copy_advance = tag_type + 1; - const size_t literal_advance = literal_len + 2; - const uint8_t* next_ip = is_literal ? (ip + literal_advance) : (ip + copy_advance); - *tag = is_literal ? ip[literal_advance - 1] : ip[copy_advance - 1]; - ip = next_ip; - return tag_type; -} - // Extract the offset for copy-1 and copy-2 returns 0 for literals or copy-4. inline uint32_t ExtractOffset(uint32_t val, size_t tag_type) { // For x86 non-static storage works better. For ARM static storage is better. @@ -1401,13 +1354,7 @@ reinterpret_cast<const char*>(&kExtractMasksCombined) + 2 * tag_type, sizeof(result)); return val & result; - // For AArch64 and RISC-V, use a bit-twiddling trick to extract the mask from a - // single combined constant instead of a lookup table. The constant packs multiple - // 16-bit masks based on tag_type (see implementation below). The code calculates - // the shift amount from tag_type, right-shifts the constant to move the desired - // mask to the LSB position, then extracts it with & 0xFFFF. This branchless - // approach is often more performant on modern CPUs. -#elif defined(__aarch64__) || (defined(__riscv) && (__riscv_xlen == 64)) +#elif defined(__aarch64__) constexpr uint64_t kExtractMasksCombined = 0x0000FFFF00FF0000ull; return val & static_cast<uint32_t>( (kExtractMasksCombined >> (tag_type * 16)) & 0xFFFF); @@ -1471,11 +1418,6 @@ // We never need more than 16 bits. Doing a Load16 allows the compiler // to elide the masking operation in ExtractOffset. next = LittleEndian::Load16(old_ip); -#elif defined(__riscv) - size_t tag_type = AdvanceToNextTagRVOptimized(&ip, &tag); - // We never need more than 16 bits. Doing a Load16 allows the compiler - // to elide the masking operation in ExtractOffset. - next = LittleEndian::Load16(old_ip); #else size_t tag_type = AdvanceToNextTagX86Optimized(&ip, &tag); next = LittleEndian::Load32(old_ip); @@ -1554,7 +1496,7 @@ // If ip < ip_limit_min_maxtaglen_ it's safe to read kMaxTagLength from // buffer. const char* ip_limit_min_maxtaglen_; - uint64_t peeked_; // Bytes peeked from reader (need to skip) + uint32_t peeked_; // Bytes peeked from reader (need to skip) bool eof_; // Hit end of input without an error? char scratch_[kMaximumTagLength]; // See RefillTag(). @@ -1745,8 +1687,7 @@ #if __cplusplus >= 201402L constexpr bool VerifyCalculateNeeded() { for (int i = 0; i < 1; i++) { - if (CalculateNeeded(i) != static_cast<uint32_t>((char_table[i] >> 11)) + 1) - return false; + if (CalculateNeeded(i) != (char_table[i] >> 11) + 1) return false; } return true; } @@ -1782,7 +1723,7 @@ assert(needed <= sizeof(scratch_)); // Read more bytes from reader if needed - uint64_t nbuf = ip_limit_ - ip; + uint32_t nbuf = ip_limit_ - ip; if (nbuf < needed) { // Stitch together bytes from ip and reader to form the word // contents. We store the needed bytes in "scratch_". They @@ -1795,7 +1736,7 @@ size_t length; const char* src = reader_->Peek(&length); if (length == 0) return false; - uint64_t to_add = std::min<uint64_t>(needed - nbuf, length); + uint32_t to_add = std::min<uint32_t>(needed - nbuf, length); std::memcpy(scratch_ + nbuf, src, to_add); nbuf += to_add; reader_->Skip(to_add); @@ -1849,16 +1790,11 @@ return decompressor.ReadUncompressedLength(result); } -size_t Compress(Source* reader, Sink* writer) { - return Compress(reader, writer, CompressionOptions{}); -} - size_t Compress(Source* reader, Sink* writer, CompressionOptions options) { assert(options.level == 1 || options.level == 2); int token = 0; size_t written = 0; size_t N = reader->Available(); - assert(N <= 0xFFFFFFFFu); const size_t uncompressed_size = N; char ulength[Varint::kMax32]; char* p = Varint::Encode32(ulength, N); @@ -1950,16 +1886,16 @@ if (total_size > 0 && curr_size_remaining_ == 0) Advance(); } - ~SnappyIOVecReader() override = default; + ~SnappyIOVecReader() = default; - size_t Available() const override { return total_size_remaining_; } + size_t Available() const { return total_size_remaining_; } - const char* Peek(size_t* len) override { + const char* Peek(size_t* len) { *len = curr_size_remaining_; return curr_pos_; } - void Skip(size_t n) override { + void Skip(size_t n) { while (n >= curr_size_remaining_ && n > 0) { n -= curr_size_remaining_; Advance(); @@ -2361,12 +2297,6 @@ } void RawCompress(const char* input, size_t input_length, char* compressed, - size_t* compressed_length) { - RawCompress(input, input_length, compressed, compressed_length, - CompressionOptions{}); -} - -void RawCompress(const char* input, size_t input_length, char* compressed, size_t* compressed_length, CompressionOptions options) { ByteArraySource reader(input, input_length); UncheckedByteArraySink writer(compressed); @@ -2377,12 +2307,6 @@ } void RawCompressFromIOVec(const struct iovec* iov, size_t uncompressed_length, - char* compressed, size_t* compressed_length) { - RawCompressFromIOVec(iov, uncompressed_length, compressed, compressed_length, - CompressionOptions{}); -} - -void RawCompressFromIOVec(const struct iovec* iov, size_t uncompressed_length, char* compressed, size_t* compressed_length, CompressionOptions options) { SnappyIOVecReader reader(iov, uncompressed_length); @@ -2393,11 +2317,6 @@ *compressed_length = writer.CurrentDestination() - compressed; } -size_t Compress(const char* input, size_t input_length, - std::string* compressed) { - return Compress(input, input_length, compressed, CompressionOptions{}); -} - size_t Compress(const char* input, size_t input_length, std::string* compressed, CompressionOptions options) { // Pre-grow the buffer to the max length of the compressed output @@ -2411,11 +2330,6 @@ } size_t CompressFromIOVec(const struct iovec* iov, size_t iov_cnt, - std::string* compressed) { - return CompressFromIOVec(iov, iov_cnt, compressed, CompressionOptions{}); -} - -size_t CompressFromIOVec(const struct iovec* iov, size_t iov_cnt, std::string* compressed, CompressionOptions options) { // Compute the number of bytes to be compressed. size_t uncompressed_length = 0; @@ -2619,6 +2533,7 @@ class SnappySinkAllocator { public: explicit SnappySinkAllocator(Sink* dest) : dest_(dest) {} + ~SnappySinkAllocator() {} char* Allocate(int size) { Datablock block(new char[size], size);
diff --git a/snappy.h b/snappy.h index 2f1b802..04b7a96 100644 --- a/snappy.h +++ b/snappy.h
@@ -64,9 +64,6 @@ // faster decompression speeds than snappy:1 and zstd:-3. int level = DefaultCompressionLevel(); - constexpr CompressionOptions() = default; - constexpr CompressionOptions(int compression_level) - : level(compression_level) {} static constexpr int MinCompressionLevel() { return 1; } static constexpr int MaxCompressionLevel() { return 2; } static constexpr int DefaultCompressionLevel() { return 1; } @@ -78,10 +75,8 @@ // Compress the bytes read from "*reader" and append to "*writer". Return the // number of bytes written. - // First version is to preserve ABI. - size_t Compress(Source* reader, Sink* writer); size_t Compress(Source* reader, Sink* writer, - CompressionOptions options); + CompressionOptions options = {}); // Find the uncompressed length of the given stream, as given by the header. // Note that the true length could deviate from this; the stream could e.g. @@ -100,22 +95,16 @@ // Original contents of *compressed are lost. // // REQUIRES: "input[]" is not an alias of "*compressed". - // First version is to preserve ABI. size_t Compress(const char* input, size_t input_length, - std::string* compressed); - size_t Compress(const char* input, size_t input_length, - std::string* compressed, CompressionOptions options); + std::string* compressed, CompressionOptions options = {}); // Same as `Compress` above but taking an `iovec` array as input. Note that // this function preprocesses the inputs to compute the sum of // `iov[0..iov_cnt-1].iov_len` before reading. To avoid this, use // `RawCompressFromIOVec` below. - // First version is to preserve ABI. - size_t CompressFromIOVec(const struct iovec* iov, size_t iov_cnt, - std::string* compressed); size_t CompressFromIOVec(const struct iovec* iov, size_t iov_cnt, std::string* compressed, - CompressionOptions options); + CompressionOptions options = {}); // Decompresses "compressed[0..compressed_length-1]" to "*uncompressed". // Original contents of "*uncompressed" are lost. @@ -159,18 +148,14 @@ // ... Process(output, output_length) ... // delete [] output; void RawCompress(const char* input, size_t input_length, char* compressed, - size_t* compressed_length); - void RawCompress(const char* input, size_t input_length, char* compressed, - size_t* compressed_length, CompressionOptions options); + size_t* compressed_length, CompressionOptions options = {}); // Same as `RawCompress` above but taking an `iovec` array as input. Note that // `uncompressed_length` is the total number of bytes to be read from the // elements of `iov` (_not_ the number of elements in `iov`). void RawCompressFromIOVec(const struct iovec* iov, size_t uncompressed_length, - char* compressed, size_t* compressed_length); - void RawCompressFromIOVec(const struct iovec* iov, size_t uncompressed_length, char* compressed, size_t* compressed_length, - CompressionOptions options); + CompressionOptions options = {}); // Given data in "compressed[0..compressed_length-1]" generated by // calling the Snappy::Compress routine, this routine
diff --git a/snappy_benchmark.cc b/snappy_benchmark.cc index d6e35d3..90243a8 100644 --- a/snappy_benchmark.cc +++ b/snappy_benchmark.cc
@@ -31,10 +31,12 @@ #include <string> #include <vector> +#include "snappy-test.h" + #include "benchmark/benchmark.h" + #include "snappy-internal.h" #include "snappy-sinksource.h" -#include "snappy-test.h" #include "snappy.h" #include "snappy_test_data.h" @@ -42,7 +44,7 @@ namespace { -void FilesAndLevels(benchmark::internal::Benchmark* benchmark) { +void FilesAndLevels(::testing::Benchmark* benchmark) { for (int i = 0; i < ARRAYSIZE(kTestDataFiles); ++i) { for (int level = snappy::CompressionOptions::MinCompressionLevel(); level <= snappy::CompressionOptions::MaxCompressionLevel(); ++level) { @@ -62,9 +64,8 @@ kTestDataFiles[file_index].size_limit); std::string zcontents; - snappy::Compress( - contents.data(), contents.size(), &zcontents, - snappy::CompressionOptions{/*level=*/static_cast<int>(state.range(1))}); + snappy::Compress(contents.data(), contents.size(), &zcontents, + snappy::CompressionOptions{.level = state.range(1)}); char* dst = new char[contents.size()]; for (auto s : state) { @@ -128,9 +129,8 @@ kTestDataFiles[file_index].size_limit); std::string zcontents; - snappy::Compress( - contents.data(), contents.size(), &zcontents, - snappy::CompressionOptions{/*level=*/static_cast<int>(state.range(1))}); + snappy::Compress(contents.data(), contents.size(), &zcontents, + snappy::CompressionOptions{.level = state.range(1)}); for (auto s : state) { CHECK(snappy::IsValidCompressedBuffer(zcontents.data(), zcontents.size())); @@ -193,7 +193,7 @@ size_t zsize = 0; for (auto s : state) { snappy::RawCompressFromIOVec(iov, contents.size(), dst, &zsize, - snappy::CompressionOptions{/*level=*/level}); + snappy::CompressionOptions{.level = level}); benchmark::DoNotOptimize(iov); } state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * @@ -226,7 +226,7 @@ // Uncompress into an iovec containing ten entries. const int kNumEntries = 10; struct iovec iov[kNumEntries]; - char* dst = new char[contents.size()]; + char *dst = new char[contents.size()]; size_t used_so_far = 0; for (int i = 0; i < kNumEntries; ++i) { iov[i].iov_base = dst + used_so_far; @@ -267,9 +267,8 @@ kTestDataFiles[file_index].size_limit); std::string zcontents; - snappy::Compress( - contents.data(), contents.size(), &zcontents, - snappy::CompressionOptions{/*level=*/static_cast<int>(state.range(1))}); + snappy::Compress(contents.data(), contents.size(), &zcontents, + snappy::CompressionOptions{.level = state.range(1)}); char* dst = new char[contents.size()]; for (auto s : state) { @@ -305,7 +304,7 @@ size_t zsize = 0; for (auto s : state) { snappy::RawCompress(contents.data(), contents.size(), dst, &zsize, - snappy::CompressionOptions{/*level=*/level}); + snappy::CompressionOptions{.level = level}); benchmark::DoNotOptimize(dst); } state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * @@ -341,7 +340,7 @@ for (auto s : state) { for (int i = 0; i < num_files; ++i) { snappy::RawCompress(contents[i].data(), contents[i].size(), dst[i], - &zsize, snappy::CompressionOptions{/*level=*/level}); + &zsize, snappy::CompressionOptions{.level = level}); benchmark::DoNotOptimize(dst); } } @@ -378,7 +377,7 @@ for (auto s : state) { for (size_t i = 0; i < contents.size(); ++i) { snappy::RawCompress(contents[i].data(), contents[i].size(), dst[i], - &zsize, snappy::CompressionOptions{/*level=*/level}); + &zsize, snappy::CompressionOptions{.level = level}); benchmark::DoNotOptimize(dst); } }
diff --git a/snappy_compress_fuzzer.cc b/snappy_compress_fuzzer.cc index 93254a2..144f438 100644 --- a/snappy_compress_fuzzer.cc +++ b/snappy_compress_fuzzer.cc
@@ -44,7 +44,7 @@ std::string compressed; size_t compressed_size = snappy::Compress(input.data(), input.size(), &compressed, - snappy::CompressionOptions{/*level=*/level}); + snappy::CompressionOptions{.level = level}); (void)compressed_size; // Variable only used in debug builds. assert(compressed_size == compressed.size());
diff --git a/snappy_unittest.cc b/snappy_unittest.cc index 923a0ec..e57b13d 100644 --- a/snappy_unittest.cc +++ b/snappy_unittest.cc
@@ -27,7 +27,6 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <algorithm> -#include <cinttypes> #include <cmath> #include <cstdlib> #include <random> @@ -485,18 +484,6 @@ Verify(input); } -// Issue #201, when output is more than 4GB, we had a data corruption bug. -// We cannot run this test always because of CI constraints. -TEST(Snappy, DISABLED_MoreThan4GB) { - std::mt19937 rng; - std::uniform_int_distribution<int> uniform_byte(0, 255); - std::string input; - input.resize((1ull << 32) - 1); - for (uint64_t i = 0; i < ((1ull << 32) - 1); ++i) - input[i] = static_cast<char>(uniform_byte(rng)); - Verify(input); -} - TEST(Snappy, RandomData) { std::minstd_rand0 rng(snappy::GetFlag(FLAGS_test_random_seed)); std::uniform_int_distribution<int> uniform_0_to_3(0, 3);