Merge branch 'dev' into unified-target
This commit is contained in:
+1
-1
@@ -2,8 +2,8 @@ task:
|
||||
name: FreeBSD (shortest)
|
||||
freebsd_instance:
|
||||
matrix:
|
||||
image_family: freebsd-14-0
|
||||
image_family: freebsd-13-2
|
||||
image_family: freebsd-12-4
|
||||
install_script: pkg install -y gmake coreutils
|
||||
script: |
|
||||
MOREFLAGS="-Werror" gmake -j all
|
||||
|
||||
@@ -247,7 +247,7 @@ jobs:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
|
||||
- uses: msys2/setup-msys2@5beef6d11f48bba68b9eb503e3adc60b23c0cc36 # tag=v2
|
||||
- uses: msys2/setup-msys2@cc11e9188b693c2b100158c3322424c4cc1dadea # tag=v2.22.0
|
||||
with:
|
||||
msystem: MINGW64
|
||||
install: make
|
||||
@@ -290,7 +290,7 @@ jobs:
|
||||
dry-run: false
|
||||
sanitizer: ${{ matrix.sanitizer }}
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # tag=v3.1.3
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1
|
||||
if: failure() && steps.build.outcome == 'success'
|
||||
with:
|
||||
name: ${{ matrix.sanitizer }}-artifacts
|
||||
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
|
||||
- name: build zstd bin against a dynamic lib (debuglevel for more dependencies)
|
||||
run: |
|
||||
make -C lib lib-mt-release
|
||||
make -C lib lib-mt-release
|
||||
DEBUGLEVEL=2 make -C programs zstd-dll
|
||||
|
||||
gcc-7-libzstd:
|
||||
@@ -80,19 +80,16 @@ jobs:
|
||||
make clean
|
||||
LDFLAGS=-Wl,--no-undefined make -C lib libzstd-mt
|
||||
|
||||
# candidate test (to check) : underlink test
|
||||
# candidate test (for discussion) : underlink test
|
||||
# LDFLAGS=-Wl,--no-undefined : will make the linker fail if dll is underlinked
|
||||
|
||||
cmake-build-and-test-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
|
||||
- name: cmake build and test check
|
||||
- name: cmake build and test
|
||||
run: |
|
||||
FUZZERTEST=-T1mn ZSTREAM_TESTTIME=-T1mn make cmakebuild
|
||||
cp -r ./ "../zstd source"
|
||||
cd "../zstd source"
|
||||
FUZZERTEST=-T1mn ZSTREAM_TESTTIME=-T1mn make cmakebuild
|
||||
FUZZERTEST=-T1mn ZSTREAM_TESTTIME=-T1mn make cmakebuild V=1
|
||||
|
||||
cpp-gnu90-c99-compatibility:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -246,14 +243,12 @@ jobs:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
|
||||
- name: Install packages
|
||||
run: pip install --pre meson
|
||||
- name: Initialize the MSVC dev command prompt
|
||||
uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89
|
||||
- name: Configure with Meson
|
||||
run: |
|
||||
meson setup build/meson/ builddir -Dbin_tests=true -Dbin_programs=true -Dbin_contrib=true
|
||||
meson setup --vsenv build/meson/ builddir -Dbin_tests=true -Dbin_programs=true -Dbin_contrib=true
|
||||
- name: Build with Meson
|
||||
run: |
|
||||
ninja -C builddir/
|
||||
meson compile -C builddir/
|
||||
- name: Test with Meson
|
||||
run: |
|
||||
meson test -C builddir/ --print-errorlogs
|
||||
@@ -276,7 +271,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@1ff57057b5cfdc39105cd07a01d78e9b0ea0c14c # tag=v1.3
|
||||
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0
|
||||
- name: Build
|
||||
working-directory: ${{env.GITHUB_WORKSPACE}}
|
||||
run: |
|
||||
@@ -303,7 +298,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@1ff57057b5cfdc39105cd07a01d78e9b0ea0c14c # tag=v1.3
|
||||
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0
|
||||
- name: Build ${{matrix.name}}
|
||||
working-directory: ${{env.GITHUB_WORKSPACE}}
|
||||
# See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference
|
||||
@@ -386,6 +381,7 @@ jobs:
|
||||
{ name: S390X, xcc_pkg: gcc-s390x-linux-gnu, xcc: s390x-linux-gnu-gcc, xemu_pkg: qemu-system-s390x, xemu: qemu-s390x-static },
|
||||
{ name: MIPS, xcc_pkg: gcc-mips-linux-gnu, xcc: mips-linux-gnu-gcc, xemu_pkg: qemu-system-mips, xemu: qemu-mips-static },
|
||||
{ name: M68K, xcc_pkg: gcc-m68k-linux-gnu, xcc: m68k-linux-gnu-gcc, xemu_pkg: qemu-system-m68k, xemu: qemu-m68k-static },
|
||||
{ name: SPARC, xcc_pkg: gcc-sparc64-linux-gnu, xcc: sparc64-linux-gnu-gcc, xemu_pkg: qemu-system-sparc, xemu: qemu-sparc64-static },
|
||||
]
|
||||
env: # Set environment variables
|
||||
XCC: ${{ matrix.xcc }}
|
||||
@@ -432,6 +428,10 @@ jobs:
|
||||
if: ${{ matrix.name == 'M68K' }}
|
||||
run: |
|
||||
LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make clean check
|
||||
- name: SPARC
|
||||
if: ${{ matrix.name == 'SPARC' }}
|
||||
run: |
|
||||
LDFLAGS="-static" CC=$XCC QEMU_SYS=$XEMU make clean check
|
||||
|
||||
mingw-short-test:
|
||||
runs-on: windows-latest
|
||||
@@ -448,7 +448,7 @@ jobs:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
|
||||
- uses: msys2/setup-msys2@5beef6d11f48bba68b9eb503e3adc60b23c0cc36 # tag=v2
|
||||
- uses: msys2/setup-msys2@cc11e9188b693c2b100158c3322424c4cc1dadea # tag=v2.22.0
|
||||
with:
|
||||
msystem: ${{ matrix.msystem }}
|
||||
install: make diffutils
|
||||
@@ -485,7 +485,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@1ff57057b5cfdc39105cd07a01d78e9b0ea0c14c # tag=v1.3
|
||||
uses: microsoft/setup-msbuild@6fb02220983dee41ce7ae257b6f4d8f9bf5ed4ce # tag=v2.0.0
|
||||
- name: Build and run tests
|
||||
working-directory: ${{env.GITHUB_WORKSPACE}}
|
||||
env:
|
||||
@@ -526,25 +526,6 @@ jobs:
|
||||
make -C tests fuzzer &&
|
||||
./tests/fuzzer.exe -v -T1m
|
||||
|
||||
intel-cet-compatibility:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
|
||||
- name: Build Zstd
|
||||
run: |
|
||||
make -j zstd V=1
|
||||
readelf -n zstd
|
||||
- name: Get Intel SDE
|
||||
run: |
|
||||
curl -LO https://downloadmirror.intel.com/684899/sde-external-9.0.0-2021-11-07-lin.tar.xz
|
||||
tar xJvf sde-external-9.0.0-2021-11-07-lin.tar.xz
|
||||
- name: Configure Permissions
|
||||
run: |
|
||||
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
|
||||
- name: Run Under SDE
|
||||
run: |
|
||||
sde-external-9.0.0-2021-11-07-lin/sde -cet -cet-raise 0 -cet-endbr-exe -cet-stderr -cet-abort -- ./zstd -b3
|
||||
|
||||
pkg-config:
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
@@ -601,10 +582,29 @@ jobs:
|
||||
make -C programs zstd-pgo
|
||||
./programs/zstd -b
|
||||
|
||||
intel-cet-compatibility:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # tag=v3
|
||||
- name: Build Zstd
|
||||
run: |
|
||||
make -j zstd V=1
|
||||
readelf -n zstd
|
||||
- name: Get Intel SDE
|
||||
run: |
|
||||
curl -LO https://downloadmirror.intel.com/813591/sde-external-9.33.0-2024-01-07-lin.tar.xz
|
||||
tar xJvf sde-external-9.33.0-2024-01-07-lin.tar.xz
|
||||
- name: Configure Permissions
|
||||
run: |
|
||||
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
|
||||
- name: Run Under SDE
|
||||
run: |
|
||||
sde-external-9.33.0-2024-01-07-lin/sde -cet -cet-raise 0 -cet-endbr-exe -cet-stderr -cet-abort -- ./zstd -b3
|
||||
|
||||
|
||||
# Failing tests, for reference
|
||||
|
||||
# For reference : icc tests
|
||||
# icc tests are currently failing on Github Actions, likely to issues during installation stage
|
||||
# To be fixed later
|
||||
#
|
||||
# icc:
|
||||
# name: icc-check
|
||||
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # tag=v3.1.3
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
@@ -59,6 +59,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@a09933a12a80f87b87005513f0abb1494c27a716 # tag=v2.21.4
|
||||
uses: github/codeql-action/upload-sarif@e5f05b81d5b6ff8cfa111c80c22c5fd02a384118 # tag=v3.23.0
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
cd ..
|
||||
|
||||
- name: Publish zstd-$VERSION-${{matrix.ziparch}}.zip
|
||||
uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # tag=v3
|
||||
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # tag=v4.3.1
|
||||
with:
|
||||
path: ${{ github.workspace }}/zstd-${{ github.ref_name }}-${{matrix.ziparch}}.zip
|
||||
name: zstd-${{ github.ref_name }}-${{matrix.ziparch}}.zip
|
||||
|
||||
+7
-2
@@ -27,6 +27,8 @@ tmp*
|
||||
dictionary.
|
||||
dictionary
|
||||
NUL
|
||||
cmakebuild/
|
||||
install/
|
||||
|
||||
# Build artefacts
|
||||
contrib/linux-kernel/linux/
|
||||
@@ -37,12 +39,15 @@ buck-out/
|
||||
build-*
|
||||
*.gcda
|
||||
|
||||
# IDE
|
||||
.clang_complete
|
||||
compile_flags.txt
|
||||
.clang-format
|
||||
|
||||
# Other files
|
||||
.directory
|
||||
_codelite/
|
||||
_zstdbench/
|
||||
.clang_complete
|
||||
compile_flags.txt
|
||||
*.idea
|
||||
*.swp
|
||||
.DS_Store
|
||||
|
||||
@@ -145,7 +145,7 @@ clean:
|
||||
$(Q)$(MAKE) -C contrib/largeNbDicts $@ > $(VOID)
|
||||
$(Q)$(MAKE) -C contrib/externalSequenceProducer $@ > $(VOID)
|
||||
$(Q)$(RM) zstd$(EXT) zstdmt$(EXT) tmp*
|
||||
$(Q)$(RM) -r lz4
|
||||
$(Q)$(RM) -r lz4 cmakebuild install
|
||||
@echo Cleaning completed
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
@@ -328,8 +328,9 @@ asan-%: clean
|
||||
msan: clean
|
||||
$(MAKE) test CC=clang MOREFLAGS="-g -fsanitize=memory -fno-omit-frame-pointer -Werror $(MOREFLAGS)" HAVE_LZMA=0 # datagen.c fails this test for no obvious reason
|
||||
|
||||
msan-%: clean
|
||||
LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=memory -fno-omit-frame-pointer -Werror $(MOREFLAGS)" FUZZER_FLAGS="--no-big-tests $(FUZZER_FLAGS)" $(MAKE) -C $(TESTDIR) HAVE_LZMA=0 $*
|
||||
msan-%:
|
||||
$(MAKE) clean
|
||||
LDFLAGS=-fuse-ld=gold MOREFLAGS="-g -fno-sanitize-recover=all -fsanitize=memory -fno-omit-frame-pointer -Werror $(MOREFLAGS)" FUZZER_FLAGS="--no-big-tests $(FUZZER_FLAGS)" $(MAKE) -j -C $(TESTDIR) HAVE_LZMA=0 $*
|
||||
|
||||
asan32: clean
|
||||
$(MAKE) -C $(TESTDIR) test32 CC=clang MOREFLAGS="-g -fsanitize=address $(MOREFLAGS)"
|
||||
@@ -389,28 +390,32 @@ lz4install:
|
||||
endif
|
||||
|
||||
|
||||
CMAKE_PARAMS = -DZSTD_BUILD_CONTRIB:BOOL=ON -DZSTD_BUILD_STATIC:BOOL=ON -DZSTD_BUILD_TESTS:BOOL=ON -DZSTD_ZLIB_SUPPORT:BOOL=ON -DZSTD_LZMA_SUPPORT:BOOL=ON -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
ifneq (,$(filter MSYS%,$(shell uname)))
|
||||
HOST_OS = MSYS
|
||||
CMAKE_PARAMS = -G"MSYS Makefiles" -DCMAKE_BUILD_TYPE=Debug -DZSTD_MULTITHREAD_SUPPORT:BOOL=OFF -DZSTD_BUILD_STATIC:BOOL=ON -DZSTD_BUILD_TESTS:BOOL=ON
|
||||
endif
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
# target specific tests
|
||||
#------------------------------------------------------------------------
|
||||
ifneq (,$(filter $(HOST_OS),MSYS POSIX))
|
||||
.PHONY: cmakebuild c89build gnu90build c99build gnu99build c11build bmix64build bmix32build bmi32build staticAnalyze
|
||||
cmakebuild:
|
||||
cmake --version
|
||||
$(RM) -r $(BUILDIR)/cmake/build
|
||||
$(MKDIR) $(BUILDIR)/cmake/build
|
||||
cd $(BUILDIR)/cmake/build; cmake -DCMAKE_INSTALL_PREFIX:PATH=~/install_test_dir $(CMAKE_PARAMS) ..
|
||||
$(MAKE) -C $(BUILDIR)/cmake/build -j4;
|
||||
$(MAKE) -C $(BUILDIR)/cmake/build install;
|
||||
$(MAKE) -C $(BUILDIR)/cmake/build uninstall;
|
||||
cd $(BUILDIR)/cmake/build; ctest -V -L Medium
|
||||
|
||||
CMAKE ?= cmake
|
||||
CMAKE_PARAMS = -DZSTD_BUILD_CONTRIB:BOOL=ON -DZSTD_BUILD_STATIC:BOOL=ON -DZSTD_BUILD_TESTS:BOOL=ON -DZSTD_ZLIB_SUPPORT:BOOL=ON -DZSTD_LZMA_SUPPORT:BOOL=ON
|
||||
|
||||
ifneq (,$(filter MSYS%,$(shell uname)))
|
||||
CMAKE_PARAMS = -G"MSYS Makefiles" -DZSTD_MULTITHREAD_SUPPORT:BOOL=OFF -DZSTD_BUILD_STATIC:BOOL=ON -DZSTD_BUILD_TESTS:BOOL=ON
|
||||
endif
|
||||
|
||||
.PHONY: cmakebuild
|
||||
cmakebuild:
|
||||
$(CMAKE) --version
|
||||
$(RM) -r cmakebuild install
|
||||
$(MKDIR) cmakebuild install
|
||||
cd cmakebuild; $(CMAKE) -Wdev -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_FLAGS="-Werror -O0" -DCMAKE_INSTALL_PREFIX=install $(CMAKE_PARAMS) ../build/cmake
|
||||
$(CMAKE) --build cmakebuild --target install -- -j V=1
|
||||
cd cmakebuild; ctest -V -L Medium
|
||||
|
||||
.PHONY: c89build gnu90build c99build gnu99build c11build bmix64build bmix32build bmi32build staticAnalyze
|
||||
c89build: clean
|
||||
$(CC) -v
|
||||
CFLAGS="-std=c89 -Werror -Wno-attributes -Wpedantic -Wno-long-long -Wno-variadic-macros -O0" $(MAKE) lib zstd
|
||||
|
||||
@@ -198,6 +198,10 @@ Going into `build` directory, you will find additional possibilities:
|
||||
You can build the zstd binary via buck by executing: `buck build programs:zstd` from the root of the repo.
|
||||
The output binary will be in `buck-out/gen/programs/`.
|
||||
|
||||
### Bazel
|
||||
|
||||
You easily can integrate zstd into your Bazel project by using the module hosted on the [Bazel Central Repository](https://registry.bazel.build/modules/zstd).
|
||||
|
||||
## Testing
|
||||
|
||||
You can run quick local smoke tests by running `make check`.
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
# Reporting and Fixing Security Issues
|
||||
|
||||
Please do not open GitHub issues or pull requests - this makes the problem immediately visible to everyone, including malicious actors. Security issues in this open source project can be safely reported via the Meta Bug Bounty program:
|
||||
|
||||
https://www.facebook.com/whitehat
|
||||
|
||||
Meta's security team will triage your report and determine whether or not is it eligible for a bounty under our program.
|
||||
|
||||
# Receiving Vulnerability Notifications
|
||||
|
||||
In the case that a significant security vulnerability is reported to us or discovered by us---without being publicly known---we will, at our discretion, notify high-profile, high-exposure users of Zstandard ahead of our public disclosure of the issue and associated fix.
|
||||
|
||||
If you believe your project would benefit from inclusion in this list, please reach out to one of the maintainers.
|
||||
|
||||
<!-- Note to maintainers: this list is kept [here](https://fburl.com/wiki/cgc1l62x). -->
|
||||
@@ -356,6 +356,10 @@
|
||||
RelativePath="..\..\..\programs\dibio.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\programs\lorem.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\..\lib\dictBuilder\cover.c"
|
||||
>
|
||||
|
||||
@@ -157,6 +157,8 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\programs\util.c" />
|
||||
<ClCompile Include="..\..\..\programs\datagen.c" />
|
||||
<ClCompile Include="..\..\..\programs\lorem.c" />
|
||||
<ClCompile Include="..\..\..\tests\loremOut.c" />
|
||||
<ClCompile Include="..\..\..\tests\datagencli.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
<ClCompile Include="..\..\..\programs\dibio.c" />
|
||||
<ClCompile Include="..\..\..\programs\fileio.c" />
|
||||
<ClCompile Include="..\..\..\programs\fileio_asyncio.c" />
|
||||
<ClCompile Include="..\..\..\programs\lorem.c" />
|
||||
<ClCompile Include="..\..\..\programs\zstdcli.c" />
|
||||
<ClCompile Include="..\..\..\programs\zstdcli_trace.c" />
|
||||
</ItemGroup>
|
||||
|
||||
+10
-23
@@ -7,16 +7,14 @@
|
||||
# in the COPYING file in the root directory of this source tree).
|
||||
# ################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
|
||||
|
||||
# As of 2018-12-26 ZSTD has been validated to build with cmake version 3.13.2 new policies.
|
||||
# Set and use the newest cmake policies that are validated to work
|
||||
set(ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION "3")
|
||||
set(ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION "13") #Policies never changed at PATCH level
|
||||
if("${CMAKE_MAJOR_VERSION}" LESS 3)
|
||||
set(ZSTD_CMAKE_POLICY_VERSION "${CMAKE_VERSION}")
|
||||
elseif( "${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}" EQUAL "${CMAKE_MAJOR_VERSION}" AND
|
||||
"${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}" GREATER "${CMAKE_MINOR_VERSION}")
|
||||
if("${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}" EQUAL "${CMAKE_MAJOR_VERSION}" AND
|
||||
"${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}" GREATER "${CMAKE_MINOR_VERSION}")
|
||||
set(ZSTD_CMAKE_POLICY_VERSION "${CMAKE_VERSION}")
|
||||
else()
|
||||
set(ZSTD_CMAKE_POLICY_VERSION "${ZSTD_MAX_VALIDATED_CMAKE_MAJOR_VERSION}.${ZSTD_MAX_VALIDATED_CMAKE_MINOR_VERSION}.0")
|
||||
@@ -32,24 +30,13 @@ set(LIBRARY_DIR ${ZSTD_SOURCE_DIR}/lib)
|
||||
include(GetZstdLibraryVersion)
|
||||
GetZstdLibraryVersion(${LIBRARY_DIR}/zstd.h zstd_VERSION_MAJOR zstd_VERSION_MINOR zstd_VERSION_PATCH)
|
||||
|
||||
if( CMAKE_MAJOR_VERSION LESS 3 )
|
||||
## Provide cmake 3+ behavior for older versions of cmake
|
||||
project(zstd)
|
||||
set(PROJECT_VERSION_MAJOR ${zstd_VERSION_MAJOR})
|
||||
set(PROJECT_VERSION_MINOR ${zstd_VERSION_MINOR})
|
||||
set(PROJECT_VERSION_PATCH ${zstd_VERSION_PATCH})
|
||||
set(PROJECT_VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}")
|
||||
enable_language(C) # Main library is in C
|
||||
enable_language(ASM) # And ASM
|
||||
enable_language(CXX) # Testing contributed code also utilizes CXX
|
||||
else()
|
||||
project(zstd
|
||||
VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}"
|
||||
LANGUAGES C # Main library is in C
|
||||
ASM # And ASM
|
||||
CXX # Testing contributed code also utilizes CXX
|
||||
)
|
||||
endif()
|
||||
project(zstd
|
||||
VERSION "${zstd_VERSION_MAJOR}.${zstd_VERSION_MINOR}.${zstd_VERSION_PATCH}"
|
||||
LANGUAGES C # Main library is in C
|
||||
ASM # And ASM
|
||||
CXX # Testing contributed code also utilizes CXX
|
||||
)
|
||||
|
||||
message(STATUS "ZSTD VERSION: ${zstd_VERSION}")
|
||||
set(zstd_HOMEPAGE_URL "https://facebook.github.io/zstd")
|
||||
set(zstd_DESCRIPTION "Zstandard is a real-time compression algorithm, providing high compression ratios.")
|
||||
|
||||
@@ -18,6 +18,7 @@ set(PZSTD_DIR ${ZSTD_SOURCE_DIR}/contrib/pzstd)
|
||||
include_directories(${PROGRAMS_DIR} ${LIBRARY_DIR} ${LIBRARY_DIR}/common ${PZSTD_DIR})
|
||||
|
||||
add_executable(pzstd ${PROGRAMS_DIR}/util.c ${PZSTD_DIR}/main.cpp ${PZSTD_DIR}/Options.cpp ${PZSTD_DIR}/Pzstd.cpp ${PZSTD_DIR}/SkippableFrame.cpp)
|
||||
target_compile_features(pzstd PRIVATE cxx_std_11)
|
||||
set_property(TARGET pzstd APPEND PROPERTY COMPILE_DEFINITIONS "NDEBUG")
|
||||
set_property(TARGET pzstd APPEND PROPERTY COMPILE_OPTIONS "-Wno-shadow")
|
||||
|
||||
|
||||
@@ -38,11 +38,15 @@ include_directories(${LIBRARY_DIR} ${LIBRARY_DIR}/common)
|
||||
|
||||
file(GLOB CommonSources ${LIBRARY_DIR}/common/*.c)
|
||||
file(GLOB CompressSources ${LIBRARY_DIR}/compress/*.c)
|
||||
file(GLOB DecompressSources ${LIBRARY_DIR}/decompress/*.c)
|
||||
if (MSVC)
|
||||
file(GLOB DecompressSources ${LIBRARY_DIR}/decompress/*.c)
|
||||
add_compile_options(-DZSTD_DISABLE_ASM)
|
||||
else ()
|
||||
file(GLOB DecompressSources ${LIBRARY_DIR}/decompress/*.c ${LIBRARY_DIR}/decompress/*.S)
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "amd64.*|AMD64.*|x86_64.*|X86_64.*")
|
||||
set(DecompressSources ${DecompressSources} ${LIBRARY_DIR}/decompress/huf_decompress_amd64.S)
|
||||
else()
|
||||
add_compile_options(-DZSTD_DISABLE_ASM)
|
||||
endif()
|
||||
endif ()
|
||||
file(GLOB DictBuilderSources ${LIBRARY_DIR}/dictBuilder/*.c)
|
||||
file(GLOB DeprecatedSources ${LIBRARY_DIR}/deprecated/*.c)
|
||||
|
||||
@@ -32,12 +32,7 @@ if (MSVC)
|
||||
set(PlatformDependResources ${MSVC_RESOURCE_DIR}/zstd.rc)
|
||||
endif ()
|
||||
|
||||
set(ZSTD_PROGRAM_SRCS ${PROGRAMS_DIR}/zstdcli.c ${PROGRAMS_DIR}/util.c
|
||||
${PROGRAMS_DIR}/timefn.c ${PROGRAMS_DIR}/fileio.c
|
||||
${PROGRAMS_DIR}/fileio_asyncio.c ${PROGRAMS_DIR}/benchfn.c
|
||||
${PROGRAMS_DIR}/benchzstd.c ${PROGRAMS_DIR}/datagen.c
|
||||
${PROGRAMS_DIR}/dibio.c ${PROGRAMS_DIR}/zstdcli_trace.c
|
||||
${PlatformDependResources})
|
||||
file(GLOB ZSTD_PROGRAM_SRCS "${PROGRAMS_DIR}/*.c")
|
||||
if (MSVC AND ZSTD_PROGRAMS_LINK_SHARED)
|
||||
list(APPEND ZSTD_PROGRAM_SRCS ${LIBRARY_DIR}/common/pool.c ${LIBRARY_DIR}/common/threading.c)
|
||||
endif ()
|
||||
|
||||
@@ -50,13 +50,13 @@ set(PROGRAMS_DIR ${ZSTD_SOURCE_DIR}/programs)
|
||||
set(TESTS_DIR ${ZSTD_SOURCE_DIR}/tests)
|
||||
include_directories(${TESTS_DIR} ${PROGRAMS_DIR} ${LIBRARY_DIR} ${LIBRARY_DIR}/common ${LIBRARY_DIR}/compress ${LIBRARY_DIR}/dictBuilder)
|
||||
|
||||
add_executable(datagen ${PROGRAMS_DIR}/datagen.c ${TESTS_DIR}/datagencli.c)
|
||||
add_executable(datagen ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/lorem.c ${TESTS_DIR}/loremOut.c ${TESTS_DIR}/datagencli.c)
|
||||
target_link_libraries(datagen libzstd_static)
|
||||
|
||||
#
|
||||
# fullbench
|
||||
#
|
||||
add_executable(fullbench ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${PROGRAMS_DIR}/benchfn.c ${PROGRAMS_DIR}/benchzstd.c ${TESTS_DIR}/fullbench.c)
|
||||
add_executable(fullbench ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/lorem.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${PROGRAMS_DIR}/benchfn.c ${PROGRAMS_DIR}/benchzstd.c ${TESTS_DIR}/fullbench.c)
|
||||
if (NOT MSVC)
|
||||
target_compile_options(fullbench PRIVATE "-Wno-deprecated-declarations")
|
||||
endif()
|
||||
@@ -110,7 +110,7 @@ endif()
|
||||
# Label the "Medium" set of tests (see TESTING.md)
|
||||
set_property(TEST fuzzer zstreamtest playTests APPEND PROPERTY LABELS Medium)
|
||||
|
||||
add_executable(paramgrill ${PROGRAMS_DIR}/benchfn.c ${PROGRAMS_DIR}/benchzstd.c ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${TESTS_DIR}/paramgrill.c)
|
||||
add_executable(paramgrill ${PROGRAMS_DIR}/benchfn.c ${PROGRAMS_DIR}/benchzstd.c ${PROGRAMS_DIR}/datagen.c ${PROGRAMS_DIR}/lorem.c ${PROGRAMS_DIR}/util.c ${PROGRAMS_DIR}/timefn.c ${TESTS_DIR}/paramgrill.c)
|
||||
if (UNIX)
|
||||
target_link_libraries(paramgrill libzstd_static m) #m is math library
|
||||
else()
|
||||
|
||||
@@ -18,6 +18,7 @@ zstd_programs_sources = [join_paths(zstd_rootdir, 'programs/zstdcli.c'),
|
||||
join_paths(zstd_rootdir, 'programs/benchfn.c'),
|
||||
join_paths(zstd_rootdir, 'programs/benchzstd.c'),
|
||||
join_paths(zstd_rootdir, 'programs/datagen.c'),
|
||||
join_paths(zstd_rootdir, 'programs/lorem.c'),
|
||||
join_paths(zstd_rootdir, 'programs/dibio.c'),
|
||||
join_paths(zstd_rootdir, 'programs/zstdcli_trace.c')]
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ DECODECORPUS_TESTTIME = '-T30'
|
||||
test_includes = [ include_directories(join_paths(zstd_rootdir, 'programs')) ]
|
||||
|
||||
testcommon_sources = [join_paths(zstd_rootdir, 'programs/datagen.c'),
|
||||
join_paths(zstd_rootdir, 'programs/lorem.c'),
|
||||
join_paths(zstd_rootdir, 'programs/util.c'),
|
||||
join_paths(zstd_rootdir, 'programs/timefn.c'),
|
||||
join_paths(zstd_rootdir, 'programs/benchfn.c'),
|
||||
@@ -43,7 +44,8 @@ testcommon_dep = declare_dependency(link_with: testcommon,
|
||||
dependencies: libzstd_deps,
|
||||
include_directories: libzstd_includes)
|
||||
|
||||
datagen_sources = [join_paths(zstd_rootdir, 'tests/datagencli.c')]
|
||||
datagen_sources = [join_paths(zstd_rootdir, 'tests/datagencli.c'),
|
||||
join_paths(zstd_rootdir, 'tests/loremOut.c')]
|
||||
datagen = executable('datagen',
|
||||
datagen_sources,
|
||||
c_args: [ '-DNDEBUG' ],
|
||||
|
||||
@@ -77,7 +77,7 @@ EXPORT_SYMBOL(zstd_init_dstream);
|
||||
|
||||
size_t zstd_reset_dstream(zstd_dstream *dstream)
|
||||
{
|
||||
return ZSTD_resetDStream(dstream);
|
||||
return ZSTD_DCtx_reset(dstream, ZSTD_reset_session_only);
|
||||
}
|
||||
EXPORT_SYMBOL(zstd_reset_dstream);
|
||||
|
||||
|
||||
@@ -115,11 +115,7 @@ static uint64_t ZSTD_div64(uint64_t dividend, uint32_t divisor) {
|
||||
#ifndef ZSTD_DEPS_STDINT
|
||||
#define ZSTD_DEPS_STDINT
|
||||
|
||||
/*
|
||||
* The Linux Kernel doesn't provide intptr_t, only uintptr_t, which
|
||||
* is an unsigned long.
|
||||
*/
|
||||
typedef long intptr_t;
|
||||
/* intptr_t already provided by ZSTD_DEPS_COMMON */
|
||||
|
||||
#endif /* ZSTD_DEPS_STDINT */
|
||||
#endif /* ZSTD_DEPS_NEED_STDINT */
|
||||
|
||||
@@ -1124,6 +1124,9 @@ When last symbol reaches cumulated total of `1 << Accuracy_Log`,
|
||||
decoding is complete.
|
||||
If the last symbol makes cumulated total go above `1 << Accuracy_Log`,
|
||||
distribution is considered corrupted.
|
||||
If this process results in a non-zero probability for a value outside of the
|
||||
valid range of values that the FSE table is defined for, even if that value is
|
||||
not used, then the data is considered corrupted.
|
||||
|
||||
Then the decoder can tell how many bytes were used in this process,
|
||||
and how many symbols are present.
|
||||
@@ -1252,7 +1255,9 @@ Number_of_Bits = Weight ? (Max_Number_of_Bits + 1 - Weight) : 0
|
||||
```
|
||||
When a literal value is not present, it receives a `Weight` of 0.
|
||||
The least frequent symbol receives a `Weight` of 1.
|
||||
Consequently, the `Weight` 1 is necessarily present.
|
||||
If no literal has a `Weight` of 1, then the data is considered corrupted.
|
||||
If there are not at least two literals with non-zero `Weight`, then the data
|
||||
is considered corrupted.
|
||||
The most frequent symbol receives a `Weight` anywhere between 1 and 11 (max).
|
||||
The last symbol's `Weight` is deduced from previously retrieved Weights,
|
||||
by completing to the nearest power of 2. It's necessarily non 0.
|
||||
@@ -1353,6 +1358,9 @@ If updating state after decoding a symbol would require more bits than
|
||||
remain in the stream, it is assumed that extra bits are 0. Then,
|
||||
symbols for each of the final states are decoded and the process is complete.
|
||||
|
||||
If this process would produce more weights than the maximum number of decoded
|
||||
weights (255), then the data is considered corrupted.
|
||||
|
||||
#### Conversion from weights to Huffman prefix codes
|
||||
|
||||
All present symbols shall now have a `Weight` value.
|
||||
|
||||
+44
-23
@@ -156,7 +156,7 @@ unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize);
|
||||
* for example to size a static array on stack.
|
||||
* Will produce constant value 0 if srcSize too large.
|
||||
*/
|
||||
#define ZSTD_MAX_INPUT_SIZE ((sizeof(size_t)==8) ? 0xFF00FF00FF00FF00LLU : 0xFF00FF00U)
|
||||
#define ZSTD_MAX_INPUT_SIZE ((sizeof(size_t)==8) ? 0xFF00FF00FF00FF00ULL : 0xFF00FF00U)
|
||||
#define ZSTD_COMPRESSBOUND(srcSize) (((size_t)(srcSize) >= ZSTD_MAX_INPUT_SIZE) ? 0 : (srcSize) + ((srcSize)>>8) + (((srcSize) < (128<<10)) ? (((128<<10) - (srcSize)) >> 11) </b>/* margin, from 64 to 0 */ : 0)) /* this formula ensures that bound(A) + bound(B) <= bound(A+B) as long as A and B >= 128 KB */<b>
|
||||
size_t ZSTD_compressBound(size_t srcSize); </b>/*!< maximum compressed size in worst case single-pass scenario */<b>
|
||||
</b>/* ZSTD_isError() :<b>
|
||||
@@ -513,6 +513,7 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); </b>/* accept NULL pointer */<b>
|
||||
* ZSTD_d_forceIgnoreChecksum
|
||||
* ZSTD_d_refMultipleDDicts
|
||||
* ZSTD_d_disableHuffmanAssembly
|
||||
* ZSTD_d_maxBlockSize
|
||||
* Because they are not stable, it's necessary to define ZSTD_STATIC_LINKING_ONLY to access them.
|
||||
* note : never ever use experimentalParam? names directly
|
||||
*/
|
||||
@@ -520,7 +521,8 @@ size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx); </b>/* accept NULL pointer */<b>
|
||||
ZSTD_d_experimentalParam2=1001,
|
||||
ZSTD_d_experimentalParam3=1002,
|
||||
ZSTD_d_experimentalParam4=1003,
|
||||
ZSTD_d_experimentalParam5=1004
|
||||
ZSTD_d_experimentalParam5=1004,
|
||||
ZSTD_d_experimentalParam6=1005
|
||||
|
||||
} ZSTD_dParameter;
|
||||
</b></pre><BR>
|
||||
@@ -1386,58 +1388,61 @@ ZSTD_compressSequences( ZSTD_CCtx* cctx, void* dst, size_t dstSize,
|
||||
|
||||
<a name="Chapter16"></a><h2>Memory management</h2><pre></pre>
|
||||
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize(int compressionLevel);
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize(int maxCompressionLevel);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateDCtxSize(void);
|
||||
</b><p> These functions make it possible to estimate memory usage
|
||||
of a future {D,C}Ctx, before its creation.
|
||||
This is useful in combination with ZSTD_initStatic(),
|
||||
which makes it possible to employ a static buffer for ZSTD_CCtx* state.
|
||||
|
||||
ZSTD_estimateCCtxSize() will provide a memory budget large enough
|
||||
for any compression level up to selected one.
|
||||
Note : Unlike ZSTD_estimateCStreamSize*(), this estimate
|
||||
does not include space for a window buffer.
|
||||
Therefore, the estimation is only guaranteed for single-shot compressions, not streaming.
|
||||
to compress data of any size using one-shot compression ZSTD_compressCCtx() or ZSTD_compress2()
|
||||
associated with any compression level up to max specified one.
|
||||
The estimate will assume the input may be arbitrarily large,
|
||||
which is the worst case.
|
||||
|
||||
Note that the size estimation is specific for one-shot compression,
|
||||
it is not valid for streaming (see ZSTD_estimateCStreamSize*())
|
||||
nor other potential ways of using a ZSTD_CCtx* state.
|
||||
|
||||
When srcSize can be bound by a known and rather "small" value,
|
||||
this fact can be used to provide a tighter estimation
|
||||
because the CCtx compression context will need less memory.
|
||||
This tighter estimation can be provided by more advanced functions
|
||||
this knowledge can be used to provide a tighter budget estimation
|
||||
because the ZSTD_CCtx* state will need less memory for small inputs.
|
||||
This tighter estimation can be provided by employing more advanced functions
|
||||
ZSTD_estimateCCtxSize_usingCParams(), which can be used in tandem with ZSTD_getCParams(),
|
||||
and ZSTD_estimateCCtxSize_usingCCtxParams(), which can be used in tandem with ZSTD_CCtxParams_setParameter().
|
||||
Both can be used to estimate memory using custom compression parameters and arbitrary srcSize limits.
|
||||
|
||||
Note : only single-threaded compression is supported.
|
||||
ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1.
|
||||
|
||||
Note 2 : ZSTD_estimateCCtxSize* functions are not compatible with the Block-Level Sequence Producer API at this time.
|
||||
Size estimates assume that no external sequence producer is registered.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize(int compressionLevel);
|
||||
<pre><b>ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize(int maxCompressionLevel);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize(size_t windowSize);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize(size_t maxWindowSize);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize);
|
||||
</b><p> ZSTD_estimateCStreamSize() will provide a budget large enough for any compression level up to selected one.
|
||||
It will also consider src size to be arbitrarily "large", which is worst case.
|
||||
</b><p> ZSTD_estimateCStreamSize() will provide a memory budget large enough for streaming compression
|
||||
using any compression level up to the max specified one.
|
||||
It will also consider src size to be arbitrarily "large", which is a worst case scenario.
|
||||
If srcSize is known to always be small, ZSTD_estimateCStreamSize_usingCParams() can provide a tighter estimation.
|
||||
ZSTD_estimateCStreamSize_usingCParams() can be used in tandem with ZSTD_getCParams() to create cParams from compressionLevel.
|
||||
ZSTD_estimateCStreamSize_usingCCtxParams() can be used in tandem with ZSTD_CCtxParams_setParameter(). Only single-threaded compression is supported. This function will return an error code if ZSTD_c_nbWorkers is >= 1.
|
||||
Note : CStream size estimation is only correct for single-threaded compression.
|
||||
ZSTD_DStream memory budget depends on window Size.
|
||||
ZSTD_estimateCStreamSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1.
|
||||
Note 2 : ZSTD_estimateCStreamSize* functions are not compatible with the Block-Level Sequence Producer API at this time.
|
||||
Size estimates assume that no external sequence producer is registered.
|
||||
|
||||
ZSTD_DStream memory budget depends on frame's window Size.
|
||||
This information can be passed manually, using ZSTD_estimateDStreamSize,
|
||||
or deducted from a valid frame Header, using ZSTD_estimateDStreamSize_fromFrame();
|
||||
Any frame requesting a window size larger than max specified one will be rejected.
|
||||
Note : if streaming is init with function ZSTD_init?Stream_usingDict(),
|
||||
an internal ?Dict will be created, which additional size is not estimated here.
|
||||
In this case, get total size by adding ZSTD_estimate?DictSize
|
||||
Note 2 : only single-threaded compression is supported.
|
||||
ZSTD_estimateCStreamSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1.
|
||||
Note 3 : ZSTD_estimateCStreamSize* functions are not compatible with the Block-Level Sequence Producer API at this time.
|
||||
Size estimates assume that no external sequence producer is registered.
|
||||
|
||||
</p></pre><BR>
|
||||
|
||||
@@ -1926,7 +1931,7 @@ ZSTDLIB_STATIC_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);
|
||||
ZSTD_registerSequenceProducer(
|
||||
ZSTD_CCtx* cctx,
|
||||
void* sequenceProducerState,
|
||||
ZSTD_sequenceProducer_F* sequenceProducer
|
||||
ZSTD_sequenceProducer_F sequenceProducer
|
||||
);
|
||||
</b><p> Instruct zstd to use a block-level external sequence producer function.
|
||||
|
||||
@@ -1948,6 +1953,22 @@ ZSTD_registerSequenceProducer(
|
||||
calling this function.
|
||||
</p></pre><BR>
|
||||
|
||||
<pre><b>ZSTDLIB_STATIC_API void
|
||||
ZSTD_CCtxParams_registerSequenceProducer(
|
||||
ZSTD_CCtx_params* params,
|
||||
void* sequenceProducerState,
|
||||
ZSTD_sequenceProducer_F sequenceProducer
|
||||
);
|
||||
</b><p> Same as ZSTD_registerSequenceProducer(), but operates on ZSTD_CCtx_params.
|
||||
This is used for accurate size estimation with ZSTD_estimateCCtxSize_usingCCtxParams(),
|
||||
which is needed when creating a ZSTD_CCtx with ZSTD_initStaticCCtx().
|
||||
|
||||
If you are using the external sequence producer API in a scenario where ZSTD_initStaticCCtx()
|
||||
is required, then this function is for you. Otherwise, you probably don't need it.
|
||||
|
||||
See tests/zstreamtest.c for example usage.
|
||||
</p></pre><BR>
|
||||
|
||||
<a name="Chapter20"></a><h2>Buffer-less and synchronous inner streaming functions (DEPRECATED)</h2><pre>
|
||||
This API is deprecated, and will be removed in a future version.
|
||||
It allows streaming (de)compression with user allocated buffers.
|
||||
|
||||
@@ -178,6 +178,10 @@ The file structure is designed to make this selection manually achievable for an
|
||||
`ZSTDERRORLIB_VSIBILITY`, and `ZDICTLIB_VISIBILITY` if unset, for backwards compatibility
|
||||
with the old macro names.
|
||||
|
||||
- The C compiler macro `HUF_DISABLE_FAST_DECODE` disables the newer Huffman fast C
|
||||
and assembly decoding loops. You may want to use this macro if these loops are
|
||||
slower on your platform.
|
||||
|
||||
#### Windows : using MinGW+MSYS to create DLL
|
||||
|
||||
DLL can be created using MinGW+MSYS with the `make libzstd` command.
|
||||
|
||||
+17
-16
@@ -132,8 +132,8 @@
|
||||
/* prefetch
|
||||
* can be disabled, by declaring NO_PREFETCH build macro */
|
||||
#if defined(NO_PREFETCH)
|
||||
# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
|
||||
# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
|
||||
# define PREFETCH_L1(ptr) do { (void)(ptr); } while (0) /* disabled */
|
||||
# define PREFETCH_L2(ptr) do { (void)(ptr); } while (0) /* disabled */
|
||||
#else
|
||||
# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) && !defined(_M_ARM64EC) /* _mm_prefetch() is not defined outside of x86/x64 */
|
||||
# include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
|
||||
@@ -143,24 +143,25 @@
|
||||
# define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
|
||||
# define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
|
||||
# elif defined(__aarch64__)
|
||||
# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr)))
|
||||
# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr)))
|
||||
# define PREFETCH_L1(ptr) do { __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))); } while (0)
|
||||
# define PREFETCH_L2(ptr) do { __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))); } while (0)
|
||||
# else
|
||||
# define PREFETCH_L1(ptr) (void)(ptr) /* disabled */
|
||||
# define PREFETCH_L2(ptr) (void)(ptr) /* disabled */
|
||||
# define PREFETCH_L1(ptr) do { (void)(ptr); } while (0) /* disabled */
|
||||
# define PREFETCH_L2(ptr) do { (void)(ptr); } while (0) /* disabled */
|
||||
# endif
|
||||
#endif /* NO_PREFETCH */
|
||||
|
||||
#define CACHELINE_SIZE 64
|
||||
|
||||
#define PREFETCH_AREA(p, s) { \
|
||||
const char* const _ptr = (const char*)(p); \
|
||||
size_t const _size = (size_t)(s); \
|
||||
size_t _pos; \
|
||||
for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \
|
||||
PREFETCH_L2(_ptr + _pos); \
|
||||
} \
|
||||
}
|
||||
#define PREFETCH_AREA(p, s) \
|
||||
do { \
|
||||
const char* const _ptr = (const char*)(p); \
|
||||
size_t const _size = (size_t)(s); \
|
||||
size_t _pos; \
|
||||
for (_pos=0; _pos<_size; _pos+=CACHELINE_SIZE) { \
|
||||
PREFETCH_L2(_ptr + _pos); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* vectorization
|
||||
* older GCC (pre gcc-4.3 picked as the cutoff) uses a different syntax,
|
||||
@@ -189,9 +190,9 @@
|
||||
#endif
|
||||
|
||||
#if __has_builtin(__builtin_unreachable) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)))
|
||||
# define ZSTD_UNREACHABLE { assert(0), __builtin_unreachable(); }
|
||||
# define ZSTD_UNREACHABLE do { assert(0), __builtin_unreachable(); } while (0)
|
||||
#else
|
||||
# define ZSTD_UNREACHABLE { assert(0); }
|
||||
# define ZSTD_UNREACHABLE do { assert(0); } while (0)
|
||||
#endif
|
||||
|
||||
/* disable warnings */
|
||||
|
||||
@@ -21,4 +21,10 @@
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#if !defined(ZSTD_LINUX_KERNEL) || (DEBUGLEVEL>=2)
|
||||
/* We only use this when DEBUGLEVEL>=2, but we get -Werror=pedantic errors if a
|
||||
* translation unit is empty. So remove this from Linux kernel builds, but
|
||||
* otherwise just leave it in.
|
||||
*/
|
||||
int g_debuglevel = DEBUGLEVEL;
|
||||
#endif
|
||||
|
||||
+16
-11
@@ -85,18 +85,23 @@ extern int g_debuglevel; /* the variable is only declared,
|
||||
It's useful when enabling very verbose levels
|
||||
on selective conditions (such as position in src) */
|
||||
|
||||
# define RAWLOG(l, ...) { \
|
||||
if (l<=g_debuglevel) { \
|
||||
ZSTD_DEBUG_PRINT(__VA_ARGS__); \
|
||||
} }
|
||||
# define DEBUGLOG(l, ...) { \
|
||||
if (l<=g_debuglevel) { \
|
||||
ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \
|
||||
ZSTD_DEBUG_PRINT(" \n"); \
|
||||
} }
|
||||
# define RAWLOG(l, ...) \
|
||||
do { \
|
||||
if (l<=g_debuglevel) { \
|
||||
ZSTD_DEBUG_PRINT(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
# define DEBUGLOG(l, ...) \
|
||||
do { \
|
||||
if (l<=g_debuglevel) { \
|
||||
ZSTD_DEBUG_PRINT(__FILE__ ": " __VA_ARGS__); \
|
||||
ZSTD_DEBUG_PRINT(" \n"); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
# define RAWLOG(l, ...) {} /* disabled */
|
||||
# define DEBUGLOG(l, ...) {} /* disabled */
|
||||
# define RAWLOG(l, ...) do { } while (0) /* disabled */
|
||||
# define DEBUGLOG(l, ...) do { } while (0) /* disabled */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+45
-36
@@ -60,8 +60,13 @@ ERR_STATIC unsigned ERR_isError(size_t code) { return (code > ERROR(maxCode)); }
|
||||
ERR_STATIC ERR_enum ERR_getErrorCode(size_t code) { if (!ERR_isError(code)) return (ERR_enum)0; return (ERR_enum) (0-code); }
|
||||
|
||||
/* check and forward error code */
|
||||
#define CHECK_V_F(e, f) size_t const e = f; if (ERR_isError(e)) return e
|
||||
#define CHECK_F(f) { CHECK_V_F(_var_err__, f); }
|
||||
#define CHECK_V_F(e, f) \
|
||||
size_t const e = f; \
|
||||
do { \
|
||||
if (ERR_isError(e)) \
|
||||
return e; \
|
||||
} while (0)
|
||||
#define CHECK_F(f) do { CHECK_V_F(_var_err__, f); } while (0)
|
||||
|
||||
|
||||
/*-****************************************
|
||||
@@ -95,10 +100,12 @@ void _force_has_format_string(const char *format, ...) {
|
||||
* We want to force this function invocation to be syntactically correct, but
|
||||
* we don't want to force runtime evaluation of its arguments.
|
||||
*/
|
||||
#define _FORCE_HAS_FORMAT_STRING(...) \
|
||||
if (0) { \
|
||||
_force_has_format_string(__VA_ARGS__); \
|
||||
}
|
||||
#define _FORCE_HAS_FORMAT_STRING(...) \
|
||||
do { \
|
||||
if (0) { \
|
||||
_force_has_format_string(__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ERR_QUOTE(str) #str
|
||||
|
||||
@@ -109,48 +116,50 @@ void _force_has_format_string(const char *format, ...) {
|
||||
* In order to do that (particularly, printing the conditional that failed),
|
||||
* this can't just wrap RETURN_ERROR().
|
||||
*/
|
||||
#define RETURN_ERROR_IF(cond, err, ...) \
|
||||
if (cond) { \
|
||||
RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \
|
||||
__FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \
|
||||
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||
RAWLOG(3, ": " __VA_ARGS__); \
|
||||
RAWLOG(3, "\n"); \
|
||||
return ERROR(err); \
|
||||
}
|
||||
#define RETURN_ERROR_IF(cond, err, ...) \
|
||||
do { \
|
||||
if (cond) { \
|
||||
RAWLOG(3, "%s:%d: ERROR!: check %s failed, returning %s", \
|
||||
__FILE__, __LINE__, ERR_QUOTE(cond), ERR_QUOTE(ERROR(err))); \
|
||||
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||
RAWLOG(3, ": " __VA_ARGS__); \
|
||||
RAWLOG(3, "\n"); \
|
||||
return ERROR(err); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Unconditionally return the specified error.
|
||||
*
|
||||
* In debug modes, prints additional information.
|
||||
*/
|
||||
#define RETURN_ERROR(err, ...) \
|
||||
do { \
|
||||
RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \
|
||||
__FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \
|
||||
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||
RAWLOG(3, ": " __VA_ARGS__); \
|
||||
RAWLOG(3, "\n"); \
|
||||
return ERROR(err); \
|
||||
} while(0);
|
||||
#define RETURN_ERROR(err, ...) \
|
||||
do { \
|
||||
RAWLOG(3, "%s:%d: ERROR!: unconditional check failed, returning %s", \
|
||||
__FILE__, __LINE__, ERR_QUOTE(ERROR(err))); \
|
||||
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||
RAWLOG(3, ": " __VA_ARGS__); \
|
||||
RAWLOG(3, "\n"); \
|
||||
return ERROR(err); \
|
||||
} while(0)
|
||||
|
||||
/**
|
||||
* If the provided expression evaluates to an error code, returns that error code.
|
||||
*
|
||||
* In debug modes, prints additional information.
|
||||
*/
|
||||
#define FORWARD_IF_ERROR(err, ...) \
|
||||
do { \
|
||||
size_t const err_code = (err); \
|
||||
if (ERR_isError(err_code)) { \
|
||||
RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \
|
||||
__FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \
|
||||
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||
RAWLOG(3, ": " __VA_ARGS__); \
|
||||
RAWLOG(3, "\n"); \
|
||||
return err_code; \
|
||||
} \
|
||||
} while(0);
|
||||
#define FORWARD_IF_ERROR(err, ...) \
|
||||
do { \
|
||||
size_t const err_code = (err); \
|
||||
if (ERR_isError(err_code)) { \
|
||||
RAWLOG(3, "%s:%d: ERROR!: forwarding error in %s: %s", \
|
||||
__FILE__, __LINE__, ERR_QUOTE(err), ERR_getErrorName(err_code)); \
|
||||
_FORCE_HAS_FORMAT_STRING(__VA_ARGS__); \
|
||||
RAWLOG(3, ": " __VA_ARGS__); \
|
||||
RAWLOG(3, "\n"); \
|
||||
return err_code; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
|
||||
+1
-1
@@ -223,7 +223,7 @@ static int POOL_resize_internal(POOL_ctx* ctx, size_t numThreads)
|
||||
{ ZSTD_pthread_t* const threadPool = (ZSTD_pthread_t*)ZSTD_customCalloc(numThreads * sizeof(ZSTD_pthread_t), ctx->customMem);
|
||||
if (!threadPool) return 1;
|
||||
/* replace existing thread pool */
|
||||
ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(*threadPool));
|
||||
ZSTD_memcpy(threadPool, ctx->threads, ctx->threadCapacity * sizeof(ZSTD_pthread_t));
|
||||
ZSTD_customFree(ctx->threads, ctx->customMem);
|
||||
ctx->threads = threadPool;
|
||||
/* Initialize additional threads */
|
||||
|
||||
+5
-11
@@ -1,24 +1,18 @@
|
||||
/*
|
||||
* xxHash - Fast Hash algorithm
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* You can contact the author at :
|
||||
* - xxHash homepage: https://cyan4973.github.io/xxHash/
|
||||
* - xxHash source repository : https://github.com/Cyan4973/xxHash
|
||||
* xxHash - Extremely Fast Hash algorithm
|
||||
* Copyright (c) Yann Collet - Meta Platforms, Inc
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* xxhash.c instantiates functions defined in xxhash.h
|
||||
*/
|
||||
|
||||
#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */
|
||||
#define XXH_IMPLEMENTATION /* access definitions */
|
||||
#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */
|
||||
#define XXH_IMPLEMENTATION /* access definitions */
|
||||
|
||||
#include "xxhash.h"
|
||||
|
||||
+2295
-990
@@ -1,17 +1,15 @@
|
||||
/*
|
||||
* xxHash - Fast Hash algorithm
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* You can contact the author at :
|
||||
* - xxHash homepage: https://cyan4973.github.io/xxHash/
|
||||
* - xxHash source repository : https://github.com/Cyan4973/xxHash
|
||||
* xxHash - Extremely Fast Hash algorithm
|
||||
* Header File
|
||||
* Copyright (c) Yann Collet - Meta Platforms, Inc
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
*/
|
||||
|
||||
/* Local adaptations for Zstandard */
|
||||
|
||||
#ifndef XXH_NO_XXH3
|
||||
# define XXH_NO_XXH3
|
||||
@@ -24,46 +22,210 @@
|
||||
/*!
|
||||
* @mainpage xxHash
|
||||
*
|
||||
* xxHash is an extremely fast non-cryptographic hash algorithm, working at RAM speed
|
||||
* limits.
|
||||
*
|
||||
* It is proposed in four flavors, in three families:
|
||||
* 1. @ref XXH32_family
|
||||
* - Classic 32-bit hash function. Simple, compact, and runs on almost all
|
||||
* 32-bit and 64-bit systems.
|
||||
* 2. @ref XXH64_family
|
||||
* - Classic 64-bit adaptation of XXH32. Just as simple, and runs well on most
|
||||
* 64-bit systems (but _not_ 32-bit systems).
|
||||
* 3. @ref XXH3_family
|
||||
* - Modern 64-bit and 128-bit hash function family which features improved
|
||||
* strength and performance across the board, especially on smaller data.
|
||||
* It benefits greatly from SIMD and 64-bit without requiring it.
|
||||
*
|
||||
* Benchmarks
|
||||
* ---
|
||||
* The reference system uses an Intel i7-9700K CPU, and runs Ubuntu x64 20.04.
|
||||
* The open source benchmark program is compiled with clang v10.0 using -O3 flag.
|
||||
*
|
||||
* | Hash Name | ISA ext | Width | Large Data Speed | Small Data Velocity |
|
||||
* | -------------------- | ------- | ----: | ---------------: | ------------------: |
|
||||
* | XXH3_64bits() | @b AVX2 | 64 | 59.4 GB/s | 133.1 |
|
||||
* | MeowHash | AES-NI | 128 | 58.2 GB/s | 52.5 |
|
||||
* | XXH3_128bits() | @b AVX2 | 128 | 57.9 GB/s | 118.1 |
|
||||
* | CLHash | PCLMUL | 64 | 37.1 GB/s | 58.1 |
|
||||
* | XXH3_64bits() | @b SSE2 | 64 | 31.5 GB/s | 133.1 |
|
||||
* | XXH3_128bits() | @b SSE2 | 128 | 29.6 GB/s | 118.1 |
|
||||
* | RAM sequential read | | N/A | 28.0 GB/s | N/A |
|
||||
* | ahash | AES-NI | 64 | 22.5 GB/s | 107.2 |
|
||||
* | City64 | | 64 | 22.0 GB/s | 76.6 |
|
||||
* | T1ha2 | | 64 | 22.0 GB/s | 99.0 |
|
||||
* | City128 | | 128 | 21.7 GB/s | 57.7 |
|
||||
* | FarmHash | AES-NI | 64 | 21.3 GB/s | 71.9 |
|
||||
* | XXH64() | | 64 | 19.4 GB/s | 71.0 |
|
||||
* | SpookyHash | | 64 | 19.3 GB/s | 53.2 |
|
||||
* | Mum | | 64 | 18.0 GB/s | 67.0 |
|
||||
* | CRC32C | SSE4.2 | 32 | 13.0 GB/s | 57.9 |
|
||||
* | XXH32() | | 32 | 9.7 GB/s | 71.9 |
|
||||
* | City32 | | 32 | 9.1 GB/s | 66.0 |
|
||||
* | Blake3* | @b AVX2 | 256 | 4.4 GB/s | 8.1 |
|
||||
* | Murmur3 | | 32 | 3.9 GB/s | 56.1 |
|
||||
* | SipHash* | | 64 | 3.0 GB/s | 43.2 |
|
||||
* | Blake3* | @b SSE2 | 256 | 2.4 GB/s | 8.1 |
|
||||
* | HighwayHash | | 64 | 1.4 GB/s | 6.0 |
|
||||
* | FNV64 | | 64 | 1.2 GB/s | 62.7 |
|
||||
* | Blake2* | | 256 | 1.1 GB/s | 5.1 |
|
||||
* | SHA1* | | 160 | 0.8 GB/s | 5.6 |
|
||||
* | MD5* | | 128 | 0.6 GB/s | 7.8 |
|
||||
* @note
|
||||
* - Hashes which require a specific ISA extension are noted. SSE2 is also noted,
|
||||
* even though it is mandatory on x64.
|
||||
* - Hashes with an asterisk are cryptographic. Note that MD5 is non-cryptographic
|
||||
* by modern standards.
|
||||
* - Small data velocity is a rough average of algorithm's efficiency for small
|
||||
* data. For more accurate information, see the wiki.
|
||||
* - More benchmarks and strength tests are found on the wiki:
|
||||
* https://github.com/Cyan4973/xxHash/wiki
|
||||
*
|
||||
* Usage
|
||||
* ------
|
||||
* All xxHash variants use a similar API. Changing the algorithm is a trivial
|
||||
* substitution.
|
||||
*
|
||||
* @pre
|
||||
* For functions which take an input and length parameter, the following
|
||||
* requirements are assumed:
|
||||
* - The range from [`input`, `input + length`) is valid, readable memory.
|
||||
* - The only exception is if the `length` is `0`, `input` may be `NULL`.
|
||||
* - For C++, the objects must have the *TriviallyCopyable* property, as the
|
||||
* functions access bytes directly as if it was an array of `unsigned char`.
|
||||
*
|
||||
* @anchor single_shot_example
|
||||
* **Single Shot**
|
||||
*
|
||||
* These functions are stateless functions which hash a contiguous block of memory,
|
||||
* immediately returning the result. They are the easiest and usually the fastest
|
||||
* option.
|
||||
*
|
||||
* XXH32(), XXH64(), XXH3_64bits(), XXH3_128bits()
|
||||
*
|
||||
* @code{.c}
|
||||
* #include <string.h>
|
||||
* #include "xxhash.h"
|
||||
*
|
||||
* // Example for a function which hashes a null terminated string with XXH32().
|
||||
* XXH32_hash_t hash_string(const char* string, XXH32_hash_t seed)
|
||||
* {
|
||||
* // NULL pointers are only valid if the length is zero
|
||||
* size_t length = (string == NULL) ? 0 : strlen(string);
|
||||
* return XXH32(string, length, seed);
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* @anchor streaming_example
|
||||
* **Streaming**
|
||||
*
|
||||
* These groups of functions allow incremental hashing of unknown size, even
|
||||
* more than what would fit in a size_t.
|
||||
*
|
||||
* XXH32_reset(), XXH64_reset(), XXH3_64bits_reset(), XXH3_128bits_reset()
|
||||
*
|
||||
* @code{.c}
|
||||
* #include <stdio.h>
|
||||
* #include <assert.h>
|
||||
* #include "xxhash.h"
|
||||
* // Example for a function which hashes a FILE incrementally with XXH3_64bits().
|
||||
* XXH64_hash_t hashFile(FILE* f)
|
||||
* {
|
||||
* // Allocate a state struct. Do not just use malloc() or new.
|
||||
* XXH3_state_t* state = XXH3_createState();
|
||||
* assert(state != NULL && "Out of memory!");
|
||||
* // Reset the state to start a new hashing session.
|
||||
* XXH3_64bits_reset(state);
|
||||
* char buffer[4096];
|
||||
* size_t count;
|
||||
* // Read the file in chunks
|
||||
* while ((count = fread(buffer, 1, sizeof(buffer), f)) != 0) {
|
||||
* // Run update() as many times as necessary to process the data
|
||||
* XXH3_64bits_update(state, buffer, count);
|
||||
* }
|
||||
* // Retrieve the finalized hash. This will not change the state.
|
||||
* XXH64_hash_t result = XXH3_64bits_digest(state);
|
||||
* // Free the state. Do not use free().
|
||||
* XXH3_freeState(state);
|
||||
* return result;
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* Streaming functions generate the xxHash value from an incremental input.
|
||||
* This method is slower than single-call functions, due to state management.
|
||||
* For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized.
|
||||
*
|
||||
* An XXH state must first be allocated using `XXH*_createState()`.
|
||||
*
|
||||
* Start a new hash by initializing the state with a seed using `XXH*_reset()`.
|
||||
*
|
||||
* Then, feed the hash state by calling `XXH*_update()` as many times as necessary.
|
||||
*
|
||||
* The function returns an error code, with 0 meaning OK, and any other value
|
||||
* meaning there is an error.
|
||||
*
|
||||
* Finally, a hash value can be produced anytime, by using `XXH*_digest()`.
|
||||
* This function returns the nn-bits hash as an int or long long.
|
||||
*
|
||||
* It's still possible to continue inserting input into the hash state after a
|
||||
* digest, and generate new hash values later on by invoking `XXH*_digest()`.
|
||||
*
|
||||
* When done, release the state using `XXH*_freeState()`.
|
||||
*
|
||||
*
|
||||
* @anchor canonical_representation_example
|
||||
* **Canonical Representation**
|
||||
*
|
||||
* The default return values from XXH functions are unsigned 32, 64 and 128 bit
|
||||
* integers.
|
||||
* This the simplest and fastest format for further post-processing.
|
||||
*
|
||||
* However, this leaves open the question of what is the order on the byte level,
|
||||
* since little and big endian conventions will store the same number differently.
|
||||
*
|
||||
* The canonical representation settles this issue by mandating big-endian
|
||||
* convention, the same convention as human-readable numbers (large digits first).
|
||||
*
|
||||
* When writing hash values to storage, sending them over a network, or printing
|
||||
* them, it's highly recommended to use the canonical representation to ensure
|
||||
* portability across a wider range of systems, present and future.
|
||||
*
|
||||
* The following functions allow transformation of hash values to and from
|
||||
* canonical format.
|
||||
*
|
||||
* XXH32_canonicalFromHash(), XXH32_hashFromCanonical(),
|
||||
* XXH64_canonicalFromHash(), XXH64_hashFromCanonical(),
|
||||
* XXH128_canonicalFromHash(), XXH128_hashFromCanonical(),
|
||||
*
|
||||
* @code{.c}
|
||||
* #include <stdio.h>
|
||||
* #include "xxhash.h"
|
||||
*
|
||||
* // Example for a function which prints XXH32_hash_t in human readable format
|
||||
* void printXxh32(XXH32_hash_t hash)
|
||||
* {
|
||||
* XXH32_canonical_t cano;
|
||||
* XXH32_canonicalFromHash(&cano, hash);
|
||||
* size_t i;
|
||||
* for(i = 0; i < sizeof(cano.digest); ++i) {
|
||||
* printf("%02x", cano.digest[i]);
|
||||
* }
|
||||
* printf("\n");
|
||||
* }
|
||||
*
|
||||
* // Example for a function which converts XXH32_canonical_t to XXH32_hash_t
|
||||
* XXH32_hash_t convertCanonicalToXxh32(XXH32_canonical_t cano)
|
||||
* {
|
||||
* XXH32_hash_t hash = XXH32_hashFromCanonical(&cano);
|
||||
* return hash;
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
*
|
||||
* @file xxhash.h
|
||||
* xxHash prototypes and implementation
|
||||
*/
|
||||
/* TODO: update */
|
||||
/* Notice extracted from xxHash homepage:
|
||||
|
||||
xxHash is an extremely fast hash algorithm, running at RAM speed limits.
|
||||
It also successfully passes all tests from the SMHasher suite.
|
||||
|
||||
Comparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)
|
||||
|
||||
Name Speed Q.Score Author
|
||||
xxHash 5.4 GB/s 10
|
||||
CrapWow 3.2 GB/s 2 Andrew
|
||||
MurmurHash 3a 2.7 GB/s 10 Austin Appleby
|
||||
SpookyHash 2.0 GB/s 10 Bob Jenkins
|
||||
SBox 1.4 GB/s 9 Bret Mulvey
|
||||
Lookup3 1.2 GB/s 9 Bob Jenkins
|
||||
SuperFastHash 1.2 GB/s 1 Paul Hsieh
|
||||
CityHash64 1.05 GB/s 10 Pike & Alakuijala
|
||||
FNV 0.55 GB/s 5 Fowler, Noll, Vo
|
||||
CRC32 0.43 GB/s 9
|
||||
MD5-32 0.33 GB/s 10 Ronald L. Rivest
|
||||
SHA1-32 0.28 GB/s 10
|
||||
|
||||
Q.Score is a measure of quality of the hash function.
|
||||
It depends on successfully passing SMHasher test set.
|
||||
10 is a perfect score.
|
||||
|
||||
Note: SMHasher's CRC32 implementation is not the fastest one.
|
||||
Other speed-oriented implementations can be faster,
|
||||
especially in combination with PCLMUL instruction:
|
||||
https://fastcompression.blogspot.com/2019/03/presenting-xxh3.html?showComment=1552696407071#c3490092340461170735
|
||||
|
||||
A 64-bit version, named XXH64, is available since r35.
|
||||
It offers much better speed, but for 64-bit applications only.
|
||||
Name Speed on 64 bits Speed on 32 bits
|
||||
XXH64 13.8 GB/s 1.9 GB/s
|
||||
XXH32 6.8 GB/s 6.0 GB/s
|
||||
*/
|
||||
|
||||
#if defined (__cplusplus)
|
||||
extern "C" {
|
||||
@@ -73,21 +235,80 @@ extern "C" {
|
||||
* INLINE mode
|
||||
******************************/
|
||||
/*!
|
||||
* XXH_INLINE_ALL (and XXH_PRIVATE_API)
|
||||
* @defgroup public Public API
|
||||
* Contains details on the public xxHash functions.
|
||||
* @{
|
||||
*/
|
||||
#ifdef XXH_DOXYGEN
|
||||
/*!
|
||||
* @brief Gives access to internal state declaration, required for static allocation.
|
||||
*
|
||||
* Incompatible with dynamic linking, due to risks of ABI changes.
|
||||
*
|
||||
* Usage:
|
||||
* @code{.c}
|
||||
* #define XXH_STATIC_LINKING_ONLY
|
||||
* #include "xxhash.h"
|
||||
* @endcode
|
||||
*/
|
||||
# define XXH_STATIC_LINKING_ONLY
|
||||
/* Do not undef XXH_STATIC_LINKING_ONLY for Doxygen */
|
||||
|
||||
/*!
|
||||
* @brief Gives access to internal definitions.
|
||||
*
|
||||
* Usage:
|
||||
* @code{.c}
|
||||
* #define XXH_STATIC_LINKING_ONLY
|
||||
* #define XXH_IMPLEMENTATION
|
||||
* #include "xxhash.h"
|
||||
* @endcode
|
||||
*/
|
||||
# define XXH_IMPLEMENTATION
|
||||
/* Do not undef XXH_IMPLEMENTATION for Doxygen */
|
||||
|
||||
/*!
|
||||
* @brief Exposes the implementation and marks all functions as `inline`.
|
||||
*
|
||||
* Use these build macros to inline xxhash into the target unit.
|
||||
* Inlining improves performance on small inputs, especially when the length is
|
||||
* expressed as a compile-time constant:
|
||||
*
|
||||
* https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html
|
||||
* https://fastcompression.blogspot.com/2018/03/xxhash-for-small-keys-impressive-power.html
|
||||
*
|
||||
* It also keeps xxHash symbols private to the unit, so they are not exported.
|
||||
*
|
||||
* Usage:
|
||||
* @code{.c}
|
||||
* #define XXH_INLINE_ALL
|
||||
* #include "xxhash.h"
|
||||
*
|
||||
* @endcode
|
||||
* Do not compile and link xxhash.o as a separate object, as it is not useful.
|
||||
*/
|
||||
# define XXH_INLINE_ALL
|
||||
# undef XXH_INLINE_ALL
|
||||
/*!
|
||||
* @brief Exposes the implementation without marking functions as inline.
|
||||
*/
|
||||
# define XXH_PRIVATE_API
|
||||
# undef XXH_PRIVATE_API
|
||||
/*!
|
||||
* @brief Emulate a namespace by transparently prefixing all symbols.
|
||||
*
|
||||
* If you want to include _and expose_ xxHash functions from within your own
|
||||
* library, but also want to avoid symbol collisions with other libraries which
|
||||
* may also include xxHash, you can use @ref XXH_NAMESPACE to automatically prefix
|
||||
* any public symbol from xxhash library with the value of @ref XXH_NAMESPACE
|
||||
* (therefore, avoid empty or numeric values).
|
||||
*
|
||||
* Note that no change is required within the calling program as long as it
|
||||
* includes `xxhash.h`: Regular symbol names will be automatically translated
|
||||
* by this header.
|
||||
*/
|
||||
# define XXH_NAMESPACE /* YOUR NAME HERE */
|
||||
# undef XXH_NAMESPACE
|
||||
#endif
|
||||
|
||||
#if (defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)) \
|
||||
&& !defined(XXH_INLINE_ALL_31684351384)
|
||||
/* this section should be traversed only once */
|
||||
@@ -202,21 +423,13 @@ extern "C" {
|
||||
# undef XXHASH_H_STATIC_13879238742
|
||||
#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */
|
||||
|
||||
|
||||
|
||||
/* ****************************************************************
|
||||
* Stable API
|
||||
*****************************************************************/
|
||||
#ifndef XXHASH_H_5627135585666179
|
||||
#define XXHASH_H_5627135585666179 1
|
||||
|
||||
|
||||
/*!
|
||||
* @defgroup public Public API
|
||||
* Contains details on the public xxHash functions.
|
||||
* @{
|
||||
*/
|
||||
/* specific declaration modes for Windows */
|
||||
/*! @brief Marks a global symbol. */
|
||||
#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API)
|
||||
# if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT))
|
||||
# ifdef XXH_EXPORT
|
||||
@@ -229,24 +442,6 @@ extern "C" {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef XXH_DOXYGEN
|
||||
/*!
|
||||
* @brief Emulate a namespace by transparently prefixing all symbols.
|
||||
*
|
||||
* If you want to include _and expose_ xxHash functions from within your own
|
||||
* library, but also want to avoid symbol collisions with other libraries which
|
||||
* may also include xxHash, you can use XXH_NAMESPACE to automatically prefix
|
||||
* any public symbol from xxhash library with the value of XXH_NAMESPACE
|
||||
* (therefore, avoid empty or numeric values).
|
||||
*
|
||||
* Note that no change is required within the calling program as long as it
|
||||
* includes `xxhash.h`: Regular symbol names will be automatically translated
|
||||
* by this header.
|
||||
*/
|
||||
# define XXH_NAMESPACE /* YOUR NAME HERE */
|
||||
# undef XXH_NAMESPACE
|
||||
#endif
|
||||
|
||||
#ifdef XXH_NAMESPACE
|
||||
# define XXH_CAT(A,B) A##B
|
||||
# define XXH_NAME2(A,B) XXH_CAT(A,B)
|
||||
@@ -306,12 +501,40 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Compiler specifics
|
||||
***************************************/
|
||||
|
||||
/* specific declaration modes for Windows */
|
||||
#if !defined(XXH_INLINE_ALL) && !defined(XXH_PRIVATE_API)
|
||||
# if defined(WIN32) && defined(_MSC_VER) && (defined(XXH_IMPORT) || defined(XXH_EXPORT))
|
||||
# ifdef XXH_EXPORT
|
||||
# define XXH_PUBLIC_API __declspec(dllexport)
|
||||
# elif XXH_IMPORT
|
||||
# define XXH_PUBLIC_API __declspec(dllimport)
|
||||
# endif
|
||||
# else
|
||||
# define XXH_PUBLIC_API /* do nothing */
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined (__GNUC__)
|
||||
# define XXH_CONSTF __attribute__((const))
|
||||
# define XXH_PUREF __attribute__((pure))
|
||||
# define XXH_MALLOCF __attribute__((malloc))
|
||||
#else
|
||||
# define XXH_CONSTF /* disable */
|
||||
# define XXH_PUREF
|
||||
# define XXH_MALLOCF
|
||||
#endif
|
||||
|
||||
/* *************************************
|
||||
* Version
|
||||
***************************************/
|
||||
#define XXH_VERSION_MAJOR 0
|
||||
#define XXH_VERSION_MINOR 8
|
||||
#define XXH_VERSION_RELEASE 1
|
||||
#define XXH_VERSION_RELEASE 2
|
||||
/*! @brief Version number, encoded as two digits each */
|
||||
#define XXH_VERSION_NUMBER (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)
|
||||
|
||||
/*!
|
||||
@@ -320,16 +543,22 @@ extern "C" {
|
||||
* This is mostly useful when xxHash is compiled as a shared library,
|
||||
* since the returned value comes from the library, as opposed to header file.
|
||||
*
|
||||
* @return `XXH_VERSION_NUMBER` of the invoked library.
|
||||
* @return @ref XXH_VERSION_NUMBER of the invoked library.
|
||||
*/
|
||||
XXH_PUBLIC_API unsigned XXH_versionNumber (void);
|
||||
XXH_PUBLIC_API XXH_CONSTF unsigned XXH_versionNumber (void);
|
||||
|
||||
|
||||
/* ****************************
|
||||
* Common basic types
|
||||
******************************/
|
||||
#include <stddef.h> /* size_t */
|
||||
typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
|
||||
/*!
|
||||
* @brief Exit code for the streaming API.
|
||||
*/
|
||||
typedef enum {
|
||||
XXH_OK = 0, /*!< OK */
|
||||
XXH_ERROR /*!< Error */
|
||||
} XXH_errorcode;
|
||||
|
||||
|
||||
/*-**********************************************************************
|
||||
@@ -353,37 +582,33 @@ typedef uint32_t XXH32_hash_t;
|
||||
# include <limits.h>
|
||||
# if UINT_MAX == 0xFFFFFFFFUL
|
||||
typedef unsigned int XXH32_hash_t;
|
||||
# elif ULONG_MAX == 0xFFFFFFFFUL
|
||||
typedef unsigned long XXH32_hash_t;
|
||||
# else
|
||||
# if ULONG_MAX == 0xFFFFFFFFUL
|
||||
typedef unsigned long XXH32_hash_t;
|
||||
# else
|
||||
# error "unsupported platform: need a 32-bit type"
|
||||
# endif
|
||||
# error "unsupported platform: need a 32-bit type"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @}
|
||||
*
|
||||
* @defgroup xxh32_family XXH32 family
|
||||
* @defgroup XXH32_family XXH32 family
|
||||
* @ingroup public
|
||||
* Contains functions used in the classic 32-bit xxHash algorithm.
|
||||
*
|
||||
* @note
|
||||
* XXH32 is useful for older platforms, with no or poor 64-bit performance.
|
||||
* Note that @ref xxh3_family provides competitive speed
|
||||
* for both 32-bit and 64-bit systems, and offers true 64/128 bit hash results.
|
||||
* Note that the @ref XXH3_family provides competitive speed for both 32-bit
|
||||
* and 64-bit systems, and offers true 64/128 bit hash results.
|
||||
*
|
||||
* @see @ref xxh64_family, @ref xxh3_family : Other xxHash families
|
||||
* @see @ref xxh32_impl for implementation details
|
||||
* @see @ref XXH64_family, @ref XXH3_family : Other xxHash families
|
||||
* @see @ref XXH32_impl for implementation details
|
||||
* @{
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @brief Calculates the 32-bit hash of @p input using xxHash32.
|
||||
*
|
||||
* Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark): 5.4 GB/s
|
||||
*
|
||||
* @param input The block of data to be hashed, at least @p length bytes in size.
|
||||
* @param length The length of @p input, in bytes.
|
||||
* @param seed The 32-bit seed to alter the hash's output predictably.
|
||||
@@ -393,66 +618,13 @@ typedef uint32_t XXH32_hash_t;
|
||||
* readable, contiguous memory. However, if @p length is `0`, @p input may be
|
||||
* `NULL`. In C++, this also must be *TriviallyCopyable*.
|
||||
*
|
||||
* @return The calculated 32-bit hash value.
|
||||
* @return The calculated 32-bit xxHash32 value.
|
||||
*
|
||||
* @see
|
||||
* XXH64(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128():
|
||||
* Direct equivalents for the other variants of xxHash.
|
||||
* @see
|
||||
* XXH32_createState(), XXH32_update(), XXH32_digest(): Streaming version.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed);
|
||||
|
||||
/*!
|
||||
* Streaming functions generate the xxHash value from an incremental input.
|
||||
* This method is slower than single-call functions, due to state management.
|
||||
* For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized.
|
||||
*
|
||||
* An XXH state must first be allocated using `XXH*_createState()`.
|
||||
*
|
||||
* Start a new hash by initializing the state with a seed using `XXH*_reset()`.
|
||||
*
|
||||
* Then, feed the hash state by calling `XXH*_update()` as many times as necessary.
|
||||
*
|
||||
* The function returns an error code, with 0 meaning OK, and any other value
|
||||
* meaning there is an error.
|
||||
*
|
||||
* Finally, a hash value can be produced anytime, by using `XXH*_digest()`.
|
||||
* This function returns the nn-bits hash as an int or long long.
|
||||
*
|
||||
* It's still possible to continue inserting input into the hash state after a
|
||||
* digest, and generate new hash values later on by invoking `XXH*_digest()`.
|
||||
*
|
||||
* When done, release the state using `XXH*_freeState()`.
|
||||
*
|
||||
* Example code for incrementally hashing a file:
|
||||
* @code{.c}
|
||||
* #include <stdio.h>
|
||||
* #include <xxhash.h>
|
||||
* #define BUFFER_SIZE 256
|
||||
*
|
||||
* // Note: XXH64 and XXH3 use the same interface.
|
||||
* XXH32_hash_t
|
||||
* hashFile(FILE* stream)
|
||||
* {
|
||||
* XXH32_state_t* state;
|
||||
* unsigned char buf[BUFFER_SIZE];
|
||||
* size_t amt;
|
||||
* XXH32_hash_t hash;
|
||||
*
|
||||
* state = XXH32_createState(); // Create a state
|
||||
* assert(state != NULL); // Error check here
|
||||
* XXH32_reset(state, 0xbaad5eed); // Reset state with our seed
|
||||
* while ((amt = fread(buf, 1, sizeof(buf), stream)) != 0) {
|
||||
* XXH32_update(state, buf, amt); // Hash the file in chunks
|
||||
* }
|
||||
* hash = XXH32_digest(state); // Finalize the hash
|
||||
* XXH32_freeState(state); // Clean up
|
||||
* return hash;
|
||||
* }
|
||||
* @endcode
|
||||
* @see @ref single_shot_example "Single Shot Example" for an example.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32 (const void* input, size_t length, XXH32_hash_t seed);
|
||||
|
||||
#ifndef XXH_NO_STREAM
|
||||
/*!
|
||||
* @typedef struct XXH32_state_s XXH32_state_t
|
||||
* @brief The opaque state struct for the XXH32 streaming API.
|
||||
@@ -464,16 +636,21 @@ typedef struct XXH32_state_s XXH32_state_t;
|
||||
/*!
|
||||
* @brief Allocates an @ref XXH32_state_t.
|
||||
*
|
||||
* Must be freed with XXH32_freeState().
|
||||
* @return An allocated XXH32_state_t on success, `NULL` on failure.
|
||||
* @return An allocated pointer of @ref XXH32_state_t on success.
|
||||
* @return `NULL` on failure.
|
||||
*
|
||||
* @note Must be freed with XXH32_freeState().
|
||||
*/
|
||||
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);
|
||||
XXH_PUBLIC_API XXH_MALLOCF XXH32_state_t* XXH32_createState(void);
|
||||
/*!
|
||||
* @brief Frees an @ref XXH32_state_t.
|
||||
*
|
||||
* Must be allocated with XXH32_createState().
|
||||
* @param statePtr A pointer to an @ref XXH32_state_t allocated with @ref XXH32_createState().
|
||||
* @return XXH_OK.
|
||||
*
|
||||
* @return @ref XXH_OK.
|
||||
*
|
||||
* @note @p statePtr must be allocated with XXH32_createState().
|
||||
*
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr);
|
||||
/*!
|
||||
@@ -489,23 +666,22 @@ XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_
|
||||
/*!
|
||||
* @brief Resets an @ref XXH32_state_t to begin a new hash.
|
||||
*
|
||||
* This function resets and seeds a state. Call it before @ref XXH32_update().
|
||||
*
|
||||
* @param statePtr The state struct to reset.
|
||||
* @param seed The 32-bit seed to alter the hash result predictably.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
*
|
||||
* @return @ref XXH_OK on success, @ref XXH_ERROR on failure.
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @note This function resets and seeds a state. Call it before @ref XXH32_update().
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t seed);
|
||||
|
||||
/*!
|
||||
* @brief Consumes a block of @p input to an @ref XXH32_state_t.
|
||||
*
|
||||
* Call this to incrementally consume blocks of data.
|
||||
*
|
||||
* @param statePtr The state struct to update.
|
||||
* @param input The block of data to be hashed, at least @p length bytes in size.
|
||||
* @param length The length of @p input, in bytes.
|
||||
@@ -517,47 +693,32 @@ XXH_PUBLIC_API XXH_errorcode XXH32_reset (XXH32_state_t* statePtr, XXH32_hash_t
|
||||
* readable, contiguous memory. However, if @p length is `0`, @p input may be
|
||||
* `NULL`. In C++, this also must be *TriviallyCopyable*.
|
||||
*
|
||||
* @return @ref XXH_OK on success, @ref XXH_ERROR on failure.
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @note Call this to incrementally consume blocks of data.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);
|
||||
|
||||
/*!
|
||||
* @brief Returns the calculated hash value from an @ref XXH32_state_t.
|
||||
*
|
||||
* @note
|
||||
* Calling XXH32_digest() will not affect @p statePtr, so you can update,
|
||||
* digest, and update again.
|
||||
*
|
||||
* @param statePtr The state struct to calculate the hash from.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
*
|
||||
* @return The calculated xxHash32 value from that state.
|
||||
* @return The calculated 32-bit xxHash32 value from that state.
|
||||
*
|
||||
* @note
|
||||
* Calling XXH32_digest() will not affect @p statePtr, so you can update,
|
||||
* digest, and update again.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
|
||||
XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_digest (const XXH32_state_t* statePtr);
|
||||
#endif /* !XXH_NO_STREAM */
|
||||
|
||||
/******* Canonical representation *******/
|
||||
|
||||
/*
|
||||
* The default return values from XXH functions are unsigned 32 and 64 bit
|
||||
* integers.
|
||||
* This the simplest and fastest format for further post-processing.
|
||||
*
|
||||
* However, this leaves open the question of what is the order on the byte level,
|
||||
* since little and big endian conventions will store the same number differently.
|
||||
*
|
||||
* The canonical representation settles this issue by mandating big-endian
|
||||
* convention, the same convention as human-readable numbers (large digits first).
|
||||
*
|
||||
* When writing hash values to storage, sending them over a network, or printing
|
||||
* them, it's highly recommended to use the canonical representation to ensure
|
||||
* portability across a wider range of systems, present and future.
|
||||
*
|
||||
* The following functions allow transformation of hash values to and from
|
||||
* canonical format.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @brief Canonical (big endian) representation of @ref XXH32_hash_t.
|
||||
*/
|
||||
@@ -568,11 +729,13 @@ typedef struct {
|
||||
/*!
|
||||
* @brief Converts an @ref XXH32_hash_t to a big endian @ref XXH32_canonical_t.
|
||||
*
|
||||
* @param dst The @ref XXH32_canonical_t pointer to be stored to.
|
||||
* @param dst The @ref XXH32_canonical_t pointer to be stored to.
|
||||
* @param hash The @ref XXH32_hash_t to be converted.
|
||||
*
|
||||
* @pre
|
||||
* @p dst must not be `NULL`.
|
||||
*
|
||||
* @see @ref canonical_representation_example "Canonical Representation Example"
|
||||
*/
|
||||
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);
|
||||
|
||||
@@ -585,44 +748,75 @@ XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t
|
||||
* @p src must not be `NULL`.
|
||||
*
|
||||
* @return The converted hash.
|
||||
*
|
||||
* @see @ref canonical_representation_example "Canonical Representation Example"
|
||||
*/
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
|
||||
XXH_PUBLIC_API XXH_PUREF XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);
|
||||
|
||||
|
||||
/*! @cond Doxygen ignores this part */
|
||||
#ifdef __has_attribute
|
||||
# define XXH_HAS_ATTRIBUTE(x) __has_attribute(x)
|
||||
#else
|
||||
# define XXH_HAS_ATTRIBUTE(x) 0
|
||||
#endif
|
||||
/*! @endcond */
|
||||
|
||||
/*! @cond Doxygen ignores this part */
|
||||
/*
|
||||
* C23 __STDC_VERSION__ number hasn't been specified yet. For now
|
||||
* leave as `201711L` (C17 + 1).
|
||||
* TODO: Update to correct value when its been specified.
|
||||
*/
|
||||
#define XXH_C23_VN 201711L
|
||||
/*! @endcond */
|
||||
|
||||
/*! @cond Doxygen ignores this part */
|
||||
/* C-language Attributes are added in C23. */
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ > 201710L) && defined(__has_c_attribute)
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN) && defined(__has_c_attribute)
|
||||
# define XXH_HAS_C_ATTRIBUTE(x) __has_c_attribute(x)
|
||||
#else
|
||||
# define XXH_HAS_C_ATTRIBUTE(x) 0
|
||||
#endif
|
||||
/*! @endcond */
|
||||
|
||||
/*! @cond Doxygen ignores this part */
|
||||
#if defined(__cplusplus) && defined(__has_cpp_attribute)
|
||||
# define XXH_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
|
||||
#else
|
||||
# define XXH_HAS_CPP_ATTRIBUTE(x) 0
|
||||
#endif
|
||||
/*! @endcond */
|
||||
|
||||
/*! @cond Doxygen ignores this part */
|
||||
/*
|
||||
Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute
|
||||
introduced in CPP17 and C23.
|
||||
CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough
|
||||
C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough
|
||||
*/
|
||||
#if XXH_HAS_C_ATTRIBUTE(x)
|
||||
# define XXH_FALLTHROUGH [[fallthrough]]
|
||||
#elif XXH_HAS_CPP_ATTRIBUTE(x)
|
||||
* Define XXH_FALLTHROUGH macro for annotating switch case with the 'fallthrough' attribute
|
||||
* introduced in CPP17 and C23.
|
||||
* CPP17 : https://en.cppreference.com/w/cpp/language/attributes/fallthrough
|
||||
* C23 : https://en.cppreference.com/w/c/language/attributes/fallthrough
|
||||
*/
|
||||
#if XXH_HAS_C_ATTRIBUTE(fallthrough) || XXH_HAS_CPP_ATTRIBUTE(fallthrough)
|
||||
# define XXH_FALLTHROUGH [[fallthrough]]
|
||||
#elif XXH_HAS_ATTRIBUTE(__fallthrough__)
|
||||
# define XXH_FALLTHROUGH __attribute__ ((fallthrough))
|
||||
# define XXH_FALLTHROUGH __attribute__ ((__fallthrough__))
|
||||
#else
|
||||
# define XXH_FALLTHROUGH
|
||||
# define XXH_FALLTHROUGH /* fallthrough */
|
||||
#endif
|
||||
/*! @endcond */
|
||||
|
||||
/*! @cond Doxygen ignores this part */
|
||||
/*
|
||||
* Define XXH_NOESCAPE for annotated pointers in public API.
|
||||
* https://clang.llvm.org/docs/AttributeReference.html#noescape
|
||||
* As of writing this, only supported by clang.
|
||||
*/
|
||||
#if XXH_HAS_ATTRIBUTE(noescape)
|
||||
# define XXH_NOESCAPE __attribute__((noescape))
|
||||
#else
|
||||
# define XXH_NOESCAPE
|
||||
#endif
|
||||
/*! @endcond */
|
||||
|
||||
|
||||
/*!
|
||||
* @}
|
||||
@@ -660,7 +854,7 @@ typedef uint64_t XXH64_hash_t;
|
||||
/*!
|
||||
* @}
|
||||
*
|
||||
* @defgroup xxh64_family XXH64 family
|
||||
* @defgroup XXH64_family XXH64 family
|
||||
* @ingroup public
|
||||
* @{
|
||||
* Contains functions used in the classic 64-bit xxHash algorithm.
|
||||
@@ -671,13 +865,9 @@ typedef uint64_t XXH64_hash_t;
|
||||
* It provides better speed for systems with vector processing capabilities.
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Calculates the 64-bit hash of @p input using xxHash64.
|
||||
*
|
||||
* This function usually runs faster on 64-bit systems, but slower on 32-bit
|
||||
* systems (see benchmark).
|
||||
*
|
||||
* @param input The block of data to be hashed, at least @p length bytes in size.
|
||||
* @param length The length of @p input, in bytes.
|
||||
* @param seed The 64-bit seed to alter the hash's output predictably.
|
||||
@@ -687,41 +877,145 @@ typedef uint64_t XXH64_hash_t;
|
||||
* readable, contiguous memory. However, if @p length is `0`, @p input may be
|
||||
* `NULL`. In C++, this also must be *TriviallyCopyable*.
|
||||
*
|
||||
* @return The calculated 64-bit hash.
|
||||
* @return The calculated 64-bit xxHash64 value.
|
||||
*
|
||||
* @see
|
||||
* XXH32(), XXH3_64bits_withSeed(), XXH3_128bits_withSeed(), XXH128():
|
||||
* Direct equivalents for the other variants of xxHash.
|
||||
* @see
|
||||
* XXH64_createState(), XXH64_update(), XXH64_digest(): Streaming version.
|
||||
* @see @ref single_shot_example "Single Shot Example" for an example.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64(const void* input, size_t length, XXH64_hash_t seed);
|
||||
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed);
|
||||
|
||||
/******* Streaming *******/
|
||||
#ifndef XXH_NO_STREAM
|
||||
/*!
|
||||
* @brief The opaque state struct for the XXH64 streaming API.
|
||||
*
|
||||
* @see XXH64_state_s for details.
|
||||
*/
|
||||
typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */
|
||||
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);
|
||||
|
||||
/*!
|
||||
* @brief Allocates an @ref XXH64_state_t.
|
||||
*
|
||||
* @return An allocated pointer of @ref XXH64_state_t on success.
|
||||
* @return `NULL` on failure.
|
||||
*
|
||||
* @note Must be freed with XXH64_freeState().
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_MALLOCF XXH64_state_t* XXH64_createState(void);
|
||||
|
||||
/*!
|
||||
* @brief Frees an @ref XXH64_state_t.
|
||||
*
|
||||
* @param statePtr A pointer to an @ref XXH64_state_t allocated with @ref XXH64_createState().
|
||||
*
|
||||
* @return @ref XXH_OK.
|
||||
*
|
||||
* @note @p statePtr must be allocated with XXH64_createState().
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr);
|
||||
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, XXH64_hash_t seed);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr);
|
||||
/*!
|
||||
* @brief Copies one @ref XXH64_state_t to another.
|
||||
*
|
||||
* @param dst_state The state to copy to.
|
||||
* @param src_state The state to copy from.
|
||||
* @pre
|
||||
* @p dst_state and @p src_state must not be `NULL` and must not overlap.
|
||||
*/
|
||||
XXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dst_state, const XXH64_state_t* src_state);
|
||||
|
||||
/*!
|
||||
* @brief Resets an @ref XXH64_state_t to begin a new hash.
|
||||
*
|
||||
* @param statePtr The state struct to reset.
|
||||
* @param seed The 64-bit seed to alter the hash result predictably.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @note This function resets and seeds a state. Call it before @ref XXH64_update().
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_reset (XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed);
|
||||
|
||||
/*!
|
||||
* @brief Consumes a block of @p input to an @ref XXH64_state_t.
|
||||
*
|
||||
* @param statePtr The state struct to update.
|
||||
* @param input The block of data to be hashed, at least @p length bytes in size.
|
||||
* @param length The length of @p input, in bytes.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
* @pre
|
||||
* The memory between @p input and @p input + @p length must be valid,
|
||||
* readable, contiguous memory. However, if @p length is `0`, @p input may be
|
||||
* `NULL`. In C++, this also must be *TriviallyCopyable*.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @note Call this to incrementally consume blocks of data.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_update (XXH_NOESCAPE XXH64_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length);
|
||||
|
||||
/*!
|
||||
* @brief Returns the calculated hash value from an @ref XXH64_state_t.
|
||||
*
|
||||
* @param statePtr The state struct to calculate the hash from.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
*
|
||||
* @return The calculated 64-bit xxHash64 value from that state.
|
||||
*
|
||||
* @note
|
||||
* Calling XXH64_digest() will not affect @p statePtr, so you can update,
|
||||
* digest, and update again.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_digest (XXH_NOESCAPE const XXH64_state_t* statePtr);
|
||||
#endif /* !XXH_NO_STREAM */
|
||||
/******* Canonical representation *******/
|
||||
|
||||
/*!
|
||||
* @brief Canonical (big endian) representation of @ref XXH64_hash_t.
|
||||
*/
|
||||
typedef struct { unsigned char digest[sizeof(XXH64_hash_t)]; } XXH64_canonical_t;
|
||||
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);
|
||||
|
||||
/*!
|
||||
* @brief Converts an @ref XXH64_hash_t to a big endian @ref XXH64_canonical_t.
|
||||
*
|
||||
* @param dst The @ref XXH64_canonical_t pointer to be stored to.
|
||||
* @param hash The @ref XXH64_hash_t to be converted.
|
||||
*
|
||||
* @pre
|
||||
* @p dst must not be `NULL`.
|
||||
*
|
||||
* @see @ref canonical_representation_example "Canonical Representation Example"
|
||||
*/
|
||||
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash);
|
||||
|
||||
/*!
|
||||
* @brief Converts an @ref XXH64_canonical_t to a native @ref XXH64_hash_t.
|
||||
*
|
||||
* @param src The @ref XXH64_canonical_t to convert.
|
||||
*
|
||||
* @pre
|
||||
* @p src must not be `NULL`.
|
||||
*
|
||||
* @return The converted hash.
|
||||
*
|
||||
* @see @ref canonical_representation_example "Canonical Representation Example"
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src);
|
||||
|
||||
#ifndef XXH_NO_XXH3
|
||||
|
||||
/*!
|
||||
* @}
|
||||
* ************************************************************************
|
||||
* @defgroup xxh3_family XXH3 family
|
||||
* @defgroup XXH3_family XXH3 family
|
||||
* @ingroup public
|
||||
* @{
|
||||
*
|
||||
@@ -741,16 +1035,26 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src
|
||||
*
|
||||
* XXH3's speed benefits greatly from SIMD and 64-bit arithmetic,
|
||||
* but does not require it.
|
||||
* Any 32-bit and 64-bit targets that can run XXH32 smoothly
|
||||
* can run XXH3 at competitive speeds, even without vector support.
|
||||
* Further details are explained in the implementation.
|
||||
* Most 32-bit and 64-bit targets that can run XXH32 smoothly can run XXH3
|
||||
* at competitive speeds, even without vector support. Further details are
|
||||
* explained in the implementation.
|
||||
*
|
||||
* Optimized implementations are provided for AVX512, AVX2, SSE2, NEON, POWER8,
|
||||
* ZVector and scalar targets. This can be controlled via the XXH_VECTOR macro.
|
||||
* XXH3 has a fast scalar implementation, but it also includes accelerated SIMD
|
||||
* implementations for many common platforms:
|
||||
* - AVX512
|
||||
* - AVX2
|
||||
* - SSE2
|
||||
* - ARM NEON
|
||||
* - WebAssembly SIMD128
|
||||
* - POWER8 VSX
|
||||
* - s390x ZVector
|
||||
* This can be controlled via the @ref XXH_VECTOR macro, but it automatically
|
||||
* selects the best version according to predefined macros. For the x86 family, an
|
||||
* automatic runtime dispatcher is included separately in @ref xxh_x86dispatch.c.
|
||||
*
|
||||
* XXH3 implementation is portable:
|
||||
* it has a generic C90 formulation that can be compiled on any platform,
|
||||
* all implementations generage exactly the same hash value on all platforms.
|
||||
* all implementations generate exactly the same hash value on all platforms.
|
||||
* Starting from v0.8.0, it's also labelled "stable", meaning that
|
||||
* any future version will also generate the same hash value.
|
||||
*
|
||||
@@ -762,24 +1066,59 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src
|
||||
*
|
||||
* The API supports one-shot hashing, streaming mode, and custom secrets.
|
||||
*/
|
||||
|
||||
/*-**********************************************************************
|
||||
* XXH3 64-bit variant
|
||||
************************************************************************/
|
||||
|
||||
/* XXH3_64bits():
|
||||
* default 64-bit variant, using default secret and default seed of 0.
|
||||
* It's the fastest variant. */
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* data, size_t len);
|
||||
|
||||
/*
|
||||
* XXH3_64bits_withSeed():
|
||||
* This variant generates a custom secret on the fly
|
||||
* based on default secret altered using the `seed` value.
|
||||
* While this operation is decently fast, note that it's not completely free.
|
||||
* Note: seed==0 produces the same results as XXH3_64bits().
|
||||
/*!
|
||||
* @brief Calculates 64-bit unseeded variant of XXH3 hash of @p input.
|
||||
*
|
||||
* @param input The block of data to be hashed, at least @p length bytes in size.
|
||||
* @param length The length of @p input, in bytes.
|
||||
*
|
||||
* @pre
|
||||
* The memory between @p input and @p input + @p length must be valid,
|
||||
* readable, contiguous memory. However, if @p length is `0`, @p input may be
|
||||
* `NULL`. In C++, this also must be *TriviallyCopyable*.
|
||||
*
|
||||
* @return The calculated 64-bit XXH3 hash value.
|
||||
*
|
||||
* @note
|
||||
* This is equivalent to @ref XXH3_64bits_withSeed() with a seed of `0`, however
|
||||
* it may have slightly better performance due to constant propagation of the
|
||||
* defaults.
|
||||
*
|
||||
* @see
|
||||
* XXH3_64bits_withSeed(), XXH3_64bits_withSecret(): other seeding variants
|
||||
* @see @ref single_shot_example "Single Shot Example" for an example.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(const void* data, size_t len, XXH64_hash_t seed);
|
||||
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length);
|
||||
|
||||
/*!
|
||||
* @brief Calculates 64-bit seeded variant of XXH3 hash of @p input.
|
||||
*
|
||||
* @param input The block of data to be hashed, at least @p length bytes in size.
|
||||
* @param length The length of @p input, in bytes.
|
||||
* @param seed The 64-bit seed to alter the hash result predictably.
|
||||
*
|
||||
* @pre
|
||||
* The memory between @p input and @p input + @p length must be valid,
|
||||
* readable, contiguous memory. However, if @p length is `0`, @p input may be
|
||||
* `NULL`. In C++, this also must be *TriviallyCopyable*.
|
||||
*
|
||||
* @return The calculated 64-bit XXH3 hash value.
|
||||
*
|
||||
* @note
|
||||
* seed == 0 produces the same results as @ref XXH3_64bits().
|
||||
*
|
||||
* This variant generates a custom secret on the fly based on default secret
|
||||
* altered using the @p seed value.
|
||||
*
|
||||
* While this operation is decently fast, note that it's not completely free.
|
||||
*
|
||||
* @see @ref single_shot_example "Single Shot Example" for an example.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed);
|
||||
|
||||
/*!
|
||||
* The bare minimum size for a custom secret.
|
||||
@@ -790,27 +1129,43 @@ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSeed(const void* data, size_t len, X
|
||||
*/
|
||||
#define XXH3_SECRET_SIZE_MIN 136
|
||||
|
||||
/*
|
||||
* XXH3_64bits_withSecret():
|
||||
/*!
|
||||
* @brief Calculates 64-bit variant of XXH3 with a custom "secret".
|
||||
*
|
||||
* @param data The block of data to be hashed, at least @p len bytes in size.
|
||||
* @param len The length of @p data, in bytes.
|
||||
* @param secret The secret data.
|
||||
* @param secretSize The length of @p secret, in bytes.
|
||||
*
|
||||
* @return The calculated 64-bit XXH3 hash value.
|
||||
*
|
||||
* @pre
|
||||
* The memory between @p data and @p data + @p len must be valid,
|
||||
* readable, contiguous memory. However, if @p length is `0`, @p data may be
|
||||
* `NULL`. In C++, this also must be *TriviallyCopyable*.
|
||||
*
|
||||
* It's possible to provide any blob of bytes as a "secret" to generate the hash.
|
||||
* This makes it more difficult for an external actor to prepare an intentional collision.
|
||||
* The main condition is that secretSize *must* be large enough (>= XXH3_SECRET_SIZE_MIN).
|
||||
* The main condition is that @p secretSize *must* be large enough (>= @ref XXH3_SECRET_SIZE_MIN).
|
||||
* However, the quality of the secret impacts the dispersion of the hash algorithm.
|
||||
* Therefore, the secret _must_ look like a bunch of random bytes.
|
||||
* Avoid "trivial" or structured data such as repeated sequences or a text document.
|
||||
* Whenever in doubt about the "randomness" of the blob of bytes,
|
||||
* consider employing "XXH3_generateSecret()" instead (see below).
|
||||
* consider employing @ref XXH3_generateSecret() instead (see below).
|
||||
* It will generate a proper high entropy secret derived from the blob of bytes.
|
||||
* Another advantage of using XXH3_generateSecret() is that
|
||||
* it guarantees that all bits within the initial blob of bytes
|
||||
* will impact every bit of the output.
|
||||
* This is not necessarily the case when using the blob of bytes directly
|
||||
* because, when hashing _small_ inputs, only a portion of the secret is employed.
|
||||
*
|
||||
* @see @ref single_shot_example "Single Shot Example" for an example.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize);
|
||||
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize);
|
||||
|
||||
|
||||
/******* Streaming *******/
|
||||
#ifndef XXH_NO_STREAM
|
||||
/*
|
||||
* Streaming requires state maintenance.
|
||||
* This operation costs memory and CPU.
|
||||
@@ -819,40 +1174,124 @@ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_withSecret(const void* data, size_t len,
|
||||
*/
|
||||
|
||||
/*!
|
||||
* @brief The state struct for the XXH3 streaming API.
|
||||
* @brief The opaque state struct for the XXH3 streaming API.
|
||||
*
|
||||
* @see XXH3_state_s for details.
|
||||
*/
|
||||
typedef struct XXH3_state_s XXH3_state_t;
|
||||
XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void);
|
||||
XXH_PUBLIC_API XXH_MALLOCF XXH3_state_t* XXH3_createState(void);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr);
|
||||
XXH_PUBLIC_API void XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state);
|
||||
|
||||
/*
|
||||
* XXH3_64bits_reset():
|
||||
* Initialize with default parameters.
|
||||
* digest will be equivalent to `XXH3_64bits()`.
|
||||
/*!
|
||||
* @brief Copies one @ref XXH3_state_t to another.
|
||||
*
|
||||
* @param dst_state The state to copy to.
|
||||
* @param src_state The state to copy from.
|
||||
* @pre
|
||||
* @p dst_state and @p src_state must not be `NULL` and must not overlap.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH3_state_t* statePtr);
|
||||
/*
|
||||
* XXH3_64bits_reset_withSeed():
|
||||
* Generate a custom secret from `seed`, and store it into `statePtr`.
|
||||
* digest will be equivalent to `XXH3_64bits_withSeed()`.
|
||||
XXH_PUBLIC_API void XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state);
|
||||
|
||||
/*!
|
||||
* @brief Resets an @ref XXH3_state_t to begin a new hash.
|
||||
*
|
||||
* @param statePtr The state struct to reset.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @note
|
||||
* - This function resets `statePtr` and generate a secret with default parameters.
|
||||
* - Call this function before @ref XXH3_64bits_update().
|
||||
* - Digest will be equivalent to `XXH3_64bits()`.
|
||||
*
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed);
|
||||
/*
|
||||
* XXH3_64bits_reset_withSecret():
|
||||
* `secret` is referenced, it _must outlive_ the hash streaming session.
|
||||
* Similar to one-shot API, `secretSize` must be >= `XXH3_SECRET_SIZE_MIN`,
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr);
|
||||
|
||||
/*!
|
||||
* @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash.
|
||||
*
|
||||
* @param statePtr The state struct to reset.
|
||||
* @param seed The 64-bit seed to alter the hash result predictably.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @note
|
||||
* - This function resets `statePtr` and generate a secret from `seed`.
|
||||
* - Call this function before @ref XXH3_64bits_update().
|
||||
* - Digest will be equivalent to `XXH3_64bits_withSeed()`.
|
||||
*
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed);
|
||||
|
||||
/*!
|
||||
* @brief Resets an @ref XXH3_state_t with secret data to begin a new hash.
|
||||
*
|
||||
* @param statePtr The state struct to reset.
|
||||
* @param secret The secret data.
|
||||
* @param secretSize The length of @p secret, in bytes.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @note
|
||||
* `secret` is referenced, it _must outlive_ the hash streaming session.
|
||||
*
|
||||
* Similar to one-shot API, `secretSize` must be >= @ref XXH3_SECRET_SIZE_MIN,
|
||||
* and the quality of produced hash values depends on secret's entropy
|
||||
* (secret's content should look like a bunch of random bytes).
|
||||
* When in doubt about the randomness of a candidate `secret`,
|
||||
* consider employing `XXH3_generateSecret()` instead (see below).
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize);
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH3_state_t* statePtr, const void* input, size_t length);
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* statePtr);
|
||||
/*!
|
||||
* @brief Consumes a block of @p input to an @ref XXH3_state_t.
|
||||
*
|
||||
* @param statePtr The state struct to update.
|
||||
* @param input The block of data to be hashed, at least @p length bytes in size.
|
||||
* @param length The length of @p input, in bytes.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
* @pre
|
||||
* The memory between @p input and @p input + @p length must be valid,
|
||||
* readable, contiguous memory. However, if @p length is `0`, @p input may be
|
||||
* `NULL`. In C++, this also must be *TriviallyCopyable*.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @note Call this to incrementally consume blocks of data.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_64bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length);
|
||||
|
||||
/*!
|
||||
* @brief Returns the calculated XXH3 64-bit hash value from an @ref XXH3_state_t.
|
||||
*
|
||||
* @param statePtr The state struct to calculate the hash from.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
*
|
||||
* @return The calculated XXH3 64-bit hash value from that state.
|
||||
*
|
||||
* @note
|
||||
* Calling XXH3_64bits_digest() will not affect @p statePtr, so you can update,
|
||||
* digest, and update again.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr);
|
||||
#endif /* !XXH_NO_STREAM */
|
||||
|
||||
/* note : canonical representation of XXH3 is the same as XXH64
|
||||
* since they both produce XXH64_hash_t values */
|
||||
@@ -873,11 +1312,76 @@ typedef struct {
|
||||
XXH64_hash_t high64; /*!< `value >> 64` */
|
||||
} XXH128_hash_t;
|
||||
|
||||
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* data, size_t len);
|
||||
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSeed(const void* data, size_t len, XXH64_hash_t seed);
|
||||
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize);
|
||||
/*!
|
||||
* @brief Calculates 128-bit unseeded variant of XXH3 of @p data.
|
||||
*
|
||||
* @param data The block of data to be hashed, at least @p length bytes in size.
|
||||
* @param len The length of @p data, in bytes.
|
||||
*
|
||||
* @return The calculated 128-bit variant of XXH3 value.
|
||||
*
|
||||
* The 128-bit variant of XXH3 has more strength, but it has a bit of overhead
|
||||
* for shorter inputs.
|
||||
*
|
||||
* This is equivalent to @ref XXH3_128bits_withSeed() with a seed of `0`, however
|
||||
* it may have slightly better performance due to constant propagation of the
|
||||
* defaults.
|
||||
*
|
||||
* @see XXH3_128bits_withSeed(), XXH3_128bits_withSecret(): other seeding variants
|
||||
* @see @ref single_shot_example "Single Shot Example" for an example.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* data, size_t len);
|
||||
/*! @brief Calculates 128-bit seeded variant of XXH3 hash of @p data.
|
||||
*
|
||||
* @param data The block of data to be hashed, at least @p length bytes in size.
|
||||
* @param len The length of @p data, in bytes.
|
||||
* @param seed The 64-bit seed to alter the hash result predictably.
|
||||
*
|
||||
* @return The calculated 128-bit variant of XXH3 value.
|
||||
*
|
||||
* @note
|
||||
* seed == 0 produces the same results as @ref XXH3_64bits().
|
||||
*
|
||||
* This variant generates a custom secret on the fly based on default secret
|
||||
* altered using the @p seed value.
|
||||
*
|
||||
* While this operation is decently fast, note that it's not completely free.
|
||||
*
|
||||
* @see XXH3_128bits(), XXH3_128bits_withSecret(): other seeding variants
|
||||
* @see @ref single_shot_example "Single Shot Example" for an example.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSeed(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed);
|
||||
/*!
|
||||
* @brief Calculates 128-bit variant of XXH3 with a custom "secret".
|
||||
*
|
||||
* @param data The block of data to be hashed, at least @p len bytes in size.
|
||||
* @param len The length of @p data, in bytes.
|
||||
* @param secret The secret data.
|
||||
* @param secretSize The length of @p secret, in bytes.
|
||||
*
|
||||
* @return The calculated 128-bit variant of XXH3 value.
|
||||
*
|
||||
* It's possible to provide any blob of bytes as a "secret" to generate the hash.
|
||||
* This makes it more difficult for an external actor to prepare an intentional collision.
|
||||
* The main condition is that @p secretSize *must* be large enough (>= @ref XXH3_SECRET_SIZE_MIN).
|
||||
* However, the quality of the secret impacts the dispersion of the hash algorithm.
|
||||
* Therefore, the secret _must_ look like a bunch of random bytes.
|
||||
* Avoid "trivial" or structured data such as repeated sequences or a text document.
|
||||
* Whenever in doubt about the "randomness" of the blob of bytes,
|
||||
* consider employing @ref XXH3_generateSecret() instead (see below).
|
||||
* It will generate a proper high entropy secret derived from the blob of bytes.
|
||||
* Another advantage of using XXH3_generateSecret() is that
|
||||
* it guarantees that all bits within the initial blob of bytes
|
||||
* will impact every bit of the output.
|
||||
* This is not necessarily the case when using the blob of bytes directly
|
||||
* because, when hashing _small_ inputs, only a portion of the secret is employed.
|
||||
*
|
||||
* @see @ref single_shot_example "Single Shot Example" for an example.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_withSecret(XXH_NOESCAPE const void* data, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize);
|
||||
|
||||
/******* Streaming *******/
|
||||
#ifndef XXH_NO_STREAM
|
||||
/*
|
||||
* Streaming requires state maintenance.
|
||||
* This operation costs memory and CPU.
|
||||
@@ -890,39 +1394,163 @@ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_withSecret(const void* data, size_t le
|
||||
* All reset and streaming functions have same meaning as their 64-bit counterpart.
|
||||
*/
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH3_state_t* statePtr);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize);
|
||||
/*!
|
||||
* @brief Resets an @ref XXH3_state_t to begin a new hash.
|
||||
*
|
||||
* @param statePtr The state struct to reset.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @note
|
||||
* - This function resets `statePtr` and generate a secret with default parameters.
|
||||
* - Call it before @ref XXH3_128bits_update().
|
||||
* - Digest will be equivalent to `XXH3_128bits()`.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr);
|
||||
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH3_state_t* statePtr, const void* input, size_t length);
|
||||
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* statePtr);
|
||||
/*!
|
||||
* @brief Resets an @ref XXH3_state_t with 64-bit seed to begin a new hash.
|
||||
*
|
||||
* @param statePtr The state struct to reset.
|
||||
* @param seed The 64-bit seed to alter the hash result predictably.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @note
|
||||
* - This function resets `statePtr` and generate a secret from `seed`.
|
||||
* - Call it before @ref XXH3_128bits_update().
|
||||
* - Digest will be equivalent to `XXH3_128bits_withSeed()`.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed);
|
||||
/*!
|
||||
* @brief Resets an @ref XXH3_state_t with secret data to begin a new hash.
|
||||
*
|
||||
* @param statePtr The state struct to reset.
|
||||
* @param secret The secret data.
|
||||
* @param secretSize The length of @p secret, in bytes.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* `secret` is referenced, it _must outlive_ the hash streaming session.
|
||||
* Similar to one-shot API, `secretSize` must be >= @ref XXH3_SECRET_SIZE_MIN,
|
||||
* and the quality of produced hash values depends on secret's entropy
|
||||
* (secret's content should look like a bunch of random bytes).
|
||||
* When in doubt about the randomness of a candidate `secret`,
|
||||
* consider employing `XXH3_generateSecret()` instead (see below).
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize);
|
||||
|
||||
/*!
|
||||
* @brief Consumes a block of @p input to an @ref XXH3_state_t.
|
||||
*
|
||||
* Call this to incrementally consume blocks of data.
|
||||
*
|
||||
* @param statePtr The state struct to update.
|
||||
* @param input The block of data to be hashed, at least @p length bytes in size.
|
||||
* @param length The length of @p input, in bytes.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @note
|
||||
* The memory between @p input and @p input + @p length must be valid,
|
||||
* readable, contiguous memory. However, if @p length is `0`, @p input may be
|
||||
* `NULL`. In C++, this also must be *TriviallyCopyable*.
|
||||
*
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_128bits_update (XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* input, size_t length);
|
||||
|
||||
/*!
|
||||
* @brief Returns the calculated XXH3 128-bit hash value from an @ref XXH3_state_t.
|
||||
*
|
||||
* @param statePtr The state struct to calculate the hash from.
|
||||
*
|
||||
* @pre
|
||||
* @p statePtr must not be `NULL`.
|
||||
*
|
||||
* @return The calculated XXH3 128-bit hash value from that state.
|
||||
*
|
||||
* @note
|
||||
* Calling XXH3_128bits_digest() will not affect @p statePtr, so you can update,
|
||||
* digest, and update again.
|
||||
*
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* statePtr);
|
||||
#endif /* !XXH_NO_STREAM */
|
||||
|
||||
/* Following helper functions make it possible to compare XXH128_hast_t values.
|
||||
* Since XXH128_hash_t is a structure, this capability is not offered by the language.
|
||||
* Note: For better performance, these functions can be inlined using XXH_INLINE_ALL */
|
||||
|
||||
/*!
|
||||
* XXH128_isEqual():
|
||||
* Return: 1 if `h1` and `h2` are equal, 0 if they are not.
|
||||
* @brief Check equality of two XXH128_hash_t values
|
||||
*
|
||||
* @param h1 The 128-bit hash value.
|
||||
* @param h2 Another 128-bit hash value.
|
||||
*
|
||||
* @return `1` if `h1` and `h2` are equal.
|
||||
* @return `0` if they are not.
|
||||
*/
|
||||
XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2);
|
||||
XXH_PUBLIC_API XXH_PUREF int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2);
|
||||
|
||||
/*!
|
||||
* XXH128_cmp():
|
||||
* @brief Compares two @ref XXH128_hash_t
|
||||
*
|
||||
* This comparator is compatible with stdlib's `qsort()`/`bsearch()`.
|
||||
*
|
||||
* return: >0 if *h128_1 > *h128_2
|
||||
* =0 if *h128_1 == *h128_2
|
||||
* <0 if *h128_1 < *h128_2
|
||||
* @param h128_1 Left-hand side value
|
||||
* @param h128_2 Right-hand side value
|
||||
*
|
||||
* @return >0 if @p h128_1 > @p h128_2
|
||||
* @return =0 if @p h128_1 == @p h128_2
|
||||
* @return <0 if @p h128_1 < @p h128_2
|
||||
*/
|
||||
XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2);
|
||||
XXH_PUBLIC_API XXH_PUREF int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2);
|
||||
|
||||
|
||||
/******* Canonical representation *******/
|
||||
typedef struct { unsigned char digest[sizeof(XXH128_hash_t)]; } XXH128_canonical_t;
|
||||
XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash);
|
||||
XXH_PUBLIC_API XXH128_hash_t XXH128_hashFromCanonical(const XXH128_canonical_t* src);
|
||||
|
||||
|
||||
/*!
|
||||
* @brief Converts an @ref XXH128_hash_t to a big endian @ref XXH128_canonical_t.
|
||||
*
|
||||
* @param dst The @ref XXH128_canonical_t pointer to be stored to.
|
||||
* @param hash The @ref XXH128_hash_t to be converted.
|
||||
*
|
||||
* @pre
|
||||
* @p dst must not be `NULL`.
|
||||
* @see @ref canonical_representation_example "Canonical Representation Example"
|
||||
*/
|
||||
XXH_PUBLIC_API void XXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash);
|
||||
|
||||
/*!
|
||||
* @brief Converts an @ref XXH128_canonical_t to a native @ref XXH128_hash_t.
|
||||
*
|
||||
* @param src The @ref XXH128_canonical_t to convert.
|
||||
*
|
||||
* @pre
|
||||
* @p src must not be `NULL`.
|
||||
*
|
||||
* @return The converted hash.
|
||||
* @see @ref canonical_representation_example "Canonical Representation Example"
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src);
|
||||
|
||||
|
||||
#endif /* !XXH_NO_XXH3 */
|
||||
@@ -996,7 +1624,6 @@ struct XXH64_state_s {
|
||||
XXH64_hash_t reserved64; /*!< Reserved field. Do not read or write to it. */
|
||||
}; /* typedef'd to XXH64_state_t */
|
||||
|
||||
|
||||
#ifndef XXH_NO_XXH3
|
||||
|
||||
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* >= C11 */
|
||||
@@ -1032,6 +1659,7 @@ struct XXH64_state_s {
|
||||
#define XXH3_INTERNALBUFFER_SIZE 256
|
||||
|
||||
/*!
|
||||
* @internal
|
||||
* @brief Default size of the secret buffer (and @ref XXH3_kSecret).
|
||||
*
|
||||
* This is the size used in @ref XXH3_kSecret and the seeded functions.
|
||||
@@ -1064,7 +1692,7 @@ struct XXH64_state_s {
|
||||
*/
|
||||
struct XXH3_state_s {
|
||||
XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]);
|
||||
/*!< The 8 accumulators. Similar to `vN` in @ref XXH32_state_s::v1 and @ref XXH64_state_s */
|
||||
/*!< The 8 accumulators. See @ref XXH32_state_s::v and @ref XXH64_state_s::v */
|
||||
XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]);
|
||||
/*!< Used to store a custom secret generated from a seed. */
|
||||
XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]);
|
||||
@@ -1104,69 +1732,148 @@ struct XXH3_state_s {
|
||||
* Note that this doesn't prepare the state for a streaming operation,
|
||||
* it's still necessary to use XXH3_NNbits_reset*() afterwards.
|
||||
*/
|
||||
#define XXH3_INITSTATE(XXH3_state_ptr) { (XXH3_state_ptr)->seed = 0; }
|
||||
#define XXH3_INITSTATE(XXH3_state_ptr) \
|
||||
do { \
|
||||
XXH3_state_t* tmp_xxh3_state_ptr = (XXH3_state_ptr); \
|
||||
tmp_xxh3_state_ptr->seed = 0; \
|
||||
tmp_xxh3_state_ptr->extSecret = NULL; \
|
||||
} while(0)
|
||||
|
||||
|
||||
/* XXH128() :
|
||||
* simple alias to pre-selected XXH3_128bits variant
|
||||
/*!
|
||||
* @brief Calculates the 128-bit hash of @p data using XXH3.
|
||||
*
|
||||
* @param data The block of data to be hashed, at least @p len bytes in size.
|
||||
* @param len The length of @p data, in bytes.
|
||||
* @param seed The 64-bit seed to alter the hash's output predictably.
|
||||
*
|
||||
* @pre
|
||||
* The memory between @p data and @p data + @p len must be valid,
|
||||
* readable, contiguous memory. However, if @p len is `0`, @p data may be
|
||||
* `NULL`. In C++, this also must be *TriviallyCopyable*.
|
||||
*
|
||||
* @return The calculated 128-bit XXH3 value.
|
||||
*
|
||||
* @see @ref single_shot_example "Single Shot Example" for an example.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH128_hash_t XXH128(const void* data, size_t len, XXH64_hash_t seed);
|
||||
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t XXH128(XXH_NOESCAPE const void* data, size_t len, XXH64_hash_t seed);
|
||||
|
||||
|
||||
/* === Experimental API === */
|
||||
/* Symbols defined below must be considered tied to a specific library version. */
|
||||
|
||||
/*
|
||||
* XXH3_generateSecret():
|
||||
/*!
|
||||
* @brief Derive a high-entropy secret from any user-defined content, named customSeed.
|
||||
*
|
||||
* @param secretBuffer A writable buffer for derived high-entropy secret data.
|
||||
* @param secretSize Size of secretBuffer, in bytes. Must be >= XXH3_SECRET_DEFAULT_SIZE.
|
||||
* @param customSeed A user-defined content.
|
||||
* @param customSeedSize Size of customSeed, in bytes.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* Derive a high-entropy secret from any user-defined content, named customSeed.
|
||||
* The generated secret can be used in combination with `*_withSecret()` functions.
|
||||
* The `_withSecret()` variants are useful to provide a higher level of protection than 64-bit seed,
|
||||
* as it becomes much more difficult for an external actor to guess how to impact the calculation logic.
|
||||
* The `_withSecret()` variants are useful to provide a higher level of protection
|
||||
* than 64-bit seed, as it becomes much more difficult for an external actor to
|
||||
* guess how to impact the calculation logic.
|
||||
*
|
||||
* The function accepts as input a custom seed of any length and any content,
|
||||
* and derives from it a high-entropy secret of length @secretSize
|
||||
* into an already allocated buffer @secretBuffer.
|
||||
* @secretSize must be >= XXH3_SECRET_SIZE_MIN
|
||||
* and derives from it a high-entropy secret of length @p secretSize into an
|
||||
* already allocated buffer @p secretBuffer.
|
||||
*
|
||||
* The generated secret can then be used with any `*_withSecret()` variant.
|
||||
* Functions `XXH3_128bits_withSecret()`, `XXH3_64bits_withSecret()`,
|
||||
* `XXH3_128bits_reset_withSecret()` and `XXH3_64bits_reset_withSecret()`
|
||||
* The functions @ref XXH3_128bits_withSecret(), @ref XXH3_64bits_withSecret(),
|
||||
* @ref XXH3_128bits_reset_withSecret() and @ref XXH3_64bits_reset_withSecret()
|
||||
* are part of this list. They all accept a `secret` parameter
|
||||
* which must be large enough for implementation reasons (>= XXH3_SECRET_SIZE_MIN)
|
||||
* which must be large enough for implementation reasons (>= @ref XXH3_SECRET_SIZE_MIN)
|
||||
* _and_ feature very high entropy (consist of random-looking bytes).
|
||||
* These conditions can be a high bar to meet, so
|
||||
* XXH3_generateSecret() can be employed to ensure proper quality.
|
||||
* These conditions can be a high bar to meet, so @ref XXH3_generateSecret() can
|
||||
* be employed to ensure proper quality.
|
||||
*
|
||||
* customSeed can be anything. It can have any size, even small ones,
|
||||
* and its content can be anything, even "poor entropy" sources such as a bunch of zeroes.
|
||||
* The resulting `secret` will nonetheless provide all required qualities.
|
||||
* @p customSeed can be anything. It can have any size, even small ones,
|
||||
* and its content can be anything, even "poor entropy" sources such as a bunch
|
||||
* of zeroes. The resulting `secret` will nonetheless provide all required qualities.
|
||||
*
|
||||
* When customSeedSize > 0, supplying NULL as customSeed is undefined behavior.
|
||||
* @pre
|
||||
* - @p secretSize must be >= @ref XXH3_SECRET_SIZE_MIN
|
||||
* - When @p customSeedSize > 0, supplying NULL as customSeed is undefined behavior.
|
||||
*
|
||||
* Example code:
|
||||
* @code{.c}
|
||||
* #include <stdio.h>
|
||||
* #include <stdlib.h>
|
||||
* #include <string.h>
|
||||
* #define XXH_STATIC_LINKING_ONLY // expose unstable API
|
||||
* #include "xxhash.h"
|
||||
* // Hashes argv[2] using the entropy from argv[1].
|
||||
* int main(int argc, char* argv[])
|
||||
* {
|
||||
* char secret[XXH3_SECRET_SIZE_MIN];
|
||||
* if (argv != 3) { return 1; }
|
||||
* XXH3_generateSecret(secret, sizeof(secret), argv[1], strlen(argv[1]));
|
||||
* XXH64_hash_t h = XXH3_64bits_withSecret(
|
||||
* argv[2], strlen(argv[2]),
|
||||
* secret, sizeof(secret)
|
||||
* );
|
||||
* printf("%016llx\n", (unsigned long long) h);
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSeed, size_t customSeedSize);
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize);
|
||||
|
||||
|
||||
/*
|
||||
* XXH3_generateSecret_fromSeed():
|
||||
/*!
|
||||
* @brief Generate the same secret as the _withSeed() variants.
|
||||
*
|
||||
* Generate the same secret as the _withSeed() variants.
|
||||
*
|
||||
* The resulting secret has a length of XXH3_SECRET_DEFAULT_SIZE (necessarily).
|
||||
* @secretBuffer must be already allocated, of size at least XXH3_SECRET_DEFAULT_SIZE bytes.
|
||||
* @param secretBuffer A writable buffer of @ref XXH3_SECRET_SIZE_MIN bytes
|
||||
* @param seed The 64-bit seed to alter the hash result predictably.
|
||||
*
|
||||
* The generated secret can be used in combination with
|
||||
*`*_withSecret()` and `_withSecretandSeed()` variants.
|
||||
* This generator is notably useful in combination with `_withSecretandSeed()`,
|
||||
* as a way to emulate a faster `_withSeed()` variant.
|
||||
*
|
||||
* Example C++ `std::string` hash class:
|
||||
* @code{.cpp}
|
||||
* #include <string>
|
||||
* #define XXH_STATIC_LINKING_ONLY // expose unstable API
|
||||
* #include "xxhash.h"
|
||||
* // Slow, seeds each time
|
||||
* class HashSlow {
|
||||
* XXH64_hash_t seed;
|
||||
* public:
|
||||
* HashSlow(XXH64_hash_t s) : seed{s} {}
|
||||
* size_t operator()(const std::string& x) const {
|
||||
* return size_t{XXH3_64bits_withSeed(x.c_str(), x.length(), seed)};
|
||||
* }
|
||||
* };
|
||||
* // Fast, caches the seeded secret for future uses.
|
||||
* class HashFast {
|
||||
* unsigned char secret[XXH3_SECRET_SIZE_MIN];
|
||||
* public:
|
||||
* HashFast(XXH64_hash_t s) {
|
||||
* XXH3_generateSecret_fromSeed(secret, seed);
|
||||
* }
|
||||
* size_t operator()(const std::string& x) const {
|
||||
* return size_t{
|
||||
* XXH3_64bits_withSecret(x.c_str(), x.length(), secret, sizeof(secret))
|
||||
* };
|
||||
* }
|
||||
* };
|
||||
* @endcode
|
||||
*/
|
||||
XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(void* secretBuffer, XXH64_hash_t seed);
|
||||
XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(XXH_NOESCAPE void* secretBuffer, XXH64_hash_t seed);
|
||||
|
||||
/*
|
||||
* *_withSecretandSeed() :
|
||||
/*!
|
||||
* @brief Calculates 64/128-bit seeded variant of XXH3 hash of @p data.
|
||||
*
|
||||
* @param data The block of data to be hashed, at least @p len bytes in size.
|
||||
* @param len The length of @p data, in bytes.
|
||||
* @param secret The secret data.
|
||||
* @param secretSize The length of @p secret, in bytes.
|
||||
* @param seed The 64-bit seed to alter the hash result predictably.
|
||||
*
|
||||
* These variants generate hash values using either
|
||||
* @seed for "short" keys (< XXH3_MIDSIZE_MAX = 240 bytes)
|
||||
* or @secret for "large" keys (>= XXH3_MIDSIZE_MAX).
|
||||
* @p seed for "short" keys (< @ref XXH3_MIDSIZE_MAX = 240 bytes)
|
||||
* or @p secret for "large" keys (>= @ref XXH3_MIDSIZE_MAX).
|
||||
*
|
||||
* This generally benefits speed, compared to `_withSeed()` or `_withSecret()`.
|
||||
* `_withSeed()` has to generate the secret on the fly for "large" keys.
|
||||
@@ -1175,7 +1882,7 @@ XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(void* secretBuffer, XXH64_hash_
|
||||
* which requires more instructions than _withSeed() variants.
|
||||
* Therefore, _withSecretandSeed variant combines the best of both worlds.
|
||||
*
|
||||
* When @secret has been generated by XXH3_generateSecret_fromSeed(),
|
||||
* When @p secret has been generated by XXH3_generateSecret_fromSeed(),
|
||||
* this variant produces *exactly* the same results as `_withSeed()` variant,
|
||||
* hence offering only a pure speed benefit on "large" input,
|
||||
* by skipping the need to regenerate the secret for every large input.
|
||||
@@ -1184,33 +1891,71 @@ XXH_PUBLIC_API void XXH3_generateSecret_fromSeed(void* secretBuffer, XXH64_hash_
|
||||
* for example with XXH3_64bits(), which then becomes the seed,
|
||||
* and then employ both the seed and the secret in _withSecretandSeed().
|
||||
* On top of speed, an added benefit is that each bit in the secret
|
||||
* has a 50% chance to swap each bit in the output,
|
||||
* via its impact to the seed.
|
||||
* has a 50% chance to swap each bit in the output, via its impact to the seed.
|
||||
*
|
||||
* This is not guaranteed when using the secret directly in "small data" scenarios,
|
||||
* because only portions of the secret are employed for small data.
|
||||
*/
|
||||
XXH_PUBLIC_API XXH64_hash_t
|
||||
XXH3_64bits_withSecretandSeed(const void* data, size_t len,
|
||||
const void* secret, size_t secretSize,
|
||||
XXH_PUBLIC_API XXH_PUREF XXH64_hash_t
|
||||
XXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* data, size_t len,
|
||||
XXH_NOESCAPE const void* secret, size_t secretSize,
|
||||
XXH64_hash_t seed);
|
||||
|
||||
XXH_PUBLIC_API XXH128_hash_t
|
||||
XXH3_128bits_withSecretandSeed(const void* data, size_t len,
|
||||
const void* secret, size_t secretSize,
|
||||
/*!
|
||||
* @brief Calculates 128-bit seeded variant of XXH3 hash of @p data.
|
||||
*
|
||||
* @param input The block of data to be hashed, at least @p len bytes in size.
|
||||
* @param length The length of @p data, in bytes.
|
||||
* @param secret The secret data.
|
||||
* @param secretSize The length of @p secret, in bytes.
|
||||
* @param seed64 The 64-bit seed to alter the hash result predictably.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @see XXH3_64bits_withSecretandSeed()
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_PUREF XXH128_hash_t
|
||||
XXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length,
|
||||
XXH_NOESCAPE const void* secret, size_t secretSize,
|
||||
XXH64_hash_t seed64);
|
||||
|
||||
#ifndef XXH_NO_STREAM
|
||||
/*!
|
||||
* @brief Resets an @ref XXH3_state_t with secret data to begin a new hash.
|
||||
*
|
||||
* @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState().
|
||||
* @param secret The secret data.
|
||||
* @param secretSize The length of @p secret, in bytes.
|
||||
* @param seed64 The 64-bit seed to alter the hash result predictably.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @see XXH3_64bits_withSecretandSeed()
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
|
||||
const void* secret, size_t secretSize,
|
||||
XXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr,
|
||||
XXH_NOESCAPE const void* secret, size_t secretSize,
|
||||
XXH64_hash_t seed64);
|
||||
|
||||
/*!
|
||||
* @brief Resets an @ref XXH3_state_t with secret data to begin a new hash.
|
||||
*
|
||||
* @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState().
|
||||
* @param secret The secret data.
|
||||
* @param secretSize The length of @p secret, in bytes.
|
||||
* @param seed64 The 64-bit seed to alter the hash result predictably.
|
||||
*
|
||||
* @return @ref XXH_OK on success.
|
||||
* @return @ref XXH_ERROR on failure.
|
||||
*
|
||||
* @see XXH3_64bits_withSecretandSeed()
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
|
||||
const void* secret, size_t secretSize,
|
||||
XXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr,
|
||||
XXH_NOESCAPE const void* secret, size_t secretSize,
|
||||
XXH64_hash_t seed64);
|
||||
#endif /* !XXH_NO_STREAM */
|
||||
|
||||
|
||||
#endif /* XXH_NO_XXH3 */
|
||||
#endif /* !XXH_NO_XXH3 */
|
||||
#endif /* XXH_NO_LONG_LONG */
|
||||
#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)
|
||||
# define XXH_IMPLEMENTATION
|
||||
@@ -1264,7 +2009,7 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
|
||||
/*!
|
||||
* @brief Define this to disable 64-bit code.
|
||||
*
|
||||
* Useful if only using the @ref xxh32_family and you have a strict C90 compiler.
|
||||
* Useful if only using the @ref XXH32_family and you have a strict C90 compiler.
|
||||
*/
|
||||
# define XXH_NO_LONG_LONG
|
||||
# undef XXH_NO_LONG_LONG /* don't actually */
|
||||
@@ -1287,7 +2032,7 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
|
||||
* Use `memcpy()`. Safe and portable. Note that most modern compilers will
|
||||
* eliminate the function call and treat it as an unaligned access.
|
||||
*
|
||||
* - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((packed))`
|
||||
* - `XXH_FORCE_MEMORY_ACCESS=1`: `__attribute__((aligned(1)))`
|
||||
* @par
|
||||
* Depends on compiler extensions and is therefore not portable.
|
||||
* This method is safe _if_ your compiler supports it,
|
||||
@@ -1307,7 +2052,7 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
|
||||
* inline small `memcpy()` calls, and it might also be faster on big-endian
|
||||
* systems which lack a native byteswap instruction. However, some compilers
|
||||
* will emit literal byteshifts even if the target supports unaligned access.
|
||||
* .
|
||||
*
|
||||
*
|
||||
* @warning
|
||||
* Methods 1 and 2 rely on implementation-defined behavior. Use these with
|
||||
@@ -1320,6 +2065,34 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
|
||||
*/
|
||||
# define XXH_FORCE_MEMORY_ACCESS 0
|
||||
|
||||
/*!
|
||||
* @def XXH_SIZE_OPT
|
||||
* @brief Controls how much xxHash optimizes for size.
|
||||
*
|
||||
* xxHash, when compiled, tends to result in a rather large binary size. This
|
||||
* is mostly due to heavy usage to forced inlining and constant folding of the
|
||||
* @ref XXH3_family to increase performance.
|
||||
*
|
||||
* However, some developers prefer size over speed. This option can
|
||||
* significantly reduce the size of the generated code. When using the `-Os`
|
||||
* or `-Oz` options on GCC or Clang, this is defined to 1 by default,
|
||||
* otherwise it is defined to 0.
|
||||
*
|
||||
* Most of these size optimizations can be controlled manually.
|
||||
*
|
||||
* This is a number from 0-2.
|
||||
* - `XXH_SIZE_OPT` == 0: Default. xxHash makes no size optimizations. Speed
|
||||
* comes first.
|
||||
* - `XXH_SIZE_OPT` == 1: Default for `-Os` and `-Oz`. xxHash is more
|
||||
* conservative and disables hacks that increase code size. It implies the
|
||||
* options @ref XXH_NO_INLINE_HINTS == 1, @ref XXH_FORCE_ALIGN_CHECK == 0,
|
||||
* and @ref XXH3_NEON_LANES == 8 if they are not already defined.
|
||||
* - `XXH_SIZE_OPT` == 2: xxHash tries to make itself as small as possible.
|
||||
* Performance may cry. For example, the single shot functions just use the
|
||||
* streaming API.
|
||||
*/
|
||||
# define XXH_SIZE_OPT 0
|
||||
|
||||
/*!
|
||||
* @def XXH_FORCE_ALIGN_CHECK
|
||||
* @brief If defined to non-zero, adds a special path for aligned inputs (XXH32()
|
||||
@@ -1341,9 +2114,11 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
|
||||
*
|
||||
* In these cases, the alignment check can be removed by setting this macro to 0.
|
||||
* Then the code will always use unaligned memory access.
|
||||
* Align check is automatically disabled on x86, x64 & arm64,
|
||||
* Align check is automatically disabled on x86, x64, ARM64, and some ARM chips
|
||||
* which are platforms known to offer good unaligned memory accesses performance.
|
||||
*
|
||||
* It is also disabled by default when @ref XXH_SIZE_OPT >= 1.
|
||||
*
|
||||
* This option does not affect XXH3 (only XXH32 and XXH64).
|
||||
*/
|
||||
# define XXH_FORCE_ALIGN_CHECK 0
|
||||
@@ -1365,11 +2140,28 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
|
||||
* XXH_NO_INLINE_HINTS marks all internal functions as static, giving the
|
||||
* compiler full control on whether to inline or not.
|
||||
*
|
||||
* When not optimizing (-O0), optimizing for size (-Os, -Oz), or using
|
||||
* -fno-inline with GCC or Clang, this will automatically be defined.
|
||||
* When not optimizing (-O0), using `-fno-inline` with GCC or Clang, or if
|
||||
* @ref XXH_SIZE_OPT >= 1, this will automatically be defined.
|
||||
*/
|
||||
# define XXH_NO_INLINE_HINTS 0
|
||||
|
||||
/*!
|
||||
* @def XXH3_INLINE_SECRET
|
||||
* @brief Determines whether to inline the XXH3 withSecret code.
|
||||
*
|
||||
* When the secret size is known, the compiler can improve the performance
|
||||
* of XXH3_64bits_withSecret() and XXH3_128bits_withSecret().
|
||||
*
|
||||
* However, if the secret size is not known, it doesn't have any benefit. This
|
||||
* happens when xxHash is compiled into a global symbol. Therefore, if
|
||||
* @ref XXH_INLINE_ALL is *not* defined, this will be defined to 0.
|
||||
*
|
||||
* Additionally, this defaults to 0 on GCC 12+, which has an issue with function pointers
|
||||
* that are *sometimes* force inline on -Og, and it is impossible to automatically
|
||||
* detect this optimization level.
|
||||
*/
|
||||
# define XXH3_INLINE_SECRET 0
|
||||
|
||||
/*!
|
||||
* @def XXH32_ENDJMP
|
||||
* @brief Whether to use a jump for `XXH32_finalize`.
|
||||
@@ -1391,34 +2183,45 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
|
||||
*/
|
||||
# define XXH_OLD_NAMES
|
||||
# undef XXH_OLD_NAMES /* don't actually use, it is ugly. */
|
||||
|
||||
/*!
|
||||
* @def XXH_NO_STREAM
|
||||
* @brief Disables the streaming API.
|
||||
*
|
||||
* When xxHash is not inlined and the streaming functions are not used, disabling
|
||||
* the streaming functions can improve code size significantly, especially with
|
||||
* the @ref XXH3_family which tends to make constant folded copies of itself.
|
||||
*/
|
||||
# define XXH_NO_STREAM
|
||||
# undef XXH_NO_STREAM /* don't actually */
|
||||
#endif /* XXH_DOXYGEN */
|
||||
/*!
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifndef XXH_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */
|
||||
/* prefer __packed__ structures (method 1) for gcc on armv7+ and mips */
|
||||
# if !defined(__clang__) && \
|
||||
( \
|
||||
(defined(__INTEL_COMPILER) && !defined(_WIN32)) || \
|
||||
( \
|
||||
defined(__GNUC__) && ( \
|
||||
(defined(__ARM_ARCH) && __ARM_ARCH >= 7) || \
|
||||
( \
|
||||
defined(__mips__) && \
|
||||
(__mips <= 5 || __mips_isa_rev < 6) && \
|
||||
(!defined(__mips16) || defined(__mips_mips16e2)) \
|
||||
) \
|
||||
) \
|
||||
) \
|
||||
)
|
||||
/* prefer __packed__ structures (method 1) for GCC
|
||||
* < ARMv7 with unaligned access (e.g. Raspbian armhf) still uses byte shifting, so we use memcpy
|
||||
* which for some reason does unaligned loads. */
|
||||
# if defined(__GNUC__) && !(defined(__ARM_ARCH) && __ARM_ARCH < 7 && defined(__ARM_FEATURE_UNALIGNED))
|
||||
# define XXH_FORCE_MEMORY_ACCESS 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef XXH_SIZE_OPT
|
||||
/* default to 1 for -Os or -Oz */
|
||||
# if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE_SIZE__)
|
||||
# define XXH_SIZE_OPT 1
|
||||
# else
|
||||
# define XXH_SIZE_OPT 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */
|
||||
# if defined(__i386) || defined(__x86_64__) || defined(__aarch64__) \
|
||||
|| defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) /* visual */
|
||||
/* don't check on sizeopt, x86, aarch64, or arm when unaligned access is available */
|
||||
# if XXH_SIZE_OPT >= 1 || \
|
||||
defined(__i386) || defined(__x86_64__) || defined(__aarch64__) || defined(__ARM_FEATURE_UNALIGNED) \
|
||||
|| defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) || defined(_M_ARM) /* visual */
|
||||
# define XXH_FORCE_ALIGN_CHECK 0
|
||||
# else
|
||||
# define XXH_FORCE_ALIGN_CHECK 1
|
||||
@@ -1426,14 +2229,22 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
|
||||
#endif
|
||||
|
||||
#ifndef XXH_NO_INLINE_HINTS
|
||||
# if defined(__OPTIMIZE_SIZE__) /* -Os, -Oz */ \
|
||||
|| defined(__NO_INLINE__) /* -O0, -fno-inline */
|
||||
# if XXH_SIZE_OPT >= 1 || defined(__NO_INLINE__) /* -O0, -fno-inline */
|
||||
# define XXH_NO_INLINE_HINTS 1
|
||||
# else
|
||||
# define XXH_NO_INLINE_HINTS 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef XXH3_INLINE_SECRET
|
||||
# if (defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 12) \
|
||||
|| !defined(XXH_INLINE_ALL)
|
||||
# define XXH3_INLINE_SECRET 0
|
||||
# else
|
||||
# define XXH3_INLINE_SECRET 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef XXH32_ENDJMP
|
||||
/* generally preferable for performance */
|
||||
# define XXH32_ENDJMP 0
|
||||
@@ -1448,13 +2259,56 @@ XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr,
|
||||
/* *************************************
|
||||
* Includes & Memory related functions
|
||||
***************************************/
|
||||
/* Modify the local functions below should you wish to use some other memory routines */
|
||||
/* for ZSTD_malloc(), ZSTD_free() */
|
||||
#define ZSTD_DEPS_NEED_MALLOC
|
||||
#include "zstd_deps.h" /* size_t, ZSTD_malloc, ZSTD_free, ZSTD_memcpy */
|
||||
static void* XXH_malloc(size_t s) { return ZSTD_malloc(s); }
|
||||
static void XXH_free (void* p) { ZSTD_free(p); }
|
||||
static void* XXH_memcpy(void* dest, const void* src, size_t size) { return ZSTD_memcpy(dest,src,size); }
|
||||
#if defined(XXH_NO_STREAM)
|
||||
/* nothing */
|
||||
#elif defined(XXH_NO_STDLIB)
|
||||
|
||||
/* When requesting to disable any mention of stdlib,
|
||||
* the library loses the ability to invoked malloc / free.
|
||||
* In practice, it means that functions like `XXH*_createState()`
|
||||
* will always fail, and return NULL.
|
||||
* This flag is useful in situations where
|
||||
* xxhash.h is integrated into some kernel, embedded or limited environment
|
||||
* without access to dynamic allocation.
|
||||
*/
|
||||
|
||||
static XXH_CONSTF void* XXH_malloc(size_t s) { (void)s; return NULL; }
|
||||
static void XXH_free(void* p) { (void)p; }
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* Modify the local functions below should you wish to use
|
||||
* different memory routines for malloc() and free()
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
/*!
|
||||
* @internal
|
||||
* @brief Modify this function to use a different routine than malloc().
|
||||
*/
|
||||
static XXH_MALLOCF void* XXH_malloc(size_t s) { return malloc(s); }
|
||||
|
||||
/*!
|
||||
* @internal
|
||||
* @brief Modify this function to use a different routine than free().
|
||||
*/
|
||||
static void XXH_free(void* p) { free(p); }
|
||||
|
||||
#endif /* XXH_NO_STDLIB */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/*!
|
||||
* @internal
|
||||
* @brief Modify this function to use a different routine than memcpy().
|
||||
*/
|
||||
static void* XXH_memcpy(void* dest, const void* src, size_t size)
|
||||
{
|
||||
return memcpy(dest,src,size);
|
||||
}
|
||||
|
||||
#include <limits.h> /* ULLONG_MAX */
|
||||
|
||||
|
||||
/* *************************************
|
||||
@@ -1487,6 +2341,11 @@ static void* XXH_memcpy(void* dest, const void* src, size_t size) { return ZSTD_
|
||||
# define XXH_NO_INLINE static
|
||||
#endif
|
||||
|
||||
#if XXH3_INLINE_SECRET
|
||||
# define XXH3_WITH_SECRET_INLINE XXH_FORCE_INLINE
|
||||
#else
|
||||
# define XXH3_WITH_SECRET_INLINE XXH_NO_INLINE
|
||||
#endif
|
||||
|
||||
|
||||
/* *************************************
|
||||
@@ -1512,14 +2371,17 @@ static void* XXH_memcpy(void* dest, const void* src, size_t size) { return ZSTD_
|
||||
# include <assert.h> /* note: can still be disabled with NDEBUG */
|
||||
# define XXH_ASSERT(c) assert(c)
|
||||
#else
|
||||
# define XXH_ASSERT(c) ((void)0)
|
||||
# if defined(__INTEL_COMPILER)
|
||||
# define XXH_ASSERT(c) XXH_ASSUME((unsigned char) (c))
|
||||
# else
|
||||
# define XXH_ASSERT(c) XXH_ASSUME(c)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* note: use after variable declarations */
|
||||
#ifndef XXH_STATIC_ASSERT
|
||||
# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11 */
|
||||
# include <assert.h>
|
||||
# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0)
|
||||
# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { _Static_assert((c),m); } while(0)
|
||||
# elif defined(__cplusplus) && (__cplusplus >= 201103L) /* C++11 */
|
||||
# define XXH_STATIC_ASSERT_WITH_MESSAGE(c,m) do { static_assert((c),m); } while(0)
|
||||
# else
|
||||
@@ -1534,7 +2396,7 @@ static void* XXH_memcpy(void* dest, const void* src, size_t size) { return ZSTD_
|
||||
* @brief Used to prevent unwanted optimizations for @p var.
|
||||
*
|
||||
* It uses an empty GCC inline assembly statement with a register constraint
|
||||
* which forces @p var into a general purpose register (e.g. eax, ebx, ecx
|
||||
* which forces @p var into a general purpose register (eg eax, ebx, ecx
|
||||
* on x86) and marks it as modified.
|
||||
*
|
||||
* This is used in a few places to avoid unwanted autovectorization (e.g.
|
||||
@@ -1545,11 +2407,19 @@ static void* XXH_memcpy(void* dest, const void* src, size_t size) { return ZSTD_
|
||||
* XXH3_initCustomSecret_scalar().
|
||||
*/
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define XXH_COMPILER_GUARD(var) __asm__ __volatile__("" : "+r" (var))
|
||||
# define XXH_COMPILER_GUARD(var) __asm__("" : "+r" (var))
|
||||
#else
|
||||
# define XXH_COMPILER_GUARD(var) ((void)0)
|
||||
#endif
|
||||
|
||||
/* Specifically for NEON vectors which use the "w" constraint, on
|
||||
* Clang. */
|
||||
#if defined(__clang__) && defined(__ARM_ARCH) && !defined(__wasm__)
|
||||
# define XXH_COMPILER_GUARD_CLANG_NEON(var) __asm__("" : "+w" (var))
|
||||
#else
|
||||
# define XXH_COMPILER_GUARD_CLANG_NEON(var) ((void)0)
|
||||
#endif
|
||||
|
||||
/* *************************************
|
||||
* Basic Types
|
||||
***************************************/
|
||||
@@ -1564,6 +2434,7 @@ static void* XXH_memcpy(void* dest, const void* src, size_t size) { return ZSTD_
|
||||
typedef XXH32_hash_t xxh_u32;
|
||||
|
||||
#ifdef XXH_OLD_NAMES
|
||||
# warning "XXH_OLD_NAMES is planned to be removed starting v0.9. If the program depends on it, consider moving away from it by employing newer type names directly"
|
||||
# define BYTE xxh_u8
|
||||
# define U8 xxh_u8
|
||||
# define U32 xxh_u32
|
||||
@@ -1637,18 +2508,19 @@ static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr;
|
||||
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
|
||||
|
||||
/*
|
||||
* __pack instructions are safer but compiler specific, hence potentially
|
||||
* problematic for some compilers.
|
||||
*
|
||||
* Currently only defined for GCC and ICC.
|
||||
* __attribute__((aligned(1))) is supported by gcc and clang. Originally the
|
||||
* documentation claimed that it only increased the alignment, but actually it
|
||||
* can decrease it on gcc, clang, and icc:
|
||||
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502,
|
||||
* https://gcc.godbolt.org/z/xYez1j67Y.
|
||||
*/
|
||||
#ifdef XXH_OLD_NAMES
|
||||
typedef union { xxh_u32 u32; } __attribute__((packed)) unalign;
|
||||
#endif
|
||||
static xxh_u32 XXH_read32(const void* ptr)
|
||||
{
|
||||
typedef union { xxh_u32 u32; } __attribute__((packed)) xxh_unalign;
|
||||
return ((const xxh_unalign*)ptr)->u32;
|
||||
typedef __attribute__((aligned(1))) xxh_u32 xxh_unalign32;
|
||||
return *((const xxh_unalign32*)ptr);
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -1731,6 +2603,51 @@ static int XXH_isLittleEndian(void)
|
||||
# define XXH_HAS_BUILTIN(x) 0
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* C23 and future versions have standard "unreachable()".
|
||||
* Once it has been implemented reliably we can add it as an
|
||||
* additional case:
|
||||
*
|
||||
* ```
|
||||
* #if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= XXH_C23_VN)
|
||||
* # include <stddef.h>
|
||||
* # ifdef unreachable
|
||||
* # define XXH_UNREACHABLE() unreachable()
|
||||
* # endif
|
||||
* #endif
|
||||
* ```
|
||||
*
|
||||
* Note C++23 also has std::unreachable() which can be detected
|
||||
* as follows:
|
||||
* ```
|
||||
* #if defined(__cpp_lib_unreachable) && (__cpp_lib_unreachable >= 202202L)
|
||||
* # include <utility>
|
||||
* # define XXH_UNREACHABLE() std::unreachable()
|
||||
* #endif
|
||||
* ```
|
||||
* NB: `__cpp_lib_unreachable` is defined in the `<version>` header.
|
||||
* We don't use that as including `<utility>` in `extern "C"` blocks
|
||||
* doesn't work on GCC12
|
||||
*/
|
||||
|
||||
#if XXH_HAS_BUILTIN(__builtin_unreachable)
|
||||
# define XXH_UNREACHABLE() __builtin_unreachable()
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
# define XXH_UNREACHABLE() __assume(0)
|
||||
|
||||
#else
|
||||
# define XXH_UNREACHABLE()
|
||||
#endif
|
||||
|
||||
#if XXH_HAS_BUILTIN(__builtin_assume)
|
||||
# define XXH_ASSUME(c) __builtin_assume(c)
|
||||
#else
|
||||
# define XXH_ASSUME(c) if (!(c)) { XXH_UNREACHABLE(); }
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @internal
|
||||
* @def XXH_rotl32(x,r)
|
||||
@@ -1853,8 +2770,10 @@ XXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }
|
||||
*********************************************************************/
|
||||
/*!
|
||||
* @}
|
||||
* @defgroup xxh32_impl XXH32 implementation
|
||||
* @defgroup XXH32_impl XXH32 implementation
|
||||
* @ingroup impl
|
||||
*
|
||||
* Details on the XXH32 implementation.
|
||||
* @{
|
||||
*/
|
||||
/* #define instead of static const, to be used as initializers */
|
||||
@@ -1888,7 +2807,7 @@ static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input)
|
||||
acc += input * XXH_PRIME32_2;
|
||||
acc = XXH_rotl32(acc, 13);
|
||||
acc *= XXH_PRIME32_1;
|
||||
#if (defined(__SSE4_1__) || defined(__aarch64__)) && !defined(XXH_ENABLE_AUTOVECTORIZE)
|
||||
#if (defined(__SSE4_1__) || defined(__aarch64__) || defined(__wasm_simd128__)) && !defined(XXH_ENABLE_AUTOVECTORIZE)
|
||||
/*
|
||||
* UGLY HACK:
|
||||
* A compiler fence is the only thing that prevents GCC and Clang from
|
||||
@@ -1918,9 +2837,12 @@ static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input)
|
||||
* can load data, while v3 can multiply. SSE forces them to operate
|
||||
* together.
|
||||
*
|
||||
* This is also enabled on AArch64, as Clang autovectorizes it incorrectly
|
||||
* and it is pointless writing a NEON implementation that is basically the
|
||||
* same speed as scalar for XXH32.
|
||||
* This is also enabled on AArch64, as Clang is *very aggressive* in vectorizing
|
||||
* the loop. NEON is only faster on the A53, and with the newer cores, it is less
|
||||
* than half the speed.
|
||||
*
|
||||
* Additionally, this is used on WASM SIMD128 because it JITs to the same
|
||||
* SIMD instructions and has the same issue.
|
||||
*/
|
||||
XXH_COMPILER_GUARD(acc);
|
||||
#endif
|
||||
@@ -1934,17 +2856,17 @@ static xxh_u32 XXH32_round(xxh_u32 acc, xxh_u32 input)
|
||||
* The final mix ensures that all input bits have a chance to impact any bit in
|
||||
* the output digest, resulting in an unbiased distribution.
|
||||
*
|
||||
* @param h32 The hash to avalanche.
|
||||
* @param hash The hash to avalanche.
|
||||
* @return The avalanched hash.
|
||||
*/
|
||||
static xxh_u32 XXH32_avalanche(xxh_u32 h32)
|
||||
static xxh_u32 XXH32_avalanche(xxh_u32 hash)
|
||||
{
|
||||
h32 ^= h32 >> 15;
|
||||
h32 *= XXH_PRIME32_2;
|
||||
h32 ^= h32 >> 13;
|
||||
h32 *= XXH_PRIME32_3;
|
||||
h32 ^= h32 >> 16;
|
||||
return(h32);
|
||||
hash ^= hash >> 15;
|
||||
hash *= XXH_PRIME32_2;
|
||||
hash ^= hash >> 13;
|
||||
hash *= XXH_PRIME32_3;
|
||||
hash ^= hash >> 16;
|
||||
return hash;
|
||||
}
|
||||
|
||||
#define XXH_get32bits(p) XXH_readLE32_align(p, align)
|
||||
@@ -1957,24 +2879,25 @@ static xxh_u32 XXH32_avalanche(xxh_u32 h32)
|
||||
* This final stage will digest them to ensure that all input bytes are present
|
||||
* in the final mix.
|
||||
*
|
||||
* @param h32 The hash to finalize.
|
||||
* @param hash The hash to finalize.
|
||||
* @param ptr The pointer to the remaining input.
|
||||
* @param len The remaining length, modulo 16.
|
||||
* @param align Whether @p ptr is aligned.
|
||||
* @return The finalized hash.
|
||||
* @see XXH64_finalize().
|
||||
*/
|
||||
static xxh_u32
|
||||
XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align)
|
||||
static XXH_PUREF xxh_u32
|
||||
XXH32_finalize(xxh_u32 hash, const xxh_u8* ptr, size_t len, XXH_alignment align)
|
||||
{
|
||||
#define XXH_PROCESS1 do { \
|
||||
h32 += (*ptr++) * XXH_PRIME32_5; \
|
||||
h32 = XXH_rotl32(h32, 11) * XXH_PRIME32_1; \
|
||||
#define XXH_PROCESS1 do { \
|
||||
hash += (*ptr++) * XXH_PRIME32_5; \
|
||||
hash = XXH_rotl32(hash, 11) * XXH_PRIME32_1; \
|
||||
} while (0)
|
||||
|
||||
#define XXH_PROCESS4 do { \
|
||||
h32 += XXH_get32bits(ptr) * XXH_PRIME32_3; \
|
||||
ptr += 4; \
|
||||
h32 = XXH_rotl32(h32, 17) * XXH_PRIME32_4; \
|
||||
#define XXH_PROCESS4 do { \
|
||||
hash += XXH_get32bits(ptr) * XXH_PRIME32_3; \
|
||||
ptr += 4; \
|
||||
hash = XXH_rotl32(hash, 17) * XXH_PRIME32_4; \
|
||||
} while (0)
|
||||
|
||||
if (ptr==NULL) XXH_ASSERT(len == 0);
|
||||
@@ -1990,49 +2913,49 @@ XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align)
|
||||
XXH_PROCESS1;
|
||||
--len;
|
||||
}
|
||||
return XXH32_avalanche(h32);
|
||||
return XXH32_avalanche(hash);
|
||||
} else {
|
||||
switch(len&15) /* or switch(bEnd - p) */ {
|
||||
case 12: XXH_PROCESS4;
|
||||
XXH_FALLTHROUGH;
|
||||
XXH_FALLTHROUGH; /* fallthrough */
|
||||
case 8: XXH_PROCESS4;
|
||||
XXH_FALLTHROUGH;
|
||||
XXH_FALLTHROUGH; /* fallthrough */
|
||||
case 4: XXH_PROCESS4;
|
||||
return XXH32_avalanche(h32);
|
||||
return XXH32_avalanche(hash);
|
||||
|
||||
case 13: XXH_PROCESS4;
|
||||
XXH_FALLTHROUGH;
|
||||
XXH_FALLTHROUGH; /* fallthrough */
|
||||
case 9: XXH_PROCESS4;
|
||||
XXH_FALLTHROUGH;
|
||||
XXH_FALLTHROUGH; /* fallthrough */
|
||||
case 5: XXH_PROCESS4;
|
||||
XXH_PROCESS1;
|
||||
return XXH32_avalanche(h32);
|
||||
return XXH32_avalanche(hash);
|
||||
|
||||
case 14: XXH_PROCESS4;
|
||||
XXH_FALLTHROUGH;
|
||||
XXH_FALLTHROUGH; /* fallthrough */
|
||||
case 10: XXH_PROCESS4;
|
||||
XXH_FALLTHROUGH;
|
||||
XXH_FALLTHROUGH; /* fallthrough */
|
||||
case 6: XXH_PROCESS4;
|
||||
XXH_PROCESS1;
|
||||
XXH_PROCESS1;
|
||||
return XXH32_avalanche(h32);
|
||||
return XXH32_avalanche(hash);
|
||||
|
||||
case 15: XXH_PROCESS4;
|
||||
XXH_FALLTHROUGH;
|
||||
XXH_FALLTHROUGH; /* fallthrough */
|
||||
case 11: XXH_PROCESS4;
|
||||
XXH_FALLTHROUGH;
|
||||
XXH_FALLTHROUGH; /* fallthrough */
|
||||
case 7: XXH_PROCESS4;
|
||||
XXH_FALLTHROUGH;
|
||||
XXH_FALLTHROUGH; /* fallthrough */
|
||||
case 3: XXH_PROCESS1;
|
||||
XXH_FALLTHROUGH;
|
||||
XXH_FALLTHROUGH; /* fallthrough */
|
||||
case 2: XXH_PROCESS1;
|
||||
XXH_FALLTHROUGH;
|
||||
XXH_FALLTHROUGH; /* fallthrough */
|
||||
case 1: XXH_PROCESS1;
|
||||
XXH_FALLTHROUGH;
|
||||
case 0: return XXH32_avalanche(h32);
|
||||
XXH_FALLTHROUGH; /* fallthrough */
|
||||
case 0: return XXH32_avalanche(hash);
|
||||
}
|
||||
XXH_ASSERT(0);
|
||||
return h32; /* reaching this point is deemed impossible */
|
||||
return hash; /* reaching this point is deemed impossible */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2052,7 +2975,7 @@ XXH32_finalize(xxh_u32 h32, const xxh_u8* ptr, size_t len, XXH_alignment align)
|
||||
* @param align Whether @p input is aligned.
|
||||
* @return The calculated hash.
|
||||
*/
|
||||
XXH_FORCE_INLINE xxh_u32
|
||||
XXH_FORCE_INLINE XXH_PUREF xxh_u32
|
||||
XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment align)
|
||||
{
|
||||
xxh_u32 h32;
|
||||
@@ -2085,10 +3008,10 @@ XXH32_endian_align(const xxh_u8* input, size_t len, xxh_u32 seed, XXH_alignment
|
||||
return XXH32_finalize(h32, input, len&15, align);
|
||||
}
|
||||
|
||||
/*! @ingroup xxh32_family */
|
||||
/*! @ingroup XXH32_family */
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t seed)
|
||||
{
|
||||
#if 0
|
||||
#if !defined(XXH_NO_STREAM) && XXH_SIZE_OPT >= 2
|
||||
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||
XXH32_state_t state;
|
||||
XXH32_reset(&state, seed);
|
||||
@@ -2107,27 +3030,26 @@ XXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t len, XXH32_hash_t s
|
||||
|
||||
|
||||
/******* Hash streaming *******/
|
||||
/*!
|
||||
* @ingroup xxh32_family
|
||||
*/
|
||||
#ifndef XXH_NO_STREAM
|
||||
/*! @ingroup XXH32_family */
|
||||
XXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)
|
||||
{
|
||||
return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));
|
||||
}
|
||||
/*! @ingroup xxh32_family */
|
||||
/*! @ingroup XXH32_family */
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)
|
||||
{
|
||||
XXH_free(statePtr);
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
/*! @ingroup xxh32_family */
|
||||
/*! @ingroup XXH32_family */
|
||||
XXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)
|
||||
{
|
||||
XXH_memcpy(dstState, srcState, sizeof(*dstState));
|
||||
}
|
||||
|
||||
/*! @ingroup xxh32_family */
|
||||
/*! @ingroup XXH32_family */
|
||||
XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t seed)
|
||||
{
|
||||
XXH_ASSERT(statePtr != NULL);
|
||||
@@ -2140,7 +3062,7 @@ XXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, XXH32_hash_t s
|
||||
}
|
||||
|
||||
|
||||
/*! @ingroup xxh32_family */
|
||||
/*! @ingroup XXH32_family */
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH32_update(XXH32_state_t* state, const void* input, size_t len)
|
||||
{
|
||||
@@ -2195,7 +3117,7 @@ XXH32_update(XXH32_state_t* state, const void* input, size_t len)
|
||||
}
|
||||
|
||||
|
||||
/*! @ingroup xxh32_family */
|
||||
/*! @ingroup XXH32_family */
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state)
|
||||
{
|
||||
xxh_u32 h32;
|
||||
@@ -2213,31 +3135,18 @@ XXH_PUBLIC_API XXH32_hash_t XXH32_digest(const XXH32_state_t* state)
|
||||
|
||||
return XXH32_finalize(h32, (const xxh_u8*)state->mem32, state->memsize, XXH_aligned);
|
||||
}
|
||||
|
||||
#endif /* !XXH_NO_STREAM */
|
||||
|
||||
/******* Canonical representation *******/
|
||||
|
||||
/*!
|
||||
* @ingroup xxh32_family
|
||||
* The default return values from XXH functions are unsigned 32 and 64 bit
|
||||
* integers.
|
||||
*
|
||||
* The canonical representation uses big endian convention, the same convention
|
||||
* as human-readable numbers (large digits first).
|
||||
*
|
||||
* This way, hash values can be written into a file or buffer, remaining
|
||||
* comparable across different systems.
|
||||
*
|
||||
* The following functions allow transformation of hash values to and from their
|
||||
* canonical format.
|
||||
*/
|
||||
/*! @ingroup XXH32_family */
|
||||
XXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)
|
||||
{
|
||||
/* XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t)); */
|
||||
XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));
|
||||
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);
|
||||
XXH_memcpy(dst, &hash, sizeof(*dst));
|
||||
}
|
||||
/*! @ingroup xxh32_family */
|
||||
/*! @ingroup XXH32_family */
|
||||
XXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)
|
||||
{
|
||||
return XXH_readBE32(src);
|
||||
@@ -2278,18 +3187,19 @@ static xxh_u64 XXH_read64(const void* memPtr)
|
||||
#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))
|
||||
|
||||
/*
|
||||
* __pack instructions are safer, but compiler specific, hence potentially
|
||||
* problematic for some compilers.
|
||||
*
|
||||
* Currently only defined for GCC and ICC.
|
||||
* __attribute__((aligned(1))) is supported by gcc and clang. Originally the
|
||||
* documentation claimed that it only increased the alignment, but actually it
|
||||
* can decrease it on gcc, clang, and icc:
|
||||
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69502,
|
||||
* https://gcc.godbolt.org/z/xYez1j67Y.
|
||||
*/
|
||||
#ifdef XXH_OLD_NAMES
|
||||
typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) unalign64;
|
||||
#endif
|
||||
static xxh_u64 XXH_read64(const void* ptr)
|
||||
{
|
||||
typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) xxh_unalign64;
|
||||
return ((const xxh_unalign64*)ptr)->u64;
|
||||
typedef __attribute__((aligned(1))) xxh_u64 xxh_unalign64;
|
||||
return *((const xxh_unalign64*)ptr);
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -2380,8 +3290,10 @@ XXH_readLE64_align(const void* ptr, XXH_alignment align)
|
||||
/******* xxh64 *******/
|
||||
/*!
|
||||
* @}
|
||||
* @defgroup xxh64_impl XXH64 implementation
|
||||
* @defgroup XXH64_impl XXH64 implementation
|
||||
* @ingroup impl
|
||||
*
|
||||
* Details on the XXH64 implementation.
|
||||
* @{
|
||||
*/
|
||||
/* #define rather that static const, to be used as initializers */
|
||||
@@ -2399,6 +3311,7 @@ XXH_readLE64_align(const void* ptr, XXH_alignment align)
|
||||
# define PRIME64_5 XXH_PRIME64_5
|
||||
#endif
|
||||
|
||||
/*! @copydoc XXH32_round */
|
||||
static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input)
|
||||
{
|
||||
acc += input * XXH_PRIME64_2;
|
||||
@@ -2415,43 +3328,59 @@ static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val)
|
||||
return acc;
|
||||
}
|
||||
|
||||
static xxh_u64 XXH64_avalanche(xxh_u64 h64)
|
||||
/*! @copydoc XXH32_avalanche */
|
||||
static xxh_u64 XXH64_avalanche(xxh_u64 hash)
|
||||
{
|
||||
h64 ^= h64 >> 33;
|
||||
h64 *= XXH_PRIME64_2;
|
||||
h64 ^= h64 >> 29;
|
||||
h64 *= XXH_PRIME64_3;
|
||||
h64 ^= h64 >> 32;
|
||||
return h64;
|
||||
hash ^= hash >> 33;
|
||||
hash *= XXH_PRIME64_2;
|
||||
hash ^= hash >> 29;
|
||||
hash *= XXH_PRIME64_3;
|
||||
hash ^= hash >> 32;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
||||
#define XXH_get64bits(p) XXH_readLE64_align(p, align)
|
||||
|
||||
static xxh_u64
|
||||
XXH64_finalize(xxh_u64 h64, const xxh_u8* ptr, size_t len, XXH_alignment align)
|
||||
/*!
|
||||
* @internal
|
||||
* @brief Processes the last 0-31 bytes of @p ptr.
|
||||
*
|
||||
* There may be up to 31 bytes remaining to consume from the input.
|
||||
* This final stage will digest them to ensure that all input bytes are present
|
||||
* in the final mix.
|
||||
*
|
||||
* @param hash The hash to finalize.
|
||||
* @param ptr The pointer to the remaining input.
|
||||
* @param len The remaining length, modulo 32.
|
||||
* @param align Whether @p ptr is aligned.
|
||||
* @return The finalized hash
|
||||
* @see XXH32_finalize().
|
||||
*/
|
||||
static XXH_PUREF xxh_u64
|
||||
XXH64_finalize(xxh_u64 hash, const xxh_u8* ptr, size_t len, XXH_alignment align)
|
||||
{
|
||||
if (ptr==NULL) XXH_ASSERT(len == 0);
|
||||
len &= 31;
|
||||
while (len >= 8) {
|
||||
xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr));
|
||||
ptr += 8;
|
||||
h64 ^= k1;
|
||||
h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||
hash ^= k1;
|
||||
hash = XXH_rotl64(hash,27) * XXH_PRIME64_1 + XXH_PRIME64_4;
|
||||
len -= 8;
|
||||
}
|
||||
if (len >= 4) {
|
||||
h64 ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1;
|
||||
hash ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1;
|
||||
ptr += 4;
|
||||
h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
|
||||
hash = XXH_rotl64(hash, 23) * XXH_PRIME64_2 + XXH_PRIME64_3;
|
||||
len -= 4;
|
||||
}
|
||||
while (len > 0) {
|
||||
h64 ^= (*ptr++) * XXH_PRIME64_5;
|
||||
h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1;
|
||||
hash ^= (*ptr++) * XXH_PRIME64_5;
|
||||
hash = XXH_rotl64(hash, 11) * XXH_PRIME64_1;
|
||||
--len;
|
||||
}
|
||||
return XXH64_avalanche(h64);
|
||||
return XXH64_avalanche(hash);
|
||||
}
|
||||
|
||||
#ifdef XXH_OLD_NAMES
|
||||
@@ -2464,7 +3393,15 @@ XXH64_finalize(xxh_u64 h64, const xxh_u8* ptr, size_t len, XXH_alignment align)
|
||||
# undef XXH_PROCESS8_64
|
||||
#endif
|
||||
|
||||
XXH_FORCE_INLINE xxh_u64
|
||||
/*!
|
||||
* @internal
|
||||
* @brief The implementation for @ref XXH64().
|
||||
*
|
||||
* @param input , len , seed Directly passed from @ref XXH64().
|
||||
* @param align Whether @p input is aligned.
|
||||
* @return The calculated hash.
|
||||
*/
|
||||
XXH_FORCE_INLINE XXH_PUREF xxh_u64
|
||||
XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment align)
|
||||
{
|
||||
xxh_u64 h64;
|
||||
@@ -2501,10 +3438,10 @@ XXH64_endian_align(const xxh_u8* input, size_t len, xxh_u64 seed, XXH_alignment
|
||||
}
|
||||
|
||||
|
||||
/*! @ingroup xxh64_family */
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t len, XXH64_hash_t seed)
|
||||
/*! @ingroup XXH64_family */
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64 (XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed)
|
||||
{
|
||||
#if 0
|
||||
#if !defined(XXH_NO_STREAM) && XXH_SIZE_OPT >= 2
|
||||
/* Simple version, good for code maintenance, but unfortunately slow for small inputs */
|
||||
XXH64_state_t state;
|
||||
XXH64_reset(&state, seed);
|
||||
@@ -2522,27 +3459,27 @@ XXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t len, XXH64_hash_t s
|
||||
}
|
||||
|
||||
/******* Hash Streaming *******/
|
||||
|
||||
/*! @ingroup xxh64_family*/
|
||||
#ifndef XXH_NO_STREAM
|
||||
/*! @ingroup XXH64_family*/
|
||||
XXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)
|
||||
{
|
||||
return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));
|
||||
}
|
||||
/*! @ingroup xxh64_family */
|
||||
/*! @ingroup XXH64_family */
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)
|
||||
{
|
||||
XXH_free(statePtr);
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
/*! @ingroup xxh64_family */
|
||||
XXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)
|
||||
/*! @ingroup XXH64_family */
|
||||
XXH_PUBLIC_API void XXH64_copyState(XXH_NOESCAPE XXH64_state_t* dstState, const XXH64_state_t* srcState)
|
||||
{
|
||||
XXH_memcpy(dstState, srcState, sizeof(*dstState));
|
||||
}
|
||||
|
||||
/*! @ingroup xxh64_family */
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, XXH64_hash_t seed)
|
||||
/*! @ingroup XXH64_family */
|
||||
XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH_NOESCAPE XXH64_state_t* statePtr, XXH64_hash_t seed)
|
||||
{
|
||||
XXH_ASSERT(statePtr != NULL);
|
||||
memset(statePtr, 0, sizeof(*statePtr));
|
||||
@@ -2553,9 +3490,9 @@ XXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, XXH64_hash_t s
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
/*! @ingroup xxh64_family */
|
||||
/*! @ingroup XXH64_family */
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH64_update (XXH64_state_t* state, const void* input, size_t len)
|
||||
XXH64_update (XXH_NOESCAPE XXH64_state_t* state, XXH_NOESCAPE const void* input, size_t len)
|
||||
{
|
||||
if (input==NULL) {
|
||||
XXH_ASSERT(len == 0);
|
||||
@@ -2605,8 +3542,8 @@ XXH64_update (XXH64_state_t* state, const void* input, size_t len)
|
||||
}
|
||||
|
||||
|
||||
/*! @ingroup xxh64_family */
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_digest(const XXH64_state_t* state)
|
||||
/*! @ingroup XXH64_family */
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_digest(XXH_NOESCAPE const XXH64_state_t* state)
|
||||
{
|
||||
xxh_u64 h64;
|
||||
|
||||
@@ -2624,20 +3561,20 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_digest(const XXH64_state_t* state)
|
||||
|
||||
return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, XXH_aligned);
|
||||
}
|
||||
|
||||
#endif /* !XXH_NO_STREAM */
|
||||
|
||||
/******* Canonical representation *******/
|
||||
|
||||
/*! @ingroup xxh64_family */
|
||||
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)
|
||||
/*! @ingroup XXH64_family */
|
||||
XXH_PUBLIC_API void XXH64_canonicalFromHash(XXH_NOESCAPE XXH64_canonical_t* dst, XXH64_hash_t hash)
|
||||
{
|
||||
/* XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t)); */
|
||||
XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));
|
||||
if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);
|
||||
XXH_memcpy(dst, &hash, sizeof(*dst));
|
||||
}
|
||||
|
||||
/*! @ingroup xxh64_family */
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)
|
||||
/*! @ingroup XXH64_family */
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(XXH_NOESCAPE const XXH64_canonical_t* src)
|
||||
{
|
||||
return XXH_readBE64(src);
|
||||
}
|
||||
@@ -2650,7 +3587,7 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src
|
||||
************************************************************************ */
|
||||
/*!
|
||||
* @}
|
||||
* @defgroup xxh3_impl XXH3 implementation
|
||||
* @defgroup XXH3_impl XXH3 implementation
|
||||
* @ingroup impl
|
||||
* @{
|
||||
*/
|
||||
@@ -2658,11 +3595,19 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src
|
||||
/* === Compiler specifics === */
|
||||
|
||||
#if ((defined(sun) || defined(__sun)) && __cplusplus) /* Solaris includes __STDC_VERSION__ with C++. Tested with GCC 5.5 */
|
||||
# define XXH_RESTRICT /* disable */
|
||||
# define XXH_RESTRICT /* disable */
|
||||
#elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* >= C99 */
|
||||
# define XXH_RESTRICT restrict
|
||||
#elif (defined (__GNUC__) && ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1))) \
|
||||
|| (defined (__clang__)) \
|
||||
|| (defined (_MSC_VER) && (_MSC_VER >= 1400)) \
|
||||
|| (defined (__INTEL_COMPILER) && (__INTEL_COMPILER >= 1300))
|
||||
/*
|
||||
* There are a LOT more compilers that recognize __restrict but this
|
||||
* covers the major ones.
|
||||
*/
|
||||
# define XXH_RESTRICT __restrict
|
||||
#else
|
||||
/* Note: it might be useful to define __restrict or __restrict__ for some C++ compilers */
|
||||
# define XXH_RESTRICT /* disable */
|
||||
#endif
|
||||
|
||||
@@ -2676,10 +3621,26 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src
|
||||
# define XXH_unlikely(x) (x)
|
||||
#endif
|
||||
|
||||
#ifndef XXH_HAS_INCLUDE
|
||||
# ifdef __has_include
|
||||
/*
|
||||
* Not defined as XXH_HAS_INCLUDE(x) (function-like) because
|
||||
* this causes segfaults in Apple Clang 4.2 (on Mac OS X 10.7 Lion)
|
||||
*/
|
||||
# define XXH_HAS_INCLUDE __has_include
|
||||
# else
|
||||
# define XXH_HAS_INCLUDE(x) 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# if defined(__ARM_FEATURE_SVE)
|
||||
# include <arm_sve.h>
|
||||
# endif
|
||||
# if defined(__ARM_NEON__) || defined(__ARM_NEON) \
|
||||
|| defined(__aarch64__) || defined(_M_ARM) \
|
||||
|| defined(_M_ARM64) || defined(_M_ARM64EC)
|
||||
|| (defined(_M_ARM) && _M_ARM >= 7) \
|
||||
|| defined(_M_ARM64) || defined(_M_ARM64EC) \
|
||||
|| (defined(__wasm_simd128__) && XXH_HAS_INCLUDE(<arm_neon.h>)) /* WASM SIMD128 via SIMDe */
|
||||
# define inline __inline__ /* circumvent a clang bug */
|
||||
# include <arm_neon.h>
|
||||
# undef inline
|
||||
@@ -2790,7 +3751,7 @@ XXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src
|
||||
* Note that these are actually implemented as macros.
|
||||
*
|
||||
* If this is not defined, it is detected automatically.
|
||||
* @ref XXH_X86DISPATCH overrides this.
|
||||
* internal macro XXH_X86DISPATCH overrides this.
|
||||
*/
|
||||
enum XXH_VECTOR_TYPE /* fake enum */ {
|
||||
XXH_SCALAR = 0, /*!< Portable scalar version */
|
||||
@@ -2802,8 +3763,13 @@ enum XXH_VECTOR_TYPE /* fake enum */ {
|
||||
*/
|
||||
XXH_AVX2 = 2, /*!< AVX2 for Haswell and Bulldozer */
|
||||
XXH_AVX512 = 3, /*!< AVX512 for Skylake and Icelake */
|
||||
XXH_NEON = 4, /*!< NEON for most ARMv7-A and all AArch64 */
|
||||
XXH_NEON = 4, /*!<
|
||||
* NEON for most ARMv7-A, all AArch64, and WASM SIMD128
|
||||
* via the SIMDeverywhere polyfill provided with the
|
||||
* Emscripten SDK.
|
||||
*/
|
||||
XXH_VSX = 5, /*!< VSX and ZVector for POWER8/z13 (64-bit) */
|
||||
XXH_SVE = 6, /*!< SVE for some ARMv8-A and ARMv9-A */
|
||||
};
|
||||
/*!
|
||||
* @ingroup tuning
|
||||
@@ -2825,12 +3791,16 @@ enum XXH_VECTOR_TYPE /* fake enum */ {
|
||||
# define XXH_AVX512 3
|
||||
# define XXH_NEON 4
|
||||
# define XXH_VSX 5
|
||||
# define XXH_SVE 6
|
||||
#endif
|
||||
|
||||
#ifndef XXH_VECTOR /* can be defined on command line */
|
||||
# if ( \
|
||||
# if defined(__ARM_FEATURE_SVE)
|
||||
# define XXH_VECTOR XXH_SVE
|
||||
# elif ( \
|
||||
defined(__ARM_NEON__) || defined(__ARM_NEON) /* gcc */ \
|
||||
|| defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC) /* msvc */ \
|
||||
|| (defined(__wasm_simd128__) && XXH_HAS_INCLUDE(<arm_neon.h>)) /* wasm simd128 via SIMDe */ \
|
||||
) && ( \
|
||||
defined(_WIN32) || defined(__LITTLE_ENDIAN__) /* little endian only */ \
|
||||
|| (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) \
|
||||
@@ -2851,6 +3821,17 @@ enum XXH_VECTOR_TYPE /* fake enum */ {
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* __ARM_FEATURE_SVE is only supported by GCC & Clang. */
|
||||
#if (XXH_VECTOR == XXH_SVE) && !defined(__ARM_FEATURE_SVE)
|
||||
# ifdef _MSC_VER
|
||||
# pragma warning(once : 4606)
|
||||
# else
|
||||
# warning "__ARM_FEATURE_SVE isn't supported. Use SCALAR instead."
|
||||
# endif
|
||||
# undef XXH_VECTOR
|
||||
# define XXH_VECTOR XXH_SCALAR
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Controls the alignment of the accumulator,
|
||||
* for compatibility with aligned vector loads, which are usually faster.
|
||||
@@ -2870,16 +3851,26 @@ enum XXH_VECTOR_TYPE /* fake enum */ {
|
||||
# define XXH_ACC_ALIGN 16
|
||||
# elif XXH_VECTOR == XXH_AVX512 /* avx512 */
|
||||
# define XXH_ACC_ALIGN 64
|
||||
# elif XXH_VECTOR == XXH_SVE /* sve */
|
||||
# define XXH_ACC_ALIGN 64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \
|
||||
|| XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512
|
||||
# define XXH_SEC_ALIGN XXH_ACC_ALIGN
|
||||
#elif XXH_VECTOR == XXH_SVE
|
||||
# define XXH_SEC_ALIGN XXH_ACC_ALIGN
|
||||
#else
|
||||
# define XXH_SEC_ALIGN 8
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define XXH_ALIASING __attribute__((may_alias))
|
||||
#else
|
||||
# define XXH_ALIASING /* nothing */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* UGLY HACK:
|
||||
* GCC usually generates the best code with -O3 for xxHash.
|
||||
@@ -2903,153 +3894,126 @@ enum XXH_VECTOR_TYPE /* fake enum */ {
|
||||
*/
|
||||
#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \
|
||||
&& defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \
|
||||
&& defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */
|
||||
&& defined(__OPTIMIZE__) && XXH_SIZE_OPT <= 0 /* respect -O0 and -Os */
|
||||
# pragma GCC push_options
|
||||
# pragma GCC optimize("-O2")
|
||||
#endif
|
||||
|
||||
|
||||
#if XXH_VECTOR == XXH_NEON
|
||||
|
||||
/*
|
||||
* NEON's setup for vmlal_u32 is a little more complicated than it is on
|
||||
* SSE2, AVX2, and VSX.
|
||||
* UGLY HACK: While AArch64 GCC on Linux does not seem to care, on macOS, GCC -O3
|
||||
* optimizes out the entire hashLong loop because of the aliasing violation.
|
||||
*
|
||||
* While PMULUDQ and VMULEUW both perform a mask, VMLAL.U32 performs an upcast.
|
||||
*
|
||||
* To do the same operation, the 128-bit 'Q' register needs to be split into
|
||||
* two 64-bit 'D' registers, performing this operation::
|
||||
*
|
||||
* [ a | b ]
|
||||
* | '---------. .--------' |
|
||||
* | x |
|
||||
* | .---------' '--------. |
|
||||
* [ a & 0xFFFFFFFF | b & 0xFFFFFFFF ],[ a >> 32 | b >> 32 ]
|
||||
*
|
||||
* Due to significant changes in aarch64, the fastest method for aarch64 is
|
||||
* completely different than the fastest method for ARMv7-A.
|
||||
*
|
||||
* ARMv7-A treats D registers as unions overlaying Q registers, so modifying
|
||||
* D11 will modify the high half of Q5. This is similar to how modifying AH
|
||||
* will only affect bits 8-15 of AX on x86.
|
||||
*
|
||||
* VZIP takes two registers, and puts even lanes in one register and odd lanes
|
||||
* in the other.
|
||||
*
|
||||
* On ARMv7-A, this strangely modifies both parameters in place instead of
|
||||
* taking the usual 3-operand form.
|
||||
*
|
||||
* Therefore, if we want to do this, we can simply use a D-form VZIP.32 on the
|
||||
* lower and upper halves of the Q register to end up with the high and low
|
||||
* halves where we want - all in one instruction.
|
||||
*
|
||||
* vzip.32 d10, d11 @ d10 = { d10[0], d11[0] }; d11 = { d10[1], d11[1] }
|
||||
*
|
||||
* Unfortunately we need inline assembly for this: Instructions modifying two
|
||||
* registers at once is not possible in GCC or Clang's IR, and they have to
|
||||
* create a copy.
|
||||
*
|
||||
* aarch64 requires a different approach.
|
||||
*
|
||||
* In order to make it easier to write a decent compiler for aarch64, many
|
||||
* quirks were removed, such as conditional execution.
|
||||
*
|
||||
* NEON was also affected by this.
|
||||
*
|
||||
* aarch64 cannot access the high bits of a Q-form register, and writes to a
|
||||
* D-form register zero the high bits, similar to how writes to W-form scalar
|
||||
* registers (or DWORD registers on x86_64) work.
|
||||
*
|
||||
* The formerly free vget_high intrinsics now require a vext (with a few
|
||||
* exceptions)
|
||||
*
|
||||
* Additionally, VZIP was replaced by ZIP1 and ZIP2, which are the equivalent
|
||||
* of PUNPCKL* and PUNPCKH* in SSE, respectively, in order to only modify one
|
||||
* operand.
|
||||
*
|
||||
* The equivalent of the VZIP.32 on the lower and upper halves would be this
|
||||
* mess:
|
||||
*
|
||||
* ext v2.4s, v0.4s, v0.4s, #2 // v2 = { v0[2], v0[3], v0[0], v0[1] }
|
||||
* zip1 v1.2s, v0.2s, v2.2s // v1 = { v0[0], v2[0] }
|
||||
* zip2 v0.2s, v0.2s, v1.2s // v0 = { v0[1], v2[1] }
|
||||
*
|
||||
* Instead, we use a literal downcast, vmovn_u64 (XTN), and vshrn_n_u64 (SHRN):
|
||||
*
|
||||
* shrn v1.2s, v0.2d, #32 // v1 = (uint32x2_t)(v0 >> 32);
|
||||
* xtn v0.2s, v0.2d // v0 = (uint32x2_t)(v0 & 0xFFFFFFFF);
|
||||
*
|
||||
* This is available on ARMv7-A, but is less efficient than a single VZIP.32.
|
||||
* However, GCC is also inefficient at load-store optimization with vld1q/vst1q,
|
||||
* so the only option is to mark it as aliasing.
|
||||
*/
|
||||
typedef uint64x2_t xxh_aliasing_uint64x2_t XXH_ALIASING;
|
||||
|
||||
/*!
|
||||
* Function-like macro:
|
||||
* void XXH_SPLIT_IN_PLACE(uint64x2_t &in, uint32x2_t &outLo, uint32x2_t &outHi)
|
||||
* {
|
||||
* outLo = (uint32x2_t)(in & 0xFFFFFFFF);
|
||||
* outHi = (uint32x2_t)(in >> 32);
|
||||
* in = UNDEFINED;
|
||||
* }
|
||||
* @internal
|
||||
* @brief `vld1q_u64` but faster and alignment-safe.
|
||||
*
|
||||
* On AArch64, unaligned access is always safe, but on ARMv7-a, it is only
|
||||
* *conditionally* safe (`vld1` has an alignment bit like `movdq[ua]` in x86).
|
||||
*
|
||||
* GCC for AArch64 sees `vld1q_u8` as an intrinsic instead of a load, so it
|
||||
* prohibits load-store optimizations. Therefore, a direct dereference is used.
|
||||
*
|
||||
* Otherwise, `vld1q_u8` is used with `vreinterpretq_u8_u64` to do a safe
|
||||
* unaligned load.
|
||||
*/
|
||||
# if !defined(XXH_NO_VZIP_HACK) /* define to disable */ \
|
||||
&& (defined(__GNUC__) || defined(__clang__)) \
|
||||
&& (defined(__arm__) || defined(__thumb__) || defined(_M_ARM))
|
||||
# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \
|
||||
do { \
|
||||
/* Undocumented GCC/Clang operand modifier: %e0 = lower D half, %f0 = upper D half */ \
|
||||
/* https://github.com/gcc-mirror/gcc/blob/38cf91e5/gcc/config/arm/arm.c#L22486 */ \
|
||||
/* https://github.com/llvm-mirror/llvm/blob/2c4ca683/lib/Target/ARM/ARMAsmPrinter.cpp#L399 */ \
|
||||
__asm__("vzip.32 %e0, %f0" : "+w" (in)); \
|
||||
(outLo) = vget_low_u32 (vreinterpretq_u32_u64(in)); \
|
||||
(outHi) = vget_high_u32(vreinterpretq_u32_u64(in)); \
|
||||
} while (0)
|
||||
# else
|
||||
# define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \
|
||||
do { \
|
||||
(outLo) = vmovn_u64 (in); \
|
||||
(outHi) = vshrn_n_u64 ((in), 32); \
|
||||
} while (0)
|
||||
# endif
|
||||
#if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__)
|
||||
XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr) /* silence -Wcast-align */
|
||||
{
|
||||
return *(xxh_aliasing_uint64x2_t const *)ptr;
|
||||
}
|
||||
#else
|
||||
XXH_FORCE_INLINE uint64x2_t XXH_vld1q_u64(void const* ptr)
|
||||
{
|
||||
return vreinterpretq_u64_u8(vld1q_u8((uint8_t const*)ptr));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @internal
|
||||
* @brief `vmlal_u32` on low and high halves of a vector.
|
||||
*
|
||||
* This is a workaround for AArch64 GCC < 11 which implemented arm_neon.h with
|
||||
* inline assembly and were therefore incapable of merging the `vget_{low, high}_u32`
|
||||
* with `vmlal_u32`.
|
||||
*/
|
||||
#if defined(__aarch64__) && defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 11
|
||||
XXH_FORCE_INLINE uint64x2_t
|
||||
XXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs)
|
||||
{
|
||||
/* Inline assembly is the only way */
|
||||
__asm__("umlal %0.2d, %1.2s, %2.2s" : "+w" (acc) : "w" (lhs), "w" (rhs));
|
||||
return acc;
|
||||
}
|
||||
XXH_FORCE_INLINE uint64x2_t
|
||||
XXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs)
|
||||
{
|
||||
/* This intrinsic works as expected */
|
||||
return vmlal_high_u32(acc, lhs, rhs);
|
||||
}
|
||||
#else
|
||||
/* Portable intrinsic versions */
|
||||
XXH_FORCE_INLINE uint64x2_t
|
||||
XXH_vmlal_low_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs)
|
||||
{
|
||||
return vmlal_u32(acc, vget_low_u32(lhs), vget_low_u32(rhs));
|
||||
}
|
||||
/*! @copydoc XXH_vmlal_low_u32
|
||||
* Assume the compiler converts this to vmlal_high_u32 on aarch64 */
|
||||
XXH_FORCE_INLINE uint64x2_t
|
||||
XXH_vmlal_high_u32(uint64x2_t acc, uint32x4_t lhs, uint32x4_t rhs)
|
||||
{
|
||||
return vmlal_u32(acc, vget_high_u32(lhs), vget_high_u32(rhs));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @ingroup tuning
|
||||
* @brief Controls the NEON to scalar ratio for XXH3
|
||||
*
|
||||
* On AArch64 when not optimizing for size, XXH3 will run 6 lanes using NEON and
|
||||
* 2 lanes on scalar by default.
|
||||
* This can be set to 2, 4, 6, or 8.
|
||||
*
|
||||
* This can be set to 2, 4, 6, or 8. ARMv7 will default to all 8 NEON lanes, as the
|
||||
* emulated 64-bit arithmetic is too slow.
|
||||
* ARM Cortex CPUs are _very_ sensitive to how their pipelines are used.
|
||||
*
|
||||
* Modern ARM CPUs are _very_ sensitive to how their pipelines are used.
|
||||
* For example, the Cortex-A73 can dispatch 3 micro-ops per cycle, but only 2 of those
|
||||
* can be NEON. If you are only using NEON instructions, you are only using 2/3 of the CPU
|
||||
* bandwidth.
|
||||
*
|
||||
* For example, the Cortex-A73 can dispatch 3 micro-ops per cycle, but it can't
|
||||
* have more than 2 NEON (F0/F1) micro-ops. If you are only using NEON instructions,
|
||||
* you are only using 2/3 of the CPU bandwidth.
|
||||
*
|
||||
* This is even more noticeable on the more advanced cores like the A76 which
|
||||
* This is even more noticeable on the more advanced cores like the Cortex-A76 which
|
||||
* can dispatch 8 micro-ops per cycle, but still only 2 NEON micro-ops at once.
|
||||
*
|
||||
* Therefore, @ref XXH3_NEON_LANES lanes will be processed using NEON, and the
|
||||
* remaining lanes will use scalar instructions. This improves the bandwidth
|
||||
* and also gives the integer pipelines something to do besides twiddling loop
|
||||
* counters and pointers.
|
||||
* Therefore, to make the most out of the pipeline, it is beneficial to run 6 NEON lanes
|
||||
* and 2 scalar lanes, which is chosen by default.
|
||||
*
|
||||
* This does not apply to Apple processors or 32-bit processors, which run better with
|
||||
* full NEON. These will default to 8. Additionally, size-optimized builds run 8 lanes.
|
||||
*
|
||||
* This change benefits CPUs with large micro-op buffers without negatively affecting
|
||||
* other CPUs:
|
||||
* most other CPUs:
|
||||
*
|
||||
* | Chipset | Dispatch type | NEON only | 6:2 hybrid | Diff. |
|
||||
* |:----------------------|:--------------------|----------:|-----------:|------:|
|
||||
* | Snapdragon 730 (A76) | 2 NEON/8 micro-ops | 8.8 GB/s | 10.1 GB/s | ~16% |
|
||||
* | Snapdragon 835 (A73) | 2 NEON/3 micro-ops | 5.1 GB/s | 5.3 GB/s | ~5% |
|
||||
* | Marvell PXA1928 (A53) | In-order dual-issue | 1.9 GB/s | 1.9 GB/s | 0% |
|
||||
* | Apple M1 | 4 NEON/8 micro-ops | 37.3 GB/s | 36.1 GB/s | ~-3% |
|
||||
*
|
||||
* It also seems to fix some bad codegen on GCC, making it almost as fast as clang.
|
||||
*
|
||||
* When using WASM SIMD128, if this is 2 or 6, SIMDe will scalarize 2 of the lanes meaning
|
||||
* it effectively becomes worse 4.
|
||||
*
|
||||
* @see XXH3_accumulate_512_neon()
|
||||
*/
|
||||
# ifndef XXH3_NEON_LANES
|
||||
# if (defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) || defined(_M_ARM64EC)) \
|
||||
&& !defined(__OPTIMIZE_SIZE__)
|
||||
&& !defined(__APPLE__) && XXH_SIZE_OPT <= 0
|
||||
# define XXH3_NEON_LANES 6
|
||||
# else
|
||||
# define XXH3_NEON_LANES XXH_ACC_NB
|
||||
@@ -3066,27 +4030,42 @@ enum XXH_VECTOR_TYPE /* fake enum */ {
|
||||
* inconsistent intrinsics, spotty coverage, and multiple endiannesses.
|
||||
*/
|
||||
#if XXH_VECTOR == XXH_VSX
|
||||
/* Annoyingly, these headers _may_ define three macros: `bool`, `vector`,
|
||||
* and `pixel`. This is a problem for obvious reasons.
|
||||
*
|
||||
* These keywords are unnecessary; the spec literally says they are
|
||||
* equivalent to `__bool`, `__vector`, and `__pixel` and may be undef'd
|
||||
* after including the header.
|
||||
*
|
||||
* We use pragma push_macro/pop_macro to keep the namespace clean. */
|
||||
# pragma push_macro("bool")
|
||||
# pragma push_macro("vector")
|
||||
# pragma push_macro("pixel")
|
||||
/* silence potential macro redefined warnings */
|
||||
# undef bool
|
||||
# undef vector
|
||||
# undef pixel
|
||||
|
||||
# if defined(__s390x__)
|
||||
# include <s390intrin.h>
|
||||
# else
|
||||
/* gcc's altivec.h can have the unwanted consequence to unconditionally
|
||||
* #define bool, vector, and pixel keywords,
|
||||
* with bad consequences for programs already using these keywords for other purposes.
|
||||
* The paragraph defining these macros is skipped when __APPLE_ALTIVEC__ is defined.
|
||||
* __APPLE_ALTIVEC__ is _generally_ defined automatically by the compiler,
|
||||
* but it seems that, in some cases, it isn't.
|
||||
* Force the build macro to be defined, so that keywords are not altered.
|
||||
*/
|
||||
# if defined(__GNUC__) && !defined(__APPLE_ALTIVEC__)
|
||||
# define __APPLE_ALTIVEC__
|
||||
# endif
|
||||
# include <altivec.h>
|
||||
# endif
|
||||
|
||||
/* Restore the original macro values, if applicable. */
|
||||
# pragma pop_macro("pixel")
|
||||
# pragma pop_macro("vector")
|
||||
# pragma pop_macro("bool")
|
||||
|
||||
typedef __vector unsigned long long xxh_u64x2;
|
||||
typedef __vector unsigned char xxh_u8x16;
|
||||
typedef __vector unsigned xxh_u32x4;
|
||||
|
||||
/*
|
||||
* UGLY HACK: Similar to aarch64 macOS GCC, s390x GCC has the same aliasing issue.
|
||||
*/
|
||||
typedef xxh_u64x2 xxh_aliasing_u64x2 XXH_ALIASING;
|
||||
|
||||
# ifndef XXH_VSX_BE
|
||||
# if defined(__BIG_ENDIAN__) \
|
||||
|| (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
@@ -3138,8 +4117,9 @@ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr)
|
||||
/* s390x is always big endian, no issue on this platform */
|
||||
# define XXH_vec_mulo vec_mulo
|
||||
# define XXH_vec_mule vec_mule
|
||||
# elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw)
|
||||
# elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) && !defined(__ibmxl__)
|
||||
/* Clang has a better way to control this, we can just use the builtin which doesn't swap. */
|
||||
/* The IBM XL Compiler (which defined __clang__) only implements the vec_* operations */
|
||||
# define XXH_vec_mulo __builtin_altivec_vmulouw
|
||||
# define XXH_vec_mule __builtin_altivec_vmuleuw
|
||||
# else
|
||||
@@ -3160,13 +4140,28 @@ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b)
|
||||
# endif /* XXH_vec_mulo, XXH_vec_mule */
|
||||
#endif /* XXH_VECTOR == XXH_VSX */
|
||||
|
||||
#if XXH_VECTOR == XXH_SVE
|
||||
#define ACCRND(acc, offset) \
|
||||
do { \
|
||||
svuint64_t input_vec = svld1_u64(mask, xinput + offset); \
|
||||
svuint64_t secret_vec = svld1_u64(mask, xsecret + offset); \
|
||||
svuint64_t mixed = sveor_u64_x(mask, secret_vec, input_vec); \
|
||||
svuint64_t swapped = svtbl_u64(input_vec, kSwap); \
|
||||
svuint64_t mixed_lo = svextw_u64_x(mask, mixed); \
|
||||
svuint64_t mixed_hi = svlsr_n_u64_x(mask, mixed, 32); \
|
||||
svuint64_t mul = svmad_u64_x(mask, mixed_lo, mixed_hi, swapped); \
|
||||
acc = svadd_u64_x(mask, acc, mul); \
|
||||
} while (0)
|
||||
#endif /* XXH_VECTOR == XXH_SVE */
|
||||
|
||||
/* prefetch
|
||||
* can be disabled, by declaring XXH_NO_PREFETCH build macro */
|
||||
#if defined(XXH_NO_PREFETCH)
|
||||
# define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */
|
||||
#else
|
||||
# if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) && !defined(_M_ARM64EC) /* _mm_prefetch() not defined outside of x86/x64 */
|
||||
# if XXH_SIZE_OPT >= 1
|
||||
# define XXH_PREFETCH(ptr) (void)(ptr)
|
||||
# elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) /* _mm_prefetch() not defined outside of x86/x64 */
|
||||
# include <mmintrin.h> /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
|
||||
# define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
|
||||
# elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) )
|
||||
@@ -3203,6 +4198,8 @@ XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = {
|
||||
0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e,
|
||||
};
|
||||
|
||||
static const xxh_u64 PRIME_MX1 = 0x165667919E3779F9ULL; /*!< 0b0001011001010110011001111001000110011110001101110111100111111001 */
|
||||
static const xxh_u64 PRIME_MX2 = 0x9FB21C651E98DF25ULL; /*!< 0b1001111110110010000111000110010100011110100110001101111100100101 */
|
||||
|
||||
#ifdef XXH_OLD_NAMES
|
||||
# define kSecret XXH3_kSecret
|
||||
@@ -3394,7 +4391,7 @@ XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs)
|
||||
}
|
||||
|
||||
/*! Seems to produce slightly better code on GCC for some reason. */
|
||||
XXH_FORCE_INLINE xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift)
|
||||
XXH_FORCE_INLINE XXH_CONSTF xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift)
|
||||
{
|
||||
XXH_ASSERT(0 <= shift && shift < 64);
|
||||
return v64 ^ (v64 >> shift);
|
||||
@@ -3407,7 +4404,7 @@ XXH_FORCE_INLINE xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift)
|
||||
static XXH64_hash_t XXH3_avalanche(xxh_u64 h64)
|
||||
{
|
||||
h64 = XXH_xorshift64(h64, 37);
|
||||
h64 *= 0x165667919E3779F9ULL;
|
||||
h64 *= PRIME_MX1;
|
||||
h64 = XXH_xorshift64(h64, 32);
|
||||
return h64;
|
||||
}
|
||||
@@ -3421,9 +4418,9 @@ static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len)
|
||||
{
|
||||
/* this mix is inspired by Pelle Evensen's rrmxmx */
|
||||
h64 ^= XXH_rotl64(h64, 49) ^ XXH_rotl64(h64, 24);
|
||||
h64 *= 0x9FB21C651E98DF25ULL;
|
||||
h64 *= PRIME_MX2;
|
||||
h64 ^= (h64 >> 35) + len ;
|
||||
h64 *= 0x9FB21C651E98DF25ULL;
|
||||
h64 *= PRIME_MX2;
|
||||
return XXH_xorshift64(h64, 28);
|
||||
}
|
||||
|
||||
@@ -3461,7 +4458,7 @@ static XXH64_hash_t XXH3_rrmxmx(xxh_u64 h64, xxh_u64 len)
|
||||
*
|
||||
* This adds an extra layer of strength for custom secrets.
|
||||
*/
|
||||
XXH_FORCE_INLINE XXH64_hash_t
|
||||
XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t
|
||||
XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
|
||||
{
|
||||
XXH_ASSERT(input != NULL);
|
||||
@@ -3483,7 +4480,7 @@ XXH3_len_1to3_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_h
|
||||
}
|
||||
}
|
||||
|
||||
XXH_FORCE_INLINE XXH64_hash_t
|
||||
XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t
|
||||
XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
|
||||
{
|
||||
XXH_ASSERT(input != NULL);
|
||||
@@ -3499,7 +4496,7 @@ XXH3_len_4to8_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_h
|
||||
}
|
||||
}
|
||||
|
||||
XXH_FORCE_INLINE XXH64_hash_t
|
||||
XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t
|
||||
XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
|
||||
{
|
||||
XXH_ASSERT(input != NULL);
|
||||
@@ -3516,7 +4513,7 @@ XXH3_len_9to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_
|
||||
}
|
||||
}
|
||||
|
||||
XXH_FORCE_INLINE XXH64_hash_t
|
||||
XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t
|
||||
XXH3_len_0to16_64b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
|
||||
{
|
||||
XXH_ASSERT(len <= 16);
|
||||
@@ -3586,7 +4583,7 @@ XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input,
|
||||
}
|
||||
|
||||
/* For mid range keys, XXH3 uses a Mum-hash variant. */
|
||||
XXH_FORCE_INLINE XXH64_hash_t
|
||||
XXH_FORCE_INLINE XXH_PUREF XXH64_hash_t
|
||||
XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
|
||||
XXH64_hash_t seed)
|
||||
@@ -3595,6 +4592,14 @@ XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
XXH_ASSERT(16 < len && len <= 128);
|
||||
|
||||
{ xxh_u64 acc = len * XXH_PRIME64_1;
|
||||
#if XXH_SIZE_OPT >= 1
|
||||
/* Smaller and cleaner, but slightly slower. */
|
||||
unsigned int i = (unsigned int)(len - 1) / 32;
|
||||
do {
|
||||
acc += XXH3_mix16B(input+16 * i, secret+32*i, seed);
|
||||
acc += XXH3_mix16B(input+len-16*(i+1), secret+32*i+16, seed);
|
||||
} while (i-- != 0);
|
||||
#else
|
||||
if (len > 32) {
|
||||
if (len > 64) {
|
||||
if (len > 96) {
|
||||
@@ -3609,14 +4614,17 @@ XXH3_len_17to128_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
}
|
||||
acc += XXH3_mix16B(input+0, secret+0, seed);
|
||||
acc += XXH3_mix16B(input+len-16, secret+16, seed);
|
||||
|
||||
#endif
|
||||
return XXH3_avalanche(acc);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Maximum size of "short" key in bytes.
|
||||
*/
|
||||
#define XXH3_MIDSIZE_MAX 240
|
||||
|
||||
XXH_NO_INLINE XXH64_hash_t
|
||||
XXH_NO_INLINE XXH_PUREF XXH64_hash_t
|
||||
XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
|
||||
XXH64_hash_t seed)
|
||||
@@ -3628,13 +4636,17 @@ XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
#define XXH3_MIDSIZE_LASTOFFSET 17
|
||||
|
||||
{ xxh_u64 acc = len * XXH_PRIME64_1;
|
||||
int const nbRounds = (int)len / 16;
|
||||
int i;
|
||||
xxh_u64 acc_end;
|
||||
unsigned int const nbRounds = (unsigned int)len / 16;
|
||||
unsigned int i;
|
||||
XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX);
|
||||
for (i=0; i<8; i++) {
|
||||
acc += XXH3_mix16B(input+(16*i), secret+(16*i), seed);
|
||||
}
|
||||
acc = XXH3_avalanche(acc);
|
||||
/* last bytes */
|
||||
acc_end = XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed);
|
||||
XXH_ASSERT(nbRounds >= 8);
|
||||
acc = XXH3_avalanche(acc);
|
||||
#if defined(__clang__) /* Clang */ \
|
||||
&& (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \
|
||||
&& !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */
|
||||
@@ -3661,11 +4673,13 @@ XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
#pragma clang loop vectorize(disable)
|
||||
#endif
|
||||
for (i=8 ; i < nbRounds; i++) {
|
||||
acc += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed);
|
||||
/*
|
||||
* Prevents clang for unrolling the acc loop and interleaving with this one.
|
||||
*/
|
||||
XXH_COMPILER_GUARD(acc);
|
||||
acc_end += XXH3_mix16B(input+(16*i), secret+(16*(i-8)) + XXH3_MIDSIZE_STARTOFFSET, seed);
|
||||
}
|
||||
/* last bytes */
|
||||
acc += XXH3_mix16B(input + len - 16, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET, seed);
|
||||
return XXH3_avalanche(acc);
|
||||
return XXH3_avalanche(acc + acc_end);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3681,6 +4695,47 @@ XXH3_len_129to240_64b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
# define ACC_NB XXH_ACC_NB
|
||||
#endif
|
||||
|
||||
#ifndef XXH_PREFETCH_DIST
|
||||
# ifdef __clang__
|
||||
# define XXH_PREFETCH_DIST 320
|
||||
# else
|
||||
# if (XXH_VECTOR == XXH_AVX512)
|
||||
# define XXH_PREFETCH_DIST 512
|
||||
# else
|
||||
# define XXH_PREFETCH_DIST 384
|
||||
# endif
|
||||
# endif /* __clang__ */
|
||||
#endif /* XXH_PREFETCH_DIST */
|
||||
|
||||
/*
|
||||
* These macros are to generate an XXH3_accumulate() function.
|
||||
* The two arguments select the name suffix and target attribute.
|
||||
*
|
||||
* The name of this symbol is XXH3_accumulate_<name>() and it calls
|
||||
* XXH3_accumulate_512_<name>().
|
||||
*
|
||||
* It may be useful to hand implement this function if the compiler fails to
|
||||
* optimize the inline function.
|
||||
*/
|
||||
#define XXH3_ACCUMULATE_TEMPLATE(name) \
|
||||
void \
|
||||
XXH3_accumulate_##name(xxh_u64* XXH_RESTRICT acc, \
|
||||
const xxh_u8* XXH_RESTRICT input, \
|
||||
const xxh_u8* XXH_RESTRICT secret, \
|
||||
size_t nbStripes) \
|
||||
{ \
|
||||
size_t n; \
|
||||
for (n = 0; n < nbStripes; n++ ) { \
|
||||
const xxh_u8* const in = input + n*XXH_STRIPE_LEN; \
|
||||
XXH_PREFETCH(in + XXH_PREFETCH_DIST); \
|
||||
XXH3_accumulate_512_##name( \
|
||||
acc, \
|
||||
in, \
|
||||
secret + n*XXH_SECRET_CONSUME_RATE); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64)
|
||||
{
|
||||
if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64);
|
||||
@@ -3749,7 +4804,7 @@ XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc,
|
||||
/* data_key = data_vec ^ key_vec; */
|
||||
__m512i const data_key = _mm512_xor_si512 (data_vec, key_vec);
|
||||
/* data_key_lo = data_key >> 32; */
|
||||
__m512i const data_key_lo = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1));
|
||||
__m512i const data_key_lo = _mm512_srli_epi64 (data_key, 32);
|
||||
/* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
|
||||
__m512i const product = _mm512_mul_epu32 (data_key, data_key_lo);
|
||||
/* xacc[0] += swap(data_vec); */
|
||||
@@ -3759,6 +4814,7 @@ XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc,
|
||||
*xacc = _mm512_add_epi64(product, sum);
|
||||
}
|
||||
}
|
||||
XXH_FORCE_INLINE XXH_TARGET_AVX512 XXH3_ACCUMULATE_TEMPLATE(avx512)
|
||||
|
||||
/*
|
||||
* XXH3_scrambleAcc: Scrambles the accumulators to improve mixing.
|
||||
@@ -3792,13 +4848,12 @@ XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
|
||||
/* xacc[0] ^= (xacc[0] >> 47) */
|
||||
__m512i const acc_vec = *xacc;
|
||||
__m512i const shifted = _mm512_srli_epi64 (acc_vec, 47);
|
||||
__m512i const data_vec = _mm512_xor_si512 (acc_vec, shifted);
|
||||
/* xacc[0] ^= secret; */
|
||||
__m512i const key_vec = _mm512_loadu_si512 (secret);
|
||||
__m512i const data_key = _mm512_xor_si512 (data_vec, key_vec);
|
||||
__m512i const data_key = _mm512_ternarylogic_epi32(key_vec, acc_vec, shifted, 0x96 /* key_vec ^ acc_vec ^ shifted */);
|
||||
|
||||
/* xacc[0] *= XXH_PRIME32_1; */
|
||||
__m512i const data_key_hi = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1));
|
||||
__m512i const data_key_hi = _mm512_srli_epi64 (data_key, 32);
|
||||
__m512i const prod_lo = _mm512_mul_epu32 (data_key, prime32);
|
||||
__m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32);
|
||||
*xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32));
|
||||
@@ -3813,7 +4868,8 @@ XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
|
||||
XXH_ASSERT(((size_t)customSecret & 63) == 0);
|
||||
(void)(&XXH_writeLE64);
|
||||
{ int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i);
|
||||
__m512i const seed = _mm512_mask_set1_epi64(_mm512_set1_epi64((xxh_i64)seed64), 0xAA, (xxh_i64)(0U - seed64));
|
||||
__m512i const seed_pos = _mm512_set1_epi64((xxh_i64)seed64);
|
||||
__m512i const seed = _mm512_mask_sub_epi64(seed_pos, 0xAA, _mm512_set1_epi8(0), seed_pos);
|
||||
|
||||
const __m512i* const src = (const __m512i*) ((const void*) XXH3_kSecret);
|
||||
__m512i* const dest = ( __m512i*) customSecret;
|
||||
@@ -3821,14 +4877,7 @@ XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
|
||||
XXH_ASSERT(((size_t)src & 63) == 0); /* control alignment */
|
||||
XXH_ASSERT(((size_t)dest & 63) == 0);
|
||||
for (i=0; i < nbRounds; ++i) {
|
||||
/* GCC has a bug, _mm512_stream_load_si512 accepts 'void*', not 'void const*',
|
||||
* this will warn "discards 'const' qualifier". */
|
||||
union {
|
||||
const __m512i* cp;
|
||||
void* p;
|
||||
} remote_const_void;
|
||||
remote_const_void.cp = src + i;
|
||||
dest[i] = _mm512_add_epi64(_mm512_stream_load_si512(remote_const_void.p), seed);
|
||||
dest[i] = _mm512_add_epi64(_mm512_load_si512(src + i), seed);
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -3864,7 +4913,7 @@ XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc,
|
||||
/* data_key = data_vec ^ key_vec; */
|
||||
__m256i const data_key = _mm256_xor_si256 (data_vec, key_vec);
|
||||
/* data_key_lo = data_key >> 32; */
|
||||
__m256i const data_key_lo = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1));
|
||||
__m256i const data_key_lo = _mm256_srli_epi64 (data_key, 32);
|
||||
/* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */
|
||||
__m256i const product = _mm256_mul_epu32 (data_key, data_key_lo);
|
||||
/* xacc[i] += swap(data_vec); */
|
||||
@@ -3874,6 +4923,7 @@ XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc,
|
||||
xacc[i] = _mm256_add_epi64(product, sum);
|
||||
} }
|
||||
}
|
||||
XXH_FORCE_INLINE XXH_TARGET_AVX2 XXH3_ACCUMULATE_TEMPLATE(avx2)
|
||||
|
||||
XXH_FORCE_INLINE XXH_TARGET_AVX2 void
|
||||
XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
|
||||
@@ -3896,7 +4946,7 @@ XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
|
||||
__m256i const data_key = _mm256_xor_si256 (data_vec, key_vec);
|
||||
|
||||
/* xacc[i] *= XXH_PRIME32_1; */
|
||||
__m256i const data_key_hi = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1));
|
||||
__m256i const data_key_hi = _mm256_srli_epi64 (data_key, 32);
|
||||
__m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32);
|
||||
__m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32);
|
||||
xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32));
|
||||
@@ -3928,12 +4978,12 @@ XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTR
|
||||
XXH_ASSERT(((size_t)dest & 31) == 0);
|
||||
|
||||
/* GCC -O2 need unroll loop manually */
|
||||
dest[0] = _mm256_add_epi64(_mm256_stream_load_si256(src+0), seed);
|
||||
dest[1] = _mm256_add_epi64(_mm256_stream_load_si256(src+1), seed);
|
||||
dest[2] = _mm256_add_epi64(_mm256_stream_load_si256(src+2), seed);
|
||||
dest[3] = _mm256_add_epi64(_mm256_stream_load_si256(src+3), seed);
|
||||
dest[4] = _mm256_add_epi64(_mm256_stream_load_si256(src+4), seed);
|
||||
dest[5] = _mm256_add_epi64(_mm256_stream_load_si256(src+5), seed);
|
||||
dest[0] = _mm256_add_epi64(_mm256_load_si256(src+0), seed);
|
||||
dest[1] = _mm256_add_epi64(_mm256_load_si256(src+1), seed);
|
||||
dest[2] = _mm256_add_epi64(_mm256_load_si256(src+2), seed);
|
||||
dest[3] = _mm256_add_epi64(_mm256_load_si256(src+3), seed);
|
||||
dest[4] = _mm256_add_epi64(_mm256_load_si256(src+4), seed);
|
||||
dest[5] = _mm256_add_epi64(_mm256_load_si256(src+5), seed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3980,6 +5030,7 @@ XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc,
|
||||
xacc[i] = _mm_add_epi64(product, sum);
|
||||
} }
|
||||
}
|
||||
XXH_FORCE_INLINE XXH_TARGET_SSE2 XXH3_ACCUMULATE_TEMPLATE(sse2)
|
||||
|
||||
XXH_FORCE_INLINE XXH_TARGET_SSE2 void
|
||||
XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
|
||||
@@ -4058,14 +5109,28 @@ XXH3_scalarScrambleRound(void* XXH_RESTRICT acc,
|
||||
|
||||
/*!
|
||||
* @internal
|
||||
* @brief The bulk processing loop for NEON.
|
||||
* @brief The bulk processing loop for NEON and WASM SIMD128.
|
||||
*
|
||||
* The NEON code path is actually partially scalar when running on AArch64. This
|
||||
* is to optimize the pipelining and can have up to 15% speedup depending on the
|
||||
* CPU, and it also mitigates some GCC codegen issues.
|
||||
*
|
||||
* @see XXH3_NEON_LANES for configuring this and details about this optimization.
|
||||
*
|
||||
* NEON's 32-bit to 64-bit long multiply takes a half vector of 32-bit
|
||||
* integers instead of the other platforms which mask full 64-bit vectors,
|
||||
* so the setup is more complicated than just shifting right.
|
||||
*
|
||||
* Additionally, there is an optimization for 4 lanes at once noted below.
|
||||
*
|
||||
* Since, as stated, the most optimal amount of lanes for Cortexes is 6,
|
||||
* there needs to be *three* versions of the accumulate operation used
|
||||
* for the remaining 2 lanes.
|
||||
*
|
||||
* WASM's SIMD128 uses SIMDe's arm_neon.h polyfill because the intrinsics overlap
|
||||
* nearly perfectly.
|
||||
*/
|
||||
|
||||
XXH_FORCE_INLINE void
|
||||
XXH3_accumulate_512_neon( void* XXH_RESTRICT acc,
|
||||
const void* XXH_RESTRICT input,
|
||||
@@ -4073,101 +5138,182 @@ XXH3_accumulate_512_neon( void* XXH_RESTRICT acc,
|
||||
{
|
||||
XXH_ASSERT((((size_t)acc) & 15) == 0);
|
||||
XXH_STATIC_ASSERT(XXH3_NEON_LANES > 0 && XXH3_NEON_LANES <= XXH_ACC_NB && XXH3_NEON_LANES % 2 == 0);
|
||||
{
|
||||
uint64x2_t* const xacc = (uint64x2_t *) acc;
|
||||
{ /* GCC for darwin arm64 does not like aliasing here */
|
||||
xxh_aliasing_uint64x2_t* const xacc = (xxh_aliasing_uint64x2_t*) acc;
|
||||
/* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */
|
||||
uint8_t const* const xinput = (const uint8_t *) input;
|
||||
uint8_t const* const xsecret = (const uint8_t *) secret;
|
||||
uint8_t const* xinput = (const uint8_t *) input;
|
||||
uint8_t const* xsecret = (const uint8_t *) secret;
|
||||
|
||||
size_t i;
|
||||
/* NEON for the first few lanes (these loops are normally interleaved) */
|
||||
for (i=0; i < XXH3_NEON_LANES / 2; i++) {
|
||||
/* data_vec = xinput[i]; */
|
||||
uint8x16_t data_vec = vld1q_u8(xinput + (i * 16));
|
||||
/* key_vec = xsecret[i]; */
|
||||
uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16));
|
||||
uint64x2_t data_key;
|
||||
uint32x2_t data_key_lo, data_key_hi;
|
||||
/* xacc[i] += swap(data_vec); */
|
||||
uint64x2_t const data64 = vreinterpretq_u64_u8(data_vec);
|
||||
uint64x2_t const swapped = vextq_u64(data64, data64, 1);
|
||||
xacc[i] = vaddq_u64 (xacc[i], swapped);
|
||||
/* data_key = data_vec ^ key_vec; */
|
||||
data_key = vreinterpretq_u64_u8(veorq_u8(data_vec, key_vec));
|
||||
/* data_key_lo = (uint32x2_t) (data_key & 0xFFFFFFFF);
|
||||
* data_key_hi = (uint32x2_t) (data_key >> 32);
|
||||
* data_key = UNDEFINED; */
|
||||
XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi);
|
||||
/* xacc[i] += (uint64x2_t) data_key_lo * (uint64x2_t) data_key_hi; */
|
||||
xacc[i] = vmlal_u32 (xacc[i], data_key_lo, data_key_hi);
|
||||
|
||||
}
|
||||
/* Scalar for the remainder. This may be a zero iteration loop. */
|
||||
#ifdef __wasm_simd128__
|
||||
/*
|
||||
* On WASM SIMD128, Clang emits direct address loads when XXH3_kSecret
|
||||
* is constant propagated, which results in it converting it to this
|
||||
* inside the loop:
|
||||
*
|
||||
* a = v128.load(XXH3_kSecret + 0 + $secret_offset, offset = 0)
|
||||
* b = v128.load(XXH3_kSecret + 16 + $secret_offset, offset = 0)
|
||||
* ...
|
||||
*
|
||||
* This requires a full 32-bit address immediate (and therefore a 6 byte
|
||||
* instruction) as well as an add for each offset.
|
||||
*
|
||||
* Putting an asm guard prevents it from folding (at the cost of losing
|
||||
* the alignment hint), and uses the free offset in `v128.load` instead
|
||||
* of adding secret_offset each time which overall reduces code size by
|
||||
* about a kilobyte and improves performance.
|
||||
*/
|
||||
XXH_COMPILER_GUARD(xsecret);
|
||||
#endif
|
||||
/* Scalar lanes use the normal scalarRound routine */
|
||||
for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) {
|
||||
XXH3_scalarRound(acc, input, secret, i);
|
||||
}
|
||||
i = 0;
|
||||
/* 4 NEON lanes at a time. */
|
||||
for (; i+1 < XXH3_NEON_LANES / 2; i+=2) {
|
||||
/* data_vec = xinput[i]; */
|
||||
uint64x2_t data_vec_1 = XXH_vld1q_u64(xinput + (i * 16));
|
||||
uint64x2_t data_vec_2 = XXH_vld1q_u64(xinput + ((i+1) * 16));
|
||||
/* key_vec = xsecret[i]; */
|
||||
uint64x2_t key_vec_1 = XXH_vld1q_u64(xsecret + (i * 16));
|
||||
uint64x2_t key_vec_2 = XXH_vld1q_u64(xsecret + ((i+1) * 16));
|
||||
/* data_swap = swap(data_vec) */
|
||||
uint64x2_t data_swap_1 = vextq_u64(data_vec_1, data_vec_1, 1);
|
||||
uint64x2_t data_swap_2 = vextq_u64(data_vec_2, data_vec_2, 1);
|
||||
/* data_key = data_vec ^ key_vec; */
|
||||
uint64x2_t data_key_1 = veorq_u64(data_vec_1, key_vec_1);
|
||||
uint64x2_t data_key_2 = veorq_u64(data_vec_2, key_vec_2);
|
||||
|
||||
/*
|
||||
* If we reinterpret the 64x2 vectors as 32x4 vectors, we can use a
|
||||
* de-interleave operation for 4 lanes in 1 step with `vuzpq_u32` to
|
||||
* get one vector with the low 32 bits of each lane, and one vector
|
||||
* with the high 32 bits of each lane.
|
||||
*
|
||||
* The intrinsic returns a double vector because the original ARMv7-a
|
||||
* instruction modified both arguments in place. AArch64 and SIMD128 emit
|
||||
* two instructions from this intrinsic.
|
||||
*
|
||||
* [ dk11L | dk11H | dk12L | dk12H ] -> [ dk11L | dk12L | dk21L | dk22L ]
|
||||
* [ dk21L | dk21H | dk22L | dk22H ] -> [ dk11H | dk12H | dk21H | dk22H ]
|
||||
*/
|
||||
uint32x4x2_t unzipped = vuzpq_u32(
|
||||
vreinterpretq_u32_u64(data_key_1),
|
||||
vreinterpretq_u32_u64(data_key_2)
|
||||
);
|
||||
/* data_key_lo = data_key & 0xFFFFFFFF */
|
||||
uint32x4_t data_key_lo = unzipped.val[0];
|
||||
/* data_key_hi = data_key >> 32 */
|
||||
uint32x4_t data_key_hi = unzipped.val[1];
|
||||
/*
|
||||
* Then, we can split the vectors horizontally and multiply which, as for most
|
||||
* widening intrinsics, have a variant that works on both high half vectors
|
||||
* for free on AArch64. A similar instruction is available on SIMD128.
|
||||
*
|
||||
* sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi
|
||||
*/
|
||||
uint64x2_t sum_1 = XXH_vmlal_low_u32(data_swap_1, data_key_lo, data_key_hi);
|
||||
uint64x2_t sum_2 = XXH_vmlal_high_u32(data_swap_2, data_key_lo, data_key_hi);
|
||||
/*
|
||||
* Clang reorders
|
||||
* a += b * c; // umlal swap.2d, dkl.2s, dkh.2s
|
||||
* c += a; // add acc.2d, acc.2d, swap.2d
|
||||
* to
|
||||
* c += a; // add acc.2d, acc.2d, swap.2d
|
||||
* c += b * c; // umlal acc.2d, dkl.2s, dkh.2s
|
||||
*
|
||||
* While it would make sense in theory since the addition is faster,
|
||||
* for reasons likely related to umlal being limited to certain NEON
|
||||
* pipelines, this is worse. A compiler guard fixes this.
|
||||
*/
|
||||
XXH_COMPILER_GUARD_CLANG_NEON(sum_1);
|
||||
XXH_COMPILER_GUARD_CLANG_NEON(sum_2);
|
||||
/* xacc[i] = acc_vec + sum; */
|
||||
xacc[i] = vaddq_u64(xacc[i], sum_1);
|
||||
xacc[i+1] = vaddq_u64(xacc[i+1], sum_2);
|
||||
}
|
||||
/* Operate on the remaining NEON lanes 2 at a time. */
|
||||
for (; i < XXH3_NEON_LANES / 2; i++) {
|
||||
/* data_vec = xinput[i]; */
|
||||
uint64x2_t data_vec = XXH_vld1q_u64(xinput + (i * 16));
|
||||
/* key_vec = xsecret[i]; */
|
||||
uint64x2_t key_vec = XXH_vld1q_u64(xsecret + (i * 16));
|
||||
/* acc_vec_2 = swap(data_vec) */
|
||||
uint64x2_t data_swap = vextq_u64(data_vec, data_vec, 1);
|
||||
/* data_key = data_vec ^ key_vec; */
|
||||
uint64x2_t data_key = veorq_u64(data_vec, key_vec);
|
||||
/* For two lanes, just use VMOVN and VSHRN. */
|
||||
/* data_key_lo = data_key & 0xFFFFFFFF; */
|
||||
uint32x2_t data_key_lo = vmovn_u64(data_key);
|
||||
/* data_key_hi = data_key >> 32; */
|
||||
uint32x2_t data_key_hi = vshrn_n_u64(data_key, 32);
|
||||
/* sum = data_swap + (u64x2) data_key_lo * (u64x2) data_key_hi; */
|
||||
uint64x2_t sum = vmlal_u32(data_swap, data_key_lo, data_key_hi);
|
||||
/* Same Clang workaround as before */
|
||||
XXH_COMPILER_GUARD_CLANG_NEON(sum);
|
||||
/* xacc[i] = acc_vec + sum; */
|
||||
xacc[i] = vaddq_u64 (xacc[i], sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(neon)
|
||||
|
||||
XXH_FORCE_INLINE void
|
||||
XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
|
||||
{
|
||||
XXH_ASSERT((((size_t)acc) & 15) == 0);
|
||||
|
||||
{ uint64x2_t* xacc = (uint64x2_t*) acc;
|
||||
{ xxh_aliasing_uint64x2_t* xacc = (xxh_aliasing_uint64x2_t*) acc;
|
||||
uint8_t const* xsecret = (uint8_t const*) secret;
|
||||
uint32x2_t prime = vdup_n_u32 (XXH_PRIME32_1);
|
||||
|
||||
size_t i;
|
||||
/* NEON for the first few lanes (these loops are normally interleaved) */
|
||||
for (i=0; i < XXH3_NEON_LANES / 2; i++) {
|
||||
/* xacc[i] ^= (xacc[i] >> 47); */
|
||||
uint64x2_t acc_vec = xacc[i];
|
||||
uint64x2_t shifted = vshrq_n_u64 (acc_vec, 47);
|
||||
uint64x2_t data_vec = veorq_u64 (acc_vec, shifted);
|
||||
/* WASM uses operator overloads and doesn't need these. */
|
||||
#ifndef __wasm_simd128__
|
||||
/* { prime32_1, prime32_1 } */
|
||||
uint32x2_t const kPrimeLo = vdup_n_u32(XXH_PRIME32_1);
|
||||
/* { 0, prime32_1, 0, prime32_1 } */
|
||||
uint32x4_t const kPrimeHi = vreinterpretq_u32_u64(vdupq_n_u64((xxh_u64)XXH_PRIME32_1 << 32));
|
||||
#endif
|
||||
|
||||
/* xacc[i] ^= xsecret[i]; */
|
||||
uint8x16_t key_vec = vld1q_u8 (xsecret + (i * 16));
|
||||
uint64x2_t data_key = veorq_u64 (data_vec, vreinterpretq_u64_u8(key_vec));
|
||||
|
||||
/* xacc[i] *= XXH_PRIME32_1 */
|
||||
uint32x2_t data_key_lo, data_key_hi;
|
||||
/* data_key_lo = (uint32x2_t) (xacc[i] & 0xFFFFFFFF);
|
||||
* data_key_hi = (uint32x2_t) (xacc[i] >> 32);
|
||||
* xacc[i] = UNDEFINED; */
|
||||
XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi);
|
||||
{ /*
|
||||
* prod_hi = (data_key >> 32) * XXH_PRIME32_1;
|
||||
*
|
||||
* Avoid vmul_u32 + vshll_n_u32 since Clang 6 and 7 will
|
||||
* incorrectly "optimize" this:
|
||||
* tmp = vmul_u32(vmovn_u64(a), vmovn_u64(b));
|
||||
* shifted = vshll_n_u32(tmp, 32);
|
||||
* to this:
|
||||
* tmp = "vmulq_u64"(a, b); // no such thing!
|
||||
* shifted = vshlq_n_u64(tmp, 32);
|
||||
*
|
||||
* However, unlike SSE, Clang lacks a 64-bit multiply routine
|
||||
* for NEON, and it scalarizes two 64-bit multiplies instead.
|
||||
*
|
||||
* vmull_u32 has the same timing as vmul_u32, and it avoids
|
||||
* this bug completely.
|
||||
* See https://bugs.llvm.org/show_bug.cgi?id=39967
|
||||
*/
|
||||
uint64x2_t prod_hi = vmull_u32 (data_key_hi, prime);
|
||||
/* xacc[i] = prod_hi << 32; */
|
||||
xacc[i] = vshlq_n_u64(prod_hi, 32);
|
||||
/* xacc[i] += (prod_hi & 0xFFFFFFFF) * XXH_PRIME32_1; */
|
||||
xacc[i] = vmlal_u32(xacc[i], data_key_lo, prime);
|
||||
}
|
||||
}
|
||||
/* Scalar for the remainder. This may be a zero iteration loop. */
|
||||
/* AArch64 uses both scalar and neon at the same time */
|
||||
for (i = XXH3_NEON_LANES; i < XXH_ACC_NB; i++) {
|
||||
XXH3_scalarScrambleRound(acc, secret, i);
|
||||
}
|
||||
for (i=0; i < XXH3_NEON_LANES / 2; i++) {
|
||||
/* xacc[i] ^= (xacc[i] >> 47); */
|
||||
uint64x2_t acc_vec = xacc[i];
|
||||
uint64x2_t shifted = vshrq_n_u64(acc_vec, 47);
|
||||
uint64x2_t data_vec = veorq_u64(acc_vec, shifted);
|
||||
|
||||
/* xacc[i] ^= xsecret[i]; */
|
||||
uint64x2_t key_vec = XXH_vld1q_u64(xsecret + (i * 16));
|
||||
uint64x2_t data_key = veorq_u64(data_vec, key_vec);
|
||||
/* xacc[i] *= XXH_PRIME32_1 */
|
||||
#ifdef __wasm_simd128__
|
||||
/* SIMD128 has multiply by u64x2, use it instead of expanding and scalarizing */
|
||||
xacc[i] = data_key * XXH_PRIME32_1;
|
||||
#else
|
||||
/*
|
||||
* Expanded version with portable NEON intrinsics
|
||||
*
|
||||
* lo(x) * lo(y) + (hi(x) * lo(y) << 32)
|
||||
*
|
||||
* prod_hi = hi(data_key) * lo(prime) << 32
|
||||
*
|
||||
* Since we only need 32 bits of this multiply a trick can be used, reinterpreting the vector
|
||||
* as a uint32x4_t and multiplying by { 0, prime, 0, prime } to cancel out the unwanted bits
|
||||
* and avoid the shift.
|
||||
*/
|
||||
uint32x4_t prod_hi = vmulq_u32 (vreinterpretq_u32_u64(data_key), kPrimeHi);
|
||||
/* Extract low bits for vmlal_u32 */
|
||||
uint32x2_t data_key_lo = vmovn_u64(data_key);
|
||||
/* xacc[i] = prod_hi + lo(data_key) * XXH_PRIME32_1; */
|
||||
xacc[i] = vmlal_u32(vreinterpretq_u64_u32(prod_hi), data_key_lo, kPrimeLo);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (XXH_VECTOR == XXH_VSX)
|
||||
@@ -4178,23 +5324,23 @@ XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc,
|
||||
const void* XXH_RESTRICT secret)
|
||||
{
|
||||
/* presumed aligned */
|
||||
unsigned int* const xacc = (unsigned int*) acc;
|
||||
xxh_u64x2 const* const xinput = (xxh_u64x2 const*) input; /* no alignment restriction */
|
||||
xxh_u64x2 const* const xsecret = (xxh_u64x2 const*) secret; /* no alignment restriction */
|
||||
xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc;
|
||||
xxh_u8 const* const xinput = (xxh_u8 const*) input; /* no alignment restriction */
|
||||
xxh_u8 const* const xsecret = (xxh_u8 const*) secret; /* no alignment restriction */
|
||||
xxh_u64x2 const v32 = { 32, 32 };
|
||||
size_t i;
|
||||
for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) {
|
||||
/* data_vec = xinput[i]; */
|
||||
xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + i);
|
||||
xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + 16*i);
|
||||
/* key_vec = xsecret[i]; */
|
||||
xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i);
|
||||
xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + 16*i);
|
||||
xxh_u64x2 const data_key = data_vec ^ key_vec;
|
||||
/* shuffled = (data_key << 32) | (data_key >> 32); */
|
||||
xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32);
|
||||
/* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */
|
||||
xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled);
|
||||
/* acc_vec = xacc[i]; */
|
||||
xxh_u64x2 acc_vec = (xxh_u64x2)vec_xl(0, xacc + 4 * i);
|
||||
xxh_u64x2 acc_vec = xacc[i];
|
||||
acc_vec += product;
|
||||
|
||||
/* swap high and low halves */
|
||||
@@ -4203,18 +5349,18 @@ XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc,
|
||||
#else
|
||||
acc_vec += vec_xxpermdi(data_vec, data_vec, 2);
|
||||
#endif
|
||||
/* xacc[i] = acc_vec; */
|
||||
vec_xst((xxh_u32x4)acc_vec, 0, xacc + 4 * i);
|
||||
xacc[i] = acc_vec;
|
||||
}
|
||||
}
|
||||
XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(vsx)
|
||||
|
||||
XXH_FORCE_INLINE void
|
||||
XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
|
||||
{
|
||||
XXH_ASSERT((((size_t)acc) & 15) == 0);
|
||||
|
||||
{ xxh_u64x2* const xacc = (xxh_u64x2*) acc;
|
||||
const xxh_u64x2* const xsecret = (const xxh_u64x2*) secret;
|
||||
{ xxh_aliasing_u64x2* const xacc = (xxh_aliasing_u64x2*) acc;
|
||||
const xxh_u8* const xsecret = (const xxh_u8*) secret;
|
||||
/* constants */
|
||||
xxh_u64x2 const v32 = { 32, 32 };
|
||||
xxh_u64x2 const v47 = { 47, 47 };
|
||||
@@ -4226,7 +5372,7 @@ XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
|
||||
xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47);
|
||||
|
||||
/* xacc[i] ^= xsecret[i]; */
|
||||
xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i);
|
||||
xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + 16*i);
|
||||
xxh_u64x2 const data_key = data_vec ^ key_vec;
|
||||
|
||||
/* xacc[i] *= XXH_PRIME32_1 */
|
||||
@@ -4240,8 +5386,148 @@ XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret)
|
||||
|
||||
#endif
|
||||
|
||||
#if (XXH_VECTOR == XXH_SVE)
|
||||
|
||||
XXH_FORCE_INLINE void
|
||||
XXH3_accumulate_512_sve( void* XXH_RESTRICT acc,
|
||||
const void* XXH_RESTRICT input,
|
||||
const void* XXH_RESTRICT secret)
|
||||
{
|
||||
uint64_t *xacc = (uint64_t *)acc;
|
||||
const uint64_t *xinput = (const uint64_t *)(const void *)input;
|
||||
const uint64_t *xsecret = (const uint64_t *)(const void *)secret;
|
||||
svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1);
|
||||
uint64_t element_count = svcntd();
|
||||
if (element_count >= 8) {
|
||||
svbool_t mask = svptrue_pat_b64(SV_VL8);
|
||||
svuint64_t vacc = svld1_u64(mask, xacc);
|
||||
ACCRND(vacc, 0);
|
||||
svst1_u64(mask, xacc, vacc);
|
||||
} else if (element_count == 2) { /* sve128 */
|
||||
svbool_t mask = svptrue_pat_b64(SV_VL2);
|
||||
svuint64_t acc0 = svld1_u64(mask, xacc + 0);
|
||||
svuint64_t acc1 = svld1_u64(mask, xacc + 2);
|
||||
svuint64_t acc2 = svld1_u64(mask, xacc + 4);
|
||||
svuint64_t acc3 = svld1_u64(mask, xacc + 6);
|
||||
ACCRND(acc0, 0);
|
||||
ACCRND(acc1, 2);
|
||||
ACCRND(acc2, 4);
|
||||
ACCRND(acc3, 6);
|
||||
svst1_u64(mask, xacc + 0, acc0);
|
||||
svst1_u64(mask, xacc + 2, acc1);
|
||||
svst1_u64(mask, xacc + 4, acc2);
|
||||
svst1_u64(mask, xacc + 6, acc3);
|
||||
} else {
|
||||
svbool_t mask = svptrue_pat_b64(SV_VL4);
|
||||
svuint64_t acc0 = svld1_u64(mask, xacc + 0);
|
||||
svuint64_t acc1 = svld1_u64(mask, xacc + 4);
|
||||
ACCRND(acc0, 0);
|
||||
ACCRND(acc1, 4);
|
||||
svst1_u64(mask, xacc + 0, acc0);
|
||||
svst1_u64(mask, xacc + 4, acc1);
|
||||
}
|
||||
}
|
||||
|
||||
XXH_FORCE_INLINE void
|
||||
XXH3_accumulate_sve(xxh_u64* XXH_RESTRICT acc,
|
||||
const xxh_u8* XXH_RESTRICT input,
|
||||
const xxh_u8* XXH_RESTRICT secret,
|
||||
size_t nbStripes)
|
||||
{
|
||||
if (nbStripes != 0) {
|
||||
uint64_t *xacc = (uint64_t *)acc;
|
||||
const uint64_t *xinput = (const uint64_t *)(const void *)input;
|
||||
const uint64_t *xsecret = (const uint64_t *)(const void *)secret;
|
||||
svuint64_t kSwap = sveor_n_u64_z(svptrue_b64(), svindex_u64(0, 1), 1);
|
||||
uint64_t element_count = svcntd();
|
||||
if (element_count >= 8) {
|
||||
svbool_t mask = svptrue_pat_b64(SV_VL8);
|
||||
svuint64_t vacc = svld1_u64(mask, xacc + 0);
|
||||
do {
|
||||
/* svprfd(svbool_t, void *, enum svfprop); */
|
||||
svprfd(mask, xinput + 128, SV_PLDL1STRM);
|
||||
ACCRND(vacc, 0);
|
||||
xinput += 8;
|
||||
xsecret += 1;
|
||||
nbStripes--;
|
||||
} while (nbStripes != 0);
|
||||
|
||||
svst1_u64(mask, xacc + 0, vacc);
|
||||
} else if (element_count == 2) { /* sve128 */
|
||||
svbool_t mask = svptrue_pat_b64(SV_VL2);
|
||||
svuint64_t acc0 = svld1_u64(mask, xacc + 0);
|
||||
svuint64_t acc1 = svld1_u64(mask, xacc + 2);
|
||||
svuint64_t acc2 = svld1_u64(mask, xacc + 4);
|
||||
svuint64_t acc3 = svld1_u64(mask, xacc + 6);
|
||||
do {
|
||||
svprfd(mask, xinput + 128, SV_PLDL1STRM);
|
||||
ACCRND(acc0, 0);
|
||||
ACCRND(acc1, 2);
|
||||
ACCRND(acc2, 4);
|
||||
ACCRND(acc3, 6);
|
||||
xinput += 8;
|
||||
xsecret += 1;
|
||||
nbStripes--;
|
||||
} while (nbStripes != 0);
|
||||
|
||||
svst1_u64(mask, xacc + 0, acc0);
|
||||
svst1_u64(mask, xacc + 2, acc1);
|
||||
svst1_u64(mask, xacc + 4, acc2);
|
||||
svst1_u64(mask, xacc + 6, acc3);
|
||||
} else {
|
||||
svbool_t mask = svptrue_pat_b64(SV_VL4);
|
||||
svuint64_t acc0 = svld1_u64(mask, xacc + 0);
|
||||
svuint64_t acc1 = svld1_u64(mask, xacc + 4);
|
||||
do {
|
||||
svprfd(mask, xinput + 128, SV_PLDL1STRM);
|
||||
ACCRND(acc0, 0);
|
||||
ACCRND(acc1, 4);
|
||||
xinput += 8;
|
||||
xsecret += 1;
|
||||
nbStripes--;
|
||||
} while (nbStripes != 0);
|
||||
|
||||
svst1_u64(mask, xacc + 0, acc0);
|
||||
svst1_u64(mask, xacc + 4, acc1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* scalar variants - universal */
|
||||
|
||||
#if defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__))
|
||||
/*
|
||||
* In XXH3_scalarRound(), GCC and Clang have a similar codegen issue, where they
|
||||
* emit an excess mask and a full 64-bit multiply-add (MADD X-form).
|
||||
*
|
||||
* While this might not seem like much, as AArch64 is a 64-bit architecture, only
|
||||
* big Cortex designs have a full 64-bit multiplier.
|
||||
*
|
||||
* On the little cores, the smaller 32-bit multiplier is used, and full 64-bit
|
||||
* multiplies expand to 2-3 multiplies in microcode. This has a major penalty
|
||||
* of up to 4 latency cycles and 2 stall cycles in the multiply pipeline.
|
||||
*
|
||||
* Thankfully, AArch64 still provides the 32-bit long multiply-add (UMADDL) which does
|
||||
* not have this penalty and does the mask automatically.
|
||||
*/
|
||||
XXH_FORCE_INLINE xxh_u64
|
||||
XXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc)
|
||||
{
|
||||
xxh_u64 ret;
|
||||
/* note: %x = 64-bit register, %w = 32-bit register */
|
||||
__asm__("umaddl %x0, %w1, %w2, %x3" : "=r" (ret) : "r" (lhs), "r" (rhs), "r" (acc));
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
XXH_FORCE_INLINE xxh_u64
|
||||
XXH_mult32to64_add64(xxh_u64 lhs, xxh_u64 rhs, xxh_u64 acc)
|
||||
{
|
||||
return XXH_mult32to64((xxh_u32)lhs, (xxh_u32)rhs) + acc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @internal
|
||||
* @brief Scalar round for @ref XXH3_accumulate_512_scalar().
|
||||
@@ -4264,7 +5550,7 @@ XXH3_scalarRound(void* XXH_RESTRICT acc,
|
||||
xxh_u64 const data_val = XXH_readLE64(xinput + lane * 8);
|
||||
xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + lane * 8);
|
||||
xacc[lane ^ 1] += data_val; /* swap adjacent lanes */
|
||||
xacc[lane] += XXH_mult32to64(data_key & 0xFFFFFFFF, data_key >> 32);
|
||||
xacc[lane] = XXH_mult32to64_add64(data_key /* & 0xFFFFFFFF */, data_key >> 32, xacc[lane]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4278,10 +5564,18 @@ XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc,
|
||||
const void* XXH_RESTRICT secret)
|
||||
{
|
||||
size_t i;
|
||||
/* ARM GCC refuses to unroll this loop, resulting in a 24% slowdown on ARMv6. */
|
||||
#if defined(__GNUC__) && !defined(__clang__) \
|
||||
&& (defined(__arm__) || defined(__thumb2__)) \
|
||||
&& defined(__ARM_FEATURE_UNALIGNED) /* no unaligned access just wastes bytes */ \
|
||||
&& XXH_SIZE_OPT <= 0
|
||||
# pragma GCC unroll 8
|
||||
#endif
|
||||
for (i=0; i < XXH_ACC_NB; i++) {
|
||||
XXH3_scalarRound(acc, input, secret, i);
|
||||
}
|
||||
}
|
||||
XXH_FORCE_INLINE XXH3_ACCUMULATE_TEMPLATE(scalar)
|
||||
|
||||
/*!
|
||||
* @internal
|
||||
@@ -4333,10 +5627,10 @@ XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
|
||||
const xxh_u8* kSecretPtr = XXH3_kSecret;
|
||||
XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0);
|
||||
|
||||
#if defined(__clang__) && defined(__aarch64__)
|
||||
#if defined(__GNUC__) && defined(__aarch64__)
|
||||
/*
|
||||
* UGLY HACK:
|
||||
* Clang generates a bunch of MOV/MOVK pairs for aarch64, and they are
|
||||
* GCC and Clang generate a bunch of MOV/MOVK pairs for aarch64, and they are
|
||||
* placed sequentially, in order, at the top of the unrolled loop.
|
||||
*
|
||||
* While MOVK is great for generating constants (2 cycles for a 64-bit
|
||||
@@ -4351,7 +5645,7 @@ XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
|
||||
* ADD
|
||||
* SUB STR
|
||||
* STR
|
||||
* By forcing loads from memory (as the asm line causes Clang to assume
|
||||
* By forcing loads from memory (as the asm line causes the compiler to assume
|
||||
* that XXH3_kSecretPtr has been changed), the pipelines are used more
|
||||
* efficiently:
|
||||
* I L S
|
||||
@@ -4368,17 +5662,11 @@ XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
|
||||
*/
|
||||
XXH_COMPILER_GUARD(kSecretPtr);
|
||||
#endif
|
||||
/*
|
||||
* Note: in debug mode, this overrides the asm optimization
|
||||
* and Clang will emit MOVK chains again.
|
||||
*/
|
||||
XXH_ASSERT(kSecretPtr == XXH3_kSecret);
|
||||
|
||||
{ int const nbRounds = XXH_SECRET_DEFAULT_SIZE / 16;
|
||||
int i;
|
||||
for (i=0; i < nbRounds; i++) {
|
||||
/*
|
||||
* The asm hack causes Clang to assume that kSecretPtr aliases with
|
||||
* The asm hack causes the compiler to assume that kSecretPtr aliases with
|
||||
* customSecret, and on aarch64, this prevented LDP from merging two
|
||||
* loads together for free. Putting the loads together before the stores
|
||||
* properly generates LDP.
|
||||
@@ -4391,7 +5679,7 @@ XXH3_initCustomSecret_scalar(void* XXH_RESTRICT customSecret, xxh_u64 seed64)
|
||||
}
|
||||
|
||||
|
||||
typedef void (*XXH3_f_accumulate_512)(void* XXH_RESTRICT, const void*, const void*);
|
||||
typedef void (*XXH3_f_accumulate)(xxh_u64* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, const xxh_u8* XXH_RESTRICT, size_t);
|
||||
typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*);
|
||||
typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64);
|
||||
|
||||
@@ -4399,82 +5687,63 @@ typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64);
|
||||
#if (XXH_VECTOR == XXH_AVX512)
|
||||
|
||||
#define XXH3_accumulate_512 XXH3_accumulate_512_avx512
|
||||
#define XXH3_accumulate XXH3_accumulate_avx512
|
||||
#define XXH3_scrambleAcc XXH3_scrambleAcc_avx512
|
||||
#define XXH3_initCustomSecret XXH3_initCustomSecret_avx512
|
||||
|
||||
#elif (XXH_VECTOR == XXH_AVX2)
|
||||
|
||||
#define XXH3_accumulate_512 XXH3_accumulate_512_avx2
|
||||
#define XXH3_accumulate XXH3_accumulate_avx2
|
||||
#define XXH3_scrambleAcc XXH3_scrambleAcc_avx2
|
||||
#define XXH3_initCustomSecret XXH3_initCustomSecret_avx2
|
||||
|
||||
#elif (XXH_VECTOR == XXH_SSE2)
|
||||
|
||||
#define XXH3_accumulate_512 XXH3_accumulate_512_sse2
|
||||
#define XXH3_accumulate XXH3_accumulate_sse2
|
||||
#define XXH3_scrambleAcc XXH3_scrambleAcc_sse2
|
||||
#define XXH3_initCustomSecret XXH3_initCustomSecret_sse2
|
||||
|
||||
#elif (XXH_VECTOR == XXH_NEON)
|
||||
|
||||
#define XXH3_accumulate_512 XXH3_accumulate_512_neon
|
||||
#define XXH3_accumulate XXH3_accumulate_neon
|
||||
#define XXH3_scrambleAcc XXH3_scrambleAcc_neon
|
||||
#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
|
||||
|
||||
#elif (XXH_VECTOR == XXH_VSX)
|
||||
|
||||
#define XXH3_accumulate_512 XXH3_accumulate_512_vsx
|
||||
#define XXH3_accumulate XXH3_accumulate_vsx
|
||||
#define XXH3_scrambleAcc XXH3_scrambleAcc_vsx
|
||||
#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
|
||||
|
||||
#elif (XXH_VECTOR == XXH_SVE)
|
||||
#define XXH3_accumulate_512 XXH3_accumulate_512_sve
|
||||
#define XXH3_accumulate XXH3_accumulate_sve
|
||||
#define XXH3_scrambleAcc XXH3_scrambleAcc_scalar
|
||||
#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
|
||||
|
||||
#else /* scalar */
|
||||
|
||||
#define XXH3_accumulate_512 XXH3_accumulate_512_scalar
|
||||
#define XXH3_accumulate XXH3_accumulate_scalar
|
||||
#define XXH3_scrambleAcc XXH3_scrambleAcc_scalar
|
||||
#define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef XXH_PREFETCH_DIST
|
||||
# ifdef __clang__
|
||||
# define XXH_PREFETCH_DIST 320
|
||||
# else
|
||||
# if (XXH_VECTOR == XXH_AVX512)
|
||||
# define XXH_PREFETCH_DIST 512
|
||||
# else
|
||||
# define XXH_PREFETCH_DIST 384
|
||||
# endif
|
||||
# endif /* __clang__ */
|
||||
#endif /* XXH_PREFETCH_DIST */
|
||||
|
||||
/*
|
||||
* XXH3_accumulate()
|
||||
* Loops over XXH3_accumulate_512().
|
||||
* Assumption: nbStripes will not overflow the secret size
|
||||
*/
|
||||
XXH_FORCE_INLINE void
|
||||
XXH3_accumulate( xxh_u64* XXH_RESTRICT acc,
|
||||
const xxh_u8* XXH_RESTRICT input,
|
||||
const xxh_u8* XXH_RESTRICT secret,
|
||||
size_t nbStripes,
|
||||
XXH3_f_accumulate_512 f_acc512)
|
||||
{
|
||||
size_t n;
|
||||
for (n = 0; n < nbStripes; n++ ) {
|
||||
const xxh_u8* const in = input + n*XXH_STRIPE_LEN;
|
||||
XXH_PREFETCH(in + XXH_PREFETCH_DIST);
|
||||
f_acc512(acc,
|
||||
in,
|
||||
secret + n*XXH_SECRET_CONSUME_RATE);
|
||||
}
|
||||
}
|
||||
#if XXH_SIZE_OPT >= 1 /* don't do SIMD for initialization */
|
||||
# undef XXH3_initCustomSecret
|
||||
# define XXH3_initCustomSecret XXH3_initCustomSecret_scalar
|
||||
#endif
|
||||
|
||||
XXH_FORCE_INLINE void
|
||||
XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc,
|
||||
const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
|
||||
XXH3_f_accumulate_512 f_acc512,
|
||||
XXH3_f_accumulate f_acc,
|
||||
XXH3_f_scrambleAcc f_scramble)
|
||||
{
|
||||
size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE;
|
||||
@@ -4486,7 +5755,7 @@ XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc,
|
||||
XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN);
|
||||
|
||||
for (n = 0; n < nb_blocks; n++) {
|
||||
XXH3_accumulate(acc, input + n*block_len, secret, nbStripesPerBlock, f_acc512);
|
||||
f_acc(acc, input + n*block_len, secret, nbStripesPerBlock);
|
||||
f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN);
|
||||
}
|
||||
|
||||
@@ -4494,12 +5763,12 @@ XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc,
|
||||
XXH_ASSERT(len > XXH_STRIPE_LEN);
|
||||
{ size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN;
|
||||
XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE));
|
||||
XXH3_accumulate(acc, input + nb_blocks*block_len, secret, nbStripes, f_acc512);
|
||||
f_acc(acc, input + nb_blocks*block_len, secret, nbStripes);
|
||||
|
||||
/* last stripe */
|
||||
{ const xxh_u8* const p = input + len - XXH_STRIPE_LEN;
|
||||
#define XXH_SECRET_LASTACC_START 7 /* not aligned on 8, last secret is different from acc & scrambler */
|
||||
f_acc512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START);
|
||||
XXH3_accumulate_512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START);
|
||||
} }
|
||||
}
|
||||
|
||||
@@ -4544,12 +5813,12 @@ XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secre
|
||||
XXH_FORCE_INLINE XXH64_hash_t
|
||||
XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len,
|
||||
const void* XXH_RESTRICT secret, size_t secretSize,
|
||||
XXH3_f_accumulate_512 f_acc512,
|
||||
XXH3_f_accumulate f_acc,
|
||||
XXH3_f_scrambleAcc f_scramble)
|
||||
{
|
||||
XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC;
|
||||
|
||||
XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc512, f_scramble);
|
||||
XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, (const xxh_u8*)secret, secretSize, f_acc, f_scramble);
|
||||
|
||||
/* converge into final hash */
|
||||
XXH_STATIC_ASSERT(sizeof(acc) == 64);
|
||||
@@ -4563,13 +5832,15 @@ XXH3_hashLong_64b_internal(const void* XXH_RESTRICT input, size_t len,
|
||||
* It's important for performance to transmit secret's size (when it's static)
|
||||
* so that the compiler can properly optimize the vectorized loop.
|
||||
* This makes a big performance difference for "medium" keys (<1 KB) when using AVX instruction set.
|
||||
* When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE
|
||||
* breaks -Og, this is XXH_NO_INLINE.
|
||||
*/
|
||||
XXH_FORCE_INLINE XXH64_hash_t
|
||||
XXH3_WITH_SECRET_INLINE XXH64_hash_t
|
||||
XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len,
|
||||
XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)
|
||||
{
|
||||
(void)seed64;
|
||||
return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate_512, XXH3_scrambleAcc);
|
||||
return XXH3_hashLong_64b_internal(input, len, secret, secretLen, XXH3_accumulate, XXH3_scrambleAcc);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4578,12 +5849,12 @@ XXH3_hashLong_64b_withSecret(const void* XXH_RESTRICT input, size_t len,
|
||||
* Note that inside this no_inline function, we do inline the internal loop,
|
||||
* and provide a statically defined secret size to allow optimization of vector loop.
|
||||
*/
|
||||
XXH_NO_INLINE XXH64_hash_t
|
||||
XXH_NO_INLINE XXH_PUREF XXH64_hash_t
|
||||
XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len,
|
||||
XXH64_hash_t seed64, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)
|
||||
{
|
||||
(void)seed64; (void)secret; (void)secretLen;
|
||||
return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate_512, XXH3_scrambleAcc);
|
||||
return XXH3_hashLong_64b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_accumulate, XXH3_scrambleAcc);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4600,18 +5871,20 @@ XXH3_hashLong_64b_default(const void* XXH_RESTRICT input, size_t len,
|
||||
XXH_FORCE_INLINE XXH64_hash_t
|
||||
XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len,
|
||||
XXH64_hash_t seed,
|
||||
XXH3_f_accumulate_512 f_acc512,
|
||||
XXH3_f_accumulate f_acc,
|
||||
XXH3_f_scrambleAcc f_scramble,
|
||||
XXH3_f_initCustomSecret f_initSec)
|
||||
{
|
||||
#if XXH_SIZE_OPT <= 0
|
||||
if (seed == 0)
|
||||
return XXH3_hashLong_64b_internal(input, len,
|
||||
XXH3_kSecret, sizeof(XXH3_kSecret),
|
||||
f_acc512, f_scramble);
|
||||
f_acc, f_scramble);
|
||||
#endif
|
||||
{ XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];
|
||||
f_initSec(secret, seed);
|
||||
return XXH3_hashLong_64b_internal(input, len, secret, sizeof(secret),
|
||||
f_acc512, f_scramble);
|
||||
f_acc, f_scramble);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4619,12 +5892,12 @@ XXH3_hashLong_64b_withSeed_internal(const void* input, size_t len,
|
||||
* It's important for performance that XXH3_hashLong is not inlined.
|
||||
*/
|
||||
XXH_NO_INLINE XXH64_hash_t
|
||||
XXH3_hashLong_64b_withSeed(const void* input, size_t len,
|
||||
XXH64_hash_t seed, const xxh_u8* secret, size_t secretLen)
|
||||
XXH3_hashLong_64b_withSeed(const void* XXH_RESTRICT input, size_t len,
|
||||
XXH64_hash_t seed, const xxh_u8* XXH_RESTRICT secret, size_t secretLen)
|
||||
{
|
||||
(void)secret; (void)secretLen;
|
||||
return XXH3_hashLong_64b_withSeed_internal(input, len, seed,
|
||||
XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret);
|
||||
XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret);
|
||||
}
|
||||
|
||||
|
||||
@@ -4656,37 +5929,37 @@ XXH3_64bits_internal(const void* XXH_RESTRICT input, size_t len,
|
||||
|
||||
/* === Public entry point === */
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(const void* input, size_t len)
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits(XXH_NOESCAPE const void* input, size_t length)
|
||||
{
|
||||
return XXH3_64bits_internal(input, len, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default);
|
||||
return XXH3_64bits_internal(input, length, 0, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_default);
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH64_hash_t
|
||||
XXH3_64bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize)
|
||||
XXH3_64bits_withSecret(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize)
|
||||
{
|
||||
return XXH3_64bits_internal(input, len, 0, secret, secretSize, XXH3_hashLong_64b_withSecret);
|
||||
return XXH3_64bits_internal(input, length, 0, secret, secretSize, XXH3_hashLong_64b_withSecret);
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH64_hash_t
|
||||
XXH3_64bits_withSeed(const void* input, size_t len, XXH64_hash_t seed)
|
||||
XXH3_64bits_withSeed(XXH_NOESCAPE const void* input, size_t length, XXH64_hash_t seed)
|
||||
{
|
||||
return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed);
|
||||
return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), XXH3_hashLong_64b_withSeed);
|
||||
}
|
||||
|
||||
XXH_PUBLIC_API XXH64_hash_t
|
||||
XXH3_64bits_withSecretandSeed(const void* input, size_t len, const void* secret, size_t secretSize, XXH64_hash_t seed)
|
||||
XXH3_64bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t length, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed)
|
||||
{
|
||||
if (len <= XXH3_MIDSIZE_MAX)
|
||||
return XXH3_64bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL);
|
||||
return XXH3_hashLong_64b_withSecret(input, len, seed, (const xxh_u8*)secret, secretSize);
|
||||
if (length <= XXH3_MIDSIZE_MAX)
|
||||
return XXH3_64bits_internal(input, length, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL);
|
||||
return XXH3_hashLong_64b_withSecret(input, length, seed, (const xxh_u8*)secret, secretSize);
|
||||
}
|
||||
|
||||
|
||||
/* === XXH3 streaming === */
|
||||
|
||||
#ifndef XXH_NO_STREAM
|
||||
/*
|
||||
* Malloc's a pointer that is always aligned to align.
|
||||
*
|
||||
@@ -4710,7 +5983,7 @@ XXH3_64bits_withSecretandSeed(const void* input, size_t len, const void* secret,
|
||||
*
|
||||
* Align must be a power of 2 and 8 <= align <= 128.
|
||||
*/
|
||||
static void* XXH_alignedMalloc(size_t s, size_t align)
|
||||
static XXH_MALLOCF void* XXH_alignedMalloc(size_t s, size_t align)
|
||||
{
|
||||
XXH_ASSERT(align <= 128 && align >= 8); /* range check */
|
||||
XXH_ASSERT((align & (align-1)) == 0); /* power of 2 */
|
||||
@@ -4752,7 +6025,15 @@ static void XXH_alignedFree(void* p)
|
||||
XXH_free(base);
|
||||
}
|
||||
}
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
/*!
|
||||
* @brief Allocate an @ref XXH3_state_t.
|
||||
*
|
||||
* @return An allocated pointer of @ref XXH3_state_t on success.
|
||||
* @return `NULL` on failure.
|
||||
*
|
||||
* @note Must be freed with XXH3_freeState().
|
||||
*/
|
||||
XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void)
|
||||
{
|
||||
XXH3_state_t* const state = (XXH3_state_t*)XXH_alignedMalloc(sizeof(XXH3_state_t), 64);
|
||||
@@ -4761,16 +6042,25 @@ XXH_PUBLIC_API XXH3_state_t* XXH3_createState(void)
|
||||
return state;
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
/*!
|
||||
* @brief Frees an @ref XXH3_state_t.
|
||||
*
|
||||
* @param statePtr A pointer to an @ref XXH3_state_t allocated with @ref XXH3_createState().
|
||||
*
|
||||
* @return @ref XXH_OK.
|
||||
*
|
||||
* @note Must be allocated with XXH3_createState().
|
||||
*/
|
||||
XXH_PUBLIC_API XXH_errorcode XXH3_freeState(XXH3_state_t* statePtr)
|
||||
{
|
||||
XXH_alignedFree(statePtr);
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API void
|
||||
XXH3_copyState(XXH3_state_t* dst_state, const XXH3_state_t* src_state)
|
||||
XXH3_copyState(XXH_NOESCAPE XXH3_state_t* dst_state, XXH_NOESCAPE const XXH3_state_t* src_state)
|
||||
{
|
||||
XXH_memcpy(dst_state, src_state, sizeof(*dst_state));
|
||||
}
|
||||
@@ -4802,18 +6092,18 @@ XXH3_reset_internal(XXH3_state_t* statePtr,
|
||||
statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE;
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH3_64bits_reset(XXH3_state_t* statePtr)
|
||||
XXH3_64bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr)
|
||||
{
|
||||
if (statePtr == NULL) return XXH_ERROR;
|
||||
XXH3_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE);
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize)
|
||||
XXH3_64bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize)
|
||||
{
|
||||
if (statePtr == NULL) return XXH_ERROR;
|
||||
XXH3_reset_internal(statePtr, 0, secret, secretSize);
|
||||
@@ -4822,9 +6112,9 @@ XXH3_64bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed)
|
||||
XXH3_64bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed)
|
||||
{
|
||||
if (statePtr == NULL) return XXH_ERROR;
|
||||
if (seed==0) return XXH3_64bits_reset(statePtr);
|
||||
@@ -4834,9 +6124,9 @@ XXH3_64bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed)
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr, const void* secret, size_t secretSize, XXH64_hash_t seed64)
|
||||
XXH3_64bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed64)
|
||||
{
|
||||
if (statePtr == NULL) return XXH_ERROR;
|
||||
if (secret == NULL) return XXH_ERROR;
|
||||
@@ -4846,35 +6136,61 @@ XXH3_64bits_reset_withSecretandSeed(XXH3_state_t* statePtr, const void* secret,
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
/* Note : when XXH3_consumeStripes() is invoked,
|
||||
* there must be a guarantee that at least one more byte must be consumed from input
|
||||
* so that the function can blindly consume all stripes using the "normal" secret segment */
|
||||
XXH_FORCE_INLINE void
|
||||
/*!
|
||||
* @internal
|
||||
* @brief Processes a large input for XXH3_update() and XXH3_digest_long().
|
||||
*
|
||||
* Unlike XXH3_hashLong_internal_loop(), this can process data that overlaps a block.
|
||||
*
|
||||
* @param acc Pointer to the 8 accumulator lanes
|
||||
* @param nbStripesSoFarPtr In/out pointer to the number of leftover stripes in the block*
|
||||
* @param nbStripesPerBlock Number of stripes in a block
|
||||
* @param input Input pointer
|
||||
* @param nbStripes Number of stripes to process
|
||||
* @param secret Secret pointer
|
||||
* @param secretLimit Offset of the last block in @p secret
|
||||
* @param f_acc Pointer to an XXH3_accumulate implementation
|
||||
* @param f_scramble Pointer to an XXH3_scrambleAcc implementation
|
||||
* @return Pointer past the end of @p input after processing
|
||||
*/
|
||||
XXH_FORCE_INLINE const xxh_u8 *
|
||||
XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc,
|
||||
size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock,
|
||||
const xxh_u8* XXH_RESTRICT input, size_t nbStripes,
|
||||
const xxh_u8* XXH_RESTRICT secret, size_t secretLimit,
|
||||
XXH3_f_accumulate_512 f_acc512,
|
||||
XXH3_f_accumulate f_acc,
|
||||
XXH3_f_scrambleAcc f_scramble)
|
||||
{
|
||||
XXH_ASSERT(nbStripes <= nbStripesPerBlock); /* can handle max 1 scramble per invocation */
|
||||
XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock);
|
||||
if (nbStripesPerBlock - *nbStripesSoFarPtr <= nbStripes) {
|
||||
/* need a scrambling operation */
|
||||
size_t const nbStripesToEndofBlock = nbStripesPerBlock - *nbStripesSoFarPtr;
|
||||
size_t const nbStripesAfterBlock = nbStripes - nbStripesToEndofBlock;
|
||||
XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripesToEndofBlock, f_acc512);
|
||||
f_scramble(acc, secret + secretLimit);
|
||||
XXH3_accumulate(acc, input + nbStripesToEndofBlock * XXH_STRIPE_LEN, secret, nbStripesAfterBlock, f_acc512);
|
||||
*nbStripesSoFarPtr = nbStripesAfterBlock;
|
||||
} else {
|
||||
XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripes, f_acc512);
|
||||
const xxh_u8* initialSecret = secret + *nbStripesSoFarPtr * XXH_SECRET_CONSUME_RATE;
|
||||
/* Process full blocks */
|
||||
if (nbStripes >= (nbStripesPerBlock - *nbStripesSoFarPtr)) {
|
||||
/* Process the initial partial block... */
|
||||
size_t nbStripesThisIter = nbStripesPerBlock - *nbStripesSoFarPtr;
|
||||
|
||||
do {
|
||||
/* Accumulate and scramble */
|
||||
f_acc(acc, input, initialSecret, nbStripesThisIter);
|
||||
f_scramble(acc, secret + secretLimit);
|
||||
input += nbStripesThisIter * XXH_STRIPE_LEN;
|
||||
nbStripes -= nbStripesThisIter;
|
||||
/* Then continue the loop with the full block size */
|
||||
nbStripesThisIter = nbStripesPerBlock;
|
||||
initialSecret = secret;
|
||||
} while (nbStripes >= nbStripesPerBlock);
|
||||
*nbStripesSoFarPtr = 0;
|
||||
}
|
||||
/* Process a partial block */
|
||||
if (nbStripes > 0) {
|
||||
f_acc(acc, input, initialSecret, nbStripes);
|
||||
input += nbStripes * XXH_STRIPE_LEN;
|
||||
*nbStripesSoFarPtr += nbStripes;
|
||||
}
|
||||
/* Return end pointer */
|
||||
return input;
|
||||
}
|
||||
|
||||
#ifndef XXH3_STREAM_USE_STACK
|
||||
# ifndef __clang__ /* clang doesn't need additional stack space */
|
||||
# if XXH_SIZE_OPT <= 0 && !defined(__clang__) /* clang doesn't need additional stack space */
|
||||
# define XXH3_STREAM_USE_STACK 1
|
||||
# endif
|
||||
#endif
|
||||
@@ -4884,7 +6200,7 @@ XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc,
|
||||
XXH_FORCE_INLINE XXH_errorcode
|
||||
XXH3_update(XXH3_state_t* XXH_RESTRICT const state,
|
||||
const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
XXH3_f_accumulate_512 f_acc512,
|
||||
XXH3_f_accumulate f_acc,
|
||||
XXH3_f_scrambleAcc f_scramble)
|
||||
{
|
||||
if (input==NULL) {
|
||||
@@ -4900,7 +6216,8 @@ XXH3_update(XXH3_state_t* XXH_RESTRICT const state,
|
||||
* when operating accumulators directly into state.
|
||||
* Operating into stack space seems to enable proper optimization.
|
||||
* clang, on the other hand, doesn't seem to need this trick */
|
||||
XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[8]; memcpy(acc, state->acc, sizeof(acc));
|
||||
XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[8];
|
||||
XXH_memcpy(acc, state->acc, sizeof(acc));
|
||||
#else
|
||||
xxh_u64* XXH_RESTRICT const acc = state->acc;
|
||||
#endif
|
||||
@@ -4908,7 +6225,7 @@ XXH3_update(XXH3_state_t* XXH_RESTRICT const state,
|
||||
XXH_ASSERT(state->bufferedSize <= XXH3_INTERNALBUFFER_SIZE);
|
||||
|
||||
/* small input : just fill in tmp buffer */
|
||||
if (state->bufferedSize + len <= XXH3_INTERNALBUFFER_SIZE) {
|
||||
if (len <= XXH3_INTERNALBUFFER_SIZE - state->bufferedSize) {
|
||||
XXH_memcpy(state->buffer + state->bufferedSize, input, len);
|
||||
state->bufferedSize += (XXH32_hash_t)len;
|
||||
return XXH_OK;
|
||||
@@ -4930,57 +6247,20 @@ XXH3_update(XXH3_state_t* XXH_RESTRICT const state,
|
||||
&state->nbStripesSoFar, state->nbStripesPerBlock,
|
||||
state->buffer, XXH3_INTERNALBUFFER_STRIPES,
|
||||
secret, state->secretLimit,
|
||||
f_acc512, f_scramble);
|
||||
f_acc, f_scramble);
|
||||
state->bufferedSize = 0;
|
||||
}
|
||||
XXH_ASSERT(input < bEnd);
|
||||
|
||||
/* large input to consume : ingest per full block */
|
||||
if ((size_t)(bEnd - input) > state->nbStripesPerBlock * XXH_STRIPE_LEN) {
|
||||
if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) {
|
||||
size_t nbStripes = (size_t)(bEnd - 1 - input) / XXH_STRIPE_LEN;
|
||||
XXH_ASSERT(state->nbStripesPerBlock >= state->nbStripesSoFar);
|
||||
/* join to current block's end */
|
||||
{ size_t const nbStripesToEnd = state->nbStripesPerBlock - state->nbStripesSoFar;
|
||||
XXH_ASSERT(nbStripesToEnd <= nbStripes);
|
||||
XXH3_accumulate(acc, input, secret + state->nbStripesSoFar * XXH_SECRET_CONSUME_RATE, nbStripesToEnd, f_acc512);
|
||||
f_scramble(acc, secret + state->secretLimit);
|
||||
state->nbStripesSoFar = 0;
|
||||
input += nbStripesToEnd * XXH_STRIPE_LEN;
|
||||
nbStripes -= nbStripesToEnd;
|
||||
}
|
||||
/* consume per entire blocks */
|
||||
while(nbStripes >= state->nbStripesPerBlock) {
|
||||
XXH3_accumulate(acc, input, secret, state->nbStripesPerBlock, f_acc512);
|
||||
f_scramble(acc, secret + state->secretLimit);
|
||||
input += state->nbStripesPerBlock * XXH_STRIPE_LEN;
|
||||
nbStripes -= state->nbStripesPerBlock;
|
||||
}
|
||||
/* consume last partial block */
|
||||
XXH3_accumulate(acc, input, secret, nbStripes, f_acc512);
|
||||
input += nbStripes * XXH_STRIPE_LEN;
|
||||
XXH_ASSERT(input < bEnd); /* at least some bytes left */
|
||||
state->nbStripesSoFar = nbStripes;
|
||||
/* buffer predecessor of last partial stripe */
|
||||
XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN);
|
||||
XXH_ASSERT(bEnd - input <= XXH_STRIPE_LEN);
|
||||
} else {
|
||||
/* content to consume <= block size */
|
||||
/* Consume input by a multiple of internal buffer size */
|
||||
if (bEnd - input > XXH3_INTERNALBUFFER_SIZE) {
|
||||
const xxh_u8* const limit = bEnd - XXH3_INTERNALBUFFER_SIZE;
|
||||
do {
|
||||
XXH3_consumeStripes(acc,
|
||||
input = XXH3_consumeStripes(acc,
|
||||
&state->nbStripesSoFar, state->nbStripesPerBlock,
|
||||
input, XXH3_INTERNALBUFFER_STRIPES,
|
||||
secret, state->secretLimit,
|
||||
f_acc512, f_scramble);
|
||||
input += XXH3_INTERNALBUFFER_SIZE;
|
||||
} while (input<limit);
|
||||
/* buffer predecessor of last partial stripe */
|
||||
XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN);
|
||||
}
|
||||
}
|
||||
input, nbStripes,
|
||||
secret, state->secretLimit,
|
||||
f_acc, f_scramble);
|
||||
XXH_memcpy(state->buffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN);
|
||||
|
||||
}
|
||||
/* Some remaining input (always) : buffer it */
|
||||
XXH_ASSERT(input < bEnd);
|
||||
XXH_ASSERT(bEnd - input <= XXH3_INTERNALBUFFER_SIZE);
|
||||
@@ -4989,19 +6269,19 @@ XXH3_update(XXH3_state_t* XXH_RESTRICT const state,
|
||||
state->bufferedSize = (XXH32_hash_t)(bEnd-input);
|
||||
#if defined(XXH3_STREAM_USE_STACK) && XXH3_STREAM_USE_STACK >= 1
|
||||
/* save stack accumulators into state */
|
||||
memcpy(state->acc, acc, sizeof(acc));
|
||||
XXH_memcpy(state->acc, acc, sizeof(acc));
|
||||
#endif
|
||||
}
|
||||
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH3_64bits_update(XXH3_state_t* state, const void* input, size_t len)
|
||||
XXH3_64bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len)
|
||||
{
|
||||
return XXH3_update(state, (const xxh_u8*)input, len,
|
||||
XXH3_accumulate_512, XXH3_scrambleAcc);
|
||||
XXH3_accumulate, XXH3_scrambleAcc);
|
||||
}
|
||||
|
||||
|
||||
@@ -5010,37 +6290,40 @@ XXH3_digest_long (XXH64_hash_t* acc,
|
||||
const XXH3_state_t* state,
|
||||
const unsigned char* secret)
|
||||
{
|
||||
xxh_u8 lastStripe[XXH_STRIPE_LEN];
|
||||
const xxh_u8* lastStripePtr;
|
||||
|
||||
/*
|
||||
* Digest on a local copy. This way, the state remains unaltered, and it can
|
||||
* continue ingesting more input afterwards.
|
||||
*/
|
||||
XXH_memcpy(acc, state->acc, sizeof(state->acc));
|
||||
if (state->bufferedSize >= XXH_STRIPE_LEN) {
|
||||
/* Consume remaining stripes then point to remaining data in buffer */
|
||||
size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN;
|
||||
size_t nbStripesSoFar = state->nbStripesSoFar;
|
||||
XXH3_consumeStripes(acc,
|
||||
&nbStripesSoFar, state->nbStripesPerBlock,
|
||||
state->buffer, nbStripes,
|
||||
secret, state->secretLimit,
|
||||
XXH3_accumulate_512, XXH3_scrambleAcc);
|
||||
/* last stripe */
|
||||
XXH3_accumulate_512(acc,
|
||||
state->buffer + state->bufferedSize - XXH_STRIPE_LEN,
|
||||
secret + state->secretLimit - XXH_SECRET_LASTACC_START);
|
||||
XXH3_accumulate, XXH3_scrambleAcc);
|
||||
lastStripePtr = state->buffer + state->bufferedSize - XXH_STRIPE_LEN;
|
||||
} else { /* bufferedSize < XXH_STRIPE_LEN */
|
||||
xxh_u8 lastStripe[XXH_STRIPE_LEN];
|
||||
/* Copy to temp buffer */
|
||||
size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize;
|
||||
XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */
|
||||
XXH_memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize);
|
||||
XXH_memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize);
|
||||
XXH3_accumulate_512(acc,
|
||||
lastStripe,
|
||||
secret + state->secretLimit - XXH_SECRET_LASTACC_START);
|
||||
lastStripePtr = lastStripe;
|
||||
}
|
||||
/* Last stripe */
|
||||
XXH3_accumulate_512(acc,
|
||||
lastStripePtr,
|
||||
secret + state->secretLimit - XXH_SECRET_LASTACC_START);
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state)
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (XXH_NOESCAPE const XXH3_state_t* state)
|
||||
{
|
||||
const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;
|
||||
if (state->totalLen > XXH3_MIDSIZE_MAX) {
|
||||
@@ -5056,7 +6339,7 @@ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state)
|
||||
return XXH3_64bits_withSecret(state->buffer, (size_t)(state->totalLen),
|
||||
secret, state->secretLimit + XXH_STRIPE_LEN);
|
||||
}
|
||||
|
||||
#endif /* !XXH_NO_STREAM */
|
||||
|
||||
|
||||
/* ==========================================
|
||||
@@ -5076,7 +6359,7 @@ XXH_PUBLIC_API XXH64_hash_t XXH3_64bits_digest (const XXH3_state_t* state)
|
||||
* fast for a _128-bit_ hash on 32-bit (it usually clears XXH64).
|
||||
*/
|
||||
|
||||
XXH_FORCE_INLINE XXH128_hash_t
|
||||
XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t
|
||||
XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
|
||||
{
|
||||
/* A doubled version of 1to3_64b with different constants. */
|
||||
@@ -5105,7 +6388,7 @@ XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_
|
||||
}
|
||||
}
|
||||
|
||||
XXH_FORCE_INLINE XXH128_hash_t
|
||||
XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t
|
||||
XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
|
||||
{
|
||||
XXH_ASSERT(input != NULL);
|
||||
@@ -5125,14 +6408,14 @@ XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_
|
||||
m128.low64 ^= (m128.high64 >> 3);
|
||||
|
||||
m128.low64 = XXH_xorshift64(m128.low64, 35);
|
||||
m128.low64 *= 0x9FB21C651E98DF25ULL;
|
||||
m128.low64 *= PRIME_MX2;
|
||||
m128.low64 = XXH_xorshift64(m128.low64, 28);
|
||||
m128.high64 = XXH3_avalanche(m128.high64);
|
||||
return m128;
|
||||
}
|
||||
}
|
||||
|
||||
XXH_FORCE_INLINE XXH128_hash_t
|
||||
XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t
|
||||
XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
|
||||
{
|
||||
XXH_ASSERT(input != NULL);
|
||||
@@ -5207,7 +6490,7 @@ XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64
|
||||
/*
|
||||
* Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN
|
||||
*/
|
||||
XXH_FORCE_INLINE XXH128_hash_t
|
||||
XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t
|
||||
XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed)
|
||||
{
|
||||
XXH_ASSERT(len <= 16);
|
||||
@@ -5238,7 +6521,7 @@ XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2,
|
||||
}
|
||||
|
||||
|
||||
XXH_FORCE_INLINE XXH128_hash_t
|
||||
XXH_FORCE_INLINE XXH_PUREF XXH128_hash_t
|
||||
XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
|
||||
XXH64_hash_t seed)
|
||||
@@ -5249,6 +6532,16 @@ XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
{ XXH128_hash_t acc;
|
||||
acc.low64 = len * XXH_PRIME64_1;
|
||||
acc.high64 = 0;
|
||||
|
||||
#if XXH_SIZE_OPT >= 1
|
||||
{
|
||||
/* Smaller, but slightly slower. */
|
||||
unsigned int i = (unsigned int)(len - 1) / 32;
|
||||
do {
|
||||
acc = XXH128_mix32B(acc, input+16*i, input+len-16*(i+1), secret+32*i, seed);
|
||||
} while (i-- != 0);
|
||||
}
|
||||
#else
|
||||
if (len > 32) {
|
||||
if (len > 64) {
|
||||
if (len > 96) {
|
||||
@@ -5259,6 +6552,7 @@ XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed);
|
||||
}
|
||||
acc = XXH128_mix32B(acc, input, input+len-16, secret, seed);
|
||||
#endif
|
||||
{ XXH128_hash_t h128;
|
||||
h128.low64 = acc.low64 + acc.high64;
|
||||
h128.high64 = (acc.low64 * XXH_PRIME64_1)
|
||||
@@ -5271,7 +6565,7 @@ XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
}
|
||||
}
|
||||
|
||||
XXH_NO_INLINE XXH128_hash_t
|
||||
XXH_NO_INLINE XXH_PUREF XXH128_hash_t
|
||||
XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
|
||||
XXH64_hash_t seed)
|
||||
@@ -5280,25 +6574,34 @@ XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX);
|
||||
|
||||
{ XXH128_hash_t acc;
|
||||
int const nbRounds = (int)len / 32;
|
||||
int i;
|
||||
unsigned i;
|
||||
acc.low64 = len * XXH_PRIME64_1;
|
||||
acc.high64 = 0;
|
||||
for (i=0; i<4; i++) {
|
||||
/*
|
||||
* We set as `i` as offset + 32. We do this so that unchanged
|
||||
* `len` can be used as upper bound. This reaches a sweet spot
|
||||
* where both x86 and aarch64 get simple agen and good codegen
|
||||
* for the loop.
|
||||
*/
|
||||
for (i = 32; i < 160; i += 32) {
|
||||
acc = XXH128_mix32B(acc,
|
||||
input + (32 * i),
|
||||
input + (32 * i) + 16,
|
||||
secret + (32 * i),
|
||||
input + i - 32,
|
||||
input + i - 16,
|
||||
secret + i - 32,
|
||||
seed);
|
||||
}
|
||||
acc.low64 = XXH3_avalanche(acc.low64);
|
||||
acc.high64 = XXH3_avalanche(acc.high64);
|
||||
XXH_ASSERT(nbRounds >= 4);
|
||||
for (i=4 ; i < nbRounds; i++) {
|
||||
/*
|
||||
* NB: `i <= len` will duplicate the last 32-bytes if
|
||||
* len % 32 was zero. This is an unfortunate necessity to keep
|
||||
* the hash result stable.
|
||||
*/
|
||||
for (i=160; i <= len; i += 32) {
|
||||
acc = XXH128_mix32B(acc,
|
||||
input + (32 * i),
|
||||
input + (32 * i) + 16,
|
||||
secret + XXH3_MIDSIZE_STARTOFFSET + (32 * (i - 4)),
|
||||
input + i - 32,
|
||||
input + i - 16,
|
||||
secret + XXH3_MIDSIZE_STARTOFFSET + i - 160,
|
||||
seed);
|
||||
}
|
||||
/* last bytes */
|
||||
@@ -5306,7 +6609,7 @@ XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
input + len - 16,
|
||||
input + len - 32,
|
||||
secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16,
|
||||
0ULL - seed);
|
||||
(XXH64_hash_t)0 - seed);
|
||||
|
||||
{ XXH128_hash_t h128;
|
||||
h128.low64 = acc.low64 + acc.high64;
|
||||
@@ -5323,12 +6626,12 @@ XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len,
|
||||
XXH_FORCE_INLINE XXH128_hash_t
|
||||
XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len,
|
||||
const xxh_u8* XXH_RESTRICT secret, size_t secretSize,
|
||||
XXH3_f_accumulate_512 f_acc512,
|
||||
XXH3_f_accumulate f_acc,
|
||||
XXH3_f_scrambleAcc f_scramble)
|
||||
{
|
||||
XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC;
|
||||
|
||||
XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc512, f_scramble);
|
||||
XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc, f_scramble);
|
||||
|
||||
/* converge into final hash */
|
||||
XXH_STATIC_ASSERT(sizeof(acc) == 64);
|
||||
@@ -5346,47 +6649,50 @@ XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len,
|
||||
}
|
||||
|
||||
/*
|
||||
* It's important for performance that XXH3_hashLong is not inlined.
|
||||
* It's important for performance that XXH3_hashLong() is not inlined.
|
||||
*/
|
||||
XXH_NO_INLINE XXH128_hash_t
|
||||
XXH_NO_INLINE XXH_PUREF XXH128_hash_t
|
||||
XXH3_hashLong_128b_default(const void* XXH_RESTRICT input, size_t len,
|
||||
XXH64_hash_t seed64,
|
||||
const void* XXH_RESTRICT secret, size_t secretLen)
|
||||
{
|
||||
(void)seed64; (void)secret; (void)secretLen;
|
||||
return XXH3_hashLong_128b_internal(input, len, XXH3_kSecret, sizeof(XXH3_kSecret),
|
||||
XXH3_accumulate_512, XXH3_scrambleAcc);
|
||||
XXH3_accumulate, XXH3_scrambleAcc);
|
||||
}
|
||||
|
||||
/*
|
||||
* It's important for performance to pass @secretLen (when it's static)
|
||||
* It's important for performance to pass @p secretLen (when it's static)
|
||||
* to the compiler, so that it can properly optimize the vectorized loop.
|
||||
*
|
||||
* When the secret size is unknown, or on GCC 12 where the mix of NO_INLINE and FORCE_INLINE
|
||||
* breaks -Og, this is XXH_NO_INLINE.
|
||||
*/
|
||||
XXH_FORCE_INLINE XXH128_hash_t
|
||||
XXH3_WITH_SECRET_INLINE XXH128_hash_t
|
||||
XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len,
|
||||
XXH64_hash_t seed64,
|
||||
const void* XXH_RESTRICT secret, size_t secretLen)
|
||||
{
|
||||
(void)seed64;
|
||||
return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen,
|
||||
XXH3_accumulate_512, XXH3_scrambleAcc);
|
||||
XXH3_accumulate, XXH3_scrambleAcc);
|
||||
}
|
||||
|
||||
XXH_FORCE_INLINE XXH128_hash_t
|
||||
XXH3_hashLong_128b_withSeed_internal(const void* XXH_RESTRICT input, size_t len,
|
||||
XXH64_hash_t seed64,
|
||||
XXH3_f_accumulate_512 f_acc512,
|
||||
XXH3_f_accumulate f_acc,
|
||||
XXH3_f_scrambleAcc f_scramble,
|
||||
XXH3_f_initCustomSecret f_initSec)
|
||||
{
|
||||
if (seed64 == 0)
|
||||
return XXH3_hashLong_128b_internal(input, len,
|
||||
XXH3_kSecret, sizeof(XXH3_kSecret),
|
||||
f_acc512, f_scramble);
|
||||
f_acc, f_scramble);
|
||||
{ XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];
|
||||
f_initSec(secret, seed64);
|
||||
return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, sizeof(secret),
|
||||
f_acc512, f_scramble);
|
||||
f_acc, f_scramble);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5399,7 +6705,7 @@ XXH3_hashLong_128b_withSeed(const void* input, size_t len,
|
||||
{
|
||||
(void)secret; (void)secretLen;
|
||||
return XXH3_hashLong_128b_withSeed_internal(input, len, seed64,
|
||||
XXH3_accumulate_512, XXH3_scrambleAcc, XXH3_initCustomSecret);
|
||||
XXH3_accumulate, XXH3_scrambleAcc, XXH3_initCustomSecret);
|
||||
}
|
||||
|
||||
typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t,
|
||||
@@ -5429,94 +6735,93 @@ XXH3_128bits_internal(const void* input, size_t len,
|
||||
|
||||
/* === Public XXH128 API === */
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(const void* input, size_t len)
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits(XXH_NOESCAPE const void* input, size_t len)
|
||||
{
|
||||
return XXH3_128bits_internal(input, len, 0,
|
||||
XXH3_kSecret, sizeof(XXH3_kSecret),
|
||||
XXH3_hashLong_128b_default);
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH128_hash_t
|
||||
XXH3_128bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize)
|
||||
XXH3_128bits_withSecret(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize)
|
||||
{
|
||||
return XXH3_128bits_internal(input, len, 0,
|
||||
(const xxh_u8*)secret, secretSize,
|
||||
XXH3_hashLong_128b_withSecret);
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH128_hash_t
|
||||
XXH3_128bits_withSeed(const void* input, size_t len, XXH64_hash_t seed)
|
||||
XXH3_128bits_withSeed(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed)
|
||||
{
|
||||
return XXH3_128bits_internal(input, len, seed,
|
||||
XXH3_kSecret, sizeof(XXH3_kSecret),
|
||||
XXH3_hashLong_128b_withSeed);
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH128_hash_t
|
||||
XXH3_128bits_withSecretandSeed(const void* input, size_t len, const void* secret, size_t secretSize, XXH64_hash_t seed)
|
||||
XXH3_128bits_withSecretandSeed(XXH_NOESCAPE const void* input, size_t len, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed)
|
||||
{
|
||||
if (len <= XXH3_MIDSIZE_MAX)
|
||||
return XXH3_128bits_internal(input, len, seed, XXH3_kSecret, sizeof(XXH3_kSecret), NULL);
|
||||
return XXH3_hashLong_128b_withSecret(input, len, seed, secret, secretSize);
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH128_hash_t
|
||||
XXH128(const void* input, size_t len, XXH64_hash_t seed)
|
||||
XXH128(XXH_NOESCAPE const void* input, size_t len, XXH64_hash_t seed)
|
||||
{
|
||||
return XXH3_128bits_withSeed(input, len, seed);
|
||||
}
|
||||
|
||||
|
||||
/* === XXH3 128-bit streaming === */
|
||||
|
||||
#ifndef XXH_NO_STREAM
|
||||
/*
|
||||
* All initialization and update functions are identical to 64-bit streaming variant.
|
||||
* The only difference is the finalization routine.
|
||||
*/
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH3_128bits_reset(XXH3_state_t* statePtr)
|
||||
XXH3_128bits_reset(XXH_NOESCAPE XXH3_state_t* statePtr)
|
||||
{
|
||||
return XXH3_64bits_reset(statePtr);
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH3_128bits_reset_withSecret(XXH3_state_t* statePtr, const void* secret, size_t secretSize)
|
||||
XXH3_128bits_reset_withSecret(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize)
|
||||
{
|
||||
return XXH3_64bits_reset_withSecret(statePtr, secret, secretSize);
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH3_128bits_reset_withSeed(XXH3_state_t* statePtr, XXH64_hash_t seed)
|
||||
XXH3_128bits_reset_withSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH64_hash_t seed)
|
||||
{
|
||||
return XXH3_64bits_reset_withSeed(statePtr, seed);
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH3_128bits_reset_withSecretandSeed(XXH3_state_t* statePtr, const void* secret, size_t secretSize, XXH64_hash_t seed)
|
||||
XXH3_128bits_reset_withSecretandSeed(XXH_NOESCAPE XXH3_state_t* statePtr, XXH_NOESCAPE const void* secret, size_t secretSize, XXH64_hash_t seed)
|
||||
{
|
||||
return XXH3_64bits_reset_withSecretandSeed(statePtr, secret, secretSize, seed);
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH3_128bits_update(XXH3_state_t* state, const void* input, size_t len)
|
||||
XXH3_128bits_update(XXH_NOESCAPE XXH3_state_t* state, XXH_NOESCAPE const void* input, size_t len)
|
||||
{
|
||||
return XXH3_update(state, (const xxh_u8*)input, len,
|
||||
XXH3_accumulate_512, XXH3_scrambleAcc);
|
||||
return XXH3_64bits_update(state, input, len);
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state)
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (XXH_NOESCAPE const XXH3_state_t* state)
|
||||
{
|
||||
const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret;
|
||||
if (state->totalLen > XXH3_MIDSIZE_MAX) {
|
||||
@@ -5540,13 +6845,13 @@ XXH_PUBLIC_API XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state)
|
||||
return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen),
|
||||
secret, state->secretLimit + XXH_STRIPE_LEN);
|
||||
}
|
||||
|
||||
#endif /* !XXH_NO_STREAM */
|
||||
/* 128-bit utility functions */
|
||||
|
||||
#include <string.h> /* memcmp, memcpy */
|
||||
|
||||
/* return : 1 is equal, 0 if different */
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2)
|
||||
{
|
||||
/* note : XXH128_hash_t is compact, it has no padding byte */
|
||||
@@ -5554,11 +6859,11 @@ XXH_PUBLIC_API int XXH128_isEqual(XXH128_hash_t h1, XXH128_hash_t h2)
|
||||
}
|
||||
|
||||
/* This prototype is compatible with stdlib's qsort().
|
||||
* return : >0 if *h128_1 > *h128_2
|
||||
* <0 if *h128_1 < *h128_2
|
||||
* =0 if *h128_1 == *h128_2 */
|
||||
/*! @ingroup xxh3_family */
|
||||
XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2)
|
||||
* @return : >0 if *h128_1 > *h128_2
|
||||
* <0 if *h128_1 < *h128_2
|
||||
* =0 if *h128_1 == *h128_2 */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API int XXH128_cmp(XXH_NOESCAPE const void* h128_1, XXH_NOESCAPE const void* h128_2)
|
||||
{
|
||||
XXH128_hash_t const h1 = *(const XXH128_hash_t*)h128_1;
|
||||
XXH128_hash_t const h2 = *(const XXH128_hash_t*)h128_2;
|
||||
@@ -5570,9 +6875,9 @@ XXH_PUBLIC_API int XXH128_cmp(const void* h128_1, const void* h128_2)
|
||||
|
||||
|
||||
/*====== Canonical representation ======*/
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API void
|
||||
XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash)
|
||||
XXH128_canonicalFromHash(XXH_NOESCAPE XXH128_canonical_t* dst, XXH128_hash_t hash)
|
||||
{
|
||||
XXH_STATIC_ASSERT(sizeof(XXH128_canonical_t) == sizeof(XXH128_hash_t));
|
||||
if (XXH_CPU_LITTLE_ENDIAN) {
|
||||
@@ -5583,9 +6888,9 @@ XXH128_canonicalFromHash(XXH128_canonical_t* dst, XXH128_hash_t hash)
|
||||
XXH_memcpy((char*)dst + sizeof(hash.high64), &hash.low64, sizeof(hash.low64));
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH128_hash_t
|
||||
XXH128_hashFromCanonical(const XXH128_canonical_t* src)
|
||||
XXH128_hashFromCanonical(XXH_NOESCAPE const XXH128_canonical_t* src)
|
||||
{
|
||||
XXH128_hash_t h;
|
||||
h.high64 = XXH_readBE64(src);
|
||||
@@ -5607,9 +6912,9 @@ XXH_FORCE_INLINE void XXH3_combine16(void* dst, XXH128_hash_t h128)
|
||||
XXH_writeLE64( (char*)dst+8, XXH_readLE64((char*)dst+8) ^ h128.high64 );
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API XXH_errorcode
|
||||
XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSeed, size_t customSeedSize)
|
||||
XXH3_generateSecret(XXH_NOESCAPE void* secretBuffer, size_t secretSize, XXH_NOESCAPE const void* customSeed, size_t customSeedSize)
|
||||
{
|
||||
#if (XXH_DEBUGLEVEL >= 1)
|
||||
XXH_ASSERT(secretBuffer != NULL);
|
||||
@@ -5652,9 +6957,9 @@ XXH3_generateSecret(void* secretBuffer, size_t secretSize, const void* customSee
|
||||
return XXH_OK;
|
||||
}
|
||||
|
||||
/*! @ingroup xxh3_family */
|
||||
/*! @ingroup XXH3_family */
|
||||
XXH_PUBLIC_API void
|
||||
XXH3_generateSecret_fromSeed(void* secretBuffer, XXH64_hash_t seed)
|
||||
XXH3_generateSecret_fromSeed(XXH_NOESCAPE void* secretBuffer, XXH64_hash_t seed)
|
||||
{
|
||||
XXH_ALIGN(XXH_SEC_ALIGN) xxh_u8 secret[XXH_SECRET_DEFAULT_SIZE];
|
||||
XXH3_initCustomSecret(secret, seed);
|
||||
@@ -5667,7 +6972,7 @@ XXH3_generateSecret_fromSeed(void* secretBuffer, XXH64_hash_t seed)
|
||||
/* Pop our optimization override from above */
|
||||
#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \
|
||||
&& defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \
|
||||
&& defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */
|
||||
&& defined(__OPTIMIZE__) && XXH_SIZE_OPT <= 0 /* respect -O0 and -Os */
|
||||
# pragma GCC pop_options
|
||||
#endif
|
||||
|
||||
@@ -5682,5 +6987,5 @@ XXH3_generateSecret_fromSeed(void* secretBuffer, XXH64_hash_t seed)
|
||||
|
||||
|
||||
#if defined (__cplusplus)
|
||||
}
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -178,7 +178,7 @@ static void ZSTD_copy8(void* dst, const void* src) {
|
||||
ZSTD_memcpy(dst, src, 8);
|
||||
#endif
|
||||
}
|
||||
#define COPY8(d,s) { ZSTD_copy8(d,s); d+=8; s+=8; }
|
||||
#define COPY8(d,s) do { ZSTD_copy8(d,s); d+=8; s+=8; } while (0)
|
||||
|
||||
/* Need to use memmove here since the literal buffer can now be located within
|
||||
the dst buffer. In circumstances where the op "catches up" to where the
|
||||
@@ -198,7 +198,7 @@ static void ZSTD_copy16(void* dst, const void* src) {
|
||||
ZSTD_memcpy(dst, copy16_buf, 16);
|
||||
#endif
|
||||
}
|
||||
#define COPY16(d,s) { ZSTD_copy16(d,s); d+=16; s+=16; }
|
||||
#define COPY16(d,s) do { ZSTD_copy16(d,s); d+=16; s+=16; } while (0)
|
||||
|
||||
#define WILDCOPY_OVERLENGTH 32
|
||||
#define WILDCOPY_VECLEN 16
|
||||
@@ -227,7 +227,7 @@ void ZSTD_wildcopy(void* dst, const void* src, ptrdiff_t length, ZSTD_overlap_e
|
||||
if (ovtype == ZSTD_overlap_src_before_dst && diff < WILDCOPY_VECLEN) {
|
||||
/* Handle short offset copies. */
|
||||
do {
|
||||
COPY8(op, ip)
|
||||
COPY8(op, ip);
|
||||
} while (op < oend);
|
||||
} else {
|
||||
assert(diff >= WILDCOPY_VECLEN || diff <= -WILDCOPY_VECLEN);
|
||||
|
||||
@@ -1062,12 +1062,12 @@ HUF_compress1X_usingCTable_internal_body(void* dst, size_t dstSize,
|
||||
const BYTE* ip = (const BYTE*) src;
|
||||
BYTE* const ostart = (BYTE*)dst;
|
||||
BYTE* const oend = ostart + dstSize;
|
||||
BYTE* op = ostart;
|
||||
HUF_CStream_t bitC;
|
||||
|
||||
/* init */
|
||||
if (dstSize < 8) return 0; /* not enough space to compress */
|
||||
{ size_t const initErr = HUF_initCStream(&bitC, op, (size_t)(oend-op));
|
||||
{ BYTE* op = ostart;
|
||||
size_t const initErr = HUF_initCStream(&bitC, op, (size_t)(oend-op));
|
||||
if (HUF_isError(initErr)) return 0; }
|
||||
|
||||
if (dstSize < HUF_tightCompressBound(srcSize, (size_t)tableLog) || tableLog > 11)
|
||||
@@ -1288,7 +1288,7 @@ unsigned HUF_optimalTableLog(
|
||||
|
||||
{ BYTE* dst = (BYTE*)workSpace + sizeof(HUF_WriteCTableWksp);
|
||||
size_t dstSize = wkspSize - sizeof(HUF_WriteCTableWksp);
|
||||
size_t maxBits, hSize, newSize;
|
||||
size_t hSize, newSize;
|
||||
const unsigned symbolCardinality = HUF_cardinality(count, maxSymbolValue);
|
||||
const unsigned minTableLog = HUF_minTableLog(symbolCardinality);
|
||||
size_t optSize = ((size_t) ~0) - 1;
|
||||
@@ -1299,12 +1299,14 @@ unsigned HUF_optimalTableLog(
|
||||
/* Search until size increases */
|
||||
for (optLogGuess = minTableLog; optLogGuess <= maxTableLog; optLogGuess++) {
|
||||
DEBUGLOG(7, "checking for huffLog=%u", optLogGuess);
|
||||
maxBits = HUF_buildCTable_wksp(table, count, maxSymbolValue, optLogGuess, workSpace, wkspSize);
|
||||
if (ERR_isError(maxBits)) continue;
|
||||
|
||||
if (maxBits < optLogGuess && optLogGuess > minTableLog) break;
|
||||
{ size_t maxBits = HUF_buildCTable_wksp(table, count, maxSymbolValue, optLogGuess, workSpace, wkspSize);
|
||||
if (ERR_isError(maxBits)) continue;
|
||||
|
||||
hSize = HUF_writeCTable_wksp(dst, dstSize, table, maxSymbolValue, (U32)maxBits, workSpace, wkspSize);
|
||||
if (maxBits < optLogGuess && optLogGuess > minTableLog) break;
|
||||
|
||||
hSize = HUF_writeCTable_wksp(dst, dstSize, table, maxSymbolValue, (U32)maxBits, workSpace, wkspSize);
|
||||
}
|
||||
|
||||
if (ERR_isError(hSize)) continue;
|
||||
|
||||
|
||||
@@ -650,10 +650,11 @@ static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define BOUNDCHECK(cParam, val) { \
|
||||
RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \
|
||||
parameter_outOfBound, "Param out of bounds"); \
|
||||
}
|
||||
#define BOUNDCHECK(cParam, val) \
|
||||
do { \
|
||||
RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \
|
||||
parameter_outOfBound, "Param out of bounds"); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
|
||||
@@ -1364,7 +1365,6 @@ size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset)
|
||||
RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
|
||||
"Reset parameters is only possible during init stage.");
|
||||
ZSTD_clearAllDicts(cctx);
|
||||
ZSTD_memset(&cctx->externalMatchCtx, 0, sizeof(cctx->externalMatchCtx));
|
||||
return ZSTD_CCtxParams_reset(&cctx->requestedParams);
|
||||
}
|
||||
return 0;
|
||||
@@ -1392,11 +1392,12 @@ size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
|
||||
static ZSTD_compressionParameters
|
||||
ZSTD_clampCParams(ZSTD_compressionParameters cParams)
|
||||
{
|
||||
# define CLAMP_TYPE(cParam, val, type) { \
|
||||
ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \
|
||||
if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \
|
||||
else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \
|
||||
}
|
||||
# define CLAMP_TYPE(cParam, val, type) \
|
||||
do { \
|
||||
ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \
|
||||
if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \
|
||||
else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \
|
||||
} while (0)
|
||||
# define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned)
|
||||
CLAMP(ZSTD_c_windowLog, cParams.windowLog);
|
||||
CLAMP(ZSTD_c_chainLog, cParams.chainLog);
|
||||
@@ -1660,8 +1661,8 @@ ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
|
||||
+ ZSTD_cwksp_aligned_alloc_size((MaxLL+1) * sizeof(U32))
|
||||
+ ZSTD_cwksp_aligned_alloc_size((MaxOff+1) * sizeof(U32))
|
||||
+ ZSTD_cwksp_aligned_alloc_size((1<<Litbits) * sizeof(U32))
|
||||
+ ZSTD_cwksp_aligned_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t))
|
||||
+ ZSTD_cwksp_aligned_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
|
||||
+ ZSTD_cwksp_aligned_alloc_size(ZSTD_OPT_SIZE * sizeof(ZSTD_match_t))
|
||||
+ ZSTD_cwksp_aligned_alloc_size(ZSTD_OPT_SIZE * sizeof(ZSTD_optimal_t));
|
||||
size_t const lazyAdditionalSpace = ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder)
|
||||
? ZSTD_cwksp_aligned_alloc_size(hSize)
|
||||
: 0;
|
||||
@@ -1750,7 +1751,7 @@ size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
||||
* be needed. However, we still allocate two 0-sized buffers, which can
|
||||
* take space under ASAN. */
|
||||
return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
|
||||
&cParams, ¶ms->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN, params->useSequenceProducer, params->maxBlockSize);
|
||||
&cParams, ¶ms->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize);
|
||||
}
|
||||
|
||||
size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
|
||||
@@ -1811,7 +1812,7 @@ size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
|
||||
|
||||
return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
|
||||
&cParams, ¶ms->ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize,
|
||||
ZSTD_CONTENTSIZE_UNKNOWN, params->useSequenceProducer, params->maxBlockSize);
|
||||
ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2044,8 +2045,8 @@ ZSTD_reset_matchState(ZSTD_matchState_t* ms,
|
||||
ms->opt.litLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxLL+1) * sizeof(unsigned));
|
||||
ms->opt.matchLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxML+1) * sizeof(unsigned));
|
||||
ms->opt.offCodeFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxOff+1) * sizeof(unsigned));
|
||||
ms->opt.matchTable = (ZSTD_match_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t));
|
||||
ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
|
||||
ms->opt.matchTable = (ZSTD_match_t*)ZSTD_cwksp_reserve_aligned(ws, ZSTD_OPT_SIZE * sizeof(ZSTD_match_t));
|
||||
ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, ZSTD_OPT_SIZE * sizeof(ZSTD_optimal_t));
|
||||
}
|
||||
|
||||
ms->cParams = *cParams;
|
||||
@@ -2117,7 +2118,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
|
||||
{ size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params->cParams.windowLog), pledgedSrcSize));
|
||||
size_t const blockSize = MIN(params->maxBlockSize, windowSize);
|
||||
size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, params->cParams.minMatch, params->useSequenceProducer);
|
||||
size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, params->cParams.minMatch, ZSTD_hasExtSeqProd(params));
|
||||
size_t const buffOutSize = (zbuff == ZSTDb_buffered && params->outBufferMode == ZSTD_bm_buffered)
|
||||
? ZSTD_compressBound(blockSize) + 1
|
||||
: 0;
|
||||
@@ -2134,8 +2135,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
size_t const neededSpace =
|
||||
ZSTD_estimateCCtxSize_usingCCtxParams_internal(
|
||||
¶ms->cParams, ¶ms->ldmParams, zc->staticSize != 0, params->useRowMatchFinder,
|
||||
buffInSize, buffOutSize, pledgedSrcSize, params->useSequenceProducer, params->maxBlockSize);
|
||||
int resizeWorkspace;
|
||||
buffInSize, buffOutSize, pledgedSrcSize, ZSTD_hasExtSeqProd(params), params->maxBlockSize);
|
||||
|
||||
FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!");
|
||||
|
||||
@@ -2144,7 +2144,7 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
{ /* Check if workspace is large enough, alloc a new one if needed */
|
||||
int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace;
|
||||
int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace);
|
||||
resizeWorkspace = workspaceTooSmall || workspaceWasteful;
|
||||
int resizeWorkspace = workspaceTooSmall || workspaceWasteful;
|
||||
DEBUGLOG(4, "Need %zu B workspace", neededSpace);
|
||||
DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
|
||||
|
||||
@@ -2219,10 +2219,10 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
|
||||
}
|
||||
|
||||
/* reserve space for block-level external sequences */
|
||||
if (params->useSequenceProducer) {
|
||||
if (ZSTD_hasExtSeqProd(params)) {
|
||||
size_t const maxNbExternalSeq = ZSTD_sequenceBound(blockSize);
|
||||
zc->externalMatchCtx.seqBufferCapacity = maxNbExternalSeq;
|
||||
zc->externalMatchCtx.seqBuffer =
|
||||
zc->extSeqBufCapacity = maxNbExternalSeq;
|
||||
zc->extSeqBuf =
|
||||
(ZSTD_Sequence*)ZSTD_cwksp_reserve_aligned(ws, maxNbExternalSeq * sizeof(ZSTD_Sequence));
|
||||
}
|
||||
|
||||
@@ -3246,7 +3246,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
|
||||
/* External matchfinder + LDM is technically possible, just not implemented yet.
|
||||
* We need to revisit soon and implement it. */
|
||||
RETURN_ERROR_IF(
|
||||
zc->appliedParams.useSequenceProducer,
|
||||
ZSTD_hasExtSeqProd(&zc->appliedParams),
|
||||
parameter_combination_unsupported,
|
||||
"Long-distance matching with external sequence producer enabled is not currently supported."
|
||||
);
|
||||
@@ -3265,7 +3265,7 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
|
||||
/* External matchfinder + LDM is technically possible, just not implemented yet.
|
||||
* We need to revisit soon and implement it. */
|
||||
RETURN_ERROR_IF(
|
||||
zc->appliedParams.useSequenceProducer,
|
||||
ZSTD_hasExtSeqProd(&zc->appliedParams),
|
||||
parameter_combination_unsupported,
|
||||
"Long-distance matching with external sequence producer enabled is not currently supported."
|
||||
);
|
||||
@@ -3284,18 +3284,18 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
|
||||
zc->appliedParams.useRowMatchFinder,
|
||||
src, srcSize);
|
||||
assert(ldmSeqStore.pos == ldmSeqStore.size);
|
||||
} else if (zc->appliedParams.useSequenceProducer) {
|
||||
} else if (ZSTD_hasExtSeqProd(&zc->appliedParams)) {
|
||||
assert(
|
||||
zc->externalMatchCtx.seqBufferCapacity >= ZSTD_sequenceBound(srcSize)
|
||||
zc->extSeqBufCapacity >= ZSTD_sequenceBound(srcSize)
|
||||
);
|
||||
assert(zc->externalMatchCtx.mFinder != NULL);
|
||||
assert(zc->appliedParams.extSeqProdFunc != NULL);
|
||||
|
||||
{ U32 const windowSize = (U32)1 << zc->appliedParams.cParams.windowLog;
|
||||
|
||||
size_t const nbExternalSeqs = (zc->externalMatchCtx.mFinder)(
|
||||
zc->externalMatchCtx.mState,
|
||||
zc->externalMatchCtx.seqBuffer,
|
||||
zc->externalMatchCtx.seqBufferCapacity,
|
||||
size_t const nbExternalSeqs = (zc->appliedParams.extSeqProdFunc)(
|
||||
zc->appliedParams.extSeqProdState,
|
||||
zc->extSeqBuf,
|
||||
zc->extSeqBufCapacity,
|
||||
src, srcSize,
|
||||
NULL, 0, /* dict and dictSize, currently not supported */
|
||||
zc->appliedParams.compressionLevel,
|
||||
@@ -3303,21 +3303,21 @@ static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
|
||||
);
|
||||
|
||||
size_t const nbPostProcessedSeqs = ZSTD_postProcessSequenceProducerResult(
|
||||
zc->externalMatchCtx.seqBuffer,
|
||||
zc->extSeqBuf,
|
||||
nbExternalSeqs,
|
||||
zc->externalMatchCtx.seqBufferCapacity,
|
||||
zc->extSeqBufCapacity,
|
||||
srcSize
|
||||
);
|
||||
|
||||
/* Return early if there is no error, since we don't need to worry about last literals */
|
||||
if (!ZSTD_isError(nbPostProcessedSeqs)) {
|
||||
ZSTD_sequencePosition seqPos = {0,0,0};
|
||||
size_t const seqLenSum = ZSTD_fastSequenceLengthSum(zc->externalMatchCtx.seqBuffer, nbPostProcessedSeqs);
|
||||
size_t const seqLenSum = ZSTD_fastSequenceLengthSum(zc->extSeqBuf, nbPostProcessedSeqs);
|
||||
RETURN_ERROR_IF(seqLenSum > srcSize, externalSequences_invalid, "External sequences imply too large a block!");
|
||||
FORWARD_IF_ERROR(
|
||||
ZSTD_copySequencesToSeqStoreExplicitBlockDelim(
|
||||
zc, &seqPos,
|
||||
zc->externalMatchCtx.seqBuffer, nbPostProcessedSeqs,
|
||||
zc->extSeqBuf, nbPostProcessedSeqs,
|
||||
src, srcSize,
|
||||
zc->appliedParams.searchForExternalRepcodes
|
||||
),
|
||||
@@ -5175,14 +5175,13 @@ static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
|
||||
{
|
||||
BYTE* const ostart = (BYTE*)dst;
|
||||
BYTE* op = ostart;
|
||||
size_t fhSize = 0;
|
||||
|
||||
DEBUGLOG(4, "ZSTD_writeEpilogue");
|
||||
RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing");
|
||||
|
||||
/* special case : empty frame */
|
||||
if (cctx->stage == ZSTDcs_init) {
|
||||
fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0);
|
||||
size_t fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0);
|
||||
FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed");
|
||||
dstCapacity -= fhSize;
|
||||
op += fhSize;
|
||||
@@ -5524,7 +5523,7 @@ ZSTD_CDict* ZSTD_createCDict_advanced2(
|
||||
cctxParams.useRowMatchFinder, cctxParams.enableDedicatedDictSearch,
|
||||
customMem);
|
||||
|
||||
if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
|
||||
if (!cdict || ZSTD_isError( ZSTD_initCDict_internal(cdict,
|
||||
dict, dictSize,
|
||||
dictLoadMethod, dictContentType,
|
||||
cctxParams) )) {
|
||||
@@ -6207,7 +6206,7 @@ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
|
||||
#ifdef ZSTD_MULTITHREAD
|
||||
/* If external matchfinder is enabled, make sure to fail before checking job size (for consistency) */
|
||||
RETURN_ERROR_IF(
|
||||
params.useSequenceProducer == 1 && params.nbWorkers >= 1,
|
||||
ZSTD_hasExtSeqProd(¶ms) && params.nbWorkers >= 1,
|
||||
parameter_combination_unsupported,
|
||||
"External sequence producer isn't supported with nbWorkers >= 1"
|
||||
);
|
||||
@@ -6499,7 +6498,7 @@ ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx,
|
||||
if (cctx->appliedParams.validateSequences) {
|
||||
seqPos->posInSrc += litLength + matchLength;
|
||||
FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc,
|
||||
cctx->appliedParams.cParams.windowLog, dictSize, cctx->appliedParams.useSequenceProducer),
|
||||
cctx->appliedParams.cParams.windowLog, dictSize, ZSTD_hasExtSeqProd(&cctx->appliedParams)),
|
||||
"Sequence validation failed");
|
||||
}
|
||||
RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid,
|
||||
@@ -6637,7 +6636,7 @@ ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition*
|
||||
if (cctx->appliedParams.validateSequences) {
|
||||
seqPos->posInSrc += litLength + matchLength;
|
||||
FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc,
|
||||
cctx->appliedParams.cParams.windowLog, dictSize, cctx->appliedParams.useSequenceProducer),
|
||||
cctx->appliedParams.cParams.windowLog, dictSize, ZSTD_hasExtSeqProd(&cctx->appliedParams)),
|
||||
"Sequence validation failed");
|
||||
}
|
||||
DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength);
|
||||
@@ -7083,19 +7082,27 @@ ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeH
|
||||
}
|
||||
|
||||
void ZSTD_registerSequenceProducer(
|
||||
ZSTD_CCtx* zc, void* mState,
|
||||
ZSTD_sequenceProducer_F* mFinder
|
||||
ZSTD_CCtx* zc,
|
||||
void* extSeqProdState,
|
||||
ZSTD_sequenceProducer_F extSeqProdFunc
|
||||
) {
|
||||
if (mFinder != NULL) {
|
||||
ZSTD_externalMatchCtx emctx;
|
||||
emctx.mState = mState;
|
||||
emctx.mFinder = mFinder;
|
||||
emctx.seqBuffer = NULL;
|
||||
emctx.seqBufferCapacity = 0;
|
||||
zc->externalMatchCtx = emctx;
|
||||
zc->requestedParams.useSequenceProducer = 1;
|
||||
assert(zc != NULL);
|
||||
ZSTD_CCtxParams_registerSequenceProducer(
|
||||
&zc->requestedParams, extSeqProdState, extSeqProdFunc
|
||||
);
|
||||
}
|
||||
|
||||
void ZSTD_CCtxParams_registerSequenceProducer(
|
||||
ZSTD_CCtx_params* params,
|
||||
void* extSeqProdState,
|
||||
ZSTD_sequenceProducer_F extSeqProdFunc
|
||||
) {
|
||||
assert(params != NULL);
|
||||
if (extSeqProdFunc != NULL) {
|
||||
params->extSeqProdFunc = extSeqProdFunc;
|
||||
params->extSeqProdState = extSeqProdState;
|
||||
} else {
|
||||
ZSTD_memset(&zc->externalMatchCtx, 0, sizeof(zc->externalMatchCtx));
|
||||
zc->requestedParams.useSequenceProducer = 0;
|
||||
params->extSeqProdFunc = NULL;
|
||||
params->extSeqProdState = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,23 +159,24 @@ typedef struct {
|
||||
UNUSED_ATTR static const rawSeqStore_t kNullRawSeqStore = {NULL, 0, 0, 0, 0};
|
||||
|
||||
typedef struct {
|
||||
int price;
|
||||
U32 off;
|
||||
U32 mlen;
|
||||
U32 litlen;
|
||||
U32 rep[ZSTD_REP_NUM];
|
||||
int price; /* price from beginning of segment to this position */
|
||||
U32 off; /* offset of previous match */
|
||||
U32 mlen; /* length of previous match */
|
||||
U32 litlen; /* nb of literals since previous match */
|
||||
U32 rep[ZSTD_REP_NUM]; /* offset history after previous match */
|
||||
} ZSTD_optimal_t;
|
||||
|
||||
typedef enum { zop_dynamic=0, zop_predef } ZSTD_OptPrice_e;
|
||||
|
||||
#define ZSTD_OPT_SIZE (ZSTD_OPT_NUM+3)
|
||||
typedef struct {
|
||||
/* All tables are allocated inside cctx->workspace by ZSTD_resetCCtx_internal() */
|
||||
unsigned* litFreq; /* table of literals statistics, of size 256 */
|
||||
unsigned* litLengthFreq; /* table of litLength statistics, of size (MaxLL+1) */
|
||||
unsigned* matchLengthFreq; /* table of matchLength statistics, of size (MaxML+1) */
|
||||
unsigned* offCodeFreq; /* table of offCode statistics, of size (MaxOff+1) */
|
||||
ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_NUM+1 */
|
||||
ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_NUM+1 */
|
||||
ZSTD_match_t* matchTable; /* list of found matches, of size ZSTD_OPT_SIZE */
|
||||
ZSTD_optimal_t* priceTable; /* All positions tracked by optimal parser, of size ZSTD_OPT_SIZE */
|
||||
|
||||
U32 litSum; /* nb of literals */
|
||||
U32 litLengthSum; /* nb of litLength codes */
|
||||
@@ -360,10 +361,11 @@ struct ZSTD_CCtx_params_s {
|
||||
* if the external matchfinder returns an error code. */
|
||||
int enableMatchFinderFallback;
|
||||
|
||||
/* Indicates whether an external matchfinder has been referenced.
|
||||
* Users can't set this externally.
|
||||
* It is set internally in ZSTD_registerSequenceProducer(). */
|
||||
int useSequenceProducer;
|
||||
/* Parameters for the external sequence producer API.
|
||||
* Users set these parameters through ZSTD_registerSequenceProducer().
|
||||
* It is not possible to set these parameters individually through the public API. */
|
||||
void* extSeqProdState;
|
||||
ZSTD_sequenceProducer_F extSeqProdFunc;
|
||||
|
||||
/* Adjust the max block size*/
|
||||
size_t maxBlockSize;
|
||||
@@ -401,14 +403,6 @@ typedef struct {
|
||||
ZSTD_entropyCTablesMetadata_t entropyMetadata;
|
||||
} ZSTD_blockSplitCtx;
|
||||
|
||||
/* Context for block-level external matchfinder API */
|
||||
typedef struct {
|
||||
void* mState;
|
||||
ZSTD_sequenceProducer_F* mFinder;
|
||||
ZSTD_Sequence* seqBuffer;
|
||||
size_t seqBufferCapacity;
|
||||
} ZSTD_externalMatchCtx;
|
||||
|
||||
struct ZSTD_CCtx_s {
|
||||
ZSTD_compressionStage_e stage;
|
||||
int cParamsChanged; /* == 1 if cParams(except wlog) or compression level are changed in requestedParams. Triggers transmission of new params to ZSTDMT (if available) then reset to 0. */
|
||||
@@ -479,8 +473,9 @@ struct ZSTD_CCtx_s {
|
||||
/* Workspace for block splitter */
|
||||
ZSTD_blockSplitCtx blockSplitCtx;
|
||||
|
||||
/* Workspace for external matchfinder */
|
||||
ZSTD_externalMatchCtx externalMatchCtx;
|
||||
/* Buffer for output from external sequence producer */
|
||||
ZSTD_Sequence* extSeqBuf;
|
||||
size_t extSeqBufCapacity;
|
||||
};
|
||||
|
||||
typedef enum { ZSTD_dtlm_fast, ZSTD_dtlm_full } ZSTD_dictTableLoadMethod_e;
|
||||
@@ -1512,6 +1507,10 @@ ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition*
|
||||
const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
|
||||
const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch);
|
||||
|
||||
/* Returns 1 if an external sequence producer is registered, otherwise returns 0. */
|
||||
MEM_STATIC int ZSTD_hasExtSeqProd(const ZSTD_CCtx_params* params) {
|
||||
return params->extSeqProdFunc != NULL;
|
||||
}
|
||||
|
||||
/* ===============================================================
|
||||
* Deprecated definitions that are still used internally to avoid
|
||||
|
||||
@@ -76,8 +76,8 @@ ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
|
||||
}
|
||||
|
||||
{ int const flags = bmi2 ? HUF_flags_bmi2 : 0;
|
||||
const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, oend-op, literals, litSize, hufTable, flags)
|
||||
: HUF_compress4X_usingCTable(op, oend-op, literals, litSize, hufTable, flags);
|
||||
const size_t cSize = singleStream ? HUF_compress1X_usingCTable(op, (size_t)(oend-op), literals, litSize, hufTable, flags)
|
||||
: HUF_compress4X_usingCTable(op, (size_t)(oend-op), literals, litSize, hufTable, flags);
|
||||
op += cSize;
|
||||
cLitSize += cSize;
|
||||
if (cSize == 0 || ERR_isError(cSize)) {
|
||||
@@ -102,7 +102,7 @@ ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
|
||||
switch(lhSize)
|
||||
{
|
||||
case 3: /* 2 - 2 - 10 - 10 */
|
||||
{ U32 const lhc = hType + ((!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14);
|
||||
{ U32 const lhc = hType + ((U32)(!singleStream) << 2) + ((U32)litSize<<4) + ((U32)cLitSize<<14);
|
||||
MEM_writeLE24(ostart, lhc);
|
||||
break;
|
||||
}
|
||||
@@ -122,30 +122,30 @@ ZSTD_compressSubBlock_literal(const HUF_CElt* hufTable,
|
||||
}
|
||||
*entropyWritten = 1;
|
||||
DEBUGLOG(5, "Compressed literals: %u -> %u", (U32)litSize, (U32)(op-ostart));
|
||||
return op-ostart;
|
||||
return (size_t)(op-ostart);
|
||||
}
|
||||
|
||||
static size_t
|
||||
ZSTD_seqDecompressedSize(seqStore_t const* seqStore,
|
||||
const seqDef* sequences, size_t nbSeq,
|
||||
size_t litSize, int lastSequence)
|
||||
const seqDef* sequences, size_t nbSeqs,
|
||||
size_t litSize, int lastSubBlock)
|
||||
{
|
||||
const seqDef* const sstart = sequences;
|
||||
const seqDef* const send = sequences + nbSeq;
|
||||
const seqDef* sp = sstart;
|
||||
size_t matchLengthSum = 0;
|
||||
size_t litLengthSum = 0;
|
||||
(void)(litLengthSum); /* suppress unused variable warning on some environments */
|
||||
while (send-sp > 0) {
|
||||
ZSTD_sequenceLength const seqLen = ZSTD_getSequenceLength(seqStore, sp);
|
||||
size_t n;
|
||||
for (n=0; n<nbSeqs; n++) {
|
||||
const ZSTD_sequenceLength seqLen = ZSTD_getSequenceLength(seqStore, sequences+n);
|
||||
litLengthSum += seqLen.litLength;
|
||||
matchLengthSum += seqLen.matchLength;
|
||||
sp++;
|
||||
}
|
||||
assert(litLengthSum <= litSize);
|
||||
if (!lastSequence) {
|
||||
DEBUGLOG(5, "ZSTD_seqDecompressedSize: %u sequences from %p: %u literals + %u matchlength",
|
||||
(unsigned)nbSeqs, (const void*)sequences,
|
||||
(unsigned)litLengthSum, (unsigned)matchLengthSum);
|
||||
if (!lastSubBlock)
|
||||
assert(litLengthSum == litSize);
|
||||
}
|
||||
else
|
||||
assert(litLengthSum <= litSize);
|
||||
(void)litLengthSum;
|
||||
return matchLengthSum + litSize;
|
||||
}
|
||||
|
||||
@@ -187,7 +187,7 @@ ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,
|
||||
else
|
||||
op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
|
||||
if (nbSeq==0) {
|
||||
return op - ostart;
|
||||
return (size_t)(op - ostart);
|
||||
}
|
||||
|
||||
/* seqHead : flags for FSE encoding type */
|
||||
@@ -209,7 +209,7 @@ ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,
|
||||
}
|
||||
|
||||
{ size_t const bitstreamSize = ZSTD_encodeSequences(
|
||||
op, oend - op,
|
||||
op, (size_t)(oend - op),
|
||||
fseTables->matchlengthCTable, mlCode,
|
||||
fseTables->offcodeCTable, ofCode,
|
||||
fseTables->litlengthCTable, llCode,
|
||||
@@ -253,7 +253,7 @@ ZSTD_compressSubBlock_sequences(const ZSTD_fseCTables_t* fseTables,
|
||||
#endif
|
||||
|
||||
*entropyWritten = 1;
|
||||
return op - ostart;
|
||||
return (size_t)(op - ostart);
|
||||
}
|
||||
|
||||
/** ZSTD_compressSubBlock() :
|
||||
@@ -279,7 +279,8 @@ static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,
|
||||
litSize, nbSeq, writeLitEntropy, writeSeqEntropy, lastBlock);
|
||||
{ size_t cLitSize = ZSTD_compressSubBlock_literal((const HUF_CElt*)entropy->huf.CTable,
|
||||
&entropyMetadata->hufMetadata, literals, litSize,
|
||||
op, oend-op, bmi2, writeLitEntropy, litEntropyWritten);
|
||||
op, (size_t)(oend-op),
|
||||
bmi2, writeLitEntropy, litEntropyWritten);
|
||||
FORWARD_IF_ERROR(cLitSize, "ZSTD_compressSubBlock_literal failed");
|
||||
if (cLitSize == 0) return 0;
|
||||
op += cLitSize;
|
||||
@@ -289,18 +290,18 @@ static size_t ZSTD_compressSubBlock(const ZSTD_entropyCTables_t* entropy,
|
||||
sequences, nbSeq,
|
||||
llCode, mlCode, ofCode,
|
||||
cctxParams,
|
||||
op, oend-op,
|
||||
op, (size_t)(oend-op),
|
||||
bmi2, writeSeqEntropy, seqEntropyWritten);
|
||||
FORWARD_IF_ERROR(cSeqSize, "ZSTD_compressSubBlock_sequences failed");
|
||||
if (cSeqSize == 0) return 0;
|
||||
op += cSeqSize;
|
||||
}
|
||||
/* Write block header */
|
||||
{ size_t cSize = (op-ostart)-ZSTD_blockHeaderSize;
|
||||
{ size_t cSize = (size_t)(op-ostart) - ZSTD_blockHeaderSize;
|
||||
U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
|
||||
MEM_writeLE24(ostart, cBlockHeader24);
|
||||
}
|
||||
return op-ostart;
|
||||
return (size_t)(op-ostart);
|
||||
}
|
||||
|
||||
static size_t ZSTD_estimateSubBlockSize_literal(const BYTE* literals, size_t litSize,
|
||||
@@ -389,7 +390,11 @@ static size_t ZSTD_estimateSubBlockSize_sequences(const BYTE* ofCodeTable,
|
||||
return cSeqSizeEstimate + sequencesSectionHeaderSize;
|
||||
}
|
||||
|
||||
static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize,
|
||||
typedef struct {
|
||||
size_t estLitSize;
|
||||
size_t estBlockSize;
|
||||
} EstimatedBlockSize;
|
||||
static EstimatedBlockSize ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize,
|
||||
const BYTE* ofCodeTable,
|
||||
const BYTE* llCodeTable,
|
||||
const BYTE* mlCodeTable,
|
||||
@@ -397,15 +402,17 @@ static size_t ZSTD_estimateSubBlockSize(const BYTE* literals, size_t litSize,
|
||||
const ZSTD_entropyCTables_t* entropy,
|
||||
const ZSTD_entropyCTablesMetadata_t* entropyMetadata,
|
||||
void* workspace, size_t wkspSize,
|
||||
int writeLitEntropy, int writeSeqEntropy) {
|
||||
size_t cSizeEstimate = 0;
|
||||
cSizeEstimate += ZSTD_estimateSubBlockSize_literal(literals, litSize,
|
||||
&entropy->huf, &entropyMetadata->hufMetadata,
|
||||
workspace, wkspSize, writeLitEntropy);
|
||||
cSizeEstimate += ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,
|
||||
int writeLitEntropy, int writeSeqEntropy)
|
||||
{
|
||||
EstimatedBlockSize ebs;
|
||||
ebs.estLitSize = ZSTD_estimateSubBlockSize_literal(literals, litSize,
|
||||
&entropy->huf, &entropyMetadata->hufMetadata,
|
||||
workspace, wkspSize, writeLitEntropy);
|
||||
ebs.estBlockSize = ZSTD_estimateSubBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable,
|
||||
nbSeq, &entropy->fse, &entropyMetadata->fseMetadata,
|
||||
workspace, wkspSize, writeSeqEntropy);
|
||||
return cSizeEstimate + ZSTD_blockHeaderSize;
|
||||
ebs.estBlockSize += ebs.estLitSize + ZSTD_blockHeaderSize;
|
||||
return ebs;
|
||||
}
|
||||
|
||||
static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMetadata)
|
||||
@@ -419,13 +426,58 @@ static int ZSTD_needSequenceEntropyTables(ZSTD_fseCTablesMetadata_t const* fseMe
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t countLiterals(seqStore_t const* seqStore, const seqDef* sp, size_t seqCount)
|
||||
{
|
||||
size_t n, total = 0;
|
||||
assert(sp != NULL);
|
||||
for (n=0; n<seqCount; n++) {
|
||||
total += ZSTD_getSequenceLength(seqStore, sp+n).litLength;
|
||||
}
|
||||
DEBUGLOG(6, "countLiterals for %zu sequences from %p => %zu bytes", seqCount, (const void*)sp, total);
|
||||
return total;
|
||||
}
|
||||
|
||||
#define BYTESCALE 256
|
||||
|
||||
static size_t sizeBlockSequences(const seqDef* sp, size_t nbSeqs,
|
||||
size_t targetBudget, size_t avgLitCost, size_t avgSeqCost,
|
||||
int firstSubBlock)
|
||||
{
|
||||
size_t n, budget = 0, inSize=0;
|
||||
/* entropy headers */
|
||||
size_t const headerSize = (size_t)firstSubBlock * 120 * BYTESCALE; /* generous estimate */
|
||||
assert(firstSubBlock==0 || firstSubBlock==1);
|
||||
budget += headerSize;
|
||||
|
||||
/* first sequence => at least one sequence*/
|
||||
budget += sp[0].litLength * avgLitCost + avgSeqCost;
|
||||
if (budget > targetBudget) return 1;
|
||||
inSize = sp[0].litLength + (sp[0].mlBase+MINMATCH);
|
||||
|
||||
/* loop over sequences */
|
||||
for (n=1; n<nbSeqs; n++) {
|
||||
size_t currentCost = sp[n].litLength * avgLitCost + avgSeqCost;
|
||||
budget += currentCost;
|
||||
inSize += sp[n].litLength + (sp[n].mlBase+MINMATCH);
|
||||
/* stop when sub-block budget is reached */
|
||||
if ( (budget > targetBudget)
|
||||
/* though continue to expand until the sub-block is deemed compressible */
|
||||
&& (budget < inSize * BYTESCALE) )
|
||||
break;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
#define CBLOCK_TARGET_SIZE_MIN 1340 /* suitable to fit into an ethernet / wifi / 4G transport frame */
|
||||
|
||||
/** ZSTD_compressSubBlock_multi() :
|
||||
* Breaks super-block into multiple sub-blocks and compresses them.
|
||||
* Entropy will be written to the first block.
|
||||
* The following blocks will use repeat mode to compress.
|
||||
* All sub-blocks are compressed blocks (no raw or rle blocks).
|
||||
* @return : compressed size of the super block (which is multiple ZSTD blocks)
|
||||
* Or 0 if it failed to compress. */
|
||||
* Entropy will be written into the first block.
|
||||
* The following blocks use repeat_mode to compress.
|
||||
* Sub-blocks are all compressed, except the last one when beneficial.
|
||||
* @return : compressed size of the super block (which features multiple ZSTD blocks)
|
||||
* or 0 if it failed to compress. */
|
||||
static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
|
||||
const ZSTD_compressedBlockState_t* prevCBlock,
|
||||
ZSTD_compressedBlockState_t* nextCBlock,
|
||||
@@ -438,10 +490,12 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
|
||||
{
|
||||
const seqDef* const sstart = seqStorePtr->sequencesStart;
|
||||
const seqDef* const send = seqStorePtr->sequences;
|
||||
const seqDef* sp = sstart;
|
||||
const seqDef* sp = sstart; /* tracks progresses within seqStorePtr->sequences */
|
||||
size_t const nbSeqs = (size_t)(send - sstart);
|
||||
const BYTE* const lstart = seqStorePtr->litStart;
|
||||
const BYTE* const lend = seqStorePtr->lit;
|
||||
const BYTE* lp = lstart;
|
||||
size_t const nbLiterals = (size_t)(lend - lstart);
|
||||
BYTE const* ip = (BYTE const*)src;
|
||||
BYTE const* const iend = ip + srcSize;
|
||||
BYTE* const ostart = (BYTE*)dst;
|
||||
@@ -450,96 +504,152 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
|
||||
const BYTE* llCodePtr = seqStorePtr->llCode;
|
||||
const BYTE* mlCodePtr = seqStorePtr->mlCode;
|
||||
const BYTE* ofCodePtr = seqStorePtr->ofCode;
|
||||
size_t targetCBlockSize = cctxParams->targetCBlockSize;
|
||||
size_t litSize, seqCount;
|
||||
int writeLitEntropy = entropyMetadata->hufMetadata.hType == set_compressed;
|
||||
size_t const minTarget = CBLOCK_TARGET_SIZE_MIN; /* enforce minimum size, to reduce undesirable side effects */
|
||||
size_t const targetCBlockSize = MAX(minTarget, cctxParams->targetCBlockSize);
|
||||
int writeLitEntropy = (entropyMetadata->hufMetadata.hType == set_compressed);
|
||||
int writeSeqEntropy = 1;
|
||||
int lastSequence = 0;
|
||||
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi (litSize=%u, nbSeq=%u)",
|
||||
(unsigned)(lend-lp), (unsigned)(send-sstart));
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi (srcSize=%u, litSize=%u, nbSeq=%u)",
|
||||
(unsigned)srcSize, (unsigned)(lend-lstart), (unsigned)(send-sstart));
|
||||
|
||||
litSize = 0;
|
||||
seqCount = 0;
|
||||
do {
|
||||
size_t cBlockSizeEstimate = 0;
|
||||
if (sstart == send) {
|
||||
lastSequence = 1;
|
||||
} else {
|
||||
const seqDef* const sequence = sp + seqCount;
|
||||
lastSequence = sequence == send - 1;
|
||||
litSize += ZSTD_getSequenceLength(seqStorePtr, sequence).litLength;
|
||||
seqCount++;
|
||||
/* let's start by a general estimation for the full block */
|
||||
if (nbSeqs > 0) {
|
||||
EstimatedBlockSize const ebs =
|
||||
ZSTD_estimateSubBlockSize(lp, nbLiterals,
|
||||
ofCodePtr, llCodePtr, mlCodePtr, nbSeqs,
|
||||
&nextCBlock->entropy, entropyMetadata,
|
||||
workspace, wkspSize,
|
||||
writeLitEntropy, writeSeqEntropy);
|
||||
/* quick estimation */
|
||||
size_t const avgLitCost = nbLiterals ? (ebs.estLitSize * BYTESCALE) / nbLiterals : BYTESCALE;
|
||||
size_t const avgSeqCost = ((ebs.estBlockSize - ebs.estLitSize) * BYTESCALE) / nbSeqs;
|
||||
const size_t nbSubBlocks = MAX((ebs.estBlockSize + (targetCBlockSize/2)) / targetCBlockSize, 1);
|
||||
size_t n, avgBlockBudget, blockBudgetSupp=0;
|
||||
avgBlockBudget = (ebs.estBlockSize * BYTESCALE) / nbSubBlocks;
|
||||
DEBUGLOG(5, "estimated fullblock size=%u bytes ; avgLitCost=%.2f ; avgSeqCost=%.2f ; targetCBlockSize=%u, nbSubBlocks=%u ; avgBlockBudget=%.0f bytes",
|
||||
(unsigned)ebs.estBlockSize, (double)avgLitCost/BYTESCALE, (double)avgSeqCost/BYTESCALE,
|
||||
(unsigned)targetCBlockSize, (unsigned)nbSubBlocks, (double)avgBlockBudget/BYTESCALE);
|
||||
/* simplification: if estimates states that the full superblock doesn't compress, just bail out immediately
|
||||
* this will result in the production of a single uncompressed block covering @srcSize.*/
|
||||
if (ebs.estBlockSize > srcSize) return 0;
|
||||
|
||||
/* compress and write sub-blocks */
|
||||
assert(nbSubBlocks>0);
|
||||
for (n=0; n < nbSubBlocks-1; n++) {
|
||||
/* determine nb of sequences for current sub-block + nbLiterals from next sequence */
|
||||
size_t const seqCount = sizeBlockSequences(sp, (size_t)(send-sp),
|
||||
avgBlockBudget + blockBudgetSupp, avgLitCost, avgSeqCost, n==0);
|
||||
/* if reached last sequence : break to last sub-block (simplification) */
|
||||
assert(seqCount <= (size_t)(send-sp));
|
||||
if (sp + seqCount == send) break;
|
||||
assert(seqCount > 0);
|
||||
/* compress sub-block */
|
||||
{ int litEntropyWritten = 0;
|
||||
int seqEntropyWritten = 0;
|
||||
size_t litSize = countLiterals(seqStorePtr, sp, seqCount);
|
||||
const size_t decompressedSize =
|
||||
ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, 0);
|
||||
size_t const cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,
|
||||
sp, seqCount,
|
||||
lp, litSize,
|
||||
llCodePtr, mlCodePtr, ofCodePtr,
|
||||
cctxParams,
|
||||
op, (size_t)(oend-op),
|
||||
bmi2, writeLitEntropy, writeSeqEntropy,
|
||||
&litEntropyWritten, &seqEntropyWritten,
|
||||
0);
|
||||
FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");
|
||||
|
||||
/* check compressibility, update state components */
|
||||
if (cSize > 0 && cSize < decompressedSize) {
|
||||
DEBUGLOG(5, "Committed sub-block compressing %u bytes => %u bytes",
|
||||
(unsigned)decompressedSize, (unsigned)cSize);
|
||||
assert(ip + decompressedSize <= iend);
|
||||
ip += decompressedSize;
|
||||
lp += litSize;
|
||||
op += cSize;
|
||||
llCodePtr += seqCount;
|
||||
mlCodePtr += seqCount;
|
||||
ofCodePtr += seqCount;
|
||||
/* Entropy only needs to be written once */
|
||||
if (litEntropyWritten) {
|
||||
writeLitEntropy = 0;
|
||||
}
|
||||
if (seqEntropyWritten) {
|
||||
writeSeqEntropy = 0;
|
||||
}
|
||||
sp += seqCount;
|
||||
blockBudgetSupp = 0;
|
||||
} }
|
||||
/* otherwise : do not compress yet, coalesce current sub-block with following one */
|
||||
}
|
||||
if (lastSequence) {
|
||||
assert(lp <= lend);
|
||||
assert(litSize <= (size_t)(lend - lp));
|
||||
litSize = (size_t)(lend - lp);
|
||||
}
|
||||
/* I think there is an optimization opportunity here.
|
||||
* Calling ZSTD_estimateSubBlockSize for every sequence can be wasteful
|
||||
* since it recalculates estimate from scratch.
|
||||
* For example, it would recount literal distribution and symbol codes every time.
|
||||
*/
|
||||
cBlockSizeEstimate = ZSTD_estimateSubBlockSize(lp, litSize, ofCodePtr, llCodePtr, mlCodePtr, seqCount,
|
||||
&nextCBlock->entropy, entropyMetadata,
|
||||
workspace, wkspSize, writeLitEntropy, writeSeqEntropy);
|
||||
if (cBlockSizeEstimate > targetCBlockSize || lastSequence) {
|
||||
int litEntropyWritten = 0;
|
||||
int seqEntropyWritten = 0;
|
||||
const size_t decompressedSize = ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, lastSequence);
|
||||
const size_t cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,
|
||||
sp, seqCount,
|
||||
lp, litSize,
|
||||
llCodePtr, mlCodePtr, ofCodePtr,
|
||||
cctxParams,
|
||||
op, oend-op,
|
||||
bmi2, writeLitEntropy, writeSeqEntropy,
|
||||
&litEntropyWritten, &seqEntropyWritten,
|
||||
lastBlock && lastSequence);
|
||||
FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");
|
||||
if (cSize > 0 && cSize < decompressedSize) {
|
||||
DEBUGLOG(5, "Committed the sub-block");
|
||||
assert(ip + decompressedSize <= iend);
|
||||
ip += decompressedSize;
|
||||
sp += seqCount;
|
||||
lp += litSize;
|
||||
op += cSize;
|
||||
llCodePtr += seqCount;
|
||||
mlCodePtr += seqCount;
|
||||
ofCodePtr += seqCount;
|
||||
litSize = 0;
|
||||
seqCount = 0;
|
||||
/* Entropy only needs to be written once */
|
||||
if (litEntropyWritten) {
|
||||
writeLitEntropy = 0;
|
||||
}
|
||||
if (seqEntropyWritten) {
|
||||
writeSeqEntropy = 0;
|
||||
}
|
||||
} /* if (nbSeqs > 0) */
|
||||
|
||||
/* write last block */
|
||||
DEBUGLOG(2, "Generate last sub-block: %u sequences remaining", (unsigned)(send - sp));
|
||||
{ int litEntropyWritten = 0;
|
||||
int seqEntropyWritten = 0;
|
||||
size_t litSize = (size_t)(lend - lp);
|
||||
size_t seqCount = (size_t)(send - sp);
|
||||
const size_t decompressedSize =
|
||||
ZSTD_seqDecompressedSize(seqStorePtr, sp, seqCount, litSize, 1);
|
||||
size_t const cSize = ZSTD_compressSubBlock(&nextCBlock->entropy, entropyMetadata,
|
||||
sp, seqCount,
|
||||
lp, litSize,
|
||||
llCodePtr, mlCodePtr, ofCodePtr,
|
||||
cctxParams,
|
||||
op, (size_t)(oend-op),
|
||||
bmi2, writeLitEntropy, writeSeqEntropy,
|
||||
&litEntropyWritten, &seqEntropyWritten,
|
||||
lastBlock);
|
||||
FORWARD_IF_ERROR(cSize, "ZSTD_compressSubBlock failed");
|
||||
|
||||
/* update pointers, the nb of literals borrowed from next sequence must be preserved */
|
||||
if (cSize > 0 && cSize < decompressedSize) {
|
||||
DEBUGLOG(2, "Last sub-block compressed %u bytes => %u bytes",
|
||||
(unsigned)decompressedSize, (unsigned)cSize);
|
||||
assert(ip + decompressedSize <= iend);
|
||||
ip += decompressedSize;
|
||||
lp += litSize;
|
||||
op += cSize;
|
||||
llCodePtr += seqCount;
|
||||
mlCodePtr += seqCount;
|
||||
ofCodePtr += seqCount;
|
||||
/* Entropy only needs to be written once */
|
||||
if (litEntropyWritten) {
|
||||
writeLitEntropy = 0;
|
||||
}
|
||||
if (seqEntropyWritten) {
|
||||
writeSeqEntropy = 0;
|
||||
}
|
||||
sp += seqCount;
|
||||
}
|
||||
} while (!lastSequence);
|
||||
}
|
||||
|
||||
|
||||
if (writeLitEntropy) {
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi has literal entropy tables unwritten");
|
||||
DEBUGLOG(5, "Literal entropy tables were never written");
|
||||
ZSTD_memcpy(&nextCBlock->entropy.huf, &prevCBlock->entropy.huf, sizeof(prevCBlock->entropy.huf));
|
||||
}
|
||||
if (writeSeqEntropy && ZSTD_needSequenceEntropyTables(&entropyMetadata->fseMetadata)) {
|
||||
/* If we haven't written our entropy tables, then we've violated our contract and
|
||||
* must emit an uncompressed block.
|
||||
*/
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi has sequence entropy tables unwritten");
|
||||
DEBUGLOG(5, "Sequence entropy tables were never written => cancel, emit an uncompressed block");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ip < iend) {
|
||||
size_t const cSize = ZSTD_noCompressBlock(op, oend - op, ip, iend - ip, lastBlock);
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi last sub-block uncompressed, %zu bytes", (size_t)(iend - ip));
|
||||
/* some data left : last part of the block sent uncompressed */
|
||||
size_t const rSize = (size_t)((iend - ip));
|
||||
size_t const cSize = ZSTD_noCompressBlock(op, (size_t)(oend - op), ip, rSize, lastBlock);
|
||||
DEBUGLOG(2, "Generate last uncompressed sub-block of %u bytes", (unsigned)(rSize));
|
||||
FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
|
||||
assert(cSize != 0);
|
||||
op += cSize;
|
||||
/* We have to regenerate the repcodes because we've skipped some sequences */
|
||||
if (sp < send) {
|
||||
seqDef const* seq;
|
||||
const seqDef* seq;
|
||||
repcodes_t rep;
|
||||
ZSTD_memcpy(&rep, prevCBlock->rep, sizeof(rep));
|
||||
for (seq = sstart; seq < sp; ++seq) {
|
||||
@@ -548,14 +658,17 @@ static size_t ZSTD_compressSubBlock_multi(const seqStore_t* seqStorePtr,
|
||||
ZSTD_memcpy(nextCBlock->rep, &rep, sizeof(rep));
|
||||
}
|
||||
}
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed");
|
||||
return op-ostart;
|
||||
|
||||
DEBUGLOG(5, "ZSTD_compressSubBlock_multi compressed all subBlocks: total compressed size = %u",
|
||||
(unsigned)(op-ostart));
|
||||
return (size_t)(op-ostart);
|
||||
}
|
||||
|
||||
size_t ZSTD_compressSuperBlock(ZSTD_CCtx* zc,
|
||||
void* dst, size_t dstCapacity,
|
||||
void const* src, size_t srcSize,
|
||||
unsigned lastBlock) {
|
||||
const void* src, size_t srcSize,
|
||||
unsigned lastBlock)
|
||||
{
|
||||
ZSTD_entropyCTablesMetadata_t entropyMetadata;
|
||||
|
||||
FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(&zc->seqStore,
|
||||
|
||||
@@ -356,8 +356,8 @@ size_t ZSTD_compressBlock_doubleFast_dictMatchState_generic(
|
||||
if (ms->prefetchCDictTables) {
|
||||
size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32);
|
||||
size_t const chainTableBytes = (((size_t)1) << dictCParams->chainLog) * sizeof(U32);
|
||||
PREFETCH_AREA(dictHashLong, hashTableBytes)
|
||||
PREFETCH_AREA(dictHashSmall, chainTableBytes)
|
||||
PREFETCH_AREA(dictHashLong, hashTableBytes);
|
||||
PREFETCH_AREA(dictHashSmall, chainTableBytes);
|
||||
}
|
||||
|
||||
/* init */
|
||||
|
||||
@@ -508,7 +508,7 @@ size_t ZSTD_compressBlock_fast_dictMatchState_generic(
|
||||
|
||||
if (ms->prefetchCDictTables) {
|
||||
size_t const hashTableBytes = (((size_t)1) << dictCParams->hashLog) * sizeof(U32);
|
||||
PREFETCH_AREA(dictHashTable, hashTableBytes)
|
||||
PREFETCH_AREA(dictHashTable, hashTableBytes);
|
||||
}
|
||||
|
||||
/* init */
|
||||
|
||||
@@ -695,7 +695,6 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
||||
/* maybeSplitSequence updates rawSeqStore->pos */
|
||||
rawSeq const sequence = maybeSplitSequence(rawSeqStore,
|
||||
(U32)(iend - ip), minMatch);
|
||||
int i;
|
||||
/* End signal */
|
||||
if (sequence.offset == 0)
|
||||
break;
|
||||
@@ -708,6 +707,7 @@ size_t ZSTD_ldm_blockCompress(rawSeqStore_t* rawSeqStore,
|
||||
/* Run the block compressor */
|
||||
DEBUGLOG(5, "pos %u : calling block compressor on segment of size %u", (unsigned)(ip-istart), sequence.litLength);
|
||||
{
|
||||
int i;
|
||||
size_t const newLitLength =
|
||||
blockCompressor(ms, seqStore, rep, ip, sequence.litLength);
|
||||
ip += sequence.litLength;
|
||||
|
||||
+171
-95
@@ -267,6 +267,7 @@ static U32 ZSTD_rawLiteralsCost(const BYTE* const literals, U32 const litLength,
|
||||
const optState_t* const optPtr,
|
||||
int optLevel)
|
||||
{
|
||||
DEBUGLOG(8, "ZSTD_rawLiteralsCost (%u literals)", litLength);
|
||||
if (litLength == 0) return 0;
|
||||
|
||||
if (!ZSTD_compressedLiterals(optPtr))
|
||||
@@ -566,7 +567,7 @@ void ZSTD_updateTree_internal(
|
||||
const BYTE* const base = ms->window.base;
|
||||
U32 const target = (U32)(ip - base);
|
||||
U32 idx = ms->nextToUpdate;
|
||||
DEBUGLOG(6, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)",
|
||||
DEBUGLOG(7, "ZSTD_updateTree_internal, from %u to %u (dictMode:%u)",
|
||||
idx, target, dictMode);
|
||||
|
||||
while(idx < target) {
|
||||
@@ -1047,11 +1048,6 @@ ZSTD_optLdm_processMatchCandidate(ZSTD_optLdm_t* optLdm,
|
||||
* Optimal parser
|
||||
*********************************/
|
||||
|
||||
static U32 ZSTD_totalLen(ZSTD_optimal_t sol)
|
||||
{
|
||||
return sol.litlen + sol.mlen;
|
||||
}
|
||||
|
||||
#if 0 /* debug */
|
||||
|
||||
static void
|
||||
@@ -1069,6 +1065,10 @@ listStats(const U32* table, int lastEltID)
|
||||
|
||||
#endif
|
||||
|
||||
#define LIT_PRICE(_p) (int)ZSTD_rawLiteralsCost(_p, 1, optStatePtr, optLevel)
|
||||
#define LL_PRICE(_l) (int)ZSTD_litLengthPrice(_l, optStatePtr, optLevel)
|
||||
#define LL_INCPRICE(_l) (LL_PRICE(_l) - LL_PRICE(_l-1))
|
||||
|
||||
FORCE_INLINE_TEMPLATE
|
||||
ZSTD_ALLOW_POINTER_OVERFLOW_ATTR
|
||||
size_t
|
||||
@@ -1097,10 +1097,10 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
|
||||
ZSTD_optimal_t* const opt = optStatePtr->priceTable;
|
||||
ZSTD_match_t* const matches = optStatePtr->matchTable;
|
||||
ZSTD_optimal_t lastSequence;
|
||||
ZSTD_optimal_t lastStretch;
|
||||
ZSTD_optLdm_t optLdm;
|
||||
|
||||
ZSTD_memset(&lastSequence, 0, sizeof(ZSTD_optimal_t));
|
||||
ZSTD_memset(&lastStretch, 0, sizeof(ZSTD_optimal_t));
|
||||
|
||||
optLdm.seqStore = ms->ldmSeqStore ? *ms->ldmSeqStore : kNullRawSeqStore;
|
||||
optLdm.endPosInBlock = optLdm.startPosInBlock = optLdm.offset = 0;
|
||||
@@ -1122,19 +1122,31 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
U32 const ll0 = !litlen;
|
||||
U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, ip, iend, rep, ll0, minMatch);
|
||||
ZSTD_optLdm_processMatchCandidate(&optLdm, matches, &nbMatches,
|
||||
(U32)(ip-istart), (U32)(iend - ip));
|
||||
if (!nbMatches) { ip++; continue; }
|
||||
(U32)(ip-istart), (U32)(iend-ip));
|
||||
if (!nbMatches) {
|
||||
DEBUGLOG(8, "no match found at cPos %u", (unsigned)(ip-istart));
|
||||
ip++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Match found: let's store this solution, and eventually find more candidates.
|
||||
* During this forward pass, @opt is used to store stretches,
|
||||
* defined as "a match followed by N literals".
|
||||
* Note how this is different from a Sequence, which is "N literals followed by a match".
|
||||
* Storing stretches allows us to store different match predecessors
|
||||
* for each literal position part of a literals run. */
|
||||
|
||||
/* initialize opt[0] */
|
||||
{ U32 i ; for (i=0; i<ZSTD_REP_NUM; i++) opt[0].rep[i] = rep[i]; }
|
||||
opt[0].mlen = 0; /* means is_a_literal */
|
||||
opt[0].mlen = 0; /* there are only literals so far */
|
||||
opt[0].litlen = litlen;
|
||||
/* We don't need to include the actual price of the literals because
|
||||
* it is static for the duration of the forward pass, and is included
|
||||
* in every price. We include the literal length to avoid negative
|
||||
* prices when we subtract the previous literal length.
|
||||
/* No need to include the actual price of the literals before the first match
|
||||
* because it is static for the duration of the forward pass, and is included
|
||||
* in every subsequent price. But, we include the literal length because
|
||||
* the cost variation of litlen depends on the value of litlen.
|
||||
*/
|
||||
opt[0].price = (int)ZSTD_litLengthPrice(litlen, optStatePtr, optLevel);
|
||||
opt[0].price = LL_PRICE(litlen);
|
||||
ZSTD_STATIC_ASSERT(sizeof(opt[0].rep[0]) == sizeof(rep[0]));
|
||||
ZSTD_memcpy(&opt[0].rep, rep, sizeof(opt[0].rep));
|
||||
|
||||
/* large match -> immediate encoding */
|
||||
{ U32 const maxML = matches[nbMatches-1].len;
|
||||
@@ -1143,82 +1155,106 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
nbMatches, maxML, maxOffBase, (U32)(ip-prefixStart));
|
||||
|
||||
if (maxML > sufficient_len) {
|
||||
lastSequence.litlen = litlen;
|
||||
lastSequence.mlen = maxML;
|
||||
lastSequence.off = maxOffBase;
|
||||
DEBUGLOG(6, "large match (%u>%u), immediate encoding",
|
||||
lastStretch.litlen = 0;
|
||||
lastStretch.mlen = maxML;
|
||||
lastStretch.off = maxOffBase;
|
||||
DEBUGLOG(6, "large match (%u>%u) => immediate encoding",
|
||||
maxML, sufficient_len);
|
||||
cur = 0;
|
||||
last_pos = ZSTD_totalLen(lastSequence);
|
||||
last_pos = maxML;
|
||||
goto _shortestPath;
|
||||
} }
|
||||
|
||||
/* set prices for first matches starting position == 0 */
|
||||
assert(opt[0].price >= 0);
|
||||
{ U32 const literalsPrice = (U32)opt[0].price + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
|
||||
U32 pos;
|
||||
{ U32 pos;
|
||||
U32 matchNb;
|
||||
for (pos = 1; pos < minMatch; pos++) {
|
||||
opt[pos].price = ZSTD_MAX_PRICE; /* mlen, litlen and price will be fixed during forward scanning */
|
||||
opt[pos].price = ZSTD_MAX_PRICE;
|
||||
opt[pos].mlen = 0;
|
||||
opt[pos].litlen = litlen + pos;
|
||||
}
|
||||
for (matchNb = 0; matchNb < nbMatches; matchNb++) {
|
||||
U32 const offBase = matches[matchNb].off;
|
||||
U32 const end = matches[matchNb].len;
|
||||
for ( ; pos <= end ; pos++ ) {
|
||||
U32 const matchPrice = ZSTD_getMatchPrice(offBase, pos, optStatePtr, optLevel);
|
||||
U32 const sequencePrice = literalsPrice + matchPrice;
|
||||
int const matchPrice = (int)ZSTD_getMatchPrice(offBase, pos, optStatePtr, optLevel);
|
||||
int const sequencePrice = opt[0].price + matchPrice;
|
||||
DEBUGLOG(7, "rPos:%u => set initial price : %.2f",
|
||||
pos, ZSTD_fCost((int)sequencePrice));
|
||||
pos, ZSTD_fCost(sequencePrice));
|
||||
opt[pos].mlen = pos;
|
||||
opt[pos].off = offBase;
|
||||
opt[pos].litlen = litlen;
|
||||
opt[pos].price = (int)sequencePrice;
|
||||
} }
|
||||
opt[pos].litlen = 0; /* end of match */
|
||||
opt[pos].price = sequencePrice + LL_PRICE(0);
|
||||
}
|
||||
}
|
||||
last_pos = pos-1;
|
||||
opt[pos].price = ZSTD_MAX_PRICE;
|
||||
}
|
||||
}
|
||||
|
||||
/* check further positions */
|
||||
for (cur = 1; cur <= last_pos; cur++) {
|
||||
const BYTE* const inr = ip + cur;
|
||||
assert(cur < ZSTD_OPT_NUM);
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur)
|
||||
assert(cur <= ZSTD_OPT_NUM);
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u", inr-istart, cur);
|
||||
|
||||
/* Fix current position with one literal if cheaper */
|
||||
{ U32 const litlen = (opt[cur-1].mlen == 0) ? opt[cur-1].litlen + 1 : 1;
|
||||
{ U32 const litlen = opt[cur-1].litlen + 1;
|
||||
int const price = opt[cur-1].price
|
||||
+ (int)ZSTD_rawLiteralsCost(ip+cur-1, 1, optStatePtr, optLevel)
|
||||
+ (int)ZSTD_litLengthPrice(litlen, optStatePtr, optLevel)
|
||||
- (int)ZSTD_litLengthPrice(litlen-1, optStatePtr, optLevel);
|
||||
+ LIT_PRICE(ip+cur-1)
|
||||
+ LL_INCPRICE(litlen);
|
||||
assert(price < 1000000000); /* overflow check */
|
||||
if (price <= opt[cur].price) {
|
||||
ZSTD_optimal_t const prevMatch = opt[cur];
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u : better price (%.2f<=%.2f) using literal (ll==%u) (hist:%u,%u,%u)",
|
||||
inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price), litlen,
|
||||
opt[cur-1].rep[0], opt[cur-1].rep[1], opt[cur-1].rep[2]);
|
||||
opt[cur].mlen = 0;
|
||||
opt[cur].off = 0;
|
||||
opt[cur] = opt[cur-1];
|
||||
opt[cur].litlen = litlen;
|
||||
opt[cur].price = price;
|
||||
if ( (optLevel >= 1) /* additional check only for higher modes */
|
||||
&& (prevMatch.litlen == 0) /* replace a match */
|
||||
&& (LL_INCPRICE(1) < 0) /* ll1 is cheaper than ll0 */
|
||||
&& LIKELY(ip + cur < iend)
|
||||
) {
|
||||
/* check next position, in case it would be cheaper */
|
||||
int with1literal = prevMatch.price + LIT_PRICE(ip+cur) + LL_INCPRICE(1);
|
||||
int withMoreLiterals = price + LIT_PRICE(ip+cur) + LL_INCPRICE(litlen+1);
|
||||
DEBUGLOG(7, "then at next rPos %u : match+1lit %.2f vs %ulits %.2f",
|
||||
cur+1, ZSTD_fCost(with1literal), litlen+1, ZSTD_fCost(withMoreLiterals));
|
||||
if ( (with1literal < withMoreLiterals)
|
||||
&& (with1literal < opt[cur+1].price) ) {
|
||||
/* update offset history - before it disappears */
|
||||
U32 const prev = cur - prevMatch.mlen;
|
||||
repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, prevMatch.off, opt[prev].litlen==0);
|
||||
assert(cur >= prevMatch.mlen);
|
||||
DEBUGLOG(7, "==> match+1lit is cheaper (%.2f < %.2f) (hist:%u,%u,%u) !",
|
||||
ZSTD_fCost(with1literal), ZSTD_fCost(withMoreLiterals),
|
||||
newReps.rep[0], newReps.rep[1], newReps.rep[2] );
|
||||
opt[cur+1] = prevMatch; /* mlen & offbase */
|
||||
ZSTD_memcpy(opt[cur+1].rep, &newReps, sizeof(repcodes_t));
|
||||
opt[cur+1].litlen = 1;
|
||||
opt[cur+1].price = with1literal;
|
||||
if (last_pos < cur+1) last_pos = cur+1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f) (hist:%u,%u,%u)",
|
||||
inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price),
|
||||
opt[cur].rep[0], opt[cur].rep[1], opt[cur].rep[2]);
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u : literal would cost more (%.2f>%.2f)",
|
||||
inr-istart, cur, ZSTD_fCost(price), ZSTD_fCost(opt[cur].price));
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the repcodes of the current position. We must do it here
|
||||
* because we rely on the repcodes of the 2nd to last sequence being
|
||||
* correct to set the next chunks repcodes during the backward
|
||||
* traversal.
|
||||
/* Offset history is not updated during match comparison.
|
||||
* Do it here, now that the match is selected and confirmed.
|
||||
*/
|
||||
ZSTD_STATIC_ASSERT(sizeof(opt[cur].rep) == sizeof(repcodes_t));
|
||||
assert(cur >= opt[cur].mlen);
|
||||
if (opt[cur].mlen != 0) {
|
||||
if (opt[cur].litlen == 0) {
|
||||
/* just finished a match => alter offset history */
|
||||
U32 const prev = cur - opt[cur].mlen;
|
||||
repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, opt[cur].off, opt[cur].litlen==0);
|
||||
repcodes_t const newReps = ZSTD_newRep(opt[prev].rep, opt[cur].off, opt[prev].litlen==0);
|
||||
ZSTD_memcpy(opt[cur].rep, &newReps, sizeof(repcodes_t));
|
||||
} else {
|
||||
ZSTD_memcpy(opt[cur].rep, opt[cur - 1].rep, sizeof(repcodes_t));
|
||||
}
|
||||
|
||||
/* last match must start at a minimum distance of 8 from oend */
|
||||
@@ -1228,15 +1264,14 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
|
||||
if ( (optLevel==0) /*static_test*/
|
||||
&& (opt[cur+1].price <= opt[cur].price + (BITCOST_MULTIPLIER/2)) ) {
|
||||
DEBUGLOG(7, "move to next rPos:%u : price is <=", cur+1);
|
||||
DEBUGLOG(7, "skip current position : next rPos(%u) price is cheaper", cur+1);
|
||||
continue; /* skip unpromising positions; about ~+6% speed, -0.01 ratio */
|
||||
}
|
||||
|
||||
assert(opt[cur].price >= 0);
|
||||
{ U32 const ll0 = (opt[cur].mlen != 0);
|
||||
U32 const litlen = (opt[cur].mlen == 0) ? opt[cur].litlen : 0;
|
||||
U32 const previousPrice = (U32)opt[cur].price;
|
||||
U32 const basePrice = previousPrice + ZSTD_litLengthPrice(0, optStatePtr, optLevel);
|
||||
{ U32 const ll0 = (opt[cur].litlen == 0);
|
||||
int const previousPrice = opt[cur].price;
|
||||
int const basePrice = previousPrice + LL_PRICE(0);
|
||||
U32 nbMatches = getAllMatches(matches, ms, &nextToUpdate3, inr, iend, opt[cur].rep, ll0, minMatch);
|
||||
U32 matchNb;
|
||||
|
||||
@@ -1248,18 +1283,17 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
continue;
|
||||
}
|
||||
|
||||
{ U32 const maxML = matches[nbMatches-1].len;
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of maxLength=%u",
|
||||
inr-istart, cur, nbMatches, maxML);
|
||||
{ U32 const longestML = matches[nbMatches-1].len;
|
||||
DEBUGLOG(7, "cPos:%zi==rPos:%u, found %u matches, of longest ML=%u",
|
||||
inr-istart, cur, nbMatches, longestML);
|
||||
|
||||
if ( (maxML > sufficient_len)
|
||||
|| (cur + maxML >= ZSTD_OPT_NUM) ) {
|
||||
lastSequence.mlen = maxML;
|
||||
lastSequence.off = matches[nbMatches-1].off;
|
||||
lastSequence.litlen = litlen;
|
||||
cur -= (opt[cur].mlen==0) ? opt[cur].litlen : 0; /* last sequence is actually only literals, fix cur to last match - note : may underflow, in which case, it's first sequence, and it's okay */
|
||||
last_pos = cur + ZSTD_totalLen(lastSequence);
|
||||
if (cur > ZSTD_OPT_NUM) cur = 0; /* underflow => first match */
|
||||
if ( (longestML > sufficient_len)
|
||||
|| (cur + longestML >= ZSTD_OPT_NUM)
|
||||
|| (ip + cur + longestML >= iend) ) {
|
||||
lastStretch.mlen = longestML;
|
||||
lastStretch.off = matches[nbMatches-1].off;
|
||||
lastStretch.litlen = 0;
|
||||
last_pos = cur + longestML;
|
||||
goto _shortestPath;
|
||||
} }
|
||||
|
||||
@@ -1271,19 +1305,24 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
U32 mlen;
|
||||
|
||||
DEBUGLOG(7, "testing match %u => offBase=%4u, mlen=%2u, llen=%2u",
|
||||
matchNb, matches[matchNb].off, lastML, litlen);
|
||||
matchNb, matches[matchNb].off, lastML, opt[cur].litlen);
|
||||
|
||||
for (mlen = lastML; mlen >= startML; mlen--) { /* scan downward */
|
||||
U32 const pos = cur + mlen;
|
||||
int const price = (int)basePrice + (int)ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel);
|
||||
int const price = basePrice + (int)ZSTD_getMatchPrice(offset, mlen, optStatePtr, optLevel);
|
||||
|
||||
if ((pos > last_pos) || (price < opt[pos].price)) {
|
||||
DEBUGLOG(7, "rPos:%u (ml=%2u) => new better price (%.2f<%.2f)",
|
||||
pos, mlen, ZSTD_fCost(price), ZSTD_fCost(opt[pos].price));
|
||||
while (last_pos < pos) { opt[last_pos+1].price = ZSTD_MAX_PRICE; last_pos++; } /* fill empty positions */
|
||||
while (last_pos < pos) {
|
||||
/* fill empty positions, for future comparisons */
|
||||
last_pos++;
|
||||
opt[last_pos].price = ZSTD_MAX_PRICE;
|
||||
opt[last_pos].litlen = !0; /* just needs to be != 0, to mean "not an end of match" */
|
||||
}
|
||||
opt[pos].mlen = mlen;
|
||||
opt[pos].off = offset;
|
||||
opt[pos].litlen = litlen;
|
||||
opt[pos].litlen = 0;
|
||||
opt[pos].price = price;
|
||||
} else {
|
||||
DEBUGLOG(7, "rPos:%u (ml=%2u) => new price is worse (%.2f>=%.2f)",
|
||||
@@ -1291,47 +1330,81 @@ ZSTD_compressBlock_opt_generic(ZSTD_matchState_t* ms,
|
||||
if (optLevel==0) break; /* early update abort; gets ~+10% speed for about -0.01 ratio loss */
|
||||
}
|
||||
} } }
|
||||
opt[last_pos+1].price = ZSTD_MAX_PRICE;
|
||||
} /* for (cur = 1; cur <= last_pos; cur++) */
|
||||
|
||||
lastSequence = opt[last_pos];
|
||||
cur = last_pos > ZSTD_totalLen(lastSequence) ? last_pos - ZSTD_totalLen(lastSequence) : 0; /* single sequence, and it starts before `ip` */
|
||||
assert(cur < ZSTD_OPT_NUM); /* control overflow*/
|
||||
lastStretch = opt[last_pos];
|
||||
assert(cur >= lastStretch.mlen);
|
||||
cur = last_pos - lastStretch.mlen;
|
||||
|
||||
_shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
|
||||
assert(opt[0].mlen == 0);
|
||||
assert(last_pos >= lastStretch.mlen);
|
||||
assert(cur == last_pos - lastStretch.mlen);
|
||||
|
||||
/* Set the next chunk's repcodes based on the repcodes of the beginning
|
||||
* of the last match, and the last sequence. This avoids us having to
|
||||
* update them while traversing the sequences.
|
||||
*/
|
||||
if (lastSequence.mlen != 0) {
|
||||
repcodes_t const reps = ZSTD_newRep(opt[cur].rep, lastSequence.off, lastSequence.litlen==0);
|
||||
ZSTD_memcpy(rep, &reps, sizeof(reps));
|
||||
if (lastStretch.mlen==0) {
|
||||
/* no solution : all matches have been converted into literals */
|
||||
assert(lastStretch.litlen == (ip - anchor) + last_pos);
|
||||
ip += last_pos;
|
||||
continue;
|
||||
}
|
||||
assert(lastStretch.off > 0);
|
||||
|
||||
/* Update offset history */
|
||||
if (lastStretch.litlen == 0) {
|
||||
/* finishing on a match : update offset history */
|
||||
repcodes_t const reps = ZSTD_newRep(opt[cur].rep, lastStretch.off, opt[cur].litlen==0);
|
||||
ZSTD_memcpy(rep, &reps, sizeof(repcodes_t));
|
||||
} else {
|
||||
ZSTD_memcpy(rep, opt[cur].rep, sizeof(repcodes_t));
|
||||
ZSTD_memcpy(rep, lastStretch.rep, sizeof(repcodes_t));
|
||||
assert(cur >= lastStretch.litlen);
|
||||
cur -= lastStretch.litlen;
|
||||
}
|
||||
|
||||
{ U32 const storeEnd = cur + 1;
|
||||
/* Let's write the shortest path solution.
|
||||
* It is stored in @opt in reverse order,
|
||||
* starting from @storeEnd (==cur+2),
|
||||
* effectively partially @opt overwriting.
|
||||
* Content is changed too:
|
||||
* - So far, @opt stored stretches, aka a match followed by literals
|
||||
* - Now, it will store sequences, aka literals followed by a match
|
||||
*/
|
||||
{ U32 const storeEnd = cur + 2;
|
||||
U32 storeStart = storeEnd;
|
||||
U32 seqPos = cur;
|
||||
U32 stretchPos = cur;
|
||||
|
||||
DEBUGLOG(6, "start reverse traversal (last_pos:%u, cur:%u)",
|
||||
last_pos, cur); (void)last_pos;
|
||||
assert(storeEnd < ZSTD_OPT_NUM);
|
||||
DEBUGLOG(6, "last sequence copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
|
||||
storeEnd, lastSequence.litlen, lastSequence.mlen, lastSequence.off);
|
||||
opt[storeEnd] = lastSequence;
|
||||
while (seqPos > 0) {
|
||||
U32 const backDist = ZSTD_totalLen(opt[seqPos]);
|
||||
assert(storeEnd < ZSTD_OPT_SIZE);
|
||||
DEBUGLOG(6, "last stretch copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
|
||||
storeEnd, lastStretch.litlen, lastStretch.mlen, lastStretch.off);
|
||||
if (lastStretch.litlen > 0) {
|
||||
/* last "sequence" is unfinished: just a bunch of literals */
|
||||
opt[storeEnd].litlen = lastStretch.litlen;
|
||||
opt[storeEnd].mlen = 0;
|
||||
storeStart = storeEnd-1;
|
||||
opt[storeStart] = lastStretch;
|
||||
} {
|
||||
opt[storeEnd] = lastStretch; /* note: litlen will be fixed */
|
||||
storeStart = storeEnd;
|
||||
}
|
||||
while (1) {
|
||||
ZSTD_optimal_t nextStretch = opt[stretchPos];
|
||||
opt[storeStart].litlen = nextStretch.litlen;
|
||||
DEBUGLOG(6, "selected sequence (llen=%u,mlen=%u,ofc=%u)",
|
||||
opt[storeStart].litlen, opt[storeStart].mlen, opt[storeStart].off);
|
||||
if (nextStretch.mlen == 0) {
|
||||
/* reaching beginning of segment */
|
||||
break;
|
||||
}
|
||||
storeStart--;
|
||||
DEBUGLOG(6, "sequence from rPos=%u copied into pos=%u (llen=%u,mlen=%u,ofc=%u)",
|
||||
seqPos, storeStart, opt[seqPos].litlen, opt[seqPos].mlen, opt[seqPos].off);
|
||||
opt[storeStart] = opt[seqPos];
|
||||
seqPos = (seqPos > backDist) ? seqPos - backDist : 0;
|
||||
opt[storeStart] = nextStretch; /* note: litlen will be fixed */
|
||||
assert(nextStretch.litlen + nextStretch.mlen <= stretchPos);
|
||||
stretchPos -= nextStretch.litlen + nextStretch.mlen;
|
||||
}
|
||||
|
||||
/* save sequences */
|
||||
DEBUGLOG(6, "sending selected sequences into seqStore")
|
||||
DEBUGLOG(6, "sending selected sequences into seqStore");
|
||||
{ U32 storePos;
|
||||
for (storePos=storeStart; storePos <= storeEnd; storePos++) {
|
||||
U32 const llen = opt[storePos].litlen;
|
||||
@@ -1353,6 +1426,9 @@ _shortestPath: /* cur, last_pos, best_mlen, best_off have to be set */
|
||||
anchor += advance;
|
||||
ip = anchor;
|
||||
} }
|
||||
DEBUGLOG(7, "new offset history : %u, %u, %u", rep[0], rep[1], rep[2]);
|
||||
|
||||
/* update all costs */
|
||||
ZSTD_setBasePrices(optStatePtr, optLevel);
|
||||
}
|
||||
} /* while (ip < ilimit) */
|
||||
@@ -1448,7 +1524,7 @@ size_t ZSTD_compressBlock_btultra2(
|
||||
* Consequently, this can only work if no data has been previously loaded in tables,
|
||||
* aka, no dictionary, no prefix, no ldm preprocessing.
|
||||
* The compression ratio gain is generally small (~0.5% on first block),
|
||||
** the cost is 2x cpu time on first block. */
|
||||
* the cost is 2x cpu time on first block. */
|
||||
assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
|
||||
if ( (ms->opt.litLengthSum==0) /* first block */
|
||||
&& (seqStore->sequences == seqStore->sequencesStart) /* no ldm */
|
||||
|
||||
@@ -40,12 +40,13 @@
|
||||
# include <unistd.h>
|
||||
# include <sys/times.h>
|
||||
|
||||
# define DEBUG_PRINTHEX(l,p,n) { \
|
||||
unsigned debug_u; \
|
||||
for (debug_u=0; debug_u<(n); debug_u++) \
|
||||
RAWLOG(l, "%02X ", ((const unsigned char*)(p))[debug_u]); \
|
||||
RAWLOG(l, " \n"); \
|
||||
}
|
||||
# define DEBUG_PRINTHEX(l,p,n) \
|
||||
do { \
|
||||
unsigned debug_u; \
|
||||
for (debug_u=0; debug_u<(n); debug_u++) \
|
||||
RAWLOG(l, "%02X ", ((const unsigned char*)(p))[debug_u]); \
|
||||
RAWLOG(l, " \n"); \
|
||||
} while (0)
|
||||
|
||||
static unsigned long long GetCurrentClockTimeMicroseconds(void)
|
||||
{
|
||||
@@ -57,25 +58,28 @@ static unsigned long long GetCurrentClockTimeMicroseconds(void)
|
||||
} }
|
||||
|
||||
#define MUTEX_WAIT_TIME_DLEVEL 6
|
||||
#define ZSTD_PTHREAD_MUTEX_LOCK(mutex) { \
|
||||
if (DEBUGLEVEL >= MUTEX_WAIT_TIME_DLEVEL) { \
|
||||
unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \
|
||||
ZSTD_pthread_mutex_lock(mutex); \
|
||||
{ unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \
|
||||
unsigned long long const elapsedTime = (afterTime-beforeTime); \
|
||||
if (elapsedTime > 1000) { /* or whatever threshold you like; I'm using 1 millisecond here */ \
|
||||
DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, "Thread took %llu microseconds to acquire mutex %s \n", \
|
||||
elapsedTime, #mutex); \
|
||||
} } \
|
||||
} else { \
|
||||
ZSTD_pthread_mutex_lock(mutex); \
|
||||
} \
|
||||
}
|
||||
#define ZSTD_PTHREAD_MUTEX_LOCK(mutex) \
|
||||
do { \
|
||||
if (DEBUGLEVEL >= MUTEX_WAIT_TIME_DLEVEL) { \
|
||||
unsigned long long const beforeTime = GetCurrentClockTimeMicroseconds(); \
|
||||
ZSTD_pthread_mutex_lock(mutex); \
|
||||
{ unsigned long long const afterTime = GetCurrentClockTimeMicroseconds(); \
|
||||
unsigned long long const elapsedTime = (afterTime-beforeTime); \
|
||||
if (elapsedTime > 1000) { \
|
||||
/* or whatever threshold you like; I'm using 1 millisecond here */ \
|
||||
DEBUGLOG(MUTEX_WAIT_TIME_DLEVEL, \
|
||||
"Thread took %llu microseconds to acquire mutex %s \n", \
|
||||
elapsedTime, #mutex); \
|
||||
} } \
|
||||
} else { \
|
||||
ZSTD_pthread_mutex_lock(mutex); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
# define ZSTD_PTHREAD_MUTEX_LOCK(m) ZSTD_pthread_mutex_lock(m)
|
||||
# define DEBUG_PRINTHEX(l,p,n) {}
|
||||
# define DEBUG_PRINTHEX(l,p,n) do { } while (0)
|
||||
|
||||
#endif
|
||||
|
||||
@@ -101,10 +105,10 @@ typedef struct ZSTDMT_bufferPool_s {
|
||||
|
||||
static void ZSTDMT_freeBufferPool(ZSTDMT_bufferPool* bufPool)
|
||||
{
|
||||
unsigned u;
|
||||
DEBUGLOG(3, "ZSTDMT_freeBufferPool (address:%08X)", (U32)(size_t)bufPool);
|
||||
if (!bufPool) return; /* compatibility with free on NULL */
|
||||
if (bufPool->buffers) {
|
||||
unsigned u;
|
||||
for (u=0; u<bufPool->totalBuffers; u++) {
|
||||
DEBUGLOG(4, "free buffer %2u (address:%08X)", u, (U32)(size_t)bufPool->buffers[u].start);
|
||||
ZSTD_customFree(bufPool->buffers[u].start, bufPool->cMem);
|
||||
@@ -360,10 +364,10 @@ typedef struct {
|
||||
/* note : all CCtx borrowed from the pool must be reverted back to the pool _before_ freeing the pool */
|
||||
static void ZSTDMT_freeCCtxPool(ZSTDMT_CCtxPool* pool)
|
||||
{
|
||||
int cid;
|
||||
if (!pool) return;
|
||||
ZSTD_pthread_mutex_destroy(&pool->poolMutex);
|
||||
if (pool->cctxs) {
|
||||
int cid;
|
||||
for (cid=0; cid<pool->totalCCtx; cid++)
|
||||
ZSTD_freeCCtx(pool->cctxs[cid]); /* free compatible with NULL */
|
||||
ZSTD_customFree(pool->cctxs, pool->cMem);
|
||||
@@ -667,12 +671,13 @@ typedef struct {
|
||||
unsigned frameChecksumNeeded; /* used only by mtctx */
|
||||
} ZSTDMT_jobDescription;
|
||||
|
||||
#define JOB_ERROR(e) { \
|
||||
ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex); \
|
||||
job->cSize = e; \
|
||||
ZSTD_pthread_mutex_unlock(&job->job_mutex); \
|
||||
goto _endJob; \
|
||||
}
|
||||
#define JOB_ERROR(e) \
|
||||
do { \
|
||||
ZSTD_PTHREAD_MUTEX_LOCK(&job->job_mutex); \
|
||||
job->cSize = e; \
|
||||
ZSTD_pthread_mutex_unlock(&job->job_mutex); \
|
||||
goto _endJob; \
|
||||
} while (0)
|
||||
|
||||
/* ZSTDMT_compressionJob() is a POOL_function type */
|
||||
static void ZSTDMT_compressionJob(void* jobDescription)
|
||||
@@ -1101,7 +1106,7 @@ ZSTD_frameProgression ZSTDMT_getFrameProgression(ZSTDMT_CCtx* mtctx)
|
||||
{ unsigned jobNb;
|
||||
unsigned lastJobNb = mtctx->nextJobID + mtctx->jobReady; assert(mtctx->jobReady <= 1);
|
||||
DEBUGLOG(6, "ZSTDMT_getFrameProgression: jobs: from %u to <%u (jobReady:%u)",
|
||||
mtctx->doneJobID, lastJobNb, mtctx->jobReady)
|
||||
mtctx->doneJobID, lastJobNb, mtctx->jobReady);
|
||||
for (jobNb = mtctx->doneJobID ; jobNb < lastJobNb ; jobNb++) {
|
||||
unsigned const wJobID = jobNb & mtctx->jobIDMask;
|
||||
ZSTDMT_jobDescription* jobPtr = &mtctx->jobs[wJobID];
|
||||
|
||||
+179
-119
@@ -34,6 +34,12 @@
|
||||
* Macros
|
||||
****************************************************************/
|
||||
|
||||
#ifdef HUF_DISABLE_FAST_DECODE
|
||||
# define HUF_ENABLE_FAST_DECODE 0
|
||||
#else
|
||||
# define HUF_ENABLE_FAST_DECODE 1
|
||||
#endif
|
||||
|
||||
/* These two optional macros force the use one way or another of the two
|
||||
* Huffman decompression implementations. You can't force in both directions
|
||||
* at the same time.
|
||||
@@ -158,17 +164,18 @@ static size_t HUF_initFastDStream(BYTE const* ip) {
|
||||
* op [in/out] - The output pointers, must be updated to reflect what is written.
|
||||
* bits [in/out] - The bitstream containers, must be updated to reflect the current state.
|
||||
* dt [in] - The decoding table.
|
||||
* ilimit [in] - The input limit, stop when any input pointer is below ilimit.
|
||||
* ilowest [in] - The beginning of the valid range of the input. Decoders may read
|
||||
* down to this pointer. It may be below iend[0].
|
||||
* oend [in] - The end of the output stream. op[3] must not cross oend.
|
||||
* iend [in] - The end of each input stream. ip[i] may cross iend[i],
|
||||
* as long as it is above ilimit, but that indicates corruption.
|
||||
* as long as it is above ilowest, but that indicates corruption.
|
||||
*/
|
||||
typedef struct {
|
||||
BYTE const* ip[4];
|
||||
BYTE* op[4];
|
||||
U64 bits[4];
|
||||
void const* dt;
|
||||
BYTE const* ilimit;
|
||||
BYTE const* ilowest;
|
||||
BYTE* oend;
|
||||
BYTE const* iend[4];
|
||||
} HUF_DecompressFastArgs;
|
||||
@@ -186,7 +193,7 @@ static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* ds
|
||||
void const* dt = DTable + 1;
|
||||
U32 const dtLog = HUF_getDTableDesc(DTable).tableLog;
|
||||
|
||||
const BYTE* const ilimit = (const BYTE*)src + 6 + 8;
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
|
||||
BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize);
|
||||
|
||||
@@ -196,6 +203,11 @@ static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* ds
|
||||
if (!MEM_isLittleEndian() || MEM_32bits())
|
||||
return 0;
|
||||
|
||||
/* Avoid nullptr addition */
|
||||
if (dstSize == 0)
|
||||
return 0;
|
||||
assert(dst != NULL);
|
||||
|
||||
/* strict minimum : jump table + 1 byte per stream */
|
||||
if (srcSize < 10)
|
||||
return ERROR(corruption_detected);
|
||||
@@ -209,7 +221,6 @@ static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* ds
|
||||
|
||||
/* Read the jump table. */
|
||||
{
|
||||
const BYTE* const istart = (const BYTE*)src;
|
||||
size_t const length1 = MEM_readLE16(istart);
|
||||
size_t const length2 = MEM_readLE16(istart+2);
|
||||
size_t const length3 = MEM_readLE16(istart+4);
|
||||
@@ -221,10 +232,8 @@ static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* ds
|
||||
|
||||
/* HUF_initFastDStream() requires this, and this small of an input
|
||||
* won't benefit from the ASM loop anyways.
|
||||
* length1 must be >= 16 so that ip[0] >= ilimit before the loop
|
||||
* starts.
|
||||
*/
|
||||
if (length1 < 16 || length2 < 8 || length3 < 8 || length4 < 8)
|
||||
if (length1 < 8 || length2 < 8 || length3 < 8 || length4 < 8)
|
||||
return 0;
|
||||
if (length4 > srcSize) return ERROR(corruption_detected); /* overflow */
|
||||
}
|
||||
@@ -256,11 +265,12 @@ static size_t HUF_DecompressFastArgs_init(HUF_DecompressFastArgs* args, void* ds
|
||||
args->bits[2] = HUF_initFastDStream(args->ip[2]);
|
||||
args->bits[3] = HUF_initFastDStream(args->ip[3]);
|
||||
|
||||
/* If ip[] >= ilimit, it is guaranteed to be safe to
|
||||
* reload bits[]. It may be beyond its section, but is
|
||||
* guaranteed to be valid (>= istart).
|
||||
*/
|
||||
args->ilimit = ilimit;
|
||||
/* The decoders must be sure to never read beyond ilowest.
|
||||
* This is lower than iend[0], but allowing decoders to read
|
||||
* down to ilowest can allow an extra iteration or two in the
|
||||
* fast loop.
|
||||
*/
|
||||
args->ilowest = istart;
|
||||
|
||||
args->oend = oend;
|
||||
args->dt = dt;
|
||||
@@ -285,13 +295,31 @@ static size_t HUF_initRemainingDStream(BIT_DStream_t* bit, HUF_DecompressFastArg
|
||||
assert(sizeof(size_t) == 8);
|
||||
bit->bitContainer = MEM_readLEST(args->ip[stream]);
|
||||
bit->bitsConsumed = ZSTD_countTrailingZeros64(args->bits[stream]);
|
||||
bit->start = (const char*)args->iend[0];
|
||||
bit->start = (const char*)args->ilowest;
|
||||
bit->limitPtr = bit->start + sizeof(size_t);
|
||||
bit->ptr = (const char*)args->ip[stream];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Calls X(N) for each stream 0, 1, 2, 3. */
|
||||
#define HUF_4X_FOR_EACH_STREAM(X) \
|
||||
do { \
|
||||
X(0); \
|
||||
X(1); \
|
||||
X(2); \
|
||||
X(3); \
|
||||
} while (0)
|
||||
|
||||
/* Calls X(N, var) for each stream 0, 1, 2, 3. */
|
||||
#define HUF_4X_FOR_EACH_STREAM_WITH_VAR(X, var) \
|
||||
do { \
|
||||
X(0, (var)); \
|
||||
X(1, (var)); \
|
||||
X(2, (var)); \
|
||||
X(3, (var)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#ifndef HUF_FORCE_DECOMPRESS_X2
|
||||
|
||||
@@ -500,15 +528,19 @@ HUF_decodeSymbolX1(BIT_DStream_t* Dstream, const HUF_DEltX1* dt, const U32 dtLog
|
||||
}
|
||||
|
||||
#define HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr) \
|
||||
*ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog)
|
||||
do { *ptr++ = HUF_decodeSymbolX1(DStreamPtr, dt, dtLog); } while (0)
|
||||
|
||||
#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \
|
||||
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
||||
HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr)
|
||||
#define HUF_DECODE_SYMBOLX1_1(ptr, DStreamPtr) \
|
||||
do { \
|
||||
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
||||
HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr); \
|
||||
} while (0)
|
||||
|
||||
#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \
|
||||
if (MEM_64bits()) \
|
||||
HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr)
|
||||
#define HUF_DECODE_SYMBOLX1_2(ptr, DStreamPtr) \
|
||||
do { \
|
||||
if (MEM_64bits()) \
|
||||
HUF_DECODE_SYMBOLX1_0(ptr, DStreamPtr); \
|
||||
} while (0)
|
||||
|
||||
HINT_INLINE size_t
|
||||
HUF_decodeStreamX1(BYTE* p, BIT_DStream_t* const bitDPtr, BYTE* const pEnd, const HUF_DEltX1* const dt, const U32 dtLog)
|
||||
@@ -693,7 +725,7 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
BYTE* op[4];
|
||||
U16 const* const dtable = (U16 const*)args->dt;
|
||||
BYTE* const oend = args->oend;
|
||||
BYTE const* const ilimit = args->ilimit;
|
||||
BYTE const* const ilowest = args->ilowest;
|
||||
|
||||
/* Copy the arguments to local variables */
|
||||
ZSTD_memcpy(&bits, &args->bits, sizeof(bits));
|
||||
@@ -706,13 +738,12 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
for (;;) {
|
||||
BYTE* olimit;
|
||||
int stream;
|
||||
int symbol;
|
||||
|
||||
/* Assert loop preconditions */
|
||||
#ifndef NDEBUG
|
||||
for (stream = 0; stream < 4; ++stream) {
|
||||
assert(op[stream] <= (stream == 3 ? oend : op[stream + 1]));
|
||||
assert(ip[stream] >= ilimit);
|
||||
assert(ip[stream] >= ilowest);
|
||||
}
|
||||
#endif
|
||||
/* Compute olimit */
|
||||
@@ -722,7 +753,7 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
/* Each iteration consumes up to 11 bits * 5 = 55 bits < 7 bytes
|
||||
* per stream.
|
||||
*/
|
||||
size_t const iiters = (size_t)(ip[0] - ilimit) / 7;
|
||||
size_t const iiters = (size_t)(ip[0] - ilowest) / 7;
|
||||
/* We can safely run iters iterations before running bounds checks */
|
||||
size_t const iters = MIN(oiters, iiters);
|
||||
size_t const symbols = iters * 5;
|
||||
@@ -733,8 +764,8 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
*/
|
||||
olimit = op[3] + symbols;
|
||||
|
||||
/* Exit fast decoding loop once we get close to the end. */
|
||||
if (op[3] + 20 > olimit)
|
||||
/* Exit fast decoding loop once we reach the end. */
|
||||
if (op[3] == olimit)
|
||||
break;
|
||||
|
||||
/* Exit the decoding loop if any input pointer has crossed the
|
||||
@@ -753,27 +784,42 @@ void HUF_decompress4X1_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
}
|
||||
#endif
|
||||
|
||||
#define HUF_4X1_DECODE_SYMBOL(_stream, _symbol) \
|
||||
do { \
|
||||
int const index = (int)(bits[(_stream)] >> 53); \
|
||||
int const entry = (int)dtable[index]; \
|
||||
bits[(_stream)] <<= (entry & 0x3F); \
|
||||
op[(_stream)][(_symbol)] = (BYTE)((entry >> 8) & 0xFF); \
|
||||
} while (0)
|
||||
|
||||
#define HUF_4X1_RELOAD_STREAM(_stream) \
|
||||
do { \
|
||||
int const ctz = ZSTD_countTrailingZeros64(bits[(_stream)]); \
|
||||
int const nbBits = ctz & 7; \
|
||||
int const nbBytes = ctz >> 3; \
|
||||
op[(_stream)] += 5; \
|
||||
ip[(_stream)] -= nbBytes; \
|
||||
bits[(_stream)] = MEM_read64(ip[(_stream)]) | 1; \
|
||||
bits[(_stream)] <<= nbBits; \
|
||||
} while (0)
|
||||
|
||||
/* Manually unroll the loop because compilers don't consistently
|
||||
* unroll the inner loops, which destroys performance.
|
||||
*/
|
||||
do {
|
||||
/* Decode 5 symbols in each of the 4 streams */
|
||||
for (symbol = 0; symbol < 5; ++symbol) {
|
||||
for (stream = 0; stream < 4; ++stream) {
|
||||
int const index = (int)(bits[stream] >> 53);
|
||||
int const entry = (int)dtable[index];
|
||||
bits[stream] <<= (entry & 63);
|
||||
op[stream][symbol] = (BYTE)((entry >> 8) & 0xFF);
|
||||
}
|
||||
}
|
||||
/* Reload the bitstreams */
|
||||
for (stream = 0; stream < 4; ++stream) {
|
||||
int const ctz = ZSTD_countTrailingZeros64(bits[stream]);
|
||||
int const nbBits = ctz & 7;
|
||||
int const nbBytes = ctz >> 3;
|
||||
op[stream] += 5;
|
||||
ip[stream] -= nbBytes;
|
||||
bits[stream] = MEM_read64(ip[stream]) | 1;
|
||||
bits[stream] <<= nbBits;
|
||||
}
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 0);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 1);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 2);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 3);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X1_DECODE_SYMBOL, 4);
|
||||
|
||||
/* Reload each of the 4 the bitstreams */
|
||||
HUF_4X_FOR_EACH_STREAM(HUF_4X1_RELOAD_STREAM);
|
||||
} while (op[3] < olimit);
|
||||
|
||||
#undef HUF_4X1_DECODE_SYMBOL
|
||||
#undef HUF_4X1_RELOAD_STREAM
|
||||
}
|
||||
|
||||
_out:
|
||||
@@ -798,7 +844,7 @@ HUF_decompress4X1_usingDTable_internal_fast(
|
||||
HUF_DecompressFastLoopFn loopFn)
|
||||
{
|
||||
void const* dt = DTable + 1;
|
||||
const BYTE* const iend = (const BYTE*)cSrc + 6;
|
||||
BYTE const* const ilowest = (BYTE const*)cSrc;
|
||||
BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize);
|
||||
HUF_DecompressFastArgs args;
|
||||
{ size_t const ret = HUF_DecompressFastArgs_init(&args, dst, dstSize, cSrc, cSrcSize, DTable);
|
||||
@@ -807,18 +853,22 @@ HUF_decompress4X1_usingDTable_internal_fast(
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(args.ip[0] >= args.ilimit);
|
||||
assert(args.ip[0] >= args.ilowest);
|
||||
loopFn(&args);
|
||||
|
||||
/* Our loop guarantees that ip[] >= ilimit and that we haven't
|
||||
/* Our loop guarantees that ip[] >= ilowest and that we haven't
|
||||
* overwritten any op[].
|
||||
*/
|
||||
assert(args.ip[0] >= iend);
|
||||
assert(args.ip[1] >= iend);
|
||||
assert(args.ip[2] >= iend);
|
||||
assert(args.ip[3] >= iend);
|
||||
assert(args.ip[0] >= ilowest);
|
||||
assert(args.ip[0] >= ilowest);
|
||||
assert(args.ip[1] >= ilowest);
|
||||
assert(args.ip[2] >= ilowest);
|
||||
assert(args.ip[3] >= ilowest);
|
||||
assert(args.op[3] <= oend);
|
||||
(void)iend;
|
||||
|
||||
assert(ilowest == args.ilowest);
|
||||
assert(ilowest + 6 == args.iend[0]);
|
||||
(void)ilowest;
|
||||
|
||||
/* finish bit streams one by one. */
|
||||
{ size_t const segmentSize = (dstSize+3) / 4;
|
||||
@@ -869,7 +919,7 @@ static size_t HUF_decompress4X1_usingDTable_internal(void* dst, size_t dstSize,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(flags & HUF_flags_disableFast)) {
|
||||
if (HUF_ENABLE_FAST_DECODE && !(flags & HUF_flags_disableFast)) {
|
||||
size_t const ret = HUF_decompress4X1_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
@@ -1240,15 +1290,19 @@ HUF_decodeLastSymbolX2(void* op, BIT_DStream_t* DStream, const HUF_DEltX2* dt, c
|
||||
}
|
||||
|
||||
#define HUF_DECODE_SYMBOLX2_0(ptr, DStreamPtr) \
|
||||
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
|
||||
do { ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); } while (0)
|
||||
|
||||
#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
|
||||
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
||||
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
|
||||
#define HUF_DECODE_SYMBOLX2_1(ptr, DStreamPtr) \
|
||||
do { \
|
||||
if (MEM_64bits() || (HUF_TABLELOG_MAX<=12)) \
|
||||
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); \
|
||||
} while (0)
|
||||
|
||||
#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
|
||||
if (MEM_64bits()) \
|
||||
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog)
|
||||
#define HUF_DECODE_SYMBOLX2_2(ptr, DStreamPtr) \
|
||||
do { \
|
||||
if (MEM_64bits()) \
|
||||
ptr += HUF_decodeSymbolX2(ptr, DStreamPtr, dt, dtLog); \
|
||||
} while (0)
|
||||
|
||||
HINT_INLINE size_t
|
||||
HUF_decodeStreamX2(BYTE* p, BIT_DStream_t* bitDPtr, BYTE* const pEnd,
|
||||
@@ -1474,7 +1528,7 @@ void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
BYTE* op[4];
|
||||
BYTE* oend[4];
|
||||
HUF_DEltX2 const* const dtable = (HUF_DEltX2 const*)args->dt;
|
||||
BYTE const* const ilimit = args->ilimit;
|
||||
BYTE const* const ilowest = args->ilowest;
|
||||
|
||||
/* Copy the arguments to local registers. */
|
||||
ZSTD_memcpy(&bits, &args->bits, sizeof(bits));
|
||||
@@ -1492,13 +1546,12 @@ void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
for (;;) {
|
||||
BYTE* olimit;
|
||||
int stream;
|
||||
int symbol;
|
||||
|
||||
/* Assert loop preconditions */
|
||||
#ifndef NDEBUG
|
||||
for (stream = 0; stream < 4; ++stream) {
|
||||
assert(op[stream] <= oend[stream]);
|
||||
assert(ip[stream] >= ilimit);
|
||||
assert(ip[stream] >= ilowest);
|
||||
}
|
||||
#endif
|
||||
/* Compute olimit */
|
||||
@@ -1511,7 +1564,7 @@ void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
* We also know that each input pointer is >= ip[0]. So we can run
|
||||
* iters loops before running out of input.
|
||||
*/
|
||||
size_t iters = (size_t)(ip[0] - ilimit) / 7;
|
||||
size_t iters = (size_t)(ip[0] - ilowest) / 7;
|
||||
/* Each iteration can produce up to 10 bytes of output per stream.
|
||||
* Each output stream my advance at different rates. So take the
|
||||
* minimum number of safe iterations among all the output streams.
|
||||
@@ -1529,8 +1582,8 @@ void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
*/
|
||||
olimit = op[3] + (iters * 5);
|
||||
|
||||
/* Exit the fast decoding loop if we are too close to the end. */
|
||||
if (op[3] + 10 > olimit)
|
||||
/* Exit the fast decoding loop once we reach the end. */
|
||||
if (op[3] == olimit)
|
||||
break;
|
||||
|
||||
/* Exit the decoding loop if any input pointer has crossed the
|
||||
@@ -1549,54 +1602,58 @@ void HUF_decompress4X2_usingDTable_internal_fast_c_loop(HUF_DecompressFastArgs*
|
||||
}
|
||||
#endif
|
||||
|
||||
#define HUF_4X2_DECODE_SYMBOL(_stream, _decode3) \
|
||||
do { \
|
||||
if ((_decode3) || (_stream) != 3) { \
|
||||
int const index = (int)(bits[(_stream)] >> 53); \
|
||||
HUF_DEltX2 const entry = dtable[index]; \
|
||||
MEM_write16(op[(_stream)], entry.sequence); \
|
||||
bits[(_stream)] <<= (entry.nbBits) & 0x3F; \
|
||||
op[(_stream)] += (entry.length); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define HUF_4X2_RELOAD_STREAM(_stream) \
|
||||
do { \
|
||||
HUF_4X2_DECODE_SYMBOL(3, 1); \
|
||||
{ \
|
||||
int const ctz = ZSTD_countTrailingZeros64(bits[(_stream)]); \
|
||||
int const nbBits = ctz & 7; \
|
||||
int const nbBytes = ctz >> 3; \
|
||||
ip[(_stream)] -= nbBytes; \
|
||||
bits[(_stream)] = MEM_read64(ip[(_stream)]) | 1; \
|
||||
bits[(_stream)] <<= nbBits; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* Manually unroll the loop because compilers don't consistently
|
||||
* unroll the inner loops, which destroys performance.
|
||||
*/
|
||||
do {
|
||||
/* Do 5 table lookups for each of the first 3 streams */
|
||||
for (symbol = 0; symbol < 5; ++symbol) {
|
||||
for (stream = 0; stream < 3; ++stream) {
|
||||
int const index = (int)(bits[stream] >> 53);
|
||||
HUF_DEltX2 const entry = dtable[index];
|
||||
MEM_write16(op[stream], entry.sequence);
|
||||
bits[stream] <<= (entry.nbBits);
|
||||
op[stream] += (entry.length);
|
||||
}
|
||||
}
|
||||
/* Do 1 table lookup from the final stream */
|
||||
{
|
||||
int const index = (int)(bits[3] >> 53);
|
||||
HUF_DEltX2 const entry = dtable[index];
|
||||
MEM_write16(op[3], entry.sequence);
|
||||
bits[3] <<= (entry.nbBits);
|
||||
op[3] += (entry.length);
|
||||
}
|
||||
/* Do 4 table lookups from the final stream & reload bitstreams */
|
||||
for (stream = 0; stream < 4; ++stream) {
|
||||
/* Do a table lookup from the final stream.
|
||||
* This is interleaved with the reloading to reduce register
|
||||
* pressure. This shouldn't be necessary, but compilers can
|
||||
* struggle with codegen with high register pressure.
|
||||
*/
|
||||
{
|
||||
int const index = (int)(bits[3] >> 53);
|
||||
HUF_DEltX2 const entry = dtable[index];
|
||||
MEM_write16(op[3], entry.sequence);
|
||||
bits[3] <<= (entry.nbBits);
|
||||
op[3] += (entry.length);
|
||||
}
|
||||
/* Reload the bistreams. The final bitstream must be reloaded
|
||||
* after the 5th symbol was decoded.
|
||||
*/
|
||||
{
|
||||
int const ctz = ZSTD_countTrailingZeros64(bits[stream]);
|
||||
int const nbBits = ctz & 7;
|
||||
int const nbBytes = ctz >> 3;
|
||||
ip[stream] -= nbBytes;
|
||||
bits[stream] = MEM_read64(ip[stream]) | 1;
|
||||
bits[stream] <<= nbBits;
|
||||
}
|
||||
}
|
||||
/* Decode 5 symbols from each of the first 3 streams.
|
||||
* The final stream will be decoded during the reload phase
|
||||
* to reduce register pressure.
|
||||
*/
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
|
||||
HUF_4X_FOR_EACH_STREAM_WITH_VAR(HUF_4X2_DECODE_SYMBOL, 0);
|
||||
|
||||
/* Decode one symbol from the final stream */
|
||||
HUF_4X2_DECODE_SYMBOL(3, 1);
|
||||
|
||||
/* Decode 4 symbols from the final stream & reload bitstreams.
|
||||
* The final stream is reloaded last, meaning that all 5 symbols
|
||||
* are decoded from the final stream before it is reloaded.
|
||||
*/
|
||||
HUF_4X_FOR_EACH_STREAM(HUF_4X2_RELOAD_STREAM);
|
||||
} while (op[3] < olimit);
|
||||
}
|
||||
|
||||
#undef HUF_4X2_DECODE_SYMBOL
|
||||
#undef HUF_4X2_RELOAD_STREAM
|
||||
|
||||
_out:
|
||||
|
||||
/* Save the final values of each of the state variables back to args. */
|
||||
@@ -1613,7 +1670,7 @@ HUF_decompress4X2_usingDTable_internal_fast(
|
||||
const HUF_DTable* DTable,
|
||||
HUF_DecompressFastLoopFn loopFn) {
|
||||
void const* dt = DTable + 1;
|
||||
const BYTE* const iend = (const BYTE*)cSrc + 6;
|
||||
const BYTE* const ilowest = (const BYTE*)cSrc;
|
||||
BYTE* const oend = ZSTD_maybeNullPtrAdd((BYTE*)dst, dstSize);
|
||||
HUF_DecompressFastArgs args;
|
||||
{
|
||||
@@ -1623,16 +1680,19 @@ HUF_decompress4X2_usingDTable_internal_fast(
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(args.ip[0] >= args.ilimit);
|
||||
assert(args.ip[0] >= args.ilowest);
|
||||
loopFn(&args);
|
||||
|
||||
/* note : op4 already verified within main loop */
|
||||
assert(args.ip[0] >= iend);
|
||||
assert(args.ip[1] >= iend);
|
||||
assert(args.ip[2] >= iend);
|
||||
assert(args.ip[3] >= iend);
|
||||
assert(args.ip[0] >= ilowest);
|
||||
assert(args.ip[1] >= ilowest);
|
||||
assert(args.ip[2] >= ilowest);
|
||||
assert(args.ip[3] >= ilowest);
|
||||
assert(args.op[3] <= oend);
|
||||
(void)iend;
|
||||
|
||||
assert(ilowest == args.ilowest);
|
||||
assert(ilowest + 6 == args.iend[0]);
|
||||
(void)ilowest;
|
||||
|
||||
/* finish bitStreams one by one */
|
||||
{
|
||||
@@ -1681,7 +1741,7 @@ static size_t HUF_decompress4X2_usingDTable_internal(void* dst, size_t dstSize,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(flags & HUF_flags_disableFast)) {
|
||||
if (HUF_ENABLE_FAST_DECODE && !(flags & HUF_flags_disableFast)) {
|
||||
size_t const ret = HUF_decompress4X2_usingDTable_internal_fast(dst, dstSize, cSrc, cSrcSize, DTable, loopFn);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
@@ -131,7 +131,7 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop:
|
||||
movq 88(%rax), %bits3
|
||||
movq 96(%rax), %dtable
|
||||
push %rax /* argument */
|
||||
push 104(%rax) /* ilimit */
|
||||
push 104(%rax) /* ilowest */
|
||||
push 112(%rax) /* oend */
|
||||
push %olimit /* olimit space */
|
||||
|
||||
@@ -156,11 +156,11 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop:
|
||||
shrq $2, %r15
|
||||
|
||||
movq %ip0, %rax /* rax = ip0 */
|
||||
movq 40(%rsp), %rdx /* rdx = ilimit */
|
||||
subq %rdx, %rax /* rax = ip0 - ilimit */
|
||||
movq %rax, %rbx /* rbx = ip0 - ilimit */
|
||||
movq 40(%rsp), %rdx /* rdx = ilowest */
|
||||
subq %rdx, %rax /* rax = ip0 - ilowest */
|
||||
movq %rax, %rbx /* rbx = ip0 - ilowest */
|
||||
|
||||
/* rdx = (ip0 - ilimit) / 7 */
|
||||
/* rdx = (ip0 - ilowest) / 7 */
|
||||
movabsq $2635249153387078803, %rdx
|
||||
mulq %rdx
|
||||
subq %rdx, %rbx
|
||||
@@ -183,9 +183,8 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop:
|
||||
|
||||
/* If (op3 + 20 > olimit) */
|
||||
movq %op3, %rax /* rax = op3 */
|
||||
addq $20, %rax /* rax = op3 + 20 */
|
||||
cmpq %rax, %olimit /* op3 + 20 > olimit */
|
||||
jb .L_4X1_exit
|
||||
cmpq %rax, %olimit /* op3 == olimit */
|
||||
je .L_4X1_exit
|
||||
|
||||
/* If (ip1 < ip0) go to exit */
|
||||
cmpq %ip0, %ip1
|
||||
@@ -316,7 +315,7 @@ HUF_decompress4X1_usingDTable_internal_fast_asm_loop:
|
||||
/* Restore stack (oend & olimit) */
|
||||
pop %rax /* olimit */
|
||||
pop %rax /* oend */
|
||||
pop %rax /* ilimit */
|
||||
pop %rax /* ilowest */
|
||||
pop %rax /* arg */
|
||||
|
||||
/* Save ip / op / bits */
|
||||
@@ -387,7 +386,7 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
|
||||
movq 96(%rax), %dtable
|
||||
push %rax /* argument */
|
||||
push %rax /* olimit */
|
||||
push 104(%rax) /* ilimit */
|
||||
push 104(%rax) /* ilowest */
|
||||
|
||||
movq 112(%rax), %rax
|
||||
push %rax /* oend3 */
|
||||
@@ -414,9 +413,9 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
|
||||
|
||||
/* We can consume up to 7 input bytes each iteration. */
|
||||
movq %ip0, %rax /* rax = ip0 */
|
||||
movq 40(%rsp), %rdx /* rdx = ilimit */
|
||||
subq %rdx, %rax /* rax = ip0 - ilimit */
|
||||
movq %rax, %r15 /* r15 = ip0 - ilimit */
|
||||
movq 40(%rsp), %rdx /* rdx = ilowest */
|
||||
subq %rdx, %rax /* rax = ip0 - ilowest */
|
||||
movq %rax, %r15 /* r15 = ip0 - ilowest */
|
||||
|
||||
/* rdx = rax / 7 */
|
||||
movabsq $2635249153387078803, %rdx
|
||||
@@ -426,7 +425,7 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
|
||||
addq %r15, %rdx
|
||||
shrq $2, %rdx
|
||||
|
||||
/* r15 = (ip0 - ilimit) / 7 */
|
||||
/* r15 = (ip0 - ilowest) / 7 */
|
||||
movq %rdx, %r15
|
||||
|
||||
/* r15 = min(r15, min(oend0 - op0, oend1 - op1, oend2 - op2, oend3 - op3) / 10) */
|
||||
@@ -467,9 +466,8 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
|
||||
|
||||
/* If (op3 + 10 > olimit) */
|
||||
movq %op3, %rax /* rax = op3 */
|
||||
addq $10, %rax /* rax = op3 + 10 */
|
||||
cmpq %rax, %olimit /* op3 + 10 > olimit */
|
||||
jb .L_4X2_exit
|
||||
cmpq %rax, %olimit /* op3 == olimit */
|
||||
je .L_4X2_exit
|
||||
|
||||
/* If (ip1 < ip0) go to exit */
|
||||
cmpq %ip0, %ip1
|
||||
@@ -537,7 +535,7 @@ HUF_decompress4X2_usingDTable_internal_fast_asm_loop:
|
||||
pop %rax /* oend1 */
|
||||
pop %rax /* oend2 */
|
||||
pop %rax /* oend3 */
|
||||
pop %rax /* ilimit */
|
||||
pop %rax /* ilowest */
|
||||
pop %rax /* olimit */
|
||||
pop %rax /* arg */
|
||||
|
||||
|
||||
@@ -55,18 +55,19 @@
|
||||
/*-*******************************************************
|
||||
* Dependencies
|
||||
*********************************************************/
|
||||
#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */
|
||||
#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
|
||||
#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */
|
||||
#include "../common/error_private.h"
|
||||
#include "../common/zstd_internal.h" /* blockProperties_t */
|
||||
#include "../common/mem.h" /* low level memory routines */
|
||||
#include "../common/bits.h" /* ZSTD_highbit32 */
|
||||
#define FSE_STATIC_LINKING_ONLY
|
||||
#include "../common/fse.h"
|
||||
#include "../common/huf.h"
|
||||
#include "../common/xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */
|
||||
#include "../common/zstd_internal.h" /* blockProperties_t */
|
||||
#include "zstd_decompress_internal.h" /* ZSTD_DCtx */
|
||||
#include "zstd_ddict.h" /* ZSTD_DDictDictContent */
|
||||
#include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */
|
||||
#include "../common/bits.h" /* ZSTD_highbit32 */
|
||||
|
||||
#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
|
||||
# include "../legacy/zstd_legacy.h"
|
||||
@@ -1023,12 +1024,14 @@ static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
|
||||
default:
|
||||
RETURN_ERROR(corruption_detected, "invalid block type");
|
||||
}
|
||||
|
||||
if (ZSTD_isError(decodedSize)) return decodedSize;
|
||||
if (dctx->validateChecksum)
|
||||
FORWARD_IF_ERROR(decodedSize, "Block decompression failure");
|
||||
DEBUGLOG(5, "Decompressed block of dSize = %u", (unsigned)decodedSize);
|
||||
if (dctx->validateChecksum) {
|
||||
XXH64_update(&dctx->xxhState, op, decodedSize);
|
||||
if (decodedSize != 0)
|
||||
}
|
||||
if (decodedSize) /* support dst = NULL,0 */ {
|
||||
op += decodedSize;
|
||||
}
|
||||
assert(ip != NULL);
|
||||
ip += cBlockSize;
|
||||
remainingSrcSize -= cBlockSize;
|
||||
@@ -2173,7 +2176,7 @@ size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inB
|
||||
/* shortcut : using single-pass mode */
|
||||
size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds));
|
||||
if (ZSTD_isError(decompressedSize)) return decompressedSize;
|
||||
DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")
|
||||
DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()");
|
||||
assert(istart != NULL);
|
||||
ip = istart + cSize;
|
||||
op = op ? op + decompressedSize : op; /* can occur if frameContentSize = 0 (empty frame) */
|
||||
|
||||
@@ -1585,7 +1585,8 @@ ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx,
|
||||
/* last literal segment */
|
||||
if (dctx->litBufferLocation == ZSTD_split) {
|
||||
/* split hasn't been reached yet, first get dst then copy litExtraBuffer */
|
||||
size_t const lastLLSize = litBufferEnd - litPtr;
|
||||
size_t const lastLLSize = (size_t)(litBufferEnd - litPtr);
|
||||
DEBUGLOG(6, "copy last literals from segment : %u", (U32)lastLLSize);
|
||||
RETURN_ERROR_IF(lastLLSize > (size_t)(oend - op), dstSize_tooSmall, "");
|
||||
if (op != NULL) {
|
||||
ZSTD_memmove(op, litPtr, lastLLSize);
|
||||
@@ -1596,14 +1597,16 @@ ZSTD_decompressSequences_bodySplitLitBuffer( ZSTD_DCtx* dctx,
|
||||
dctx->litBufferLocation = ZSTD_not_in_dst;
|
||||
}
|
||||
/* copy last literals from internal buffer */
|
||||
{ size_t const lastLLSize = litBufferEnd - litPtr;
|
||||
{ size_t const lastLLSize = (size_t)(litBufferEnd - litPtr);
|
||||
DEBUGLOG(6, "copy last literals from internal buffer : %u", (U32)lastLLSize);
|
||||
RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
|
||||
if (op != NULL) {
|
||||
ZSTD_memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
} }
|
||||
|
||||
return op-ostart;
|
||||
DEBUGLOG(6, "decoded block of size %u bytes", (U32)(op - ostart));
|
||||
return (size_t)(op - ostart);
|
||||
}
|
||||
|
||||
FORCE_INLINE_TEMPLATE size_t
|
||||
@@ -1673,14 +1676,16 @@ ZSTD_decompressSequences_body(ZSTD_DCtx* dctx,
|
||||
}
|
||||
|
||||
/* last literal segment */
|
||||
{ size_t const lastLLSize = litEnd - litPtr;
|
||||
{ size_t const lastLLSize = (size_t)(litEnd - litPtr);
|
||||
DEBUGLOG(6, "copy last literals : %u", (U32)lastLLSize);
|
||||
RETURN_ERROR_IF(lastLLSize > (size_t)(oend-op), dstSize_tooSmall, "");
|
||||
if (op != NULL) {
|
||||
ZSTD_memcpy(op, litPtr, lastLLSize);
|
||||
op += lastLLSize;
|
||||
} }
|
||||
|
||||
return op-ostart;
|
||||
DEBUGLOG(6, "decoded block of size %u bytes", (U32)(op - ostart));
|
||||
return (size_t)(op - ostart);
|
||||
}
|
||||
|
||||
static size_t
|
||||
@@ -1878,7 +1883,7 @@ ZSTD_decompressSequencesLong_body(
|
||||
}
|
||||
}
|
||||
|
||||
return op-ostart;
|
||||
return (size_t)(op - ostart);
|
||||
}
|
||||
|
||||
static size_t
|
||||
@@ -2068,7 +2073,7 @@ ZSTD_decompressBlock_internal(ZSTD_DCtx* dctx,
|
||||
const void* src, size_t srcSize, const streaming_operation streaming)
|
||||
{ /* blockType == blockCompressed */
|
||||
const BYTE* ip = (const BYTE*)src;
|
||||
DEBUGLOG(5, "ZSTD_decompressBlock_internal (size : %u)", (U32)srcSize);
|
||||
DEBUGLOG(5, "ZSTD_decompressBlock_internal (cSize : %u)", (unsigned)srcSize);
|
||||
|
||||
/* Note : the wording of the specification
|
||||
* allows compressed block to be sized exactly ZSTD_blockSizeMax(dctx).
|
||||
|
||||
+12
-6
@@ -74,9 +74,9 @@ static const U32 g_selectivity_default = 9;
|
||||
* Console display
|
||||
***************************************/
|
||||
#undef DISPLAY
|
||||
#define DISPLAY(...) { fprintf(stderr, __VA_ARGS__); fflush( stderr ); }
|
||||
#define DISPLAY(...) do { fprintf(stderr, __VA_ARGS__); fflush( stderr ); } while (0)
|
||||
#undef DISPLAYLEVEL
|
||||
#define DISPLAYLEVEL(l, ...) if (notificationLevel>=l) { DISPLAY(__VA_ARGS__); } /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */
|
||||
#define DISPLAYLEVEL(l, ...) do { if (notificationLevel>=l) { DISPLAY(__VA_ARGS__); } } while (0) /* 0 : no display; 1: errors; 2: default; 3: details; 4: debug */
|
||||
|
||||
static clock_t ZDICT_clockSpan(clock_t nPrevious) { return clock() - nPrevious; }
|
||||
|
||||
@@ -477,10 +477,16 @@ static size_t ZDICT_trainBuffer_legacy(dictItem* dictList, U32 dictListSize,
|
||||
clock_t const refreshRate = CLOCKS_PER_SEC * 3 / 10;
|
||||
|
||||
# undef DISPLAYUPDATE
|
||||
# define DISPLAYUPDATE(l, ...) if (notificationLevel>=l) { \
|
||||
if (ZDICT_clockSpan(displayClock) > refreshRate) \
|
||||
{ displayClock = clock(); DISPLAY(__VA_ARGS__); \
|
||||
if (notificationLevel>=4) fflush(stderr); } }
|
||||
# define DISPLAYUPDATE(l, ...) \
|
||||
do { \
|
||||
if (notificationLevel>=l) { \
|
||||
if (ZDICT_clockSpan(displayClock) > refreshRate) { \
|
||||
displayClock = clock(); \
|
||||
DISPLAY(__VA_ARGS__); \
|
||||
} \
|
||||
if (notificationLevel>=4) fflush(stderr); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* init */
|
||||
DISPLAYLEVEL(2, "\r%70s\r", ""); /* clean display line */
|
||||
|
||||
+18
-5
@@ -1665,9 +1665,6 @@ ZSTDLIB_API unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size);
|
||||
*
|
||||
* Note : only single-threaded compression is supported.
|
||||
* ZSTD_estimateCCtxSize_usingCCtxParams() will return an error code if ZSTD_c_nbWorkers is >= 1.
|
||||
*
|
||||
* Note 2 : ZSTD_estimateCCtxSize* functions are not compatible with the Block-Level Sequence Producer API at this time.
|
||||
* Size estimates assume that no external sequence producer is registered.
|
||||
*/
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize(int maxCompressionLevel);
|
||||
ZSTDLIB_STATIC_API size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams);
|
||||
@@ -2789,7 +2786,7 @@ ZSTDLIB_STATIC_API size_t ZSTD_resetDStream(ZSTD_DStream* zds);
|
||||
|
||||
#define ZSTD_SEQUENCE_PRODUCER_ERROR ((size_t)(-1))
|
||||
|
||||
typedef size_t ZSTD_sequenceProducer_F (
|
||||
typedef size_t (*ZSTD_sequenceProducer_F) (
|
||||
void* sequenceProducerState,
|
||||
ZSTD_Sequence* outSeqs, size_t outSeqsCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
@@ -2821,7 +2818,23 @@ ZSTDLIB_STATIC_API void
|
||||
ZSTD_registerSequenceProducer(
|
||||
ZSTD_CCtx* cctx,
|
||||
void* sequenceProducerState,
|
||||
ZSTD_sequenceProducer_F* sequenceProducer
|
||||
ZSTD_sequenceProducer_F sequenceProducer
|
||||
);
|
||||
|
||||
/*! ZSTD_CCtxParams_registerSequenceProducer() :
|
||||
* Same as ZSTD_registerSequenceProducer(), but operates on ZSTD_CCtx_params.
|
||||
* This is used for accurate size estimation with ZSTD_estimateCCtxSize_usingCCtxParams(),
|
||||
* which is needed when creating a ZSTD_CCtx with ZSTD_initStaticCCtx().
|
||||
*
|
||||
* If you are using the external sequence producer API in a scenario where ZSTD_initStaticCCtx()
|
||||
* is required, then this function is for you. Otherwise, you probably don't need it.
|
||||
*
|
||||
* See tests/zstreamtest.c for example usage. */
|
||||
ZSTDLIB_STATIC_API void
|
||||
ZSTD_CCtxParams_registerSequenceProducer(
|
||||
ZSTD_CCtx_params* params,
|
||||
void* sequenceProducerState,
|
||||
ZSTD_sequenceProducer_F sequenceProducer
|
||||
);
|
||||
|
||||
|
||||
|
||||
+2
-2
@@ -108,7 +108,6 @@ static BMK_runOutcome_t BMK_setValid_runTime(BMK_runTime_t runTime)
|
||||
BMK_runOutcome_t BMK_benchFunction(BMK_benchParams_t p,
|
||||
unsigned nbLoops)
|
||||
{
|
||||
size_t dstSize = 0;
|
||||
nbLoops += !nbLoops; /* minimum nbLoops is 1 */
|
||||
|
||||
/* init */
|
||||
@@ -118,7 +117,8 @@ BMK_runOutcome_t BMK_benchFunction(BMK_benchParams_t p,
|
||||
} }
|
||||
|
||||
/* benchmark */
|
||||
{ UTIL_time_t const clockStart = UTIL_getTime();
|
||||
{ size_t dstSize = 0;
|
||||
UTIL_time_t const clockStart = UTIL_getTime();
|
||||
unsigned loopNb, blockNb;
|
||||
if (p.initFn != NULL) p.initFn(p.initPayload);
|
||||
for (loopNb = 0; loopNb < nbLoops; loopNb++) {
|
||||
|
||||
+768
-418
@@ -8,197 +8,286 @@
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
|
||||
/* **************************************
|
||||
* Tuning parameters
|
||||
****************************************/
|
||||
#ifndef BMK_TIMETEST_DEFAULT_S /* default minimum time per test */
|
||||
# define BMK_TIMETEST_DEFAULT_S 3
|
||||
* Tuning parameters
|
||||
****************************************/
|
||||
#ifndef BMK_TIMETEST_DEFAULT_S /* default minimum time per test */
|
||||
# define BMK_TIMETEST_DEFAULT_S 3
|
||||
#endif
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Includes
|
||||
***************************************/
|
||||
#include "platform.h" /* Large Files support */
|
||||
#include "util.h" /* UTIL_getFileSize, UTIL_sleep */
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
#include <string.h> /* memset, strerror */
|
||||
#include <stdio.h> /* fprintf, fopen */
|
||||
#include <errno.h>
|
||||
#include <assert.h> /* assert */
|
||||
* Includes
|
||||
***************************************/
|
||||
/* this must be included first */
|
||||
#include "platform.h" /* Large Files support, compiler specifics */
|
||||
|
||||
#include "timefn.h" /* UTIL_time_t */
|
||||
#include "benchfn.h"
|
||||
/* then following system includes */
|
||||
#include <assert.h> /* assert */
|
||||
#include <errno.h>
|
||||
#include <stdio.h> /* fprintf, fopen */
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
#include <string.h> /* memset, strerror */
|
||||
#include "util.h" /* UTIL_getFileSize, UTIL_sleep */
|
||||
#include "../lib/common/mem.h"
|
||||
#include "benchfn.h"
|
||||
#include "timefn.h" /* UTIL_time_t */
|
||||
#ifndef ZSTD_STATIC_LINKING_ONLY
|
||||
#define ZSTD_STATIC_LINKING_ONLY
|
||||
# define ZSTD_STATIC_LINKING_ONLY
|
||||
#endif
|
||||
#include "../lib/zstd.h"
|
||||
#include "datagen.h" /* RDG_genBuffer */
|
||||
#include "datagen.h" /* RDG_genBuffer */
|
||||
#include "lorem.h" /* LOREM_genBuffer */
|
||||
#ifndef XXH_INLINE_ALL
|
||||
#define XXH_INLINE_ALL
|
||||
# define XXH_INLINE_ALL
|
||||
#endif
|
||||
#include "../lib/common/xxhash.h"
|
||||
#include "benchzstd.h"
|
||||
#include "../lib/zstd_errors.h"
|
||||
|
||||
#include "benchzstd.h"
|
||||
|
||||
/* *************************************
|
||||
* Constants
|
||||
***************************************/
|
||||
* Constants
|
||||
***************************************/
|
||||
#ifndef ZSTD_GIT_COMMIT
|
||||
# define ZSTD_GIT_COMMIT_STRING ""
|
||||
# define ZSTD_GIT_COMMIT_STRING ""
|
||||
#else
|
||||
# define ZSTD_GIT_COMMIT_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_GIT_COMMIT)
|
||||
# define ZSTD_GIT_COMMIT_STRING ZSTD_EXPAND_AND_QUOTE(ZSTD_GIT_COMMIT)
|
||||
#endif
|
||||
|
||||
#define TIMELOOP_MICROSEC (1*1000000ULL) /* 1 second */
|
||||
#define TIMELOOP_NANOSEC (1*1000000000ULL) /* 1 second */
|
||||
#define ACTIVEPERIOD_MICROSEC (70*TIMELOOP_MICROSEC) /* 70 seconds */
|
||||
#define COOLPERIOD_SEC 10
|
||||
#define TIMELOOP_MICROSEC (1 * 1000000ULL) /* 1 second */
|
||||
#define TIMELOOP_NANOSEC (1 * 1000000000ULL) /* 1 second */
|
||||
#define ACTIVEPERIOD_MICROSEC (70 * TIMELOOP_MICROSEC) /* 70 seconds */
|
||||
#define COOLPERIOD_SEC 10
|
||||
|
||||
#define KB *(1 <<10)
|
||||
#define MB *(1 <<20)
|
||||
#define GB *(1U<<30)
|
||||
#define KB *(1 << 10)
|
||||
#define MB *(1 << 20)
|
||||
#define GB *(1U << 30)
|
||||
|
||||
#define BMK_RUNTEST_DEFAULT_MS 1000
|
||||
|
||||
static const size_t maxMemory = (sizeof(size_t)==4) ?
|
||||
/* 32-bit */ (2 GB - 64 MB) :
|
||||
/* 64-bit */ (size_t)(1ULL << ((sizeof(size_t)*8)-31));
|
||||
|
||||
static const size_t maxMemory = (sizeof(size_t) == 4)
|
||||
?
|
||||
/* 32-bit */ (2 GB - 64 MB)
|
||||
:
|
||||
/* 64-bit */ (size_t)(1ULL << ((sizeof(size_t) * 8) - 31));
|
||||
|
||||
/* *************************************
|
||||
* console display
|
||||
***************************************/
|
||||
#define DISPLAY(...) { fprintf(stderr, __VA_ARGS__); fflush(NULL); }
|
||||
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
/* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : + progression; 4 : + information */
|
||||
#define OUTPUT(...) { fprintf(stdout, __VA_ARGS__); fflush(NULL); }
|
||||
#define OUTPUTLEVEL(l, ...) if (displayLevel>=l) { OUTPUT(__VA_ARGS__); }
|
||||
|
||||
* console display
|
||||
***************************************/
|
||||
#define DISPLAY(...) \
|
||||
{ \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fflush(NULL); \
|
||||
}
|
||||
#define DISPLAYLEVEL(l, ...) \
|
||||
if (displayLevel >= l) { \
|
||||
DISPLAY(__VA_ARGS__); \
|
||||
}
|
||||
/* 0 : no display; 1: errors; 2 : + result + interaction + warnings; 3 : +
|
||||
* progression; 4 : + information */
|
||||
#define OUTPUT(...) \
|
||||
{ \
|
||||
fprintf(stdout, __VA_ARGS__); \
|
||||
fflush(NULL); \
|
||||
}
|
||||
#define OUTPUTLEVEL(l, ...) \
|
||||
if (displayLevel >= l) { \
|
||||
OUTPUT(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
/* *************************************
|
||||
* Exceptions
|
||||
***************************************/
|
||||
* Exceptions
|
||||
***************************************/
|
||||
#ifndef DEBUG
|
||||
# define DEBUG 0
|
||||
# define DEBUG 0
|
||||
#endif
|
||||
#define DEBUGOUTPUT(...) { if (DEBUG) DISPLAY(__VA_ARGS__); }
|
||||
#define DEBUGOUTPUT(...) \
|
||||
{ \
|
||||
if (DEBUG) \
|
||||
DISPLAY(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
#define RETURN_ERROR_INT(errorNum, ...) { \
|
||||
DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
|
||||
DISPLAYLEVEL(1, "Error %i : ", errorNum); \
|
||||
DISPLAYLEVEL(1, __VA_ARGS__); \
|
||||
DISPLAYLEVEL(1, " \n"); \
|
||||
return errorNum; \
|
||||
#define RETURN_ERROR_INT(errorNum, ...) \
|
||||
{ \
|
||||
DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
|
||||
DISPLAYLEVEL(1, "Error %i : ", errorNum); \
|
||||
DISPLAYLEVEL(1, __VA_ARGS__); \
|
||||
DISPLAYLEVEL(1, " \n"); \
|
||||
return errorNum; \
|
||||
}
|
||||
|
||||
#define CHECK_Z(zf) \
|
||||
{ \
|
||||
size_t const zerr = zf; \
|
||||
if (ZSTD_isError(zerr)) { \
|
||||
DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
|
||||
DISPLAY("Error : "); \
|
||||
DISPLAY("%s failed : %s", #zf, ZSTD_getErrorName(zerr)); \
|
||||
DISPLAY(" \n"); \
|
||||
exit(1); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define RETURN_ERROR(errorNum, retType, ...) \
|
||||
{ \
|
||||
retType r; \
|
||||
memset(&r, 0, sizeof(retType)); \
|
||||
DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
|
||||
DISPLAYLEVEL(1, "Error %i : ", errorNum); \
|
||||
DISPLAYLEVEL(1, __VA_ARGS__); \
|
||||
DISPLAYLEVEL(1, " \n"); \
|
||||
r.tag = errorNum; \
|
||||
return r; \
|
||||
}
|
||||
|
||||
/* replacement for snprintf(), which is not supported by C89
|
||||
* sprintf() would be the supported one, but it's labelled unsafe,
|
||||
* so some modern static analyzer will flag it as such, making it unusable.
|
||||
* formatString_u() replaces snprintf() for the specific case where there are only %u arguments */
|
||||
static int formatString_u(char* buffer, size_t buffer_size, const char* formatString, unsigned int value)
|
||||
{
|
||||
size_t written = 0;
|
||||
int i;
|
||||
assert(value <= 100);
|
||||
|
||||
for (i = 0; formatString[i] != '\0' && written < buffer_size - 1; ++i) {
|
||||
if (formatString[i] != '%') {
|
||||
buffer[written++] = formatString[i];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (formatString[++i] == 'u') {
|
||||
/* Handle single digit */
|
||||
if (value < 10) {
|
||||
buffer[written++] = '0' + (char)value;
|
||||
} else if (value < 100) {
|
||||
/* Handle two digits */
|
||||
if (written >= buffer_size - 2) {
|
||||
return -1; /* buffer overflow */
|
||||
}
|
||||
buffer[written++] = '0' + (char)(value / 10);
|
||||
buffer[written++] = '0' + (char)(value % 10);
|
||||
} else { /* 100 */
|
||||
if (written >= buffer_size - 3) {
|
||||
return -1; /* buffer overflow */
|
||||
}
|
||||
buffer[written++] = '1';
|
||||
buffer[written++] = '0';
|
||||
buffer[written++] = '0';
|
||||
}
|
||||
} else if (formatString[i] == '%') { /* Check for escaped percent sign */
|
||||
buffer[written++] = '%';
|
||||
} else {
|
||||
return -1; /* unsupported format */
|
||||
}
|
||||
}
|
||||
|
||||
if (written < buffer_size) {
|
||||
buffer[written] = '\0';
|
||||
} else {
|
||||
buffer[0] = '\0'; /* Handle truncation */
|
||||
}
|
||||
|
||||
return (int)written;
|
||||
}
|
||||
|
||||
#define CHECK_Z(zf) { \
|
||||
size_t const zerr = zf; \
|
||||
if (ZSTD_isError(zerr)) { \
|
||||
DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
|
||||
DISPLAY("Error : "); \
|
||||
DISPLAY("%s failed : %s", \
|
||||
#zf, ZSTD_getErrorName(zerr)); \
|
||||
DISPLAY(" \n"); \
|
||||
exit(1); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define RETURN_ERROR(errorNum, retType, ...) { \
|
||||
retType r; \
|
||||
memset(&r, 0, sizeof(retType)); \
|
||||
DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__); \
|
||||
DISPLAYLEVEL(1, "Error %i : ", errorNum); \
|
||||
DISPLAYLEVEL(1, __VA_ARGS__); \
|
||||
DISPLAYLEVEL(1, " \n"); \
|
||||
r.tag = errorNum; \
|
||||
return r; \
|
||||
}
|
||||
|
||||
|
||||
/* *************************************
|
||||
* Benchmark Parameters
|
||||
***************************************/
|
||||
* Benchmark Parameters
|
||||
***************************************/
|
||||
|
||||
BMK_advancedParams_t BMK_initAdvancedParams(void) {
|
||||
BMK_advancedParams_t BMK_initAdvancedParams(void)
|
||||
{
|
||||
BMK_advancedParams_t const res = {
|
||||
BMK_both, /* mode */
|
||||
BMK_both, /* mode */
|
||||
BMK_TIMETEST_DEFAULT_S, /* nbSeconds */
|
||||
0, /* blockSize */
|
||||
0, /* nbWorkers */
|
||||
0, /* realTime */
|
||||
0, /* additionalParam */
|
||||
0, /* ldmFlag */
|
||||
0, /* ldmMinMatch */
|
||||
0, /* ldmHashLog */
|
||||
0, /* ldmBuckSizeLog */
|
||||
0, /* ldmHashRateLog */
|
||||
ZSTD_ps_auto, /* literalCompressionMode */
|
||||
0 /* useRowMatchFinder */
|
||||
0, /* blockSize */
|
||||
0, /* targetCBlockSize */
|
||||
0, /* nbWorkers */
|
||||
0, /* realTime */
|
||||
0, /* additionalParam */
|
||||
0, /* ldmFlag */
|
||||
0, /* ldmMinMatch */
|
||||
0, /* ldmHashLog */
|
||||
0, /* ldmBuckSizeLog */
|
||||
0, /* ldmHashRateLog */
|
||||
ZSTD_ps_auto, /* literalCompressionMode */
|
||||
0 /* useRowMatchFinder */
|
||||
};
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* ********************************************************
|
||||
* Bench functions
|
||||
**********************************************************/
|
||||
* Bench functions
|
||||
**********************************************************/
|
||||
typedef struct {
|
||||
const void* srcPtr;
|
||||
size_t srcSize;
|
||||
void* cPtr;
|
||||
void* cPtr;
|
||||
size_t cRoom;
|
||||
size_t cSize;
|
||||
void* resPtr;
|
||||
void* resPtr;
|
||||
size_t resSize;
|
||||
} blockParam_t;
|
||||
|
||||
#undef MIN
|
||||
#undef MAX
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
static void
|
||||
BMK_initCCtx(ZSTD_CCtx* ctx,
|
||||
const void* dictBuffer, size_t dictBufferSize,
|
||||
int cLevel,
|
||||
const ZSTD_compressionParameters* comprParams,
|
||||
const BMK_advancedParams_t* adv)
|
||||
static void BMK_initCCtx(
|
||||
ZSTD_CCtx* ctx,
|
||||
const void* dictBuffer,
|
||||
size_t dictBufferSize,
|
||||
int cLevel,
|
||||
const ZSTD_compressionParameters* comprParams,
|
||||
const BMK_advancedParams_t* adv)
|
||||
{
|
||||
ZSTD_CCtx_reset(ctx, ZSTD_reset_session_and_parameters);
|
||||
if (adv->nbWorkers==1) {
|
||||
if (adv->nbWorkers == 1) {
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, 0));
|
||||
} else {
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_nbWorkers, adv->nbWorkers));
|
||||
}
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_compressionLevel, cLevel));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_useRowMatchFinder, adv->useRowMatchFinder));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_enableLongDistanceMatching, adv->ldmFlag));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(
|
||||
ctx, ZSTD_c_useRowMatchFinder, adv->useRowMatchFinder));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(
|
||||
ctx, ZSTD_c_enableLongDistanceMatching, adv->ldmFlag));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmMinMatch, adv->ldmMinMatch));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmHashLog, adv->ldmHashLog));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmBucketSizeLog, adv->ldmBucketSizeLog));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_ldmHashRateLog, adv->ldmHashRateLog));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_windowLog, (int)comprParams->windowLog));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_hashLog, (int)comprParams->hashLog));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_chainLog, (int)comprParams->chainLog));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_searchLog, (int)comprParams->searchLog));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_minMatch, (int)comprParams->minMatch));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_targetLength, (int)comprParams->targetLength));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_literalCompressionMode, (int)adv->literalCompressionMode));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(ctx, ZSTD_c_strategy, (int)comprParams->strategy));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(
|
||||
ctx, ZSTD_c_ldmBucketSizeLog, adv->ldmBucketSizeLog));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(
|
||||
ctx, ZSTD_c_ldmHashRateLog, adv->ldmHashRateLog));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(
|
||||
ctx, ZSTD_c_windowLog, (int)comprParams->windowLog));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(
|
||||
ctx, ZSTD_c_hashLog, (int)comprParams->hashLog));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(
|
||||
ctx, ZSTD_c_chainLog, (int)comprParams->chainLog));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(
|
||||
ctx, ZSTD_c_searchLog, (int)comprParams->searchLog));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(
|
||||
ctx, ZSTD_c_minMatch, (int)comprParams->minMatch));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(
|
||||
ctx, ZSTD_c_targetLength, (int)comprParams->targetLength));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(
|
||||
ctx,
|
||||
ZSTD_c_literalCompressionMode,
|
||||
(int)adv->literalCompressionMode));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(
|
||||
ctx, ZSTD_c_strategy, (int)comprParams->strategy));
|
||||
CHECK_Z(ZSTD_CCtx_setParameter(
|
||||
ctx, ZSTD_c_targetCBlockSize, (int)adv->targetCBlockSize));
|
||||
CHECK_Z(ZSTD_CCtx_loadDictionary(ctx, dictBuffer, dictBufferSize));
|
||||
}
|
||||
|
||||
static void BMK_initDCtx(ZSTD_DCtx* dctx,
|
||||
const void* dictBuffer, size_t dictBufferSize) {
|
||||
static void
|
||||
BMK_initDCtx(ZSTD_DCtx* dctx, const void* dictBuffer, size_t dictBufferSize)
|
||||
{
|
||||
CHECK_Z(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_and_parameters));
|
||||
CHECK_Z(ZSTD_DCtx_loadDictionary(dctx, dictBuffer, dictBufferSize));
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
ZSTD_CCtx* cctx;
|
||||
const void* dictBuffer;
|
||||
@@ -208,9 +297,16 @@ typedef struct {
|
||||
const BMK_advancedParams_t* adv;
|
||||
} BMK_initCCtxArgs;
|
||||
|
||||
static size_t local_initCCtx(void* payload) {
|
||||
static size_t local_initCCtx(void* payload)
|
||||
{
|
||||
BMK_initCCtxArgs* ag = (BMK_initCCtxArgs*)payload;
|
||||
BMK_initCCtx(ag->cctx, ag->dictBuffer, ag->dictBufferSize, ag->cLevel, ag->comprParams, ag->adv);
|
||||
BMK_initCCtx(
|
||||
ag->cctx,
|
||||
ag->dictBuffer,
|
||||
ag->dictBufferSize,
|
||||
ag->cLevel,
|
||||
ag->comprParams,
|
||||
ag->adv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -220,18 +316,20 @@ typedef struct {
|
||||
size_t dictBufferSize;
|
||||
} BMK_initDCtxArgs;
|
||||
|
||||
static size_t local_initDCtx(void* payload) {
|
||||
static size_t local_initDCtx(void* payload)
|
||||
{
|
||||
BMK_initDCtxArgs* ag = (BMK_initDCtxArgs*)payload;
|
||||
BMK_initDCtx(ag->dctx, ag->dictBuffer, ag->dictBufferSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* `addArgs` is the context */
|
||||
static size_t local_defaultCompress(
|
||||
const void* srcBuffer, size_t srcSize,
|
||||
void* dstBuffer, size_t dstSize,
|
||||
void* addArgs)
|
||||
const void* srcBuffer,
|
||||
size_t srcSize,
|
||||
void* dstBuffer,
|
||||
size_t dstSize,
|
||||
void* addArgs)
|
||||
{
|
||||
ZSTD_CCtx* const cctx = (ZSTD_CCtx*)addArgs;
|
||||
return ZSTD_compress2(cctx, dstBuffer, dstSize, srcBuffer, srcSize);
|
||||
@@ -239,18 +337,24 @@ static size_t local_defaultCompress(
|
||||
|
||||
/* `addArgs` is the context */
|
||||
static size_t local_defaultDecompress(
|
||||
const void* srcBuffer, size_t srcSize,
|
||||
void* dstBuffer, size_t dstCapacity,
|
||||
void* addArgs)
|
||||
const void* srcBuffer,
|
||||
size_t srcSize,
|
||||
void* dstBuffer,
|
||||
size_t dstCapacity,
|
||||
void* addArgs)
|
||||
{
|
||||
size_t moreToFlush = 1;
|
||||
size_t moreToFlush = 1;
|
||||
ZSTD_DCtx* const dctx = (ZSTD_DCtx*)addArgs;
|
||||
ZSTD_inBuffer in;
|
||||
ZSTD_outBuffer out;
|
||||
in.src = srcBuffer; in.size = srcSize; in.pos = 0;
|
||||
out.dst = dstBuffer; out.size = dstCapacity; out.pos = 0;
|
||||
in.src = srcBuffer;
|
||||
in.size = srcSize;
|
||||
in.pos = 0;
|
||||
out.dst = dstBuffer;
|
||||
out.size = dstCapacity;
|
||||
out.pos = 0;
|
||||
while (moreToFlush) {
|
||||
if(out.pos == out.size) {
|
||||
if (out.pos == out.size) {
|
||||
return (size_t)-ZSTD_error_dstSize_tooSmall;
|
||||
}
|
||||
moreToFlush = ZSTD_decompressStream(dctx, &out, &in);
|
||||
@@ -259,10 +363,8 @@ static size_t local_defaultDecompress(
|
||||
}
|
||||
}
|
||||
return out.pos;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* ================================================================= */
|
||||
/* Benchmark Zstandard, mem-to-mem scenarios */
|
||||
/* ================================================================= */
|
||||
@@ -286,104 +388,145 @@ static BMK_benchOutcome_t BMK_benchOutcome_error(void)
|
||||
return b;
|
||||
}
|
||||
|
||||
static BMK_benchOutcome_t BMK_benchOutcome_setValidResult(BMK_benchResult_t result)
|
||||
static BMK_benchOutcome_t BMK_benchOutcome_setValidResult(
|
||||
BMK_benchResult_t result)
|
||||
{
|
||||
BMK_benchOutcome_t b;
|
||||
b.tag = 0;
|
||||
b.tag = 0;
|
||||
b.internal_never_use_directly = result;
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
/* benchMem with no allocation */
|
||||
static BMK_benchOutcome_t
|
||||
BMK_benchMemAdvancedNoAlloc(
|
||||
const void** srcPtrs, size_t* srcSizes,
|
||||
void** cPtrs, size_t* cCapacities, size_t* cSizes,
|
||||
void** resPtrs, size_t* resSizes,
|
||||
void** resultBufferPtr, void* compressedBuffer,
|
||||
size_t maxCompressedSize,
|
||||
BMK_timedFnState_t* timeStateCompress,
|
||||
BMK_timedFnState_t* timeStateDecompress,
|
||||
static BMK_benchOutcome_t BMK_benchMemAdvancedNoAlloc(
|
||||
const void** srcPtrs,
|
||||
size_t* srcSizes,
|
||||
void** cPtrs,
|
||||
size_t* cCapacities,
|
||||
size_t* cSizes,
|
||||
void** resPtrs,
|
||||
size_t* resSizes,
|
||||
void** resultBufferPtr,
|
||||
void* compressedBuffer,
|
||||
size_t maxCompressedSize,
|
||||
BMK_timedFnState_t* timeStateCompress,
|
||||
BMK_timedFnState_t* timeStateDecompress,
|
||||
|
||||
const void* srcBuffer, size_t srcSize,
|
||||
const size_t* fileSizes, unsigned nbFiles,
|
||||
const int cLevel,
|
||||
const ZSTD_compressionParameters* comprParams,
|
||||
const void* dictBuffer, size_t dictBufferSize,
|
||||
ZSTD_CCtx* cctx, ZSTD_DCtx* dctx,
|
||||
int displayLevel, const char* displayName,
|
||||
const BMK_advancedParams_t* adv)
|
||||
const void* srcBuffer,
|
||||
size_t srcSize,
|
||||
const size_t* fileSizes,
|
||||
unsigned nbFiles,
|
||||
const int cLevel,
|
||||
const ZSTD_compressionParameters* comprParams,
|
||||
const void* dictBuffer,
|
||||
size_t dictBufferSize,
|
||||
ZSTD_CCtx* cctx,
|
||||
ZSTD_DCtx* dctx,
|
||||
int displayLevel,
|
||||
const char* displayName,
|
||||
const BMK_advancedParams_t* adv)
|
||||
{
|
||||
size_t const blockSize = ((adv->blockSize>=32 && (adv->mode != BMK_decodeOnly)) ? adv->blockSize : srcSize) + (!srcSize); /* avoid div by 0 */
|
||||
size_t const blockSize =
|
||||
((adv->blockSize >= 32 && (adv->mode != BMK_decodeOnly))
|
||||
? adv->blockSize
|
||||
: srcSize)
|
||||
+ (!srcSize); /* avoid div by 0 */
|
||||
BMK_benchResult_t benchResult;
|
||||
size_t const loadedCompressedSize = srcSize;
|
||||
size_t cSize = 0;
|
||||
double ratio = 0.;
|
||||
size_t cSize = 0;
|
||||
double ratio = 0.;
|
||||
U32 nbBlocks;
|
||||
|
||||
assert(cctx != NULL); assert(dctx != NULL);
|
||||
assert(cctx != NULL);
|
||||
assert(dctx != NULL);
|
||||
|
||||
/* init */
|
||||
memset(&benchResult, 0, sizeof(benchResult));
|
||||
if (strlen(displayName)>17) displayName += strlen(displayName) - 17; /* display last 17 characters */
|
||||
if (strlen(displayName) > 17)
|
||||
displayName +=
|
||||
strlen(displayName) - 17; /* display last 17 characters */
|
||||
if (adv->mode == BMK_decodeOnly) {
|
||||
/* benchmark only decompression : source must be already compressed */
|
||||
const char* srcPtr = (const char*)srcBuffer;
|
||||
U64 totalDSize64 = 0;
|
||||
U64 totalDSize64 = 0;
|
||||
U32 fileNb;
|
||||
for (fileNb=0; fileNb<nbFiles; fileNb++) {
|
||||
U64 const fSize64 = ZSTD_findDecompressedSize(srcPtr, fileSizes[fileNb]);
|
||||
for (fileNb = 0; fileNb < nbFiles; fileNb++) {
|
||||
U64 const fSize64 =
|
||||
ZSTD_findDecompressedSize(srcPtr, fileSizes[fileNb]);
|
||||
if (fSize64 == ZSTD_CONTENTSIZE_UNKNOWN) {
|
||||
RETURN_ERROR(32, BMK_benchOutcome_t, "Decompressed size cannot be determined: cannot benchmark");
|
||||
RETURN_ERROR(
|
||||
32,
|
||||
BMK_benchOutcome_t,
|
||||
"Decompressed size cannot be determined: cannot benchmark");
|
||||
}
|
||||
if (fSize64 == ZSTD_CONTENTSIZE_ERROR) {
|
||||
RETURN_ERROR(32, BMK_benchOutcome_t, "Error while trying to assess decompressed size: data may be invalid");
|
||||
RETURN_ERROR(
|
||||
32,
|
||||
BMK_benchOutcome_t,
|
||||
"Error while trying to assess decompressed size: data may be invalid");
|
||||
}
|
||||
totalDSize64 += fSize64;
|
||||
srcPtr += fileSizes[fileNb];
|
||||
}
|
||||
{ size_t const decodedSize = (size_t)totalDSize64;
|
||||
assert((U64)decodedSize == totalDSize64); /* check overflow */
|
||||
{
|
||||
size_t const decodedSize = (size_t)totalDSize64;
|
||||
assert((U64)decodedSize == totalDSize64); /* check overflow */
|
||||
free(*resultBufferPtr);
|
||||
if (totalDSize64 > decodedSize) { /* size_t overflow */
|
||||
RETURN_ERROR(32, BMK_benchOutcome_t, "decompressed size is too large for local system");
|
||||
if (totalDSize64 > decodedSize) { /* size_t overflow */
|
||||
RETURN_ERROR(
|
||||
32,
|
||||
BMK_benchOutcome_t,
|
||||
"decompressed size is too large for local system");
|
||||
}
|
||||
*resultBufferPtr = malloc(decodedSize);
|
||||
if (!(*resultBufferPtr)) {
|
||||
RETURN_ERROR(33, BMK_benchOutcome_t, "allocation error: not enough memory");
|
||||
RETURN_ERROR(
|
||||
33,
|
||||
BMK_benchOutcome_t,
|
||||
"allocation error: not enough memory");
|
||||
}
|
||||
cSize = srcSize;
|
||||
cSize = srcSize;
|
||||
srcSize = decodedSize;
|
||||
ratio = (double)srcSize / (double)cSize;
|
||||
ratio = (double)srcSize / (double)cSize;
|
||||
}
|
||||
}
|
||||
|
||||
/* Init data blocks */
|
||||
{ const char* srcPtr = (const char*)srcBuffer;
|
||||
char* cPtr = (char*)compressedBuffer;
|
||||
char* resPtr = (char*)(*resultBufferPtr);
|
||||
{
|
||||
const char* srcPtr = (const char*)srcBuffer;
|
||||
char* cPtr = (char*)compressedBuffer;
|
||||
char* resPtr = (char*)(*resultBufferPtr);
|
||||
U32 fileNb;
|
||||
for (nbBlocks=0, fileNb=0; fileNb<nbFiles; fileNb++) {
|
||||
size_t remaining = fileSizes[fileNb];
|
||||
U32 const nbBlocksforThisFile = (adv->mode == BMK_decodeOnly) ? 1 : (U32)((remaining + (blockSize-1)) / blockSize);
|
||||
U32 const blockEnd = nbBlocks + nbBlocksforThisFile;
|
||||
for ( ; nbBlocks<blockEnd; nbBlocks++) {
|
||||
for (nbBlocks = 0, fileNb = 0; fileNb < nbFiles; fileNb++) {
|
||||
size_t remaining = fileSizes[fileNb];
|
||||
U32 const nbBlocksforThisFile = (adv->mode == BMK_decodeOnly)
|
||||
? 1
|
||||
: (U32)((remaining + (blockSize - 1)) / blockSize);
|
||||
U32 const blockEnd = nbBlocks + nbBlocksforThisFile;
|
||||
for (; nbBlocks < blockEnd; nbBlocks++) {
|
||||
size_t const thisBlockSize = MIN(remaining, blockSize);
|
||||
srcPtrs[nbBlocks] = srcPtr;
|
||||
srcSizes[nbBlocks] = thisBlockSize;
|
||||
cPtrs[nbBlocks] = cPtr;
|
||||
cCapacities[nbBlocks] = (adv->mode == BMK_decodeOnly) ? thisBlockSize : ZSTD_compressBound(thisBlockSize);
|
||||
resPtrs[nbBlocks] = resPtr;
|
||||
resSizes[nbBlocks] = (adv->mode == BMK_decodeOnly) ? (size_t) ZSTD_findDecompressedSize(srcPtr, thisBlockSize) : thisBlockSize;
|
||||
srcPtrs[nbBlocks] = srcPtr;
|
||||
srcSizes[nbBlocks] = thisBlockSize;
|
||||
cPtrs[nbBlocks] = cPtr;
|
||||
cCapacities[nbBlocks] = (adv->mode == BMK_decodeOnly)
|
||||
? thisBlockSize
|
||||
: ZSTD_compressBound(thisBlockSize);
|
||||
resPtrs[nbBlocks] = resPtr;
|
||||
resSizes[nbBlocks] = (adv->mode == BMK_decodeOnly)
|
||||
? (size_t)ZSTD_findDecompressedSize(
|
||||
srcPtr, thisBlockSize)
|
||||
: thisBlockSize;
|
||||
srcPtr += thisBlockSize;
|
||||
cPtr += cCapacities[nbBlocks];
|
||||
resPtr += thisBlockSize;
|
||||
remaining -= thisBlockSize;
|
||||
if (adv->mode == BMK_decodeOnly) {
|
||||
cSizes[nbBlocks] = thisBlockSize;
|
||||
cSizes[nbBlocks] = thisBlockSize;
|
||||
benchResult.cSize = thisBlockSize;
|
||||
} } } }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* warming up `compressedBuffer` */
|
||||
if (adv->mode == BMK_decodeOnly) {
|
||||
@@ -393,236 +536,329 @@ BMK_benchMemAdvancedNoAlloc(
|
||||
}
|
||||
|
||||
if (!UTIL_support_MT_measurements() && adv->nbWorkers > 1) {
|
||||
OUTPUTLEVEL(2, "Warning : time measurements may be incorrect in multithreading mode... \n")
|
||||
OUTPUTLEVEL(
|
||||
2,
|
||||
"Warning : time measurements may be incorrect in multithreading mode... \n")
|
||||
}
|
||||
|
||||
/* Bench */
|
||||
{ U64 const crcOrig = (adv->mode == BMK_decodeOnly) ? 0 : XXH64(srcBuffer, srcSize, 0);
|
||||
# define NB_MARKS 4
|
||||
{
|
||||
U64 const crcOrig = (adv->mode == BMK_decodeOnly)
|
||||
? 0
|
||||
: XXH64(srcBuffer, srcSize, 0);
|
||||
#define NB_MARKS 4
|
||||
const char* marks[NB_MARKS] = { " |", " /", " =", " \\" };
|
||||
U32 markNb = 0;
|
||||
int compressionCompleted = (adv->mode == BMK_decodeOnly);
|
||||
int decompressionCompleted = (adv->mode == BMK_compressOnly);
|
||||
U32 markNb = 0;
|
||||
int compressionCompleted = (adv->mode == BMK_decodeOnly);
|
||||
int decompressionCompleted = (adv->mode == BMK_compressOnly);
|
||||
BMK_benchParams_t cbp, dbp;
|
||||
BMK_initCCtxArgs cctxprep;
|
||||
BMK_initDCtxArgs dctxprep;
|
||||
|
||||
cbp.benchFn = local_defaultCompress; /* ZSTD_compress2 */
|
||||
cbp.benchPayload = cctx;
|
||||
cbp.initFn = local_initCCtx; /* BMK_initCCtx */
|
||||
cbp.initPayload = &cctxprep;
|
||||
cbp.errorFn = ZSTD_isError;
|
||||
cbp.blockCount = nbBlocks;
|
||||
cbp.srcBuffers = srcPtrs;
|
||||
cbp.srcSizes = srcSizes;
|
||||
cbp.dstBuffers = cPtrs;
|
||||
cbp.benchFn = local_defaultCompress; /* ZSTD_compress2 */
|
||||
cbp.benchPayload = cctx;
|
||||
cbp.initFn = local_initCCtx; /* BMK_initCCtx */
|
||||
cbp.initPayload = &cctxprep;
|
||||
cbp.errorFn = ZSTD_isError;
|
||||
cbp.blockCount = nbBlocks;
|
||||
cbp.srcBuffers = srcPtrs;
|
||||
cbp.srcSizes = srcSizes;
|
||||
cbp.dstBuffers = cPtrs;
|
||||
cbp.dstCapacities = cCapacities;
|
||||
cbp.blockResults = cSizes;
|
||||
cbp.blockResults = cSizes;
|
||||
|
||||
cctxprep.cctx = cctx;
|
||||
cctxprep.dictBuffer = dictBuffer;
|
||||
cctxprep.cctx = cctx;
|
||||
cctxprep.dictBuffer = dictBuffer;
|
||||
cctxprep.dictBufferSize = dictBufferSize;
|
||||
cctxprep.cLevel = cLevel;
|
||||
cctxprep.comprParams = comprParams;
|
||||
cctxprep.adv = adv;
|
||||
cctxprep.cLevel = cLevel;
|
||||
cctxprep.comprParams = comprParams;
|
||||
cctxprep.adv = adv;
|
||||
|
||||
dbp.benchFn = local_defaultDecompress;
|
||||
dbp.benchPayload = dctx;
|
||||
dbp.initFn = local_initDCtx;
|
||||
dbp.initPayload = &dctxprep;
|
||||
dbp.errorFn = ZSTD_isError;
|
||||
dbp.blockCount = nbBlocks;
|
||||
dbp.srcBuffers = (const void* const *) cPtrs;
|
||||
dbp.srcSizes = cSizes;
|
||||
dbp.dstBuffers = resPtrs;
|
||||
dbp.benchFn = local_defaultDecompress;
|
||||
dbp.benchPayload = dctx;
|
||||
dbp.initFn = local_initDCtx;
|
||||
dbp.initPayload = &dctxprep;
|
||||
dbp.errorFn = ZSTD_isError;
|
||||
dbp.blockCount = nbBlocks;
|
||||
dbp.srcBuffers = (const void* const*)cPtrs;
|
||||
dbp.srcSizes = cSizes;
|
||||
dbp.dstBuffers = resPtrs;
|
||||
dbp.dstCapacities = resSizes;
|
||||
dbp.blockResults = NULL;
|
||||
dbp.blockResults = NULL;
|
||||
|
||||
dctxprep.dctx = dctx;
|
||||
dctxprep.dictBuffer = dictBuffer;
|
||||
dctxprep.dctx = dctx;
|
||||
dctxprep.dictBuffer = dictBuffer;
|
||||
dctxprep.dictBufferSize = dictBufferSize;
|
||||
|
||||
OUTPUTLEVEL(2, "\r%70s\r", ""); /* blank line */
|
||||
OUTPUTLEVEL(2, "\r%70s\r", ""); /* blank line */
|
||||
assert(srcSize < UINT_MAX);
|
||||
OUTPUTLEVEL(2, "%2s-%-17.17s :%10u -> \r", marks[markNb], displayName, (unsigned)srcSize);
|
||||
OUTPUTLEVEL(
|
||||
2,
|
||||
"%2s-%-17.17s :%10u -> \r",
|
||||
marks[markNb],
|
||||
displayName,
|
||||
(unsigned)srcSize);
|
||||
|
||||
while (!(compressionCompleted && decompressionCompleted)) {
|
||||
if (!compressionCompleted) {
|
||||
BMK_runOutcome_t const cOutcome = BMK_benchTimedFn( timeStateCompress, cbp);
|
||||
BMK_runOutcome_t const cOutcome =
|
||||
BMK_benchTimedFn(timeStateCompress, cbp);
|
||||
|
||||
if (!BMK_isSuccessful_runOutcome(cOutcome)) {
|
||||
RETURN_ERROR(30, BMK_benchOutcome_t, "compression error");
|
||||
}
|
||||
|
||||
{ BMK_runTime_t const cResult = BMK_extract_runTime(cOutcome);
|
||||
cSize = cResult.sumOfReturn;
|
||||
{
|
||||
BMK_runTime_t const cResult = BMK_extract_runTime(cOutcome);
|
||||
cSize = cResult.sumOfReturn;
|
||||
ratio = (double)srcSize / (double)cSize;
|
||||
{ BMK_benchResult_t newResult;
|
||||
newResult.cSpeed = (U64)((double)srcSize * TIMELOOP_NANOSEC / cResult.nanoSecPerRun);
|
||||
{
|
||||
BMK_benchResult_t newResult;
|
||||
newResult.cSpeed =
|
||||
(U64)((double)srcSize * TIMELOOP_NANOSEC
|
||||
/ cResult.nanoSecPerRun);
|
||||
benchResult.cSize = cSize;
|
||||
if (newResult.cSpeed > benchResult.cSpeed)
|
||||
benchResult.cSpeed = newResult.cSpeed;
|
||||
} }
|
||||
|
||||
{ int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
|
||||
assert(cSize < UINT_MAX);
|
||||
OUTPUTLEVEL(2, "%2s-%-17.17s :%10u ->%10u (x%5.*f), %6.*f MB/s \r",
|
||||
marks[markNb], displayName,
|
||||
(unsigned)srcSize, (unsigned)cSize,
|
||||
ratioAccuracy, ratio,
|
||||
benchResult.cSpeed < (10 * MB_UNIT) ? 2 : 1, (double)benchResult.cSpeed / MB_UNIT);
|
||||
}
|
||||
}
|
||||
compressionCompleted = BMK_isCompleted_TimedFn(timeStateCompress);
|
||||
|
||||
{
|
||||
int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
|
||||
assert(cSize < UINT_MAX);
|
||||
OUTPUTLEVEL(
|
||||
2,
|
||||
"%2s-%-17.17s :%10u ->%10u (x%5.*f), %6.*f MB/s \r",
|
||||
marks[markNb],
|
||||
displayName,
|
||||
(unsigned)srcSize,
|
||||
(unsigned)cSize,
|
||||
ratioAccuracy,
|
||||
ratio,
|
||||
benchResult.cSpeed < (10 * MB_UNIT) ? 2 : 1,
|
||||
(double)benchResult.cSpeed / MB_UNIT);
|
||||
}
|
||||
compressionCompleted =
|
||||
BMK_isCompleted_TimedFn(timeStateCompress);
|
||||
}
|
||||
|
||||
if(!decompressionCompleted) {
|
||||
BMK_runOutcome_t const dOutcome = BMK_benchTimedFn(timeStateDecompress, dbp);
|
||||
if (!decompressionCompleted) {
|
||||
BMK_runOutcome_t const dOutcome =
|
||||
BMK_benchTimedFn(timeStateDecompress, dbp);
|
||||
|
||||
if(!BMK_isSuccessful_runOutcome(dOutcome)) {
|
||||
if (!BMK_isSuccessful_runOutcome(dOutcome)) {
|
||||
RETURN_ERROR(30, BMK_benchOutcome_t, "decompression error");
|
||||
}
|
||||
|
||||
{ BMK_runTime_t const dResult = BMK_extract_runTime(dOutcome);
|
||||
U64 const newDSpeed = (U64)((double)srcSize * TIMELOOP_NANOSEC / dResult.nanoSecPerRun);
|
||||
{
|
||||
BMK_runTime_t const dResult = BMK_extract_runTime(dOutcome);
|
||||
U64 const newDSpeed =
|
||||
(U64)((double)srcSize * TIMELOOP_NANOSEC
|
||||
/ dResult.nanoSecPerRun);
|
||||
if (newDSpeed > benchResult.dSpeed)
|
||||
benchResult.dSpeed = newDSpeed;
|
||||
}
|
||||
|
||||
{ int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
|
||||
OUTPUTLEVEL(2, "%2s-%-17.17s :%10u ->%10u (x%5.*f), %6.*f MB/s, %6.1f MB/s\r",
|
||||
marks[markNb], displayName,
|
||||
(unsigned)srcSize, (unsigned)cSize,
|
||||
ratioAccuracy, ratio,
|
||||
benchResult.cSpeed < (10 * MB_UNIT) ? 2 : 1, (double)benchResult.cSpeed / MB_UNIT,
|
||||
{
|
||||
int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
|
||||
OUTPUTLEVEL(
|
||||
2,
|
||||
"%2s-%-17.17s :%10u ->%10u (x%5.*f), %6.*f MB/s, %6.1f MB/s\r",
|
||||
marks[markNb],
|
||||
displayName,
|
||||
(unsigned)srcSize,
|
||||
(unsigned)cSize,
|
||||
ratioAccuracy,
|
||||
ratio,
|
||||
benchResult.cSpeed < (10 * MB_UNIT) ? 2 : 1,
|
||||
(double)benchResult.cSpeed / MB_UNIT,
|
||||
(double)benchResult.dSpeed / MB_UNIT);
|
||||
}
|
||||
decompressionCompleted = BMK_isCompleted_TimedFn(timeStateDecompress);
|
||||
decompressionCompleted =
|
||||
BMK_isCompleted_TimedFn(timeStateDecompress);
|
||||
}
|
||||
markNb = (markNb+1) % NB_MARKS;
|
||||
} /* while (!(compressionCompleted && decompressionCompleted)) */
|
||||
markNb = (markNb + 1) % NB_MARKS;
|
||||
} /* while (!(compressionCompleted && decompressionCompleted)) */
|
||||
|
||||
/* CRC Checking */
|
||||
{ const BYTE* resultBuffer = (const BYTE*)(*resultBufferPtr);
|
||||
U64 const crcCheck = XXH64(resultBuffer, srcSize, 0);
|
||||
if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) {
|
||||
{
|
||||
const BYTE* resultBuffer = (const BYTE*)(*resultBufferPtr);
|
||||
U64 const crcCheck = XXH64(resultBuffer, srcSize, 0);
|
||||
if ((adv->mode == BMK_both) && (crcOrig != crcCheck)) {
|
||||
size_t u;
|
||||
DISPLAY("!!! WARNING !!! %14s : Invalid Checksum : %x != %x \n",
|
||||
displayName, (unsigned)crcOrig, (unsigned)crcCheck);
|
||||
for (u=0; u<srcSize; u++) {
|
||||
displayName,
|
||||
(unsigned)crcOrig,
|
||||
(unsigned)crcCheck);
|
||||
for (u = 0; u < srcSize; u++) {
|
||||
if (((const BYTE*)srcBuffer)[u] != resultBuffer[u]) {
|
||||
unsigned segNb, bNb, pos;
|
||||
size_t bacc = 0;
|
||||
DISPLAY("Decoding error at pos %u ", (unsigned)u);
|
||||
for (segNb = 0; segNb < nbBlocks; segNb++) {
|
||||
if (bacc + srcSizes[segNb] > u) break;
|
||||
if (bacc + srcSizes[segNb] > u)
|
||||
break;
|
||||
bacc += srcSizes[segNb];
|
||||
}
|
||||
pos = (U32)(u - bacc);
|
||||
bNb = pos / (128 KB);
|
||||
DISPLAY("(sample %u, block %u, pos %u) \n", segNb, bNb, pos);
|
||||
{ size_t const lowest = (u>5) ? 5 : u;
|
||||
DISPLAY("(sample %u, block %u, pos %u) \n",
|
||||
segNb,
|
||||
bNb,
|
||||
pos);
|
||||
{
|
||||
size_t const lowest = (u > 5) ? 5 : u;
|
||||
size_t n;
|
||||
DISPLAY("origin: ");
|
||||
for (n=lowest; n>0; n--)
|
||||
DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u-n]);
|
||||
for (n = lowest; n > 0; n--)
|
||||
DISPLAY("%02X ",
|
||||
((const BYTE*)srcBuffer)[u - n]);
|
||||
DISPLAY(" :%02X: ", ((const BYTE*)srcBuffer)[u]);
|
||||
for (n=1; n<3; n++)
|
||||
DISPLAY("%02X ", ((const BYTE*)srcBuffer)[u+n]);
|
||||
for (n = 1; n < 3; n++)
|
||||
DISPLAY("%02X ",
|
||||
((const BYTE*)srcBuffer)[u + n]);
|
||||
DISPLAY(" \n");
|
||||
DISPLAY("decode: ");
|
||||
for (n=lowest; n>0; n--)
|
||||
DISPLAY("%02X ", resultBuffer[u-n]);
|
||||
for (n = lowest; n > 0; n--)
|
||||
DISPLAY("%02X ", resultBuffer[u - n]);
|
||||
DISPLAY(" :%02X: ", resultBuffer[u]);
|
||||
for (n=1; n<3; n++)
|
||||
DISPLAY("%02X ", resultBuffer[u+n]);
|
||||
for (n = 1; n < 3; n++)
|
||||
DISPLAY("%02X ", resultBuffer[u + n]);
|
||||
DISPLAY(" \n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (u==srcSize-1) { /* should never happen */
|
||||
if (u == srcSize - 1) { /* should never happen */
|
||||
DISPLAY("no difference detected\n");
|
||||
}
|
||||
} /* for (u=0; u<srcSize; u++) */
|
||||
} /* if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) */
|
||||
} /* CRC Checking */
|
||||
} /* for (u=0; u<srcSize; u++) */
|
||||
} /* if ((adv->mode == BMK_both) && (crcOrig!=crcCheck)) */
|
||||
} /* CRC Checking */
|
||||
|
||||
if (displayLevel == 1) { /* hidden display mode -q, used by python speed benchmark */
|
||||
if (displayLevel
|
||||
== 1) { /* hidden display mode -q, used by python speed benchmark */
|
||||
double const cSpeed = (double)benchResult.cSpeed / MB_UNIT;
|
||||
double const dSpeed = (double)benchResult.dSpeed / MB_UNIT;
|
||||
if (adv->additionalParam) {
|
||||
OUTPUT("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s (param=%d)\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName, adv->additionalParam);
|
||||
OUTPUT("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s (param=%d)\n",
|
||||
cLevel,
|
||||
(int)cSize,
|
||||
ratio,
|
||||
cSpeed,
|
||||
dSpeed,
|
||||
displayName,
|
||||
adv->additionalParam);
|
||||
} else {
|
||||
OUTPUT("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s\n", cLevel, (int)cSize, ratio, cSpeed, dSpeed, displayName);
|
||||
OUTPUT("-%-3i%11i (%5.3f) %6.2f MB/s %6.1f MB/s %s\n",
|
||||
cLevel,
|
||||
(int)cSize,
|
||||
ratio,
|
||||
cSpeed,
|
||||
dSpeed,
|
||||
displayName);
|
||||
}
|
||||
}
|
||||
|
||||
OUTPUTLEVEL(2, "%2i#\n", cLevel);
|
||||
} /* Bench */
|
||||
} /* Bench */
|
||||
|
||||
benchResult.cMem = (1ULL << (comprParams->windowLog)) + ZSTD_sizeof_CCtx(cctx);
|
||||
benchResult.cMem =
|
||||
(1ULL << (comprParams->windowLog)) + ZSTD_sizeof_CCtx(cctx);
|
||||
return BMK_benchOutcome_setValidResult(benchResult);
|
||||
}
|
||||
|
||||
BMK_benchOutcome_t BMK_benchMemAdvanced(const void* srcBuffer, size_t srcSize,
|
||||
void* dstBuffer, size_t dstCapacity,
|
||||
const size_t* fileSizes, unsigned nbFiles,
|
||||
int cLevel, const ZSTD_compressionParameters* comprParams,
|
||||
const void* dictBuffer, size_t dictBufferSize,
|
||||
int displayLevel, const char* displayName, const BMK_advancedParams_t* adv)
|
||||
BMK_benchOutcome_t BMK_benchMemAdvanced(
|
||||
const void* srcBuffer,
|
||||
size_t srcSize,
|
||||
void* dstBuffer,
|
||||
size_t dstCapacity,
|
||||
const size_t* fileSizes,
|
||||
unsigned nbFiles,
|
||||
int cLevel,
|
||||
const ZSTD_compressionParameters* comprParams,
|
||||
const void* dictBuffer,
|
||||
size_t dictBufferSize,
|
||||
int displayLevel,
|
||||
const char* displayName,
|
||||
const BMK_advancedParams_t* adv)
|
||||
|
||||
{
|
||||
int const dstParamsError = !dstBuffer ^ !dstCapacity; /* must be both NULL or none */
|
||||
int const dstParamsError =
|
||||
!dstBuffer ^ !dstCapacity; /* must be both NULL or none */
|
||||
|
||||
size_t const blockSize = ((adv->blockSize>=32 && (adv->mode != BMK_decodeOnly)) ? adv->blockSize : srcSize) + (!srcSize) /* avoid div by 0 */ ;
|
||||
U32 const maxNbBlocks = (U32) ((srcSize + (blockSize-1)) / blockSize) + nbFiles;
|
||||
size_t const blockSize =
|
||||
((adv->blockSize >= 32 && (adv->mode != BMK_decodeOnly))
|
||||
? adv->blockSize
|
||||
: srcSize)
|
||||
+ (!srcSize) /* avoid div by 0 */;
|
||||
U32 const maxNbBlocks =
|
||||
(U32)((srcSize + (blockSize - 1)) / blockSize) + nbFiles;
|
||||
|
||||
/* these are the blockTable parameters, just split up */
|
||||
const void ** const srcPtrs = (const void**)malloc(maxNbBlocks * sizeof(void*));
|
||||
const void** const srcPtrs =
|
||||
(const void**)malloc(maxNbBlocks * sizeof(void*));
|
||||
size_t* const srcSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
|
||||
|
||||
|
||||
void ** const cPtrs = (void**)malloc(maxNbBlocks * sizeof(void*));
|
||||
size_t* const cSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
|
||||
void** const cPtrs = (void**)malloc(maxNbBlocks * sizeof(void*));
|
||||
size_t* const cSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
|
||||
size_t* const cCapacities = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
|
||||
|
||||
void ** const resPtrs = (void**)malloc(maxNbBlocks * sizeof(void*));
|
||||
void** const resPtrs = (void**)malloc(maxNbBlocks * sizeof(void*));
|
||||
size_t* const resSizes = (size_t*)malloc(maxNbBlocks * sizeof(size_t));
|
||||
|
||||
BMK_timedFnState_t* timeStateCompress = BMK_createTimedFnState(adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
|
||||
BMK_timedFnState_t* timeStateDecompress = BMK_createTimedFnState(adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
|
||||
BMK_timedFnState_t* timeStateCompress = BMK_createTimedFnState(
|
||||
adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
|
||||
BMK_timedFnState_t* timeStateDecompress = BMK_createTimedFnState(
|
||||
adv->nbSeconds * 1000, BMK_RUNTEST_DEFAULT_MS);
|
||||
|
||||
ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||
ZSTD_DCtx* const dctx = ZSTD_createDCtx();
|
||||
|
||||
const size_t maxCompressedSize = dstCapacity ? dstCapacity : ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024);
|
||||
const size_t maxCompressedSize = dstCapacity
|
||||
? dstCapacity
|
||||
: ZSTD_compressBound(srcSize) + (maxNbBlocks * 1024);
|
||||
|
||||
void* const internalDstBuffer = dstBuffer ? NULL : malloc(maxCompressedSize);
|
||||
void* const internalDstBuffer =
|
||||
dstBuffer ? NULL : malloc(maxCompressedSize);
|
||||
void* const compressedBuffer = dstBuffer ? dstBuffer : internalDstBuffer;
|
||||
|
||||
BMK_benchOutcome_t outcome = BMK_benchOutcome_error(); /* error by default */
|
||||
BMK_benchOutcome_t outcome =
|
||||
BMK_benchOutcome_error(); /* error by default */
|
||||
|
||||
void* resultBuffer = srcSize ? malloc(srcSize) : NULL;
|
||||
|
||||
int const allocationincomplete = !srcPtrs || !srcSizes || !cPtrs ||
|
||||
!cSizes || !cCapacities || !resPtrs || !resSizes ||
|
||||
!timeStateCompress || !timeStateDecompress ||
|
||||
!cctx || !dctx ||
|
||||
!compressedBuffer || !resultBuffer;
|
||||
|
||||
int const allocationincomplete = !srcPtrs || !srcSizes || !cPtrs || !cSizes
|
||||
|| !cCapacities || !resPtrs || !resSizes || !timeStateCompress
|
||||
|| !timeStateDecompress || !cctx || !dctx || !compressedBuffer
|
||||
|| !resultBuffer;
|
||||
|
||||
if (!allocationincomplete && !dstParamsError) {
|
||||
outcome = BMK_benchMemAdvancedNoAlloc(srcPtrs, srcSizes,
|
||||
cPtrs, cCapacities, cSizes,
|
||||
resPtrs, resSizes,
|
||||
&resultBuffer,
|
||||
compressedBuffer, maxCompressedSize,
|
||||
timeStateCompress, timeStateDecompress,
|
||||
srcBuffer, srcSize,
|
||||
fileSizes, nbFiles,
|
||||
cLevel, comprParams,
|
||||
dictBuffer, dictBufferSize,
|
||||
cctx, dctx,
|
||||
displayLevel, displayName, adv);
|
||||
outcome = BMK_benchMemAdvancedNoAlloc(
|
||||
srcPtrs,
|
||||
srcSizes,
|
||||
cPtrs,
|
||||
cCapacities,
|
||||
cSizes,
|
||||
resPtrs,
|
||||
resSizes,
|
||||
&resultBuffer,
|
||||
compressedBuffer,
|
||||
maxCompressedSize,
|
||||
timeStateCompress,
|
||||
timeStateDecompress,
|
||||
srcBuffer,
|
||||
srcSize,
|
||||
fileSizes,
|
||||
nbFiles,
|
||||
cLevel,
|
||||
comprParams,
|
||||
dictBuffer,
|
||||
dictBufferSize,
|
||||
cctx,
|
||||
dctx,
|
||||
displayLevel,
|
||||
displayName,
|
||||
adv);
|
||||
}
|
||||
|
||||
/* clean up */
|
||||
@@ -643,66 +879,104 @@ BMK_benchOutcome_t BMK_benchMemAdvanced(const void* srcBuffer, size_t srcSize,
|
||||
free(resPtrs);
|
||||
free(resSizes);
|
||||
|
||||
if(allocationincomplete) {
|
||||
RETURN_ERROR(31, BMK_benchOutcome_t, "allocation error : not enough memory");
|
||||
if (allocationincomplete) {
|
||||
RETURN_ERROR(
|
||||
31, BMK_benchOutcome_t, "allocation error : not enough memory");
|
||||
}
|
||||
|
||||
if(dstParamsError) {
|
||||
if (dstParamsError) {
|
||||
RETURN_ERROR(32, BMK_benchOutcome_t, "Dst parameters not coherent");
|
||||
}
|
||||
return outcome;
|
||||
}
|
||||
|
||||
BMK_benchOutcome_t BMK_benchMem(const void* srcBuffer, size_t srcSize,
|
||||
const size_t* fileSizes, unsigned nbFiles,
|
||||
int cLevel, const ZSTD_compressionParameters* comprParams,
|
||||
const void* dictBuffer, size_t dictBufferSize,
|
||||
int displayLevel, const char* displayName) {
|
||||
|
||||
BMK_benchOutcome_t BMK_benchMem(
|
||||
const void* srcBuffer,
|
||||
size_t srcSize,
|
||||
const size_t* fileSizes,
|
||||
unsigned nbFiles,
|
||||
int cLevel,
|
||||
const ZSTD_compressionParameters* comprParams,
|
||||
const void* dictBuffer,
|
||||
size_t dictBufferSize,
|
||||
int displayLevel,
|
||||
const char* displayName)
|
||||
{
|
||||
BMK_advancedParams_t const adv = BMK_initAdvancedParams();
|
||||
return BMK_benchMemAdvanced(srcBuffer, srcSize,
|
||||
NULL, 0,
|
||||
fileSizes, nbFiles,
|
||||
cLevel, comprParams,
|
||||
dictBuffer, dictBufferSize,
|
||||
displayLevel, displayName, &adv);
|
||||
return BMK_benchMemAdvanced(
|
||||
srcBuffer,
|
||||
srcSize,
|
||||
NULL,
|
||||
0,
|
||||
fileSizes,
|
||||
nbFiles,
|
||||
cLevel,
|
||||
comprParams,
|
||||
dictBuffer,
|
||||
dictBufferSize,
|
||||
displayLevel,
|
||||
displayName,
|
||||
&adv);
|
||||
}
|
||||
|
||||
static BMK_benchOutcome_t BMK_benchCLevel(const void* srcBuffer, size_t benchedSize,
|
||||
const size_t* fileSizes, unsigned nbFiles,
|
||||
int cLevel, const ZSTD_compressionParameters* comprParams,
|
||||
const void* dictBuffer, size_t dictBufferSize,
|
||||
int displayLevel, const char* displayName,
|
||||
BMK_advancedParams_t const * const adv)
|
||||
static BMK_benchOutcome_t BMK_benchCLevel(
|
||||
const void* srcBuffer,
|
||||
size_t benchedSize,
|
||||
const size_t* fileSizes,
|
||||
unsigned nbFiles,
|
||||
int cLevel,
|
||||
const ZSTD_compressionParameters* comprParams,
|
||||
const void* dictBuffer,
|
||||
size_t dictBufferSize,
|
||||
int displayLevel,
|
||||
const char* displayName,
|
||||
BMK_advancedParams_t const* const adv)
|
||||
{
|
||||
const char* pch = strrchr(displayName, '\\'); /* Windows */
|
||||
if (!pch) pch = strrchr(displayName, '/'); /* Linux */
|
||||
if (pch) displayName = pch+1;
|
||||
if (!pch)
|
||||
pch = strrchr(displayName, '/'); /* Linux */
|
||||
if (pch)
|
||||
displayName = pch + 1;
|
||||
|
||||
if (adv->realTime) {
|
||||
DISPLAYLEVEL(2, "Note : switching to real-time priority \n");
|
||||
SET_REALTIME_PRIORITY;
|
||||
}
|
||||
|
||||
if (displayLevel == 1 && !adv->additionalParam) /* --quiet mode */
|
||||
if (displayLevel == 1 && !adv->additionalParam) /* --quiet mode */
|
||||
OUTPUT("bench %s %s: input %u bytes, %u seconds, %u KB blocks\n",
|
||||
ZSTD_VERSION_STRING, ZSTD_GIT_COMMIT_STRING,
|
||||
(unsigned)benchedSize, adv->nbSeconds, (unsigned)(adv->blockSize>>10));
|
||||
ZSTD_VERSION_STRING,
|
||||
ZSTD_GIT_COMMIT_STRING,
|
||||
(unsigned)benchedSize,
|
||||
adv->nbSeconds,
|
||||
(unsigned)(adv->blockSize >> 10));
|
||||
|
||||
return BMK_benchMemAdvanced(srcBuffer, benchedSize,
|
||||
NULL, 0,
|
||||
fileSizes, nbFiles,
|
||||
cLevel, comprParams,
|
||||
dictBuffer, dictBufferSize,
|
||||
displayLevel, displayName, adv);
|
||||
return BMK_benchMemAdvanced(
|
||||
srcBuffer,
|
||||
benchedSize,
|
||||
NULL,
|
||||
0,
|
||||
fileSizes,
|
||||
nbFiles,
|
||||
cLevel,
|
||||
comprParams,
|
||||
dictBuffer,
|
||||
dictBufferSize,
|
||||
displayLevel,
|
||||
displayName,
|
||||
adv);
|
||||
}
|
||||
|
||||
int BMK_syntheticTest(int cLevel, double compressibility,
|
||||
const ZSTD_compressionParameters* compressionParams,
|
||||
int displayLevel, const BMK_advancedParams_t* adv)
|
||||
int BMK_syntheticTest(
|
||||
int cLevel,
|
||||
double compressibility,
|
||||
const ZSTD_compressionParameters* compressionParams,
|
||||
int displayLevel,
|
||||
const BMK_advancedParams_t* adv)
|
||||
{
|
||||
char name[20] = {0};
|
||||
size_t const benchedSize = 10000000;
|
||||
char nameBuff[20] = { 0 };
|
||||
const char* name = nameBuff;
|
||||
size_t const benchedSize = adv->blockSize ? adv->blockSize : 10000000;
|
||||
void* srcBuffer;
|
||||
BMK_benchOutcome_t res;
|
||||
|
||||
@@ -719,15 +993,31 @@ int BMK_syntheticTest(int cLevel, double compressibility,
|
||||
}
|
||||
|
||||
/* Fill input buffer */
|
||||
RDG_genBuffer(srcBuffer, benchedSize, compressibility, 0.0, 0);
|
||||
if (compressibility < 0.0) {
|
||||
LOREM_genBuffer(srcBuffer, benchedSize, 0);
|
||||
name = "Lorem ipsum";
|
||||
} else {
|
||||
RDG_genBuffer(srcBuffer, benchedSize, compressibility, 0.0, 0);
|
||||
formatString_u(
|
||||
nameBuff,
|
||||
sizeof(nameBuff),
|
||||
"Synthetic %u%%",
|
||||
(unsigned)(compressibility * 100));
|
||||
}
|
||||
|
||||
/* Bench */
|
||||
snprintf (name, sizeof(name), "Synthetic %2u%%", (unsigned)(compressibility*100));
|
||||
res = BMK_benchCLevel(srcBuffer, benchedSize,
|
||||
&benchedSize /* ? */, 1 /* ? */,
|
||||
cLevel, compressionParams,
|
||||
NULL, 0, /* dictionary */
|
||||
displayLevel, name, adv);
|
||||
res = BMK_benchCLevel(
|
||||
srcBuffer,
|
||||
benchedSize,
|
||||
&benchedSize /* ? */,
|
||||
1 /* ? */,
|
||||
cLevel,
|
||||
compressionParams,
|
||||
NULL,
|
||||
0, /* dictionary */
|
||||
displayLevel,
|
||||
name,
|
||||
adv);
|
||||
|
||||
/* clean up */
|
||||
free(srcBuffer);
|
||||
@@ -735,16 +1025,15 @@ int BMK_syntheticTest(int cLevel, double compressibility,
|
||||
return !BMK_isSuccessful_benchOutcome(res);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static size_t BMK_findMaxMem(U64 requiredMem)
|
||||
{
|
||||
size_t const step = 64 MB;
|
||||
BYTE* testmem = NULL;
|
||||
BYTE* testmem = NULL;
|
||||
|
||||
requiredMem = (((requiredMem >> 26) + 1) << 26);
|
||||
requiredMem += step;
|
||||
if (requiredMem > maxMemory) requiredMem = maxMemory;
|
||||
if (requiredMem > maxMemory)
|
||||
requiredMem = maxMemory;
|
||||
|
||||
do {
|
||||
testmem = (BYTE*)malloc((size_t)requiredMem);
|
||||
@@ -758,53 +1047,75 @@ static size_t BMK_findMaxMem(U64 requiredMem)
|
||||
/*! BMK_loadFiles() :
|
||||
* Loads `buffer` with content of files listed within `fileNamesTable`.
|
||||
* At most, fills `buffer` entirely. */
|
||||
static int BMK_loadFiles(void* buffer, size_t bufferSize,
|
||||
size_t* fileSizes,
|
||||
const char* const * fileNamesTable, unsigned nbFiles,
|
||||
int displayLevel)
|
||||
static int BMK_loadFiles(
|
||||
void* buffer,
|
||||
size_t bufferSize,
|
||||
size_t* fileSizes,
|
||||
const char* const* fileNamesTable,
|
||||
unsigned nbFiles,
|
||||
int displayLevel)
|
||||
{
|
||||
size_t pos = 0, totalSize = 0;
|
||||
unsigned n;
|
||||
for (n=0; n<nbFiles; n++) {
|
||||
U64 fileSize = UTIL_getFileSize(fileNamesTable[n]); /* last file may be shortened */
|
||||
for (n = 0; n < nbFiles; n++) {
|
||||
U64 fileSize = UTIL_getFileSize(
|
||||
fileNamesTable[n]); /* last file may be shortened */
|
||||
if (UTIL_isDirectory(fileNamesTable[n])) {
|
||||
DISPLAYLEVEL(2, "Ignoring %s directory... \n", fileNamesTable[n]);
|
||||
DISPLAYLEVEL(
|
||||
2, "Ignoring %s directory... \n", fileNamesTable[n]);
|
||||
fileSizes[n] = 0;
|
||||
continue;
|
||||
}
|
||||
if (fileSize == UTIL_FILESIZE_UNKNOWN) {
|
||||
DISPLAYLEVEL(2, "Cannot evaluate size of %s, ignoring ... \n", fileNamesTable[n]);
|
||||
DISPLAYLEVEL(
|
||||
2,
|
||||
"Cannot evaluate size of %s, ignoring ... \n",
|
||||
fileNamesTable[n]);
|
||||
fileSizes[n] = 0;
|
||||
continue;
|
||||
}
|
||||
{ FILE* const f = fopen(fileNamesTable[n], "rb");
|
||||
if (f==NULL) RETURN_ERROR_INT(10, "impossible to open file %s", fileNamesTable[n]);
|
||||
{
|
||||
FILE* const f = fopen(fileNamesTable[n], "rb");
|
||||
if (f == NULL)
|
||||
RETURN_ERROR_INT(
|
||||
10, "impossible to open file %s", fileNamesTable[n]);
|
||||
OUTPUTLEVEL(2, "Loading %s... \r", fileNamesTable[n]);
|
||||
if (fileSize > bufferSize-pos) fileSize = bufferSize-pos, nbFiles=n; /* buffer too small - stop after this file */
|
||||
{ size_t const readSize = fread(((char*)buffer)+pos, 1, (size_t)fileSize, f);
|
||||
if (readSize != (size_t)fileSize) RETURN_ERROR_INT(11, "could not read %s", fileNamesTable[n]);
|
||||
if (fileSize > bufferSize - pos)
|
||||
fileSize = bufferSize - pos,
|
||||
nbFiles = n; /* buffer too small - stop after this file */
|
||||
{
|
||||
size_t const readSize =
|
||||
fread(((char*)buffer) + pos, 1, (size_t)fileSize, f);
|
||||
if (readSize != (size_t)fileSize)
|
||||
RETURN_ERROR_INT(
|
||||
11, "could not read %s", fileNamesTable[n]);
|
||||
pos += readSize;
|
||||
}
|
||||
fileSizes[n] = (size_t)fileSize;
|
||||
totalSize += (size_t)fileSize;
|
||||
fclose(f);
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
if (totalSize == 0) RETURN_ERROR_INT(12, "no data to bench");
|
||||
if (totalSize == 0)
|
||||
RETURN_ERROR_INT(12, "no data to bench");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BMK_benchFilesAdvanced(
|
||||
const char* const * fileNamesTable, unsigned nbFiles,
|
||||
const char* dictFileName, int cLevel,
|
||||
const ZSTD_compressionParameters* compressionParams,
|
||||
int displayLevel, const BMK_advancedParams_t* adv)
|
||||
const char* const* fileNamesTable,
|
||||
unsigned nbFiles,
|
||||
const char* dictFileName,
|
||||
int cLevel,
|
||||
const ZSTD_compressionParameters* compressionParams,
|
||||
int displayLevel,
|
||||
const BMK_advancedParams_t* adv)
|
||||
{
|
||||
void* srcBuffer = NULL;
|
||||
size_t benchedSize;
|
||||
void* dictBuffer = NULL;
|
||||
void* dictBuffer = NULL;
|
||||
size_t dictBufferSize = 0;
|
||||
size_t* fileSizes = NULL;
|
||||
size_t* fileSizes = NULL;
|
||||
BMK_benchOutcome_t res;
|
||||
U64 const totalSizeToLoad = UTIL_getTotalFileSize(fileNamesTable, nbFiles);
|
||||
|
||||
@@ -833,7 +1144,11 @@ int BMK_benchFilesAdvanced(
|
||||
if (dictFileName != NULL) {
|
||||
U64 const dictFileSize = UTIL_getFileSize(dictFileName);
|
||||
if (dictFileSize == UTIL_FILESIZE_UNKNOWN) {
|
||||
DISPLAYLEVEL(1, "error loading %s : %s \n", dictFileName, strerror(errno));
|
||||
DISPLAYLEVEL(
|
||||
1,
|
||||
"error loading %s : %s \n",
|
||||
dictFileName,
|
||||
strerror(errno));
|
||||
free(fileSizes);
|
||||
DISPLAYLEVEL(1, "benchmark aborted");
|
||||
return 17;
|
||||
@@ -844,28 +1159,38 @@ int BMK_benchFilesAdvanced(
|
||||
return 18;
|
||||
}
|
||||
dictBufferSize = (size_t)dictFileSize;
|
||||
dictBuffer = malloc(dictBufferSize);
|
||||
if (dictBuffer==NULL) {
|
||||
dictBuffer = malloc(dictBufferSize);
|
||||
if (dictBuffer == NULL) {
|
||||
free(fileSizes);
|
||||
DISPLAYLEVEL(1, "not enough memory for dictionary (%u bytes)",
|
||||
(unsigned)dictBufferSize);
|
||||
DISPLAYLEVEL(
|
||||
1,
|
||||
"not enough memory for dictionary (%u bytes)",
|
||||
(unsigned)dictBufferSize);
|
||||
return 19;
|
||||
}
|
||||
|
||||
{ int const errorCode = BMK_loadFiles(dictBuffer, dictBufferSize,
|
||||
fileSizes, &dictFileName /*?*/,
|
||||
1 /*?*/, displayLevel);
|
||||
{
|
||||
int const errorCode = BMK_loadFiles(
|
||||
dictBuffer,
|
||||
dictBufferSize,
|
||||
fileSizes,
|
||||
&dictFileName /*?*/,
|
||||
1 /*?*/,
|
||||
displayLevel);
|
||||
if (errorCode) {
|
||||
res = BMK_benchOutcome_error();
|
||||
goto _cleanUp;
|
||||
} }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Memory allocation & restrictions */
|
||||
benchedSize = BMK_findMaxMem(totalSizeToLoad * 3) / 3;
|
||||
if ((U64)benchedSize > totalSizeToLoad) benchedSize = (size_t)totalSizeToLoad;
|
||||
if ((U64)benchedSize > totalSizeToLoad)
|
||||
benchedSize = (size_t)totalSizeToLoad;
|
||||
if (benchedSize < totalSizeToLoad)
|
||||
DISPLAY("Not enough memory; testing %u MB only...\n", (unsigned)(benchedSize >> 20));
|
||||
DISPLAY("Not enough memory; testing %u MB only...\n",
|
||||
(unsigned)(benchedSize >> 20));
|
||||
|
||||
srcBuffer = benchedSize ? malloc(benchedSize) : NULL;
|
||||
if (!srcBuffer) {
|
||||
@@ -876,25 +1201,41 @@ int BMK_benchFilesAdvanced(
|
||||
}
|
||||
|
||||
/* Load input buffer */
|
||||
{ int const errorCode = BMK_loadFiles(srcBuffer, benchedSize,
|
||||
fileSizes, fileNamesTable, nbFiles,
|
||||
displayLevel);
|
||||
{
|
||||
int const errorCode = BMK_loadFiles(
|
||||
srcBuffer,
|
||||
benchedSize,
|
||||
fileSizes,
|
||||
fileNamesTable,
|
||||
nbFiles,
|
||||
displayLevel);
|
||||
if (errorCode) {
|
||||
res = BMK_benchOutcome_error();
|
||||
goto _cleanUp;
|
||||
} }
|
||||
}
|
||||
}
|
||||
|
||||
/* Bench */
|
||||
{ char mfName[20] = {0};
|
||||
snprintf (mfName, sizeof(mfName), " %u files", nbFiles);
|
||||
{ const char* const displayName = (nbFiles > 1) ? mfName : fileNamesTable[0];
|
||||
res = BMK_benchCLevel(srcBuffer, benchedSize,
|
||||
fileSizes, nbFiles,
|
||||
cLevel, compressionParams,
|
||||
dictBuffer, dictBufferSize,
|
||||
displayLevel, displayName,
|
||||
adv);
|
||||
} }
|
||||
{
|
||||
char mfName[20] = { 0 };
|
||||
formatString_u(mfName, sizeof(mfName), " %u files", nbFiles);
|
||||
{
|
||||
const char* const displayName =
|
||||
(nbFiles > 1) ? mfName : fileNamesTable[0];
|
||||
res = BMK_benchCLevel(
|
||||
srcBuffer,
|
||||
benchedSize,
|
||||
fileSizes,
|
||||
nbFiles,
|
||||
cLevel,
|
||||
compressionParams,
|
||||
dictBuffer,
|
||||
dictBufferSize,
|
||||
displayLevel,
|
||||
displayName,
|
||||
adv);
|
||||
}
|
||||
}
|
||||
|
||||
_cleanUp:
|
||||
free(srcBuffer);
|
||||
@@ -903,12 +1244,21 @@ _cleanUp:
|
||||
return !BMK_isSuccessful_benchOutcome(res);
|
||||
}
|
||||
|
||||
|
||||
int BMK_benchFiles(const char* const * fileNamesTable, unsigned nbFiles,
|
||||
const char* dictFileName,
|
||||
int cLevel, const ZSTD_compressionParameters* compressionParams,
|
||||
int displayLevel)
|
||||
int BMK_benchFiles(
|
||||
const char* const* fileNamesTable,
|
||||
unsigned nbFiles,
|
||||
const char* dictFileName,
|
||||
int cLevel,
|
||||
const ZSTD_compressionParameters* compressionParams,
|
||||
int displayLevel)
|
||||
{
|
||||
BMK_advancedParams_t const adv = BMK_initAdvancedParams();
|
||||
return BMK_benchFilesAdvanced(fileNamesTable, nbFiles, dictFileName, cLevel, compressionParams, displayLevel, &adv);
|
||||
return BMK_benchFilesAdvanced(
|
||||
fileNamesTable,
|
||||
nbFiles,
|
||||
dictFileName,
|
||||
cLevel,
|
||||
compressionParams,
|
||||
displayLevel,
|
||||
&adv);
|
||||
}
|
||||
|
||||
@@ -100,6 +100,7 @@ typedef struct {
|
||||
BMK_mode_t mode; /* 0: all, 1: compress only 2: decode only */
|
||||
unsigned nbSeconds; /* default timing is in nbSeconds */
|
||||
size_t blockSize; /* Maximum size of each block*/
|
||||
size_t targetCBlockSize;/* Approximative size of compressed blocks */
|
||||
int nbWorkers; /* multithreading */
|
||||
unsigned realTime; /* real time priority */
|
||||
int additionalParam; /* used by python speed benchmark */
|
||||
@@ -126,11 +127,12 @@ int BMK_benchFilesAdvanced(
|
||||
|
||||
/*! BMK_syntheticTest() -- called from zstdcli */
|
||||
/* Generates a sample with datagen, using compressibility argument */
|
||||
/* cLevel - compression level to benchmark, errors if invalid
|
||||
* compressibility - determines compressibility of sample
|
||||
* compressionParams - basic compression Parameters
|
||||
* displayLevel - see benchFiles
|
||||
* adv - see advanced_Params_t
|
||||
/* @cLevel - compression level to benchmark, errors if invalid
|
||||
* @compressibility - determines compressibility of sample, range [0.0 - 1.0]
|
||||
* if @compressibility < 0.0, uses the lorem ipsum generator
|
||||
* @compressionParams - basic compression Parameters
|
||||
* @displayLevel - see benchFiles
|
||||
* @adv - see advanced_Params_t
|
||||
* @return: 0 on success, !0 on error
|
||||
*/
|
||||
int BMK_syntheticTest(int cLevel, double compressibility,
|
||||
|
||||
+11
-11
@@ -1096,15 +1096,15 @@ static void FIO_adjustParamsForPatchFromMode(FIO_prefs_t* const prefs,
|
||||
comprParams->windowLog = MAX(ZSTD_WINDOWLOG_MIN, MIN(ZSTD_WINDOWLOG_MAX, fileWindowLog));
|
||||
if (fileWindowLog > ZSTD_cycleLog(cParams.chainLog, cParams.strategy)) {
|
||||
if (!prefs->ldmFlag)
|
||||
DISPLAYLEVEL(1, "long mode automatically triggered\n");
|
||||
DISPLAYLEVEL(2, "long mode automatically triggered\n");
|
||||
FIO_setLdmFlag(prefs, 1);
|
||||
}
|
||||
if (cParams.strategy >= ZSTD_btopt) {
|
||||
DISPLAYLEVEL(1, "[Optimal parser notes] Consider the following to improve patch size at the cost of speed:\n");
|
||||
DISPLAYLEVEL(1, "- Use --single-thread mode in the zstd cli\n");
|
||||
DISPLAYLEVEL(1, "- Set a larger targetLength (e.g. --zstd=targetLength=4096)\n");
|
||||
DISPLAYLEVEL(1, "- Set a larger chainLog (e.g. --zstd=chainLog=%u)\n", ZSTD_CHAINLOG_MAX);
|
||||
DISPLAYLEVEL(1, "Also consider playing around with searchLog and hashLog\n");
|
||||
DISPLAYLEVEL(3, "[Optimal parser notes] Consider the following to improve patch size at the cost of speed:\n");
|
||||
DISPLAYLEVEL(3, "- Use --single-thread mode in the zstd cli\n");
|
||||
DISPLAYLEVEL(3, "- Set a larger targetLength (e.g. --zstd=targetLength=4096)\n");
|
||||
DISPLAYLEVEL(3, "- Set a larger chainLog (e.g. --zstd=chainLog=%u)\n", ZSTD_CHAINLOG_MAX);
|
||||
DISPLAYLEVEL(3, "Also consider playing around with searchLog and hashLog\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1839,7 +1839,6 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx,
|
||||
int closeDstFile = 0;
|
||||
int result;
|
||||
int transferStat = 0;
|
||||
FILE *dstFile;
|
||||
int dstFd = -1;
|
||||
|
||||
assert(AIO_ReadPool_getFile(ress.readCtx) != NULL);
|
||||
@@ -1854,10 +1853,11 @@ static int FIO_compressFilename_dstFile(FIO_ctx_t* const fCtx,
|
||||
|
||||
closeDstFile = 1;
|
||||
DISPLAYLEVEL(6, "FIO_compressFilename_dstFile: opening dst: %s \n", dstFileName);
|
||||
dstFile = FIO_openDstFile(fCtx, prefs, srcFileName, dstFileName, dstFileInitialPermissions);
|
||||
if (dstFile==NULL) return 1; /* could not open dstFileName */
|
||||
dstFd = fileno(dstFile);
|
||||
AIO_WritePool_setFile(ress.writeCtx, dstFile);
|
||||
{ FILE *dstFile = FIO_openDstFile(fCtx, prefs, srcFileName, dstFileName, dstFileInitialPermissions);
|
||||
if (dstFile==NULL) return 1; /* could not open dstFileName */
|
||||
dstFd = fileno(dstFile);
|
||||
AIO_WritePool_setFile(ress.writeCtx, dstFile);
|
||||
}
|
||||
/* Must only be added after FIO_openDstFile() succeeds.
|
||||
* Otherwise we may delete the destination file if it already exists,
|
||||
* and the user presses Ctrl-C when asked if they wish to overwrite.
|
||||
|
||||
@@ -453,8 +453,8 @@ static IOJob_t* AIO_ReadPool_findNextWaitingOffsetCompletedJob_locked(ReadPoolCt
|
||||
/* AIO_ReadPool_numReadsInFlight:
|
||||
* Returns the number of IO read jobs currently in flight. */
|
||||
static size_t AIO_ReadPool_numReadsInFlight(ReadPoolCtx_t* ctx) {
|
||||
const size_t jobsHeld = (ctx->currentJobHeld==NULL ? 0 : 1);
|
||||
return ctx->base.totalIoJobs - (ctx->base.availableJobsCount + ctx->completedJobsCount + jobsHeld);
|
||||
const int jobsHeld = (ctx->currentJobHeld==NULL ? 0 : 1);
|
||||
return (size_t)(ctx->base.totalIoJobs - (ctx->base.availableJobsCount + ctx->completedJobsCount + jobsHeld));
|
||||
}
|
||||
|
||||
/* AIO_ReadPool_getNextCompletedJob:
|
||||
|
||||
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
/* Implementation notes:
|
||||
*
|
||||
* This is a very simple lorem ipsum generator
|
||||
* which features a static list of words
|
||||
* and print them one after another randomly
|
||||
* with a fake sentence / paragraph structure.
|
||||
*
|
||||
* The goal is to generate a printable text
|
||||
* that can be used to fake a text compression scenario.
|
||||
* The resulting compression / ratio curve of the lorem ipsum generator
|
||||
* is more satisfying than the previous statistical generator,
|
||||
* which was initially designed for entropy compression,
|
||||
* and lacks a regularity more representative of text.
|
||||
*
|
||||
* The compression ratio achievable on the generated lorem ipsum
|
||||
* is still a bit too good, presumably because the dictionary is a bit too
|
||||
* small. It would be possible to create some more complex scheme, notably by
|
||||
* enlarging the dictionary with a word generator, and adding grammatical rules
|
||||
* (composition) and syntax rules. But that's probably overkill for the intended
|
||||
* goal.
|
||||
*/
|
||||
|
||||
#include "lorem.h"
|
||||
#include <assert.h>
|
||||
#include <limits.h> /* INT_MAX */
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
#define WORD_MAX_SIZE 20
|
||||
|
||||
/* Define the word pool */
|
||||
static const char* kWords[] = {
|
||||
"lorem", "ipsum", "dolor", "sit", "amet",
|
||||
"consectetur", "adipiscing", "elit", "sed", "do",
|
||||
"eiusmod", "tempor", "incididunt", "ut", "labore",
|
||||
"et", "dolore", "magna", "aliqua", "dis",
|
||||
"lectus", "vestibulum", "mattis", "ullamcorper", "velit",
|
||||
"commodo", "a", "lacus", "arcu", "magnis",
|
||||
"parturient", "montes", "nascetur", "ridiculus", "mus",
|
||||
"mauris", "nulla", "malesuada", "pellentesque", "eget",
|
||||
"gravida", "in", "dictum", "non", "erat",
|
||||
"nam", "voluptat", "maecenas", "blandit", "aliquam",
|
||||
"etiam", "enim", "lobortis", "scelerisque", "fermentum",
|
||||
"dui", "faucibus", "ornare", "at", "elementum",
|
||||
"eu", "facilisis", "odio", "morbi", "quis",
|
||||
"eros", "donec", "ac", "orci", "purus",
|
||||
"turpis", "cursus", "leo", "vel", "porta",
|
||||
"consequat", "interdum", "varius", "vulputate", "aliquet",
|
||||
"pharetra", "nunc", "auctor", "urna", "id",
|
||||
"metus", "viverra", "nibh", "cras", "mi",
|
||||
"unde", "omnis", "iste", "natus", "error",
|
||||
"perspiciatis", "voluptatem", "accusantium", "doloremque", "laudantium",
|
||||
"totam", "rem", "aperiam", "eaque", "ipsa",
|
||||
"quae", "ab", "illo", "inventore", "veritatis",
|
||||
"quasi", "architecto", "beatae", "vitae", "dicta",
|
||||
"sunt", "explicabo", "nemo", "ipsam", "quia",
|
||||
"voluptas", "aspernatur", "aut", "odit", "fugit",
|
||||
"consequuntur", "magni", "dolores", "eos", "qui",
|
||||
"ratione", "sequi", "nesciunt", "neque", "porro",
|
||||
"quisquam", "est", "dolorem", "adipisci", "numquam",
|
||||
"eius", "modi", "tempora", "incidunt", "magnam",
|
||||
"quaerat", "ad", "minima", "veniam", "nostrum",
|
||||
"ullam", "corporis", "suscipit", "laboriosam", "nisi",
|
||||
"aliquid", "ex", "ea", "commodi", "consequatur",
|
||||
"autem", "eum", "iure", "voluptate", "esse",
|
||||
"quam", "nihil", "molestiae", "illum", "fugiat",
|
||||
"quo", "pariatur", "vero", "accusamus", "iusto",
|
||||
"dignissimos", "ducimus", "blanditiis", "praesentium", "voluptatum",
|
||||
"deleniti", "atque", "corrupti", "quos", "quas",
|
||||
"molestias", "excepturi", "sint", "occaecati", "cupiditate",
|
||||
"provident", "similique", "culpa", "officia", "deserunt",
|
||||
"mollitia", "animi", "laborum", "dolorum", "fuga",
|
||||
"harum", "quidem", "rerum", "facilis", "expedita",
|
||||
"distinctio", "libero", "tempore", "cum", "soluta",
|
||||
"nobis", "eligendi", "optio", "cumque", "impedit",
|
||||
"minus", "quod", "maxime", "placeat", "facere",
|
||||
"possimus", "assumenda", "repellendus", "temporibus", "quibusdam",
|
||||
"officiis", "debitis", "saepe", "eveniet", "voluptates",
|
||||
"repudiandae", "recusandae", "itaque", "earum", "hic",
|
||||
"tenetur", "sapiente", "delectus", "reiciendis", "cillum",
|
||||
"maiores", "alias", "perferendis", "doloribus", "asperiores",
|
||||
"repellat", "minim", "nostrud", "exercitation", "ullamco",
|
||||
"laboris", "aliquip", "duis", "aute", "irure",
|
||||
};
|
||||
static const unsigned kNbWords = sizeof(kWords) / sizeof(kWords[0]);
|
||||
|
||||
/* simple 1-dimension distribution, based on word's length, favors small words
|
||||
*/
|
||||
static const int kWeights[] = { 0, 8, 6, 4, 3, 2 };
|
||||
static const size_t kNbWeights = sizeof(kWeights) / sizeof(kWeights[0]);
|
||||
|
||||
#define DISTRIB_SIZE_MAX 650
|
||||
static int g_distrib[DISTRIB_SIZE_MAX] = { 0 };
|
||||
static unsigned g_distribCount = 0;
|
||||
|
||||
static void countFreqs(
|
||||
const char* words[],
|
||||
size_t nbWords,
|
||||
const int* weights,
|
||||
size_t nbWeights)
|
||||
{
|
||||
unsigned total = 0;
|
||||
size_t w;
|
||||
for (w = 0; w < nbWords; w++) {
|
||||
size_t len = strlen(words[w]);
|
||||
int lmax;
|
||||
if (len >= nbWeights)
|
||||
len = nbWeights - 1;
|
||||
lmax = weights[len];
|
||||
total += (unsigned)lmax;
|
||||
}
|
||||
g_distribCount = total;
|
||||
assert(g_distribCount <= DISTRIB_SIZE_MAX);
|
||||
}
|
||||
|
||||
static void init_word_distrib(
|
||||
const char* words[],
|
||||
size_t nbWords,
|
||||
const int* weights,
|
||||
size_t nbWeights)
|
||||
{
|
||||
size_t w, d = 0;
|
||||
countFreqs(words, nbWords, weights, nbWeights);
|
||||
for (w = 0; w < nbWords; w++) {
|
||||
size_t len = strlen(words[w]);
|
||||
int l, lmax;
|
||||
if (len >= nbWeights)
|
||||
len = nbWeights - 1;
|
||||
lmax = weights[len];
|
||||
for (l = 0; l < lmax; l++) {
|
||||
g_distrib[d++] = (int)w;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: this unit only works when invoked sequentially.
|
||||
* No concurrent access is allowed */
|
||||
static char* g_ptr = NULL;
|
||||
static size_t g_nbChars = 0;
|
||||
static size_t g_maxChars = 10000000;
|
||||
static unsigned g_randRoot = 0;
|
||||
|
||||
#define RDG_rotl32(x, r) ((x << r) | (x >> (32 - r)))
|
||||
static unsigned LOREM_rand(unsigned range)
|
||||
{
|
||||
static const unsigned prime1 = 2654435761U;
|
||||
static const unsigned prime2 = 2246822519U;
|
||||
unsigned rand32 = g_randRoot;
|
||||
rand32 *= prime1;
|
||||
rand32 ^= prime2;
|
||||
rand32 = RDG_rotl32(rand32, 13);
|
||||
g_randRoot = rand32;
|
||||
return (unsigned)(((unsigned long long)rand32 * range) >> 32);
|
||||
}
|
||||
|
||||
static void writeLastCharacters(void)
|
||||
{
|
||||
size_t lastChars = g_maxChars - g_nbChars;
|
||||
assert(g_maxChars >= g_nbChars);
|
||||
if (lastChars == 0)
|
||||
return;
|
||||
g_ptr[g_nbChars++] = '.';
|
||||
if (lastChars > 2) {
|
||||
memset(g_ptr + g_nbChars, ' ', lastChars - 2);
|
||||
}
|
||||
if (lastChars > 1) {
|
||||
g_ptr[g_maxChars - 1] = '\n';
|
||||
}
|
||||
g_nbChars = g_maxChars;
|
||||
}
|
||||
|
||||
static void generateWord(const char* word, const char* separator, int upCase)
|
||||
{
|
||||
size_t const len = strlen(word) + strlen(separator);
|
||||
if (g_nbChars + len > g_maxChars) {
|
||||
writeLastCharacters();
|
||||
return;
|
||||
}
|
||||
memcpy(g_ptr + g_nbChars, word, strlen(word));
|
||||
if (upCase) {
|
||||
static const char toUp = 'A' - 'a';
|
||||
g_ptr[g_nbChars] = (char)(g_ptr[g_nbChars] + toUp);
|
||||
}
|
||||
g_nbChars += strlen(word);
|
||||
memcpy(g_ptr + g_nbChars, separator, strlen(separator));
|
||||
g_nbChars += strlen(separator);
|
||||
}
|
||||
|
||||
static int about(unsigned target)
|
||||
{
|
||||
return (int)(LOREM_rand(target) + LOREM_rand(target) + 1);
|
||||
}
|
||||
|
||||
/* Function to generate a random sentence */
|
||||
static void generateSentence(int nbWords)
|
||||
{
|
||||
int commaPos = about(9);
|
||||
int comma2 = commaPos + about(7);
|
||||
int qmark = (LOREM_rand(11) == 7);
|
||||
const char* endSep = qmark ? "? " : ". ";
|
||||
int i;
|
||||
for (i = 0; i < nbWords; i++) {
|
||||
int const wordID = g_distrib[LOREM_rand(g_distribCount)];
|
||||
const char* const word = kWords[wordID];
|
||||
const char* sep = " ";
|
||||
if (i == commaPos)
|
||||
sep = ", ";
|
||||
if (i == comma2)
|
||||
sep = ", ";
|
||||
if (i == nbWords - 1)
|
||||
sep = endSep;
|
||||
generateWord(word, sep, i == 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void generateParagraph(int nbSentences)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < nbSentences; i++) {
|
||||
int wordsPerSentence = about(11);
|
||||
generateSentence(wordsPerSentence);
|
||||
}
|
||||
if (g_nbChars < g_maxChars) {
|
||||
g_ptr[g_nbChars++] = '\n';
|
||||
}
|
||||
if (g_nbChars < g_maxChars) {
|
||||
g_ptr[g_nbChars++] = '\n';
|
||||
}
|
||||
}
|
||||
|
||||
/* It's "common" for lorem ipsum generators to start with the same first
|
||||
* pre-defined sentence */
|
||||
static void generateFirstSentence(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 18; i++) {
|
||||
const char* word = kWords[i];
|
||||
const char* separator = " ";
|
||||
if (i == 4)
|
||||
separator = ", ";
|
||||
if (i == 7)
|
||||
separator = ", ";
|
||||
generateWord(word, separator, i == 0);
|
||||
}
|
||||
generateWord(kWords[18], ". ", 0);
|
||||
}
|
||||
|
||||
size_t
|
||||
LOREM_genBlock(void* buffer, size_t size, unsigned seed, int first, int fill)
|
||||
{
|
||||
g_ptr = (char*)buffer;
|
||||
assert(size < INT_MAX);
|
||||
g_maxChars = size;
|
||||
g_nbChars = 0;
|
||||
g_randRoot = seed;
|
||||
if (g_distribCount == 0) {
|
||||
init_word_distrib(kWords, kNbWords, kWeights, kNbWeights);
|
||||
}
|
||||
|
||||
if (first) {
|
||||
generateFirstSentence();
|
||||
}
|
||||
while (g_nbChars < g_maxChars) {
|
||||
int sentencePerParagraph = about(7);
|
||||
generateParagraph(sentencePerParagraph);
|
||||
if (!fill)
|
||||
break; /* only generate one paragraph in not-fill mode */
|
||||
}
|
||||
g_ptr = NULL;
|
||||
return g_nbChars;
|
||||
}
|
||||
|
||||
void LOREM_genBuffer(void* buffer, size_t size, unsigned seed)
|
||||
{
|
||||
LOREM_genBlock(buffer, size, seed, 1, 1);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
/* lorem ipsum generator */
|
||||
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
/*
|
||||
* LOREM_genBuffer():
|
||||
* Generate @size bytes of compressible data using lorem ipsum generator
|
||||
* into provided @buffer.
|
||||
*/
|
||||
void LOREM_genBuffer(void* buffer, size_t size, unsigned seed);
|
||||
|
||||
/*
|
||||
* LOREM_genBlock():
|
||||
* Similar to LOREM_genBuffer, with additional controls :
|
||||
* - @first : generate the first sentence
|
||||
* - @fill : fill the entire @buffer,
|
||||
* if ==0: generate one paragraph at most.
|
||||
* @return : nb of bytes generated into @buffer.
|
||||
*/
|
||||
size_t LOREM_genBlock(void* buffer, size_t size,
|
||||
unsigned seed,
|
||||
int first, int fill);
|
||||
+5
-5
@@ -660,7 +660,6 @@ UTIL_createFileNamesTable_fromFileName(const char* inputFileName)
|
||||
size_t nbFiles = 0;
|
||||
char* buf;
|
||||
size_t bufSize;
|
||||
size_t pos = 0;
|
||||
stat_t statbuf;
|
||||
|
||||
if (!UTIL_stat(inputFileName, &statbuf) || !UTIL_isRegularFileStat(&statbuf))
|
||||
@@ -687,12 +686,13 @@ UTIL_createFileNamesTable_fromFileName(const char* inputFileName)
|
||||
{ const char** filenamesTable = (const char**) malloc(nbFiles * sizeof(*filenamesTable));
|
||||
CONTROL(filenamesTable != NULL);
|
||||
|
||||
{ size_t fnb;
|
||||
for (fnb = 0, pos = 0; fnb < nbFiles; fnb++) {
|
||||
{ size_t fnb, pos = 0;
|
||||
for (fnb = 0; fnb < nbFiles; fnb++) {
|
||||
filenamesTable[fnb] = buf+pos;
|
||||
pos += strlen(buf+pos)+1; /* +1 for the finishing `\0` */
|
||||
} }
|
||||
}
|
||||
assert(pos <= bufSize);
|
||||
}
|
||||
|
||||
return UTIL_assembleFileNamesTable(filenamesTable, nbFiles, buf);
|
||||
}
|
||||
@@ -753,7 +753,7 @@ void UTIL_refFilename(FileNamesTable* fnt, const char* filename)
|
||||
|
||||
static size_t getTotalTableSize(FileNamesTable* table)
|
||||
{
|
||||
size_t fnb = 0, totalSize = 0;
|
||||
size_t fnb, totalSize = 0;
|
||||
for(fnb = 0 ; fnb < table->tableSize && table->fileNames[fnb] ; ++fnb) {
|
||||
totalSize += strlen(table->fileNames[fnb]) + 1; /* +1 to add '\0' at the end of each fileName */
|
||||
}
|
||||
|
||||
@@ -218,6 +218,13 @@ the last one takes effect.
|
||||
expected. This feature allows for controlling the guess when needed.
|
||||
Exact guesses result in better compression ratios. Overestimates result in slightly
|
||||
degraded compression ratios, while underestimates may result in significant degradation.
|
||||
* `--target-compressed-block-size=#`:
|
||||
Attempt to produce compressed blocks of approximately this size.
|
||||
This will split larger blocks in order to approach this target.
|
||||
This feature is notably useful for improved latency, when the receiver can leverage receiving early incomplete data.
|
||||
This parameter defines a loose target: compressed blocks will target this size "on average", but individual blocks can still be larger or smaller.
|
||||
Enabling this feature can decrease compression speed by up to ~10% at level 1.
|
||||
Higher levels will see smaller relative speed regression, becoming invisible at higher settings.
|
||||
* `-o FILE`:
|
||||
save result into `FILE`.
|
||||
* `-f`, `--force`:
|
||||
|
||||
+30
-22
@@ -138,8 +138,8 @@ static int exeNameMatch(const char* exeName, const char* test)
|
||||
* Command Line
|
||||
**************************************/
|
||||
/* print help either in `stderr` or `stdout` depending on originating request
|
||||
* error (badusage) => stderr
|
||||
* help (usage_advanced) => stdout
|
||||
* error (badUsage) => stderr
|
||||
* help (usageAdvanced) => stdout
|
||||
*/
|
||||
static void usage(FILE* f, const char* programName)
|
||||
{
|
||||
@@ -175,7 +175,7 @@ static void usage(FILE* f, const char* programName)
|
||||
DISPLAY_F(f, "\n");
|
||||
}
|
||||
|
||||
static void usage_advanced(const char* programName)
|
||||
static void usageAdvanced(const char* programName)
|
||||
{
|
||||
DISPLAYOUT(WELCOME_MESSAGE);
|
||||
DISPLAYOUT("\n");
|
||||
@@ -316,9 +316,9 @@ static void usage_advanced(const char* programName)
|
||||
|
||||
}
|
||||
|
||||
static void badusage(const char* programName)
|
||||
static void badUsage(const char* programName, const char* parameter)
|
||||
{
|
||||
DISPLAYLEVEL(1, "Incorrect parameters \n");
|
||||
DISPLAYLEVEL(1, "Incorrect parameter: %s \n", parameter);
|
||||
if (g_displayLevel >= 2) usage(stderr, programName);
|
||||
}
|
||||
|
||||
@@ -589,7 +589,7 @@ static ZDICT_fastCover_params_t defaultFastCoverParams(void)
|
||||
|
||||
|
||||
/** parseAdaptParameters() :
|
||||
* reads adapt parameters from *stringPtr (e.g. "--zstd=min=1,max=19) and store them into adaptMinPtr and adaptMaxPtr.
|
||||
* reads adapt parameters from *stringPtr (e.g. "--adapt=min=1,max=19) and store them into adaptMinPtr and adaptMaxPtr.
|
||||
* Both adaptMinPtr and adaptMaxPtr must be already allocated and correctly initialized.
|
||||
* There is no guarantee that any of these values will be updated.
|
||||
* @return 1 means that parsing was successful,
|
||||
@@ -856,7 +856,7 @@ int main(int argCount, const char* argv[])
|
||||
ZSTD_paramSwitch_e useRowMatchFinder = ZSTD_ps_auto;
|
||||
FIO_compressionType_t cType = FIO_zstdCompression;
|
||||
unsigned nbWorkers = 0;
|
||||
double compressibility = 0.5;
|
||||
double compressibility = -1.0; /* lorem ipsum generator */
|
||||
unsigned bench_nbSeconds = 3; /* would be better if this value was synchronized from bench */
|
||||
size_t blockSize = 0;
|
||||
|
||||
@@ -933,6 +933,7 @@ int main(int argCount, const char* argv[])
|
||||
/* command switches */
|
||||
for (argNb=1; argNb<argCount; argNb++) {
|
||||
const char* argument = argv[argNb];
|
||||
const char* const originalArgument = argument;
|
||||
if (!argument) continue; /* Protection if argument empty */
|
||||
|
||||
if (nextArgumentsAreFiles) {
|
||||
@@ -958,7 +959,7 @@ int main(int argCount, const char* argv[])
|
||||
if (!strcmp(argument, "--uncompress")) { operation=zom_decompress; continue; }
|
||||
if (!strcmp(argument, "--force")) { FIO_overwriteMode(prefs); forceStdin=1; forceStdout=1; followLinks=1; allowBlockDevices=1; continue; }
|
||||
if (!strcmp(argument, "--version")) { printVersion(); CLEAN_RETURN(0); }
|
||||
if (!strcmp(argument, "--help")) { usage_advanced(programName); CLEAN_RETURN(0); }
|
||||
if (!strcmp(argument, "--help")) { usageAdvanced(programName); CLEAN_RETURN(0); }
|
||||
if (!strcmp(argument, "--verbose")) { g_displayLevel++; continue; }
|
||||
if (!strcmp(argument, "--quiet")) { g_displayLevel--; continue; }
|
||||
if (!strcmp(argument, "--stdout")) { forceStdout=1; outFileName=stdoutmark; removeSrcFile=0; continue; }
|
||||
@@ -983,7 +984,7 @@ int main(int argCount, const char* argv[])
|
||||
if (!strcmp(argument, "--adapt")) { adapt = 1; continue; }
|
||||
if (!strcmp(argument, "--no-row-match-finder")) { useRowMatchFinder = ZSTD_ps_disable; continue; }
|
||||
if (!strcmp(argument, "--row-match-finder")) { useRowMatchFinder = ZSTD_ps_enable; continue; }
|
||||
if (longCommandWArg(&argument, "--adapt=")) { adapt = 1; if (!parseAdaptParameters(argument, &adaptMin, &adaptMax)) { badusage(programName); CLEAN_RETURN(1); } continue; }
|
||||
if (longCommandWArg(&argument, "--adapt=")) { adapt = 1; if (!parseAdaptParameters(argument, &adaptMin, &adaptMax)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); } continue; }
|
||||
if (!strcmp(argument, "--single-thread")) { nbWorkers = 0; singleThread = 1; continue; }
|
||||
if (!strcmp(argument, "--format=zstd")) { suffix = ZSTD_EXTENSION; cType = FIO_zstdCompression; continue; }
|
||||
if (!strcmp(argument, "--mmap-dict")) { mmapDict = ZSTD_ps_enable; continue; }
|
||||
@@ -1022,8 +1023,8 @@ int main(int argCount, const char* argv[])
|
||||
dict = cover;
|
||||
/* Allow optional arguments following an = */
|
||||
if (*argument == 0) { memset(&coverParams, 0, sizeof(coverParams)); }
|
||||
else if (*argument++ != '=') { badusage(programName); CLEAN_RETURN(1); }
|
||||
else if (!parseCoverParameters(argument, &coverParams)) { badusage(programName); CLEAN_RETURN(1); }
|
||||
else if (*argument++ != '=') { badUsage(programName, originalArgument); CLEAN_RETURN(1); }
|
||||
else if (!parseCoverParameters(argument, &coverParams)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); }
|
||||
continue;
|
||||
}
|
||||
if (longCommandWArg(&argument, "--train-fastcover")) {
|
||||
@@ -1033,8 +1034,8 @@ int main(int argCount, const char* argv[])
|
||||
dict = fastCover;
|
||||
/* Allow optional arguments following an = */
|
||||
if (*argument == 0) { memset(&fastCoverParams, 0, sizeof(fastCoverParams)); }
|
||||
else if (*argument++ != '=') { badusage(programName); CLEAN_RETURN(1); }
|
||||
else if (!parseFastCoverParameters(argument, &fastCoverParams)) { badusage(programName); CLEAN_RETURN(1); }
|
||||
else if (*argument++ != '=') { badUsage(programName, originalArgument); CLEAN_RETURN(1); }
|
||||
else if (!parseFastCoverParameters(argument, &fastCoverParams)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); }
|
||||
continue;
|
||||
}
|
||||
if (longCommandWArg(&argument, "--train-legacy")) {
|
||||
@@ -1044,8 +1045,8 @@ int main(int argCount, const char* argv[])
|
||||
dict = legacy;
|
||||
/* Allow optional arguments following an = */
|
||||
if (*argument == 0) { continue; }
|
||||
else if (*argument++ != '=') { badusage(programName); CLEAN_RETURN(1); }
|
||||
else if (!parseLegacyParameters(argument, &dictSelect)) { badusage(programName); CLEAN_RETURN(1); }
|
||||
else if (*argument++ != '=') { badUsage(programName, originalArgument); CLEAN_RETURN(1); }
|
||||
else if (!parseLegacyParameters(argument, &dictSelect)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); }
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
@@ -1056,7 +1057,7 @@ int main(int argCount, const char* argv[])
|
||||
if (longCommandWArg(&argument, "--block-size")) { NEXT_TSIZE(blockSize); continue; }
|
||||
if (longCommandWArg(&argument, "--maxdict")) { NEXT_UINT32(maxDictSize); continue; }
|
||||
if (longCommandWArg(&argument, "--dictID")) { NEXT_UINT32(dictID); continue; }
|
||||
if (longCommandWArg(&argument, "--zstd=")) { if (!parseCompressionParameters(argument, &compressionParams)) { badusage(programName); CLEAN_RETURN(1); } ; cType = FIO_zstdCompression; continue; }
|
||||
if (longCommandWArg(&argument, "--zstd=")) { if (!parseCompressionParameters(argument, &compressionParams)) { badUsage(programName, originalArgument); CLEAN_RETURN(1); } ; cType = FIO_zstdCompression; continue; }
|
||||
if (longCommandWArg(&argument, "--stream-size")) { NEXT_TSIZE(streamSrcSize); continue; }
|
||||
if (longCommandWArg(&argument, "--target-compressed-block-size")) { NEXT_TSIZE(targetCBlockSize); continue; }
|
||||
if (longCommandWArg(&argument, "--size-hint")) { NEXT_TSIZE(srcSizeHint); continue; }
|
||||
@@ -1098,7 +1099,7 @@ int main(int argCount, const char* argv[])
|
||||
ldmWindowLog = readU32FromChar(&argument);
|
||||
} else if (*argument != 0) {
|
||||
/* Invalid character following --long */
|
||||
badusage(programName);
|
||||
badUsage(programName, originalArgument);
|
||||
CLEAN_RETURN(1);
|
||||
} else {
|
||||
ldmWindowLog = g_defaultMaxWindowLog;
|
||||
@@ -1120,12 +1121,12 @@ int main(int argCount, const char* argv[])
|
||||
if (fastLevel) {
|
||||
dictCLevel = cLevel = -(int)fastLevel;
|
||||
} else {
|
||||
badusage(programName);
|
||||
badUsage(programName, originalArgument);
|
||||
CLEAN_RETURN(1);
|
||||
}
|
||||
} else if (*argument != 0) {
|
||||
/* Invalid character following --fast */
|
||||
badusage(programName);
|
||||
badUsage(programName, originalArgument);
|
||||
CLEAN_RETURN(1);
|
||||
} else {
|
||||
cLevel = -1; /* default for --fast */
|
||||
@@ -1141,7 +1142,8 @@ int main(int argCount, const char* argv[])
|
||||
continue;
|
||||
}
|
||||
|
||||
/* fall-through, will trigger bad_usage() later on */
|
||||
badUsage(programName, originalArgument);
|
||||
CLEAN_RETURN(1);
|
||||
}
|
||||
|
||||
argument++;
|
||||
@@ -1159,7 +1161,7 @@ int main(int argCount, const char* argv[])
|
||||
{
|
||||
/* Display help */
|
||||
case 'V': printVersion(); CLEAN_RETURN(0); /* Version Only */
|
||||
case 'H': usage_advanced(programName); CLEAN_RETURN(0);
|
||||
case 'H': usageAdvanced(programName); CLEAN_RETURN(0);
|
||||
case 'h': usage(stdout, programName); CLEAN_RETURN(0);
|
||||
|
||||
/* Compress */
|
||||
@@ -1277,7 +1279,12 @@ int main(int argCount, const char* argv[])
|
||||
break;
|
||||
|
||||
/* unknown command */
|
||||
default : badusage(programName); CLEAN_RETURN(1);
|
||||
default :
|
||||
{ char shortArgument[3] = {'-', 0, 0};
|
||||
shortArgument[1] = argument[0];
|
||||
badUsage(programName, shortArgument);
|
||||
CLEAN_RETURN(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
@@ -1368,6 +1375,7 @@ int main(int argCount, const char* argv[])
|
||||
CLEAN_RETURN(1);
|
||||
}
|
||||
benchParams.blockSize = blockSize;
|
||||
benchParams.targetCBlockSize = targetCBlockSize;
|
||||
benchParams.nbWorkers = (int)nbWorkers;
|
||||
benchParams.realTime = (unsigned)setRealTimePrio;
|
||||
benchParams.nbSeconds = bench_nbSeconds;
|
||||
|
||||
+6
-5
@@ -203,10 +203,10 @@ zstreamtest-dll : $(ZSTREAM_LOCAL_FILES)
|
||||
CLEAN += paramgrill
|
||||
paramgrill : DEBUGFLAGS = # turn off debug for speed measurements
|
||||
paramgrill : LDLIBS += -lm
|
||||
paramgrill : $(ZSTD_FILES) $(PRGDIR)/util.c $(PRGDIR)/timefn.c $(PRGDIR)/benchfn.c $(PRGDIR)/benchzstd.c $(PRGDIR)/datagen.c paramgrill.c
|
||||
paramgrill : $(ZSTD_FILES) $(PRGDIR)/util.c $(PRGDIR)/timefn.c $(PRGDIR)/benchfn.c $(PRGDIR)/benchzstd.c $(PRGDIR)/datagen.c $(PRGDIR)/lorem.c paramgrill.c
|
||||
|
||||
CLEAN += datagen
|
||||
datagen : $(PRGDIR)/datagen.c datagencli.c
|
||||
datagen : $(PRGDIR)/datagen.c $(PRGDIR)/lorem.c loremOut.c datagencli.c
|
||||
$(LINK.c) $^ -o $@$(EXT)
|
||||
|
||||
CLEAN += roundTripCrash
|
||||
@@ -251,8 +251,9 @@ checkTag.o : $(ZSTDDIR)/zstd.h
|
||||
clean:
|
||||
$(MAKE) -C $(ZSTDDIR) clean
|
||||
$(MAKE) -C $(PRGDIR) clean
|
||||
$(RM) -fR $(TESTARTEFACT)
|
||||
$(RM) -rf tmp* # some test directories are named tmp*
|
||||
$(MAKE) -C fuzz clean
|
||||
$(RM) -R $(TESTARTEFACT)
|
||||
$(RM) -r tmp* # some test directories are named tmp*
|
||||
$(RM) $(CLEAN) core *.o *.tmp result* *.gcda dictionary *.zst \
|
||||
$(PRGDIR)/zstd$(EXT) $(PRGDIR)/zstd32$(EXT) \
|
||||
fullbench-dll$(EXT) fuzzer-dll$(EXT) zstreamtest-dll$(EXT)
|
||||
@@ -313,7 +314,7 @@ check: shortest
|
||||
fuzztest: test-fuzzer test-zstream test-decodecorpus
|
||||
|
||||
.PHONY: test
|
||||
test: test-zstd test-fullbench test-fuzzer test-zstream test-invalidDictionaries test-legacy test-decodecorpus test-cli-tests
|
||||
test: test-zstd test-cli-tests test-fullbench test-fuzzer test-zstream test-invalidDictionaries test-legacy test-decodecorpus
|
||||
ifeq ($(QEMU_SYS),)
|
||||
test: test-pool
|
||||
endif
|
||||
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
println "+ zstd --blah" >&2
|
||||
zstd --blah
|
||||
println "+ zstd -xz" >&2
|
||||
zstd -xz
|
||||
println "+ zstd --adapt=min=1,maxx=2 file.txt" >&2
|
||||
zstd --adapt=min=1,maxx=2 file.txt
|
||||
println "+ zstd --train-cover=k=48,d=8,steps32 file.txt" >&2
|
||||
zstd --train-cover=k=48,d=8,steps32 file.txt
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,28 @@
|
||||
+ zstd --blah
|
||||
Incorrect parameter: --blah
|
||||
...
|
||||
Usage: zstd *
|
||||
|
||||
Options:
|
||||
...
|
||||
+ zstd -xz
|
||||
Incorrect parameter: -x
|
||||
...
|
||||
Usage: zstd *
|
||||
|
||||
Options:
|
||||
...
|
||||
+ zstd --adapt=min=1,maxx=2 file.txt
|
||||
Incorrect parameter: --adapt=min=1,maxx=2
|
||||
...
|
||||
Usage: zstd *
|
||||
|
||||
Options:
|
||||
...
|
||||
+ zstd --train-cover=k=48,d=8,steps32 file.txt
|
||||
Incorrect parameter: --train-cover=k=48,d=8,steps32
|
||||
...
|
||||
Usage: zstd *
|
||||
|
||||
Options:
|
||||
...
|
||||
+105
-86
@@ -8,122 +8,141 @@
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
/*-************************************
|
||||
* Dependencies
|
||||
**************************************/
|
||||
#include <stdio.h> /* fprintf, stderr */
|
||||
#include "datagen.h" /* RDG_generate */
|
||||
#include "loremOut.h" /* LOREM_genOut */
|
||||
#include "util.h" /* Compiler options */
|
||||
|
||||
/*-************************************
|
||||
* Dependencies
|
||||
**************************************/
|
||||
#include "util.h" /* Compiler options */
|
||||
#include <stdio.h> /* fprintf, stderr */
|
||||
#include "datagen.h" /* RDG_generate */
|
||||
|
||||
|
||||
/*-************************************
|
||||
* Constants
|
||||
**************************************/
|
||||
#define KB *(1 <<10)
|
||||
#define MB *(1 <<20)
|
||||
#define GB *(1U<<30)
|
||||
* Constants
|
||||
**************************************/
|
||||
#define KB *(1 << 10)
|
||||
#define MB *(1 << 20)
|
||||
#define GB *(1U << 30)
|
||||
|
||||
#define SIZE_DEFAULT ((64 KB) + 1)
|
||||
#define SEED_DEFAULT 0
|
||||
#define COMPRESSIBILITY_DEFAULT 50
|
||||
|
||||
#define COMPRESSIBILITY_DEFAULT 9999
|
||||
|
||||
/*-************************************
|
||||
* Macros
|
||||
**************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) if (displayLevel>=l) { DISPLAY(__VA_ARGS__); }
|
||||
* Macros
|
||||
**************************************/
|
||||
#define DISPLAY(...) fprintf(stderr, __VA_ARGS__)
|
||||
#define DISPLAYLEVEL(l, ...) \
|
||||
if (displayLevel >= l) { \
|
||||
DISPLAY(__VA_ARGS__); \
|
||||
}
|
||||
static unsigned displayLevel = 2;
|
||||
|
||||
|
||||
/*-*******************************************************
|
||||
* Command line
|
||||
*********************************************************/
|
||||
* Command line
|
||||
*********************************************************/
|
||||
static int usage(const char* programName)
|
||||
{
|
||||
DISPLAY( "Compressible data generator\n");
|
||||
DISPLAY( "Usage :\n");
|
||||
DISPLAY( " %s [args]\n", programName);
|
||||
DISPLAY( "\n");
|
||||
DISPLAY( "Arguments :\n");
|
||||
DISPLAY( " -g# : generate # data (default:%i)\n", SIZE_DEFAULT);
|
||||
DISPLAY( " -s# : Select seed (default:%i)\n", SEED_DEFAULT);
|
||||
DISPLAY( " -P# : Select compressibility in %% (default:%i%%)\n",
|
||||
COMPRESSIBILITY_DEFAULT);
|
||||
DISPLAY( " -h : display help and exit\n");
|
||||
DISPLAY("Compressible data generator\n");
|
||||
DISPLAY("Usage :\n");
|
||||
DISPLAY(" %s [args]\n", programName);
|
||||
DISPLAY("\n");
|
||||
DISPLAY("Arguments :\n");
|
||||
DISPLAY(" -g# : generate # data (default:%i)\n", SIZE_DEFAULT);
|
||||
DISPLAY(" -s# : Select seed (default:%i)\n", SEED_DEFAULT);
|
||||
DISPLAY(" -P# : Select compressibility in %% (range [0-100])\n");
|
||||
DISPLAY(" -h : display help and exit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
unsigned probaU32 = COMPRESSIBILITY_DEFAULT;
|
||||
double litProba = 0.0;
|
||||
U64 size = SIZE_DEFAULT;
|
||||
U32 seed = SEED_DEFAULT;
|
||||
unsigned probaU32 = COMPRESSIBILITY_DEFAULT;
|
||||
double litProba = 0.0;
|
||||
U64 size = SIZE_DEFAULT;
|
||||
U32 seed = SEED_DEFAULT;
|
||||
const char* const programName = argv[0];
|
||||
|
||||
int argNb;
|
||||
for(argNb=1; argNb<argc; argNb++) {
|
||||
for (argNb = 1; argNb < argc; argNb++) {
|
||||
const char* argument = argv[argNb];
|
||||
|
||||
if(!argument) continue; /* Protection if argument empty */
|
||||
if (!argument)
|
||||
continue; /* Protection if argument empty */
|
||||
|
||||
/* Handle commands. Aggregated commands are allowed */
|
||||
if (*argument=='-') {
|
||||
if (*argument == '-') {
|
||||
argument++;
|
||||
while (*argument!=0) {
|
||||
switch(*argument)
|
||||
{
|
||||
case 'h':
|
||||
return usage(programName);
|
||||
case 'g':
|
||||
argument++;
|
||||
size=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
size *= 10, size += *argument++ - '0';
|
||||
if (*argument=='K') { size <<= 10; argument++; }
|
||||
if (*argument=='M') { size <<= 20; argument++; }
|
||||
if (*argument=='G') { size <<= 30; argument++; }
|
||||
if (*argument=='B') { argument++; }
|
||||
break;
|
||||
case 's':
|
||||
argument++;
|
||||
seed=0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
seed *= 10, seed += *argument++ - '0';
|
||||
break;
|
||||
case 'P':
|
||||
argument++;
|
||||
probaU32 = 0;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
probaU32 *= 10, probaU32 += *argument++ - '0';
|
||||
if (probaU32>100) probaU32 = 100;
|
||||
break;
|
||||
case 'L': /* hidden argument : Literal distribution probability */
|
||||
argument++;
|
||||
litProba=0.;
|
||||
while ((*argument>='0') && (*argument<='9'))
|
||||
litProba *= 10, litProba += *argument++ - '0';
|
||||
if (litProba>100.) litProba=100.;
|
||||
litProba /= 100.;
|
||||
break;
|
||||
case 'v':
|
||||
displayLevel = 4;
|
||||
argument++;
|
||||
break;
|
||||
default:
|
||||
return usage(programName);
|
||||
while (*argument != 0) {
|
||||
switch (*argument) {
|
||||
case 'h':
|
||||
return usage(programName);
|
||||
case 'g':
|
||||
argument++;
|
||||
size = 0;
|
||||
while ((*argument >= '0') && (*argument <= '9'))
|
||||
size *= 10, size += (U64)(*argument++ - '0');
|
||||
if (*argument == 'K') {
|
||||
size <<= 10;
|
||||
argument++;
|
||||
}
|
||||
if (*argument == 'M') {
|
||||
size <<= 20;
|
||||
argument++;
|
||||
}
|
||||
if (*argument == 'G') {
|
||||
size <<= 30;
|
||||
argument++;
|
||||
}
|
||||
if (*argument == 'B') {
|
||||
argument++;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
argument++;
|
||||
seed = 0;
|
||||
while ((*argument >= '0') && (*argument <= '9'))
|
||||
seed *= 10, seed += (U32)(*argument++ - '0');
|
||||
break;
|
||||
case 'P':
|
||||
argument++;
|
||||
probaU32 = 0;
|
||||
while ((*argument >= '0') && (*argument <= '9'))
|
||||
probaU32 *= 10,
|
||||
probaU32 += (U32)(*argument++ - '0');
|
||||
if (probaU32 > 100)
|
||||
probaU32 = 100;
|
||||
break;
|
||||
case 'L': /* hidden argument : Literal distribution
|
||||
probability */
|
||||
argument++;
|
||||
litProba = 0.;
|
||||
while ((*argument >= '0') && (*argument <= '9'))
|
||||
litProba *= 10, litProba += *argument++ - '0';
|
||||
if (litProba > 100.)
|
||||
litProba = 100.;
|
||||
litProba /= 100.;
|
||||
break;
|
||||
case 'v':
|
||||
displayLevel = 4;
|
||||
argument++;
|
||||
break;
|
||||
default:
|
||||
return usage(programName);
|
||||
}
|
||||
} } } /* for(argNb=1; argNb<argc; argNb++) */
|
||||
}
|
||||
}
|
||||
} /* for(argNb=1; argNb<argc; argNb++) */
|
||||
|
||||
DISPLAYLEVEL(4, "Compressible data Generator \n");
|
||||
if (probaU32!=COMPRESSIBILITY_DEFAULT)
|
||||
DISPLAYLEVEL(3, "Compressibility : %i%%\n", probaU32);
|
||||
DISPLAYLEVEL(3, "Seed = %u \n", (unsigned)seed);
|
||||
|
||||
RDG_genStdout(size, (double)probaU32/100, litProba, seed);
|
||||
if (probaU32 != COMPRESSIBILITY_DEFAULT) {
|
||||
DISPLAYLEVEL(3, "Compressibility : %i%%\n", probaU32);
|
||||
RDG_genStdout(size, (double)probaU32 / 100, litProba, seed);
|
||||
} else {
|
||||
LOREM_genOut(size, seed);
|
||||
}
|
||||
|
||||
DISPLAYLEVEL(3, "\n");
|
||||
|
||||
return 0;
|
||||
|
||||
+1
-1
@@ -257,7 +257,7 @@ corpora: $(patsubst %,corpora/%,$(FUZZ_TARGETS))
|
||||
seedcorpora: $(patsubst %,corpora/%_seed_corpus.zip,$(FUZZ_TARGETS))
|
||||
|
||||
regressiontest: corpora
|
||||
CC="$(CC)" CXX="$(CXX)" CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" LDFLAGS="$(LDFLAGS)" $(PYTHON) ./fuzz.py build all
|
||||
CC="$(CC)" CXX="$(CXX)" CFLAGS="$(CFLAGS)" CXXFLAGS="$(CXXFLAGS)" LDFLAGS="$(LDFLAGS)" $(PYTHON) ./fuzz.py build all --debug=$(DEBUGLEVEL)
|
||||
$(PYTHON) ./fuzz.py regression all
|
||||
|
||||
clean:
|
||||
|
||||
@@ -23,13 +23,13 @@
|
||||
#include "fuzz_data_producer.h"
|
||||
#include "fuzz_third_party_seq_prod.h"
|
||||
|
||||
static ZSTD_CCtx *cctx = NULL;
|
||||
static ZSTD_DCtx *dctx = NULL;
|
||||
static ZSTD_CCtx* cctx = NULL;
|
||||
static ZSTD_DCtx* dctx = NULL;
|
||||
|
||||
static size_t roundTripTest(void *result, size_t resultCapacity,
|
||||
void *compressed, size_t compressedCapacity,
|
||||
const void *src, size_t srcSize,
|
||||
FUZZ_dataProducer_t *producer)
|
||||
static size_t roundTripTest(void* result, size_t resultCapacity,
|
||||
void* compressed, size_t compressedCapacity,
|
||||
const void* src, size_t srcSize,
|
||||
FUZZ_dataProducer_t* producer)
|
||||
{
|
||||
ZSTD_dictContentType_e dictContentType = ZSTD_dct_auto;
|
||||
FUZZ_dict_t dict = FUZZ_train(src, srcSize, producer);
|
||||
|
||||
@@ -492,6 +492,7 @@ def build(args):
|
||||
subprocess.check_call(clean_cmd)
|
||||
build_cmd = [
|
||||
'make',
|
||||
'-j',
|
||||
cc_str,
|
||||
cxx_str,
|
||||
cppflags_str,
|
||||
|
||||
+2
-2
@@ -952,7 +952,7 @@ static int basicUnitTests(U32 const seed, double compressibility)
|
||||
ZSTD_freeCDict(cdict);
|
||||
ZSTD_freeCCtx(cctx);
|
||||
}
|
||||
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : maxBlockSize = 2K", testNb++);
|
||||
{
|
||||
ZSTD_CCtx* cctx = ZSTD_createCCtx();
|
||||
@@ -1374,7 +1374,7 @@ static int basicUnitTests(U32 const seed, double compressibility)
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(3, "test%3d: superblock uncompressible data, too many nocompress superblocks : ", testNb++);
|
||||
DISPLAYLEVEL(3, "test%3d : superblock uncompressible data: too many nocompress superblocks : ", testNb++);
|
||||
{
|
||||
ZSTD_CCtx* const cctx = ZSTD_createCCtx();
|
||||
const BYTE* src = (BYTE*)CNBuffer; BYTE* dst = (BYTE*)compressedBuffer;
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
/* Implementation notes:
|
||||
* Generates a stream of Lorem ipsum paragraphs to stdout,
|
||||
* up to the requested size, which can be very large (> 4 GB).
|
||||
* Note that, beyond 1 paragraph, this generator produces
|
||||
* a different content than LOREM_genBuffer (even when using same seed).
|
||||
*/
|
||||
|
||||
#include "loremOut.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include "lorem.h" /* LOREM_genBlock */
|
||||
#include "platform.h" /* Compiler options, SET_BINARY_MODE */
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define LOREM_BLOCKSIZE (1 << 10)
|
||||
void LOREM_genOut(unsigned long long size, unsigned seed)
|
||||
{
|
||||
char buff[LOREM_BLOCKSIZE] = { 0 };
|
||||
unsigned long long total = 0;
|
||||
size_t genBlockSize = (size_t)MIN(size, LOREM_BLOCKSIZE);
|
||||
|
||||
/* init */
|
||||
SET_BINARY_MODE(stdout);
|
||||
|
||||
/* Generate Ipsum text, one paragraph at a time */
|
||||
while (total < size) {
|
||||
size_t generated =
|
||||
LOREM_genBlock(buff, genBlockSize, seed++, total == 0, 0);
|
||||
assert(generated <= genBlockSize);
|
||||
total += generated;
|
||||
assert(total <= size);
|
||||
fwrite(buff,
|
||||
1,
|
||||
generated,
|
||||
stdout); /* note: should check potential write error */
|
||||
if (size - total < genBlockSize)
|
||||
genBlockSize = (size_t)(size - total);
|
||||
}
|
||||
assert(total == size);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under both the BSD-style license (found in the
|
||||
* LICENSE file in the root directory of this source tree) and the GPLv2 (found
|
||||
* in the COPYING file in the root directory of this source tree).
|
||||
* You may select, at your option, one of the above-listed licenses.
|
||||
*/
|
||||
|
||||
/* LOREM_genOut():
|
||||
* Generate @size bytes of compressible data using lorem ipsum generator into
|
||||
* stdout.
|
||||
*/
|
||||
void LOREM_genOut(unsigned long long size, unsigned seed);
|
||||
+35
-34
@@ -1,6 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
set -e # exit immediately on error
|
||||
# set -x # print commands before execution (debug)
|
||||
|
||||
unset ZSTD_CLEVEL
|
||||
unset ZSTD_NBTHREADS
|
||||
@@ -91,7 +92,13 @@ fi
|
||||
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
|
||||
PRGDIR="$SCRIPT_DIR/../programs"
|
||||
TESTDIR="$SCRIPT_DIR/../tests"
|
||||
UNAME=$(uname)
|
||||
UNAME=${UNAME:-$(uname)}
|
||||
GREP=${GREP:-grep}
|
||||
|
||||
case "$UNAME" in
|
||||
SunOS) DIFF=${DIFF:-gdiff} ;;
|
||||
*) DIFF=${DIFF:-diff} ;;
|
||||
esac
|
||||
|
||||
detectedTerminal=false
|
||||
if [ -t 0 ] && [ -t 1 ]
|
||||
@@ -151,11 +158,6 @@ assertSamePermissions() {
|
||||
[ "$STAT1" = "$STAT2" ] || die "permissions on $1 don't match those on $2 ($STAT1 != $STAT2)"
|
||||
}
|
||||
|
||||
DIFF="diff"
|
||||
case "$UNAME" in
|
||||
SunOS) DIFF="gdiff" ;;
|
||||
esac
|
||||
|
||||
|
||||
# check if ZSTD_BIN is defined. if not, use the default value
|
||||
if [ -z "${ZSTD_BIN}" ]; then
|
||||
@@ -177,7 +179,7 @@ fi
|
||||
[ -n "$DATAGEN_BIN" ] || die "datagen not found at $DATAGEN_BIN! \n Please define DATAGEN_BIN pointing to the datagen binary. You might also consider rebuilding zstd tests following the instructions in README.md. "
|
||||
println "\nStarting playTests.sh isWindows=$isWindows EXE_PREFIX='$EXE_PREFIX' ZSTD_BIN='$ZSTD_BIN' DATAGEN_BIN='$DATAGEN_BIN'"
|
||||
|
||||
if echo hello | zstd -v -T2 2>&1 > $INTOVOID | grep -q 'multi-threading is disabled'
|
||||
if echo hello | zstd -v -T2 2>&1 > $INTOVOID | $GREP -q 'multi-threading is disabled'
|
||||
then
|
||||
hasMT=""
|
||||
else
|
||||
@@ -253,8 +255,8 @@ println "test : null-length file roundtrip"
|
||||
println -n '' | zstd - --stdout | zstd -d --stdout
|
||||
println "test : ensure small file doesn't add 3-bytes null block"
|
||||
datagen -g1 > tmp1
|
||||
zstd tmp1 -c | wc -c | grep "14"
|
||||
zstd < tmp1 | wc -c | grep "14"
|
||||
zstd tmp1 -c | wc -c | $GREP "14"
|
||||
zstd < tmp1 | wc -c | $GREP "14"
|
||||
println "test : decompress file with wrong suffix (must fail)"
|
||||
zstd -d tmpCompressed && die "wrong suffix error not detected!"
|
||||
zstd -df tmp && die "should have refused : wrong extension"
|
||||
@@ -291,9 +293,9 @@ println "test: --no-progress flag"
|
||||
zstd tmpro -c --no-progress | zstd -d -f -o "$INTOVOID" --no-progress
|
||||
zstd tmpro -cv --no-progress | zstd -dv -f -o "$INTOVOID" --no-progress
|
||||
println "test: --progress flag"
|
||||
zstd tmpro -c | zstd -d -f -o "$INTOVOID" --progress 2>&1 | grep -E "[A-Za-z0-9._ ]+: [0-9]+ bytes"
|
||||
zstd tmpro -c | zstd -d -f -q -o "$INTOVOID" --progress 2>&1 | grep -E "[A-Za-z0-9._ ]+: [0-9]+ bytes"
|
||||
zstd tmpro -c | zstd -d -f -v -o "$INTOVOID" 2>&1 | grep -E "[A-Za-z0-9._ ]+: [0-9]+ bytes"
|
||||
zstd tmpro -c | zstd -d -f -o "$INTOVOID" --progress 2>&1 | $GREP '[A-Za-z0-9._ ]*: [0-9]* bytes'
|
||||
zstd tmpro -c | zstd -d -f -q -o "$INTOVOID" --progress 2>&1 | $GREP '[A-Za-z0-9._ ]*: [0-9]* bytes'
|
||||
zstd tmpro -c | zstd -d -f -v -o "$INTOVOID" 2>&1 | $GREP '[A-Za-z0-9._ ]*: [0-9]* bytes'
|
||||
rm -f tmpro tmpro.zst
|
||||
println "test: overwrite input file (must fail)"
|
||||
zstd tmp -fo tmp && die "zstd compression overwrote the input file"
|
||||
@@ -320,7 +322,7 @@ zstd -d -f tmp.zst --no-check
|
||||
if [ "$isWindows" = false ] && [ "$UNAME" != "AIX" ]; then
|
||||
if [ -n "$(which readelf)" ]; then
|
||||
println "test: check if binary has executable stack (#2963)"
|
||||
readelf -lW "$ZSTD_BIN" | grep 'GNU_STACK .* RW ' || die "zstd binary has executable stack!"
|
||||
readelf -lW "$ZSTD_BIN" | $GREP 'GNU_STACK .* RW ' || die "zstd binary has executable stack!"
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -413,9 +415,9 @@ zstd -q tmp tmp2 -o tmp3.zst --rm && die "should refuse to concatenate"
|
||||
println "test : should quietly not remove non-regular file"
|
||||
println hello > tmp
|
||||
zstd tmp -f -o "$DEVDEVICE" 2>tmplog > "$INTOVOID"
|
||||
grep "Refusing to remove non-regular file" tmplog && die
|
||||
$GREP "Refusing to remove non-regular file" tmplog && die
|
||||
rm -f tmplog
|
||||
zstd tmp -f -o "$INTOVOID" 2>&1 | grep "Refusing to remove non-regular file" && die
|
||||
zstd tmp -f -o "$INTOVOID" 2>&1 | $GREP "Refusing to remove non-regular file" && die
|
||||
println "test : --rm on stdin"
|
||||
println a | zstd --rm > $INTOVOID # --rm should remain silent
|
||||
rm -f tmp
|
||||
@@ -615,7 +617,7 @@ if [ -n "$DEVNULLRIGHTS" ] ; then
|
||||
zstd tmp -f -o tmp.zst
|
||||
sudoZstd -d tmp.zst -c > $INTOVOID
|
||||
sudoZstd -d tmp.zst -o $INTOVOID
|
||||
ls -las $INTOVOID | grep "rw-rw-rw-"
|
||||
ls -las $INTOVOID | $GREP "rw-rw-rw-"
|
||||
fi
|
||||
|
||||
if [ -n "$READFROMBLOCKDEVICE" ] ; then
|
||||
@@ -625,7 +627,7 @@ if [ -n "$READFROMBLOCKDEVICE" ] ; then
|
||||
println "\n===> checking that zstd can read from a block device"
|
||||
datagen -g65536 > tmp.img
|
||||
sudo losetup -fP tmp.img
|
||||
LOOP_DEV=$(losetup -a | grep 'tmp\.img' | cut -f1 -d:)
|
||||
LOOP_DEV=$(losetup -a | $GREP 'tmp\.img' | cut -f1 -d:)
|
||||
[ -z "$LOOP_DEV" ] && die "failed to get loopback device"
|
||||
sudoZstd $LOOP_DEV -c > tmp.img.zst && die "should fail without -f"
|
||||
sudoZstd -f $LOOP_DEV -c > tmp.img.zst
|
||||
@@ -774,13 +776,13 @@ println "\n===> --[no-]content-size tests"
|
||||
|
||||
datagen > tmp_contentsize
|
||||
zstd -f tmp_contentsize
|
||||
zstd -lv tmp_contentsize.zst | grep "Decompressed Size:"
|
||||
zstd -lv tmp_contentsize.zst | $GREP "Decompressed Size:"
|
||||
zstd -f --no-content-size tmp_contentsize
|
||||
zstd -lv tmp_contentsize.zst | grep "Decompressed Size:" && die
|
||||
zstd -lv tmp_contentsize.zst | $GREP "Decompressed Size:" && die
|
||||
zstd -f --content-size tmp_contentsize
|
||||
zstd -lv tmp_contentsize.zst | grep "Decompressed Size:"
|
||||
zstd -lv tmp_contentsize.zst | $GREP "Decompressed Size:"
|
||||
zstd -f --content-size --no-content-size tmp_contentsize
|
||||
zstd -lv tmp_contentsize.zst | grep "Decompressed Size:" && die
|
||||
zstd -lv tmp_contentsize.zst | $GREP "Decompressed Size:" && die
|
||||
rm -rf tmp*
|
||||
|
||||
println "test : show-default-cparams regular"
|
||||
@@ -800,8 +802,7 @@ rm -rf tmp*
|
||||
println "test : show compression parameters in verbose mode"
|
||||
datagen > tmp
|
||||
zstd -vv tmp 2>&1 | \
|
||||
grep -q -E -- "--zstd=wlog=[[:digit:]]+,clog=[[:digit:]]+,hlog=[[:digit:]]+,\
|
||||
slog=[[:digit:]]+,mml=[[:digit:]]+,tlen=[[:digit:]]+,strat=[[:digit:]]+"
|
||||
$GREP -q -- "--zstd=wlog=[0-9]*,clog=[0-9]*,hlog=[0-9]*,slog=[0-9]*,mml=[0-9]*,tlen=[0-9]*,strat=[0-9]*"
|
||||
rm -rf tmp*
|
||||
|
||||
println "\n===> Advanced compression parameters "
|
||||
@@ -1098,8 +1099,8 @@ println "- Test --memory for dictionary compression"
|
||||
datagen -g12M -P90 > tmpCorpusHighCompress
|
||||
zstd --train -B2K tmpCorpusHighCompress -o tmpDictHighCompress --memory=10K && die "Dictionary training should fail : --memory too low (10K)"
|
||||
zstd --train -B2K tmpCorpusHighCompress -o tmpDictHighCompress --memory=5MB 2> zstTrainWithMemLimitStdErr
|
||||
cat zstTrainWithMemLimitStdErr | grep "setting manual memory limit for dictionary training data at 5 MB"
|
||||
cat zstTrainWithMemLimitStdErr | grep "Training samples set too large (12 MB); training on 5 MB only..."
|
||||
cat zstTrainWithMemLimitStdErr | $GREP "setting manual memory limit for dictionary training data at 5 MB"
|
||||
cat zstTrainWithMemLimitStdErr | $GREP "Training samples set too large (12 MB); training on 5 MB only..."
|
||||
rm zstTrainWithMemLimitStdErr
|
||||
|
||||
println "\n===> fastCover dictionary builder : advanced options "
|
||||
@@ -1385,16 +1386,16 @@ println "\n===> suffix list test"
|
||||
! zstd -d tmp.abc 2> tmplg
|
||||
|
||||
if [ $GZIPMODE -ne 1 ]; then
|
||||
grep ".gz" tmplg > $INTOVOID && die "Unsupported suffix listed"
|
||||
$GREP ".gz" tmplg > $INTOVOID && die "Unsupported suffix listed"
|
||||
fi
|
||||
|
||||
if [ $LZMAMODE -ne 1 ]; then
|
||||
grep ".lzma" tmplg > $INTOVOID && die "Unsupported suffix listed"
|
||||
grep ".xz" tmplg > $INTOVOID && die "Unsupported suffix listed"
|
||||
$GREP ".lzma" tmplg > $INTOVOID && die "Unsupported suffix listed"
|
||||
$GREP ".xz" tmplg > $INTOVOID && die "Unsupported suffix listed"
|
||||
fi
|
||||
|
||||
if [ $LZ4MODE -ne 1 ]; then
|
||||
grep ".lz4" tmplg > $INTOVOID && die "Unsupported suffix listed"
|
||||
$GREP ".lz4" tmplg > $INTOVOID && die "Unsupported suffix listed"
|
||||
fi
|
||||
|
||||
touch tmp1
|
||||
@@ -1523,7 +1524,7 @@ datagen > tmp2
|
||||
datagen > tmp3
|
||||
zstd tmp*
|
||||
zstd -l ./*.zst
|
||||
zstd -lv ./*.zst | grep "Decompressed Size:" # check that decompressed size is present in header
|
||||
zstd -lv ./*.zst | $GREP "Decompressed Size:" # check that decompressed size is present in header
|
||||
zstd --list ./*.zst
|
||||
zstd --list -v ./*.zst
|
||||
|
||||
@@ -1566,13 +1567,13 @@ datagen -g0 > tmp5
|
||||
zstd tmp5
|
||||
zstd -l tmp5.zst
|
||||
zstd -l tmp5* && die "-l must fail on non-zstd file"
|
||||
zstd -lv tmp5.zst | grep "Decompressed Size: 0 B (0 B)" # check that 0 size is present in header
|
||||
zstd -lv tmp5.zst | $GREP "Decompressed Size: 0 B (0 B)" # check that 0 size is present in header
|
||||
zstd -lv tmp5* && die "-l must fail on non-zstd file"
|
||||
|
||||
println "\n===> zstd --list/-l test with no content size field "
|
||||
datagen -g513K | zstd > tmp6.zst
|
||||
zstd -l tmp6.zst
|
||||
zstd -lv tmp6.zst | grep "Decompressed Size:" && die "Field :Decompressed Size: should not be available in this compressed file"
|
||||
zstd -lv tmp6.zst | $GREP "Decompressed Size:" && die "Field :Decompressed Size: should not be available in this compressed file"
|
||||
|
||||
println "\n===> zstd --list/-l test with no checksum "
|
||||
zstd -f --no-check tmp1
|
||||
@@ -1723,7 +1724,7 @@ else
|
||||
datagen -g5000000 > tmp_dict
|
||||
datagen -g5000000 > tmp_patch
|
||||
fi
|
||||
zstd -15 --patch-from=tmp_dict tmp_patch 2>&1 | grep "long mode automatically triggered"
|
||||
zstd -15 --patch-from=tmp_dict tmp_patch 2>&1 | $GREP "long mode automatically triggered"
|
||||
rm -rf tmp*
|
||||
|
||||
println "\n===> patch-from very large dictionary and file test"
|
||||
|
||||
+132
-132
@@ -11,10 +11,10 @@ silesia.tar, level 6, compress
|
||||
silesia.tar, level 7, compress simple, 4579828
|
||||
silesia.tar, level 9, compress simple, 4555448
|
||||
silesia.tar, level 13, compress simple, 4502956
|
||||
silesia.tar, level 16, compress simple, 4360546
|
||||
silesia.tar, level 19, compress simple, 4265911
|
||||
silesia.tar, level 16, compress simple, 4360385
|
||||
silesia.tar, level 19, compress simple, 4260939
|
||||
silesia.tar, uncompressed literals, compress simple, 4854086
|
||||
silesia.tar, uncompressed literals optimal, compress simple, 4265911
|
||||
silesia.tar, uncompressed literals optimal, compress simple, 4260939
|
||||
silesia.tar, huffman literals, compress simple, 6179047
|
||||
github.tar, level -5, compress simple, 52115
|
||||
github.tar, level -3, compress simple, 45678
|
||||
@@ -29,9 +29,9 @@ github.tar, level 7, compress
|
||||
github.tar, level 9, compress simple, 36723
|
||||
github.tar, level 13, compress simple, 35501
|
||||
github.tar, level 16, compress simple, 40466
|
||||
github.tar, level 19, compress simple, 32276
|
||||
github.tar, level 19, compress simple, 32262
|
||||
github.tar, uncompressed literals, compress simple, 38831
|
||||
github.tar, uncompressed literals optimal, compress simple, 32276
|
||||
github.tar, uncompressed literals optimal, compress simple, 32262
|
||||
github.tar, huffman literals, compress simple, 42560
|
||||
silesia, level -5, compress cctx, 6857372
|
||||
silesia, level -3, compress cctx, 6503412
|
||||
@@ -45,8 +45,8 @@ silesia, level 6, compress
|
||||
silesia, level 7, compress cctx, 4570271
|
||||
silesia, level 9, compress cctx, 4545850
|
||||
silesia, level 13, compress cctx, 4493990
|
||||
silesia, level 16, compress cctx, 4360041
|
||||
silesia, level 19, compress cctx, 4296055
|
||||
silesia, level 16, compress cctx, 4359652
|
||||
silesia, level 19, compress cctx, 4266582
|
||||
silesia, long distance mode, compress cctx, 4842075
|
||||
silesia, multithreaded, compress cctx, 4842075
|
||||
silesia, multithreaded long distance mode, compress cctx, 4842075
|
||||
@@ -55,7 +55,7 @@ silesia, small hash log, compress
|
||||
silesia, small chain log, compress cctx, 4912197
|
||||
silesia, explicit params, compress cctx, 4794318
|
||||
silesia, uncompressed literals, compress cctx, 4842075
|
||||
silesia, uncompressed literals optimal, compress cctx, 4296055
|
||||
silesia, uncompressed literals optimal, compress cctx, 4266582
|
||||
silesia, huffman literals, compress cctx, 6172202
|
||||
silesia, multithreaded with advanced params, compress cctx, 4842075
|
||||
github, level -5, compress cctx, 204407
|
||||
@@ -83,9 +83,9 @@ github, level 9 with dict, compress
|
||||
github, level 13, compress cctx, 132878
|
||||
github, level 13 with dict, compress cctx, 39948
|
||||
github, level 16, compress cctx, 133209
|
||||
github, level 16 with dict, compress cctx, 37568
|
||||
github, level 16 with dict, compress cctx, 37892
|
||||
github, level 19, compress cctx, 132879
|
||||
github, level 19 with dict, compress cctx, 37567
|
||||
github, level 19 with dict, compress cctx, 37906
|
||||
github, long distance mode, compress cctx, 141069
|
||||
github, multithreaded, compress cctx, 141069
|
||||
github, multithreaded long distance mode, compress cctx, 141069
|
||||
@@ -109,8 +109,8 @@ silesia, level 6, zstdcli,
|
||||
silesia, level 7, zstdcli, 4570319
|
||||
silesia, level 9, zstdcli, 4545898
|
||||
silesia, level 13, zstdcli, 4494038
|
||||
silesia, level 16, zstdcli, 4360089
|
||||
silesia, level 19, zstdcli, 4296103
|
||||
silesia, level 16, zstdcli, 4359700
|
||||
silesia, level 19, zstdcli, 4266630
|
||||
silesia, long distance mode, zstdcli, 4833785
|
||||
silesia, multithreaded, zstdcli, 4842123
|
||||
silesia, multithreaded long distance mode, zstdcli, 4833785
|
||||
@@ -119,7 +119,7 @@ silesia, small hash log, zstdcli,
|
||||
silesia, small chain log, zstdcli, 4912245
|
||||
silesia, explicit params, zstdcli, 4795840
|
||||
silesia, uncompressed literals, zstdcli, 5120614
|
||||
silesia, uncompressed literals optimal, zstdcli, 4319566
|
||||
silesia, uncompressed literals optimal, zstdcli, 4316928
|
||||
silesia, huffman literals, zstdcli, 5321417
|
||||
silesia, multithreaded with advanced params, zstdcli, 5120614
|
||||
silesia.tar, level -5, zstdcli, 6862049
|
||||
@@ -134,8 +134,8 @@ silesia.tar, level 6, zstdcli,
|
||||
silesia.tar, level 7, zstdcli, 4581791
|
||||
silesia.tar, level 9, zstdcli, 4555452
|
||||
silesia.tar, level 13, zstdcli, 4502960
|
||||
silesia.tar, level 16, zstdcli, 4360550
|
||||
silesia.tar, level 19, zstdcli, 4265915
|
||||
silesia.tar, level 16, zstdcli, 4360389
|
||||
silesia.tar, level 19, zstdcli, 4260943
|
||||
silesia.tar, no source size, zstdcli, 4854160
|
||||
silesia.tar, long distance mode, zstdcli, 4845745
|
||||
silesia.tar, multithreaded, zstdcli, 4854164
|
||||
@@ -145,7 +145,7 @@ silesia.tar, small hash log, zstdcli,
|
||||
silesia.tar, small chain log, zstdcli, 4917022
|
||||
silesia.tar, explicit params, zstdcli, 4821112
|
||||
silesia.tar, uncompressed literals, zstdcli, 5122571
|
||||
silesia.tar, uncompressed literals optimal, zstdcli, 4310145
|
||||
silesia.tar, uncompressed literals optimal, zstdcli, 4308455
|
||||
silesia.tar, huffman literals, zstdcli, 5342074
|
||||
silesia.tar, multithreaded with advanced params, zstdcli, 5122571
|
||||
github, level -5, zstdcli, 206407
|
||||
@@ -173,9 +173,9 @@ github, level 9 with dict, zstdcli,
|
||||
github, level 13, zstdcli, 134878
|
||||
github, level 13 with dict, zstdcli, 41900
|
||||
github, level 16, zstdcli, 135209
|
||||
github, level 16 with dict, zstdcli, 39577
|
||||
github, level 16 with dict, zstdcli, 39902
|
||||
github, level 19, zstdcli, 134879
|
||||
github, level 19 with dict, zstdcli, 39576
|
||||
github, level 19 with dict, zstdcli, 39916
|
||||
github, long distance mode, zstdcli, 138332
|
||||
github, multithreaded, zstdcli, 138332
|
||||
github, multithreaded long distance mode, zstdcli, 138332
|
||||
@@ -212,9 +212,9 @@ github.tar, level 9 with dict, zstdcli,
|
||||
github.tar, level 13, zstdcli, 35505
|
||||
github.tar, level 13 with dict, zstdcli, 37134
|
||||
github.tar, level 16, zstdcli, 40470
|
||||
github.tar, level 16 with dict, zstdcli, 33378
|
||||
github.tar, level 19, zstdcli, 32280
|
||||
github.tar, level 19 with dict, zstdcli, 32716
|
||||
github.tar, level 16 with dict, zstdcli, 33379
|
||||
github.tar, level 19, zstdcli, 32266
|
||||
github.tar, level 19 with dict, zstdcli, 32705
|
||||
github.tar, no source size, zstdcli, 38832
|
||||
github.tar, no source size with dict, zstdcli, 38004
|
||||
github.tar, long distance mode, zstdcli, 40236
|
||||
@@ -225,7 +225,7 @@ github.tar, small hash log, zstdcli,
|
||||
github.tar, small chain log, zstdcli, 41673
|
||||
github.tar, explicit params, zstdcli, 41385
|
||||
github.tar, uncompressed literals, zstdcli, 41529
|
||||
github.tar, uncompressed literals optimal, zstdcli, 35401
|
||||
github.tar, uncompressed literals optimal, zstdcli, 35360
|
||||
github.tar, huffman literals, zstdcli, 38857
|
||||
github.tar, multithreaded with advanced params, zstdcli, 41529
|
||||
silesia, level -5, advanced one pass, 6857372
|
||||
@@ -248,8 +248,8 @@ silesia, level 11 row 2, advanced
|
||||
silesia, level 12 row 1, advanced one pass, 4505658
|
||||
silesia, level 12 row 2, advanced one pass, 4503429
|
||||
silesia, level 13, advanced one pass, 4493990
|
||||
silesia, level 16, advanced one pass, 4360041
|
||||
silesia, level 19, advanced one pass, 4296055
|
||||
silesia, level 16, advanced one pass, 4359652
|
||||
silesia, level 19, advanced one pass, 4266582
|
||||
silesia, no source size, advanced one pass, 4842075
|
||||
silesia, long distance mode, advanced one pass, 4833710
|
||||
silesia, multithreaded, advanced one pass, 4842075
|
||||
@@ -259,7 +259,7 @@ silesia, small hash log, advanced
|
||||
silesia, small chain log, advanced one pass, 4912197
|
||||
silesia, explicit params, advanced one pass, 4795840
|
||||
silesia, uncompressed literals, advanced one pass, 5120566
|
||||
silesia, uncompressed literals optimal, advanced one pass, 4319518
|
||||
silesia, uncompressed literals optimal, advanced one pass, 4316880
|
||||
silesia, huffman literals, advanced one pass, 5321369
|
||||
silesia, multithreaded with advanced params, advanced one pass, 5120566
|
||||
silesia.tar, level -5, advanced one pass, 6861055
|
||||
@@ -282,8 +282,8 @@ silesia.tar, level 11 row 2, advanced
|
||||
silesia.tar, level 12 row 1, advanced one pass, 4514517
|
||||
silesia.tar, level 12 row 2, advanced one pass, 4514007
|
||||
silesia.tar, level 13, advanced one pass, 4502956
|
||||
silesia.tar, level 16, advanced one pass, 4360546
|
||||
silesia.tar, level 19, advanced one pass, 4265911
|
||||
silesia.tar, level 16, advanced one pass, 4360385
|
||||
silesia.tar, level 19, advanced one pass, 4260939
|
||||
silesia.tar, no source size, advanced one pass, 4854086
|
||||
silesia.tar, long distance mode, advanced one pass, 4840452
|
||||
silesia.tar, multithreaded, advanced one pass, 4854160
|
||||
@@ -293,7 +293,7 @@ silesia.tar, small hash log, advanced
|
||||
silesia.tar, small chain log, advanced one pass, 4917041
|
||||
silesia.tar, explicit params, advanced one pass, 4807274
|
||||
silesia.tar, uncompressed literals, advanced one pass, 5122473
|
||||
silesia.tar, uncompressed literals optimal, advanced one pass, 4310141
|
||||
silesia.tar, uncompressed literals optimal, advanced one pass, 4308451
|
||||
silesia.tar, huffman literals, advanced one pass, 5341705
|
||||
silesia.tar, multithreaded with advanced params, advanced one pass, 5122567
|
||||
github, level -5, advanced one pass, 204407
|
||||
@@ -397,17 +397,17 @@ github, level 13 with dict dds, advanced
|
||||
github, level 13 with dict copy, advanced one pass, 39948
|
||||
github, level 13 with dict load, advanced one pass, 42624
|
||||
github, level 16, advanced one pass, 133209
|
||||
github, level 16 with dict, advanced one pass, 37577
|
||||
github, level 16 with dict dms, advanced one pass, 37577
|
||||
github, level 16 with dict dds, advanced one pass, 37577
|
||||
github, level 16 with dict copy, advanced one pass, 37568
|
||||
github, level 16 with dict load, advanced one pass, 42338
|
||||
github, level 16 with dict, advanced one pass, 37902
|
||||
github, level 16 with dict dms, advanced one pass, 37902
|
||||
github, level 16 with dict dds, advanced one pass, 37902
|
||||
github, level 16 with dict copy, advanced one pass, 37892
|
||||
github, level 16 with dict load, advanced one pass, 42402
|
||||
github, level 19, advanced one pass, 132879
|
||||
github, level 19 with dict, advanced one pass, 37576
|
||||
github, level 19 with dict dms, advanced one pass, 37576
|
||||
github, level 19 with dict dds, advanced one pass, 37576
|
||||
github, level 19 with dict copy, advanced one pass, 37567
|
||||
github, level 19 with dict load, advanced one pass, 39613
|
||||
github, level 19 with dict, advanced one pass, 37916
|
||||
github, level 19 with dict dms, advanced one pass, 37916
|
||||
github, level 19 with dict dds, advanced one pass, 37916
|
||||
github, level 19 with dict copy, advanced one pass, 37906
|
||||
github, level 19 with dict load, advanced one pass, 39770
|
||||
github, no source size, advanced one pass, 136332
|
||||
github, no source size with dict, advanced one pass, 41148
|
||||
github, long distance mode, advanced one pass, 136332
|
||||
@@ -522,17 +522,17 @@ github.tar, level 13 with dict dds, advanced
|
||||
github.tar, level 13 with dict copy, advanced one pass, 37130
|
||||
github.tar, level 13 with dict load, advanced one pass, 36010
|
||||
github.tar, level 16, advanced one pass, 40466
|
||||
github.tar, level 16 with dict, advanced one pass, 33374
|
||||
github.tar, level 16 with dict dms, advanced one pass, 33206
|
||||
github.tar, level 16 with dict dds, advanced one pass, 33206
|
||||
github.tar, level 16 with dict copy, advanced one pass, 33374
|
||||
github.tar, level 16 with dict, advanced one pass, 33375
|
||||
github.tar, level 16 with dict dms, advanced one pass, 33207
|
||||
github.tar, level 16 with dict dds, advanced one pass, 33207
|
||||
github.tar, level 16 with dict copy, advanced one pass, 33375
|
||||
github.tar, level 16 with dict load, advanced one pass, 39081
|
||||
github.tar, level 19, advanced one pass, 32276
|
||||
github.tar, level 19 with dict, advanced one pass, 32712
|
||||
github.tar, level 19 with dict dms, advanced one pass, 32555
|
||||
github.tar, level 19 with dict dds, advanced one pass, 32555
|
||||
github.tar, level 19 with dict copy, advanced one pass, 32712
|
||||
github.tar, level 19 with dict load, advanced one pass, 32479
|
||||
github.tar, level 19, advanced one pass, 32262
|
||||
github.tar, level 19 with dict, advanced one pass, 32701
|
||||
github.tar, level 19 with dict dms, advanced one pass, 32565
|
||||
github.tar, level 19 with dict dds, advanced one pass, 32565
|
||||
github.tar, level 19 with dict copy, advanced one pass, 32701
|
||||
github.tar, level 19 with dict load, advanced one pass, 32428
|
||||
github.tar, no source size, advanced one pass, 38831
|
||||
github.tar, no source size with dict, advanced one pass, 37995
|
||||
github.tar, long distance mode, advanced one pass, 40252
|
||||
@@ -543,7 +543,7 @@ github.tar, small hash log, advanced
|
||||
github.tar, small chain log, advanced one pass, 41669
|
||||
github.tar, explicit params, advanced one pass, 41385
|
||||
github.tar, uncompressed literals, advanced one pass, 41525
|
||||
github.tar, uncompressed literals optimal, advanced one pass, 35397
|
||||
github.tar, uncompressed literals optimal, advanced one pass, 35356
|
||||
github.tar, huffman literals, advanced one pass, 38853
|
||||
github.tar, multithreaded with advanced params, advanced one pass, 41525
|
||||
silesia, level -5, advanced one pass small out, 6857372
|
||||
@@ -566,8 +566,8 @@ silesia, level 11 row 2, advanced
|
||||
silesia, level 12 row 1, advanced one pass small out, 4505658
|
||||
silesia, level 12 row 2, advanced one pass small out, 4503429
|
||||
silesia, level 13, advanced one pass small out, 4493990
|
||||
silesia, level 16, advanced one pass small out, 4360041
|
||||
silesia, level 19, advanced one pass small out, 4296055
|
||||
silesia, level 16, advanced one pass small out, 4359652
|
||||
silesia, level 19, advanced one pass small out, 4266582
|
||||
silesia, no source size, advanced one pass small out, 4842075
|
||||
silesia, long distance mode, advanced one pass small out, 4833710
|
||||
silesia, multithreaded, advanced one pass small out, 4842075
|
||||
@@ -577,7 +577,7 @@ silesia, small hash log, advanced
|
||||
silesia, small chain log, advanced one pass small out, 4912197
|
||||
silesia, explicit params, advanced one pass small out, 4795840
|
||||
silesia, uncompressed literals, advanced one pass small out, 5120566
|
||||
silesia, uncompressed literals optimal, advanced one pass small out, 4319518
|
||||
silesia, uncompressed literals optimal, advanced one pass small out, 4316880
|
||||
silesia, huffman literals, advanced one pass small out, 5321369
|
||||
silesia, multithreaded with advanced params, advanced one pass small out, 5120566
|
||||
silesia.tar, level -5, advanced one pass small out, 6861055
|
||||
@@ -600,8 +600,8 @@ silesia.tar, level 11 row 2, advanced
|
||||
silesia.tar, level 12 row 1, advanced one pass small out, 4514517
|
||||
silesia.tar, level 12 row 2, advanced one pass small out, 4514007
|
||||
silesia.tar, level 13, advanced one pass small out, 4502956
|
||||
silesia.tar, level 16, advanced one pass small out, 4360546
|
||||
silesia.tar, level 19, advanced one pass small out, 4265911
|
||||
silesia.tar, level 16, advanced one pass small out, 4360385
|
||||
silesia.tar, level 19, advanced one pass small out, 4260939
|
||||
silesia.tar, no source size, advanced one pass small out, 4854086
|
||||
silesia.tar, long distance mode, advanced one pass small out, 4840452
|
||||
silesia.tar, multithreaded, advanced one pass small out, 4854160
|
||||
@@ -611,7 +611,7 @@ silesia.tar, small hash log, advanced
|
||||
silesia.tar, small chain log, advanced one pass small out, 4917041
|
||||
silesia.tar, explicit params, advanced one pass small out, 4807274
|
||||
silesia.tar, uncompressed literals, advanced one pass small out, 5122473
|
||||
silesia.tar, uncompressed literals optimal, advanced one pass small out, 4310141
|
||||
silesia.tar, uncompressed literals optimal, advanced one pass small out, 4308451
|
||||
silesia.tar, huffman literals, advanced one pass small out, 5341705
|
||||
silesia.tar, multithreaded with advanced params, advanced one pass small out, 5122567
|
||||
github, level -5, advanced one pass small out, 204407
|
||||
@@ -715,17 +715,17 @@ github, level 13 with dict dds, advanced
|
||||
github, level 13 with dict copy, advanced one pass small out, 39948
|
||||
github, level 13 with dict load, advanced one pass small out, 42624
|
||||
github, level 16, advanced one pass small out, 133209
|
||||
github, level 16 with dict, advanced one pass small out, 37577
|
||||
github, level 16 with dict dms, advanced one pass small out, 37577
|
||||
github, level 16 with dict dds, advanced one pass small out, 37577
|
||||
github, level 16 with dict copy, advanced one pass small out, 37568
|
||||
github, level 16 with dict load, advanced one pass small out, 42338
|
||||
github, level 16 with dict, advanced one pass small out, 37902
|
||||
github, level 16 with dict dms, advanced one pass small out, 37902
|
||||
github, level 16 with dict dds, advanced one pass small out, 37902
|
||||
github, level 16 with dict copy, advanced one pass small out, 37892
|
||||
github, level 16 with dict load, advanced one pass small out, 42402
|
||||
github, level 19, advanced one pass small out, 132879
|
||||
github, level 19 with dict, advanced one pass small out, 37576
|
||||
github, level 19 with dict dms, advanced one pass small out, 37576
|
||||
github, level 19 with dict dds, advanced one pass small out, 37576
|
||||
github, level 19 with dict copy, advanced one pass small out, 37567
|
||||
github, level 19 with dict load, advanced one pass small out, 39613
|
||||
github, level 19 with dict, advanced one pass small out, 37916
|
||||
github, level 19 with dict dms, advanced one pass small out, 37916
|
||||
github, level 19 with dict dds, advanced one pass small out, 37916
|
||||
github, level 19 with dict copy, advanced one pass small out, 37906
|
||||
github, level 19 with dict load, advanced one pass small out, 39770
|
||||
github, no source size, advanced one pass small out, 136332
|
||||
github, no source size with dict, advanced one pass small out, 41148
|
||||
github, long distance mode, advanced one pass small out, 136332
|
||||
@@ -840,17 +840,17 @@ github.tar, level 13 with dict dds, advanced
|
||||
github.tar, level 13 with dict copy, advanced one pass small out, 37130
|
||||
github.tar, level 13 with dict load, advanced one pass small out, 36010
|
||||
github.tar, level 16, advanced one pass small out, 40466
|
||||
github.tar, level 16 with dict, advanced one pass small out, 33374
|
||||
github.tar, level 16 with dict dms, advanced one pass small out, 33206
|
||||
github.tar, level 16 with dict dds, advanced one pass small out, 33206
|
||||
github.tar, level 16 with dict copy, advanced one pass small out, 33374
|
||||
github.tar, level 16 with dict, advanced one pass small out, 33375
|
||||
github.tar, level 16 with dict dms, advanced one pass small out, 33207
|
||||
github.tar, level 16 with dict dds, advanced one pass small out, 33207
|
||||
github.tar, level 16 with dict copy, advanced one pass small out, 33375
|
||||
github.tar, level 16 with dict load, advanced one pass small out, 39081
|
||||
github.tar, level 19, advanced one pass small out, 32276
|
||||
github.tar, level 19 with dict, advanced one pass small out, 32712
|
||||
github.tar, level 19 with dict dms, advanced one pass small out, 32555
|
||||
github.tar, level 19 with dict dds, advanced one pass small out, 32555
|
||||
github.tar, level 19 with dict copy, advanced one pass small out, 32712
|
||||
github.tar, level 19 with dict load, advanced one pass small out, 32479
|
||||
github.tar, level 19, advanced one pass small out, 32262
|
||||
github.tar, level 19 with dict, advanced one pass small out, 32701
|
||||
github.tar, level 19 with dict dms, advanced one pass small out, 32565
|
||||
github.tar, level 19 with dict dds, advanced one pass small out, 32565
|
||||
github.tar, level 19 with dict copy, advanced one pass small out, 32701
|
||||
github.tar, level 19 with dict load, advanced one pass small out, 32428
|
||||
github.tar, no source size, advanced one pass small out, 38831
|
||||
github.tar, no source size with dict, advanced one pass small out, 37995
|
||||
github.tar, long distance mode, advanced one pass small out, 40252
|
||||
@@ -861,7 +861,7 @@ github.tar, small hash log, advanced
|
||||
github.tar, small chain log, advanced one pass small out, 41669
|
||||
github.tar, explicit params, advanced one pass small out, 41385
|
||||
github.tar, uncompressed literals, advanced one pass small out, 41525
|
||||
github.tar, uncompressed literals optimal, advanced one pass small out, 35397
|
||||
github.tar, uncompressed literals optimal, advanced one pass small out, 35356
|
||||
github.tar, huffman literals, advanced one pass small out, 38853
|
||||
github.tar, multithreaded with advanced params, advanced one pass small out, 41525
|
||||
silesia, level -5, advanced streaming, 6854744
|
||||
@@ -884,8 +884,8 @@ silesia, level 11 row 2, advanced
|
||||
silesia, level 12 row 1, advanced streaming, 4505658
|
||||
silesia, level 12 row 2, advanced streaming, 4503429
|
||||
silesia, level 13, advanced streaming, 4493990
|
||||
silesia, level 16, advanced streaming, 4360041
|
||||
silesia, level 19, advanced streaming, 4296055
|
||||
silesia, level 16, advanced streaming, 4359652
|
||||
silesia, level 19, advanced streaming, 4266582
|
||||
silesia, no source size, advanced streaming, 4842039
|
||||
silesia, long distance mode, advanced streaming, 4833710
|
||||
silesia, multithreaded, advanced streaming, 4842075
|
||||
@@ -895,7 +895,7 @@ silesia, small hash log, advanced
|
||||
silesia, small chain log, advanced streaming, 4912197
|
||||
silesia, explicit params, advanced streaming, 4795857
|
||||
silesia, uncompressed literals, advanced streaming, 5120566
|
||||
silesia, uncompressed literals optimal, advanced streaming, 4319518
|
||||
silesia, uncompressed literals optimal, advanced streaming, 4316880
|
||||
silesia, huffman literals, advanced streaming, 5321370
|
||||
silesia, multithreaded with advanced params, advanced streaming, 5120566
|
||||
silesia.tar, level -5, advanced streaming, 6856523
|
||||
@@ -918,8 +918,8 @@ silesia.tar, level 11 row 2, advanced
|
||||
silesia.tar, level 12 row 1, advanced streaming, 4514514
|
||||
silesia.tar, level 12 row 2, advanced streaming, 4514003
|
||||
silesia.tar, level 13, advanced streaming, 4502956
|
||||
silesia.tar, level 16, advanced streaming, 4360546
|
||||
silesia.tar, level 19, advanced streaming, 4265911
|
||||
silesia.tar, level 16, advanced streaming, 4360385
|
||||
silesia.tar, level 19, advanced streaming, 4260939
|
||||
silesia.tar, no source size, advanced streaming, 4859267
|
||||
silesia.tar, long distance mode, advanced streaming, 4840452
|
||||
silesia.tar, multithreaded, advanced streaming, 4854160
|
||||
@@ -929,7 +929,7 @@ silesia.tar, small hash log, advanced
|
||||
silesia.tar, small chain log, advanced streaming, 4917021
|
||||
silesia.tar, explicit params, advanced streaming, 4807288
|
||||
silesia.tar, uncompressed literals, advanced streaming, 5127423
|
||||
silesia.tar, uncompressed literals optimal, advanced streaming, 4310141
|
||||
silesia.tar, uncompressed literals optimal, advanced streaming, 4308451
|
||||
silesia.tar, huffman literals, advanced streaming, 5341712
|
||||
silesia.tar, multithreaded with advanced params, advanced streaming, 5122567
|
||||
github, level -5, advanced streaming, 204407
|
||||
@@ -1033,17 +1033,17 @@ github, level 13 with dict dds, advanced
|
||||
github, level 13 with dict copy, advanced streaming, 39948
|
||||
github, level 13 with dict load, advanced streaming, 42624
|
||||
github, level 16, advanced streaming, 133209
|
||||
github, level 16 with dict, advanced streaming, 37577
|
||||
github, level 16 with dict dms, advanced streaming, 37577
|
||||
github, level 16 with dict dds, advanced streaming, 37577
|
||||
github, level 16 with dict copy, advanced streaming, 37568
|
||||
github, level 16 with dict load, advanced streaming, 42338
|
||||
github, level 16 with dict, advanced streaming, 37902
|
||||
github, level 16 with dict dms, advanced streaming, 37902
|
||||
github, level 16 with dict dds, advanced streaming, 37902
|
||||
github, level 16 with dict copy, advanced streaming, 37892
|
||||
github, level 16 with dict load, advanced streaming, 42402
|
||||
github, level 19, advanced streaming, 132879
|
||||
github, level 19 with dict, advanced streaming, 37576
|
||||
github, level 19 with dict dms, advanced streaming, 37576
|
||||
github, level 19 with dict dds, advanced streaming, 37576
|
||||
github, level 19 with dict copy, advanced streaming, 37567
|
||||
github, level 19 with dict load, advanced streaming, 39613
|
||||
github, level 19 with dict, advanced streaming, 37916
|
||||
github, level 19 with dict dms, advanced streaming, 37916
|
||||
github, level 19 with dict dds, advanced streaming, 37916
|
||||
github, level 19 with dict copy, advanced streaming, 37906
|
||||
github, level 19 with dict load, advanced streaming, 39770
|
||||
github, no source size, advanced streaming, 136332
|
||||
github, no source size with dict, advanced streaming, 41148
|
||||
github, long distance mode, advanced streaming, 136332
|
||||
@@ -1158,17 +1158,17 @@ github.tar, level 13 with dict dds, advanced
|
||||
github.tar, level 13 with dict copy, advanced streaming, 37130
|
||||
github.tar, level 13 with dict load, advanced streaming, 36010
|
||||
github.tar, level 16, advanced streaming, 40466
|
||||
github.tar, level 16 with dict, advanced streaming, 33374
|
||||
github.tar, level 16 with dict dms, advanced streaming, 33206
|
||||
github.tar, level 16 with dict dds, advanced streaming, 33206
|
||||
github.tar, level 16 with dict copy, advanced streaming, 33374
|
||||
github.tar, level 16 with dict, advanced streaming, 33375
|
||||
github.tar, level 16 with dict dms, advanced streaming, 33207
|
||||
github.tar, level 16 with dict dds, advanced streaming, 33207
|
||||
github.tar, level 16 with dict copy, advanced streaming, 33375
|
||||
github.tar, level 16 with dict load, advanced streaming, 39081
|
||||
github.tar, level 19, advanced streaming, 32276
|
||||
github.tar, level 19 with dict, advanced streaming, 32712
|
||||
github.tar, level 19 with dict dms, advanced streaming, 32555
|
||||
github.tar, level 19 with dict dds, advanced streaming, 32555
|
||||
github.tar, level 19 with dict copy, advanced streaming, 32712
|
||||
github.tar, level 19 with dict load, advanced streaming, 32479
|
||||
github.tar, level 19, advanced streaming, 32262
|
||||
github.tar, level 19 with dict, advanced streaming, 32701
|
||||
github.tar, level 19 with dict dms, advanced streaming, 32565
|
||||
github.tar, level 19 with dict dds, advanced streaming, 32565
|
||||
github.tar, level 19 with dict copy, advanced streaming, 32701
|
||||
github.tar, level 19 with dict load, advanced streaming, 32428
|
||||
github.tar, no source size, advanced streaming, 38828
|
||||
github.tar, no source size with dict, advanced streaming, 38000
|
||||
github.tar, long distance mode, advanced streaming, 40252
|
||||
@@ -1179,7 +1179,7 @@ github.tar, small hash log, advanced
|
||||
github.tar, small chain log, advanced streaming, 41669
|
||||
github.tar, explicit params, advanced streaming, 41385
|
||||
github.tar, uncompressed literals, advanced streaming, 41525
|
||||
github.tar, uncompressed literals optimal, advanced streaming, 35397
|
||||
github.tar, uncompressed literals optimal, advanced streaming, 35356
|
||||
github.tar, huffman literals, advanced streaming, 38853
|
||||
github.tar, multithreaded with advanced params, advanced streaming, 41525
|
||||
silesia, level -5, old streaming, 6854744
|
||||
@@ -1194,11 +1194,11 @@ silesia, level 6, old stre
|
||||
silesia, level 7, old streaming, 4570271
|
||||
silesia, level 9, old streaming, 4545850
|
||||
silesia, level 13, old streaming, 4493990
|
||||
silesia, level 16, old streaming, 4360041
|
||||
silesia, level 19, old streaming, 4296055
|
||||
silesia, level 16, old streaming, 4359652
|
||||
silesia, level 19, old streaming, 4266582
|
||||
silesia, no source size, old streaming, 4842039
|
||||
silesia, uncompressed literals, old streaming, 4842075
|
||||
silesia, uncompressed literals optimal, old streaming, 4296055
|
||||
silesia, uncompressed literals optimal, old streaming, 4266582
|
||||
silesia, huffman literals, old streaming, 6172207
|
||||
silesia.tar, level -5, old streaming, 6856523
|
||||
silesia.tar, level -3, old streaming, 6505954
|
||||
@@ -1212,11 +1212,11 @@ silesia.tar, level 6, old stre
|
||||
silesia.tar, level 7, old streaming, 4579823
|
||||
silesia.tar, level 9, old streaming, 4555445
|
||||
silesia.tar, level 13, old streaming, 4502956
|
||||
silesia.tar, level 16, old streaming, 4360546
|
||||
silesia.tar, level 19, old streaming, 4265911
|
||||
silesia.tar, level 16, old streaming, 4360385
|
||||
silesia.tar, level 19, old streaming, 4260939
|
||||
silesia.tar, no source size, old streaming, 4859267
|
||||
silesia.tar, uncompressed literals, old streaming, 4859271
|
||||
silesia.tar, uncompressed literals optimal, old streaming, 4265911
|
||||
silesia.tar, uncompressed literals optimal, old streaming, 4260939
|
||||
silesia.tar, huffman literals, old streaming, 6179056
|
||||
github, level -5, old streaming, 204407
|
||||
github, level -5 with dict, old streaming, 45832
|
||||
@@ -1243,9 +1243,9 @@ github, level 9 with dict, old stre
|
||||
github, level 13, old streaming, 132878
|
||||
github, level 13 with dict, old streaming, 39900
|
||||
github, level 16, old streaming, 133209
|
||||
github, level 16 with dict, old streaming, 37577
|
||||
github, level 16 with dict, old streaming, 37902
|
||||
github, level 19, old streaming, 132879
|
||||
github, level 19 with dict, old streaming, 37576
|
||||
github, level 19 with dict, old streaming, 37916
|
||||
github, no source size, old streaming, 140599
|
||||
github, no source size with dict, old streaming, 40654
|
||||
github, uncompressed literals, old streaming, 136332
|
||||
@@ -1276,13 +1276,13 @@ github.tar, level 9 with dict, old stre
|
||||
github.tar, level 13, old streaming, 35501
|
||||
github.tar, level 13 with dict, old streaming, 37130
|
||||
github.tar, level 16, old streaming, 40466
|
||||
github.tar, level 16 with dict, old streaming, 33374
|
||||
github.tar, level 19, old streaming, 32276
|
||||
github.tar, level 19 with dict, old streaming, 32712
|
||||
github.tar, level 16 with dict, old streaming, 33375
|
||||
github.tar, level 19, old streaming, 32262
|
||||
github.tar, level 19 with dict, old streaming, 32701
|
||||
github.tar, no source size, old streaming, 38828
|
||||
github.tar, no source size with dict, old streaming, 38000
|
||||
github.tar, uncompressed literals, old streaming, 38831
|
||||
github.tar, uncompressed literals optimal, old streaming, 32276
|
||||
github.tar, uncompressed literals optimal, old streaming, 32262
|
||||
github.tar, huffman literals, old streaming, 42560
|
||||
silesia, level -5, old streaming advanced, 6854744
|
||||
silesia, level -3, old streaming advanced, 6503319
|
||||
@@ -1296,8 +1296,8 @@ silesia, level 6, old stre
|
||||
silesia, level 7, old streaming advanced, 4570271
|
||||
silesia, level 9, old streaming advanced, 4545850
|
||||
silesia, level 13, old streaming advanced, 4493990
|
||||
silesia, level 16, old streaming advanced, 4360041
|
||||
silesia, level 19, old streaming advanced, 4296055
|
||||
silesia, level 16, old streaming advanced, 4359652
|
||||
silesia, level 19, old streaming advanced, 4266582
|
||||
silesia, no source size, old streaming advanced, 4842039
|
||||
silesia, long distance mode, old streaming advanced, 4842075
|
||||
silesia, multithreaded, old streaming advanced, 4842075
|
||||
@@ -1307,7 +1307,7 @@ silesia, small hash log, old stre
|
||||
silesia, small chain log, old streaming advanced, 4912197
|
||||
silesia, explicit params, old streaming advanced, 4795857
|
||||
silesia, uncompressed literals, old streaming advanced, 4842075
|
||||
silesia, uncompressed literals optimal, old streaming advanced, 4296055
|
||||
silesia, uncompressed literals optimal, old streaming advanced, 4266582
|
||||
silesia, huffman literals, old streaming advanced, 6172207
|
||||
silesia, multithreaded with advanced params, old streaming advanced, 4842075
|
||||
silesia.tar, level -5, old streaming advanced, 6856523
|
||||
@@ -1322,8 +1322,8 @@ silesia.tar, level 6, old stre
|
||||
silesia.tar, level 7, old streaming advanced, 4579823
|
||||
silesia.tar, level 9, old streaming advanced, 4555445
|
||||
silesia.tar, level 13, old streaming advanced, 4502956
|
||||
silesia.tar, level 16, old streaming advanced, 4360546
|
||||
silesia.tar, level 19, old streaming advanced, 4265911
|
||||
silesia.tar, level 16, old streaming advanced, 4360385
|
||||
silesia.tar, level 19, old streaming advanced, 4260939
|
||||
silesia.tar, no source size, old streaming advanced, 4859267
|
||||
silesia.tar, long distance mode, old streaming advanced, 4859271
|
||||
silesia.tar, multithreaded, old streaming advanced, 4859271
|
||||
@@ -1333,7 +1333,7 @@ silesia.tar, small hash log, old stre
|
||||
silesia.tar, small chain log, old streaming advanced, 4917021
|
||||
silesia.tar, explicit params, old streaming advanced, 4807288
|
||||
silesia.tar, uncompressed literals, old streaming advanced, 4859271
|
||||
silesia.tar, uncompressed literals optimal, old streaming advanced, 4265911
|
||||
silesia.tar, uncompressed literals optimal, old streaming advanced, 4260939
|
||||
silesia.tar, huffman literals, old streaming advanced, 6179056
|
||||
silesia.tar, multithreaded with advanced params, old streaming advanced, 4859271
|
||||
github, level -5, old streaming advanced, 213265
|
||||
@@ -1361,9 +1361,9 @@ github, level 9 with dict, old stre
|
||||
github, level 13, old streaming advanced, 138676
|
||||
github, level 13 with dict, old streaming advanced, 39725
|
||||
github, level 16, old streaming advanced, 138575
|
||||
github, level 16 with dict, old streaming advanced, 40789
|
||||
github, level 16 with dict, old streaming advanced, 40804
|
||||
github, level 19, old streaming advanced, 132879
|
||||
github, level 19 with dict, old streaming advanced, 37576
|
||||
github, level 19 with dict, old streaming advanced, 37916
|
||||
github, no source size, old streaming advanced, 140599
|
||||
github, no source size with dict, old streaming advanced, 40608
|
||||
github, long distance mode, old streaming advanced, 141104
|
||||
@@ -1403,8 +1403,8 @@ github.tar, level 13, old stre
|
||||
github.tar, level 13 with dict, old streaming advanced, 35807
|
||||
github.tar, level 16, old streaming advanced, 40466
|
||||
github.tar, level 16 with dict, old streaming advanced, 38578
|
||||
github.tar, level 19, old streaming advanced, 32276
|
||||
github.tar, level 19 with dict, old streaming advanced, 32704
|
||||
github.tar, level 19, old streaming advanced, 32262
|
||||
github.tar, level 19 with dict, old streaming advanced, 32678
|
||||
github.tar, no source size, old streaming advanced, 38828
|
||||
github.tar, no source size with dict, old streaming advanced, 38015
|
||||
github.tar, long distance mode, old streaming advanced, 38831
|
||||
@@ -1415,7 +1415,7 @@ github.tar, small hash log, old stre
|
||||
github.tar, small chain log, old streaming advanced, 41669
|
||||
github.tar, explicit params, old streaming advanced, 41385
|
||||
github.tar, uncompressed literals, old streaming advanced, 38831
|
||||
github.tar, uncompressed literals optimal, old streaming advanced, 32276
|
||||
github.tar, uncompressed literals optimal, old streaming advanced, 32262
|
||||
github.tar, huffman literals, old streaming advanced, 42560
|
||||
github.tar, multithreaded with advanced params, old streaming advanced, 38831
|
||||
github, level -5 with dict, old streaming cdict, 45832
|
||||
@@ -1430,8 +1430,8 @@ github, level 6 with dict, old stre
|
||||
github, level 7 with dict, old streaming cdict, 38765
|
||||
github, level 9 with dict, old streaming cdict, 39439
|
||||
github, level 13 with dict, old streaming cdict, 39900
|
||||
github, level 16 with dict, old streaming cdict, 37577
|
||||
github, level 19 with dict, old streaming cdict, 37576
|
||||
github, level 16 with dict, old streaming cdict, 37902
|
||||
github, level 19 with dict, old streaming cdict, 37916
|
||||
github, no source size with dict, old streaming cdict, 40654
|
||||
github.tar, level -5 with dict, old streaming cdict, 51286
|
||||
github.tar, level -3 with dict, old streaming cdict, 45147
|
||||
@@ -1446,7 +1446,7 @@ github.tar, level 7 with dict, old stre
|
||||
github.tar, level 9 with dict, old streaming cdict, 36322
|
||||
github.tar, level 13 with dict, old streaming cdict, 36010
|
||||
github.tar, level 16 with dict, old streaming cdict, 39081
|
||||
github.tar, level 19 with dict, old streaming cdict, 32479
|
||||
github.tar, level 19 with dict, old streaming cdict, 32428
|
||||
github.tar, no source size with dict, old streaming cdict, 38000
|
||||
github, level -5 with dict, old streaming advanced cdict, 46708
|
||||
github, level -3 with dict, old streaming advanced cdict, 45476
|
||||
@@ -1460,8 +1460,8 @@ github, level 6 with dict, old stre
|
||||
github, level 7 with dict, old streaming advanced cdict, 38875
|
||||
github, level 9 with dict, old streaming advanced cdict, 38941
|
||||
github, level 13 with dict, old streaming advanced cdict, 39725
|
||||
github, level 16 with dict, old streaming advanced cdict, 40789
|
||||
github, level 19 with dict, old streaming advanced cdict, 37576
|
||||
github, level 16 with dict, old streaming advanced cdict, 40804
|
||||
github, level 19 with dict, old streaming advanced cdict, 37916
|
||||
github, no source size with dict, old streaming advanced cdict, 40608
|
||||
github.tar, level -5 with dict, old streaming advanced cdict, 50791
|
||||
github.tar, level -3 with dict, old streaming advanced cdict, 44926
|
||||
@@ -1476,5 +1476,5 @@ github.tar, level 7 with dict, old stre
|
||||
github.tar, level 9 with dict, old streaming advanced cdict, 36241
|
||||
github.tar, level 13 with dict, old streaming advanced cdict, 35807
|
||||
github.tar, level 16 with dict, old streaming advanced cdict, 38578
|
||||
github.tar, level 19 with dict, old streaming advanced cdict, 32704
|
||||
github.tar, level 19 with dict, old streaming advanced cdict, 32678
|
||||
github.tar, no source size with dict, old streaming advanced cdict, 38015
|
||||
|
||||
|
+53
-1
@@ -1920,7 +1920,7 @@ static int basicUnitTests(U32 seed, double compressibility, int bigTests)
|
||||
DISPLAYLEVEL(3, "test%3i : Block-Level External Sequence Producer API: ", testNb++);
|
||||
{
|
||||
size_t const dstBufSize = ZSTD_compressBound(CNBufferSize);
|
||||
BYTE* const dstBuf = (BYTE*)malloc(ZSTD_compressBound(dstBufSize));
|
||||
BYTE* const dstBuf = (BYTE*)malloc(dstBufSize);
|
||||
size_t const checkBufSize = CNBufferSize;
|
||||
BYTE* const checkBuf = (BYTE*)malloc(checkBufSize);
|
||||
int enableFallback;
|
||||
@@ -2356,6 +2356,58 @@ static int basicUnitTests(U32 seed, double compressibility, int bigTests)
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
DISPLAYLEVEL(3, "test%3i : Testing external sequence producer with static CCtx: ", testNb++);
|
||||
{
|
||||
size_t const dstBufSize = ZSTD_compressBound(CNBufferSize);
|
||||
BYTE* const dstBuf = (BYTE*)malloc(dstBufSize);
|
||||
size_t const checkBufSize = CNBufferSize;
|
||||
BYTE* const checkBuf = (BYTE*)malloc(checkBufSize);
|
||||
ZSTD_CCtx_params* params = ZSTD_createCCtxParams();
|
||||
ZSTD_CCtx* staticCCtx;
|
||||
void* cctxBuf;
|
||||
EMF_testCase seqProdState;
|
||||
|
||||
CHECK_Z(ZSTD_CCtxParams_setParameter(params, ZSTD_c_validateSequences, 1));
|
||||
CHECK_Z(ZSTD_CCtxParams_setParameter(params, ZSTD_c_enableSeqProducerFallback, 0));
|
||||
ZSTD_CCtxParams_registerSequenceProducer(params, &seqProdState, zstreamSequenceProducer);
|
||||
|
||||
{
|
||||
size_t const cctxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
|
||||
cctxBuf = malloc(cctxSize);
|
||||
staticCCtx = ZSTD_initStaticCCtx(cctxBuf, cctxSize);
|
||||
ZSTD_CCtx_setParametersUsingCCtxParams(staticCCtx, params);
|
||||
}
|
||||
|
||||
// Check that compression with external sequence producer succeeds when expected
|
||||
seqProdState = EMF_LOTS_OF_SEQS;
|
||||
{
|
||||
size_t dResult;
|
||||
size_t const cResult = ZSTD_compress2(staticCCtx, dstBuf, dstBufSize, CNBuffer, CNBufferSize);
|
||||
CHECK(ZSTD_isError(cResult), "EMF: Compression error: %s", ZSTD_getErrorName(cResult));
|
||||
dResult = ZSTD_decompress(checkBuf, checkBufSize, dstBuf, cResult);
|
||||
CHECK(ZSTD_isError(dResult), "EMF: Decompression error: %s", ZSTD_getErrorName(dResult));
|
||||
CHECK(dResult != CNBufferSize, "EMF: Corruption!");
|
||||
CHECK(memcmp(CNBuffer, checkBuf, CNBufferSize) != 0, "EMF: Corruption!");
|
||||
}
|
||||
|
||||
// Check that compression with external sequence producer fails when expected
|
||||
seqProdState = EMF_BIG_ERROR;
|
||||
{
|
||||
size_t const cResult = ZSTD_compress2(staticCCtx, dstBuf, dstBufSize, CNBuffer, CNBufferSize);
|
||||
CHECK(!ZSTD_isError(cResult), "EMF: Should have raised an error!");
|
||||
CHECK(
|
||||
ZSTD_getErrorCode(cResult) != ZSTD_error_sequenceProducer_failed,
|
||||
"EMF: Wrong error code: %s", ZSTD_getErrorName(cResult)
|
||||
);
|
||||
}
|
||||
|
||||
free(dstBuf);
|
||||
free(checkBuf);
|
||||
free(cctxBuf);
|
||||
ZSTD_freeCCtxParams(params);
|
||||
}
|
||||
DISPLAYLEVEL(3, "OK \n");
|
||||
|
||||
_end:
|
||||
FUZ_freeDictionary(dictionary);
|
||||
ZSTD_freeCStream(zc);
|
||||
|
||||
@@ -77,9 +77,7 @@ int main _Z_OF((int argc, char *argv[]));
|
||||
void *myalloc _Z_OF((void *, unsigned, unsigned));
|
||||
void myfree _Z_OF((void *, void *));
|
||||
|
||||
void *myalloc(q, n, m)
|
||||
void *q;
|
||||
unsigned n, m;
|
||||
void *myalloc(void *q, unsigned n, unsigned m)
|
||||
{
|
||||
void *buf = calloc(n, m);
|
||||
q = Z_NULL;
|
||||
@@ -110,10 +108,8 @@ void test_gzio _Z_OF((const char *fname,
|
||||
/* ===========================================================================
|
||||
* Test compress() and uncompress()
|
||||
*/
|
||||
void test_compress(compr, comprLen, uncompr, uncomprLen)
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen, uncomprLen;
|
||||
{
|
||||
void test_compress(Byte *compr, uLong comprLen, Byte *uncompr,
|
||||
uLong uncomprLen) {
|
||||
int err;
|
||||
uLong len = (uLong)strlen(hello)+1;
|
||||
|
||||
@@ -136,11 +132,7 @@ void test_compress(compr, comprLen, uncompr, uncomprLen)
|
||||
/* ===========================================================================
|
||||
* Test read/write of .gz files
|
||||
*/
|
||||
void test_gzio(fname, uncompr, uncomprLen)
|
||||
const char *fname; /* compressed file name */
|
||||
Byte *uncompr;
|
||||
uLong uncomprLen;
|
||||
{
|
||||
void test_gzio(const char *fname, Byte *uncompr, uLong uncomprLen) {
|
||||
#ifdef NO_GZCOMPRESS
|
||||
fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n");
|
||||
#else
|
||||
@@ -222,10 +214,7 @@ void test_gzio(fname, uncompr, uncomprLen)
|
||||
/* ===========================================================================
|
||||
* Test deflate() with small buffers
|
||||
*/
|
||||
void test_deflate(compr, comprLen)
|
||||
Byte *compr;
|
||||
uLong comprLen;
|
||||
{
|
||||
void test_deflate(Byte *compr, uLong comprLen) {
|
||||
z_stream c_stream; /* compression stream */
|
||||
int err;
|
||||
uLong len = (uLong)strlen(hello)+1;
|
||||
@@ -260,10 +249,8 @@ void test_deflate(compr, comprLen)
|
||||
/* ===========================================================================
|
||||
* Test inflate() with small buffers
|
||||
*/
|
||||
void test_inflate(compr, comprLen, uncompr, uncomprLen)
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen, uncomprLen;
|
||||
{
|
||||
void test_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
|
||||
uLong uncomprLen) {
|
||||
int err;
|
||||
z_stream d_stream; /* decompression stream */
|
||||
|
||||
@@ -301,10 +288,8 @@ void test_inflate(compr, comprLen, uncompr, uncomprLen)
|
||||
/* ===========================================================================
|
||||
* Test deflate() with large buffers and dynamic change of compression level
|
||||
*/
|
||||
void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen, uncomprLen;
|
||||
{
|
||||
void test_large_deflate(Byte *compr, uLong comprLen, Byte *uncompr,
|
||||
uLong uncomprLen) {
|
||||
z_stream c_stream; /* compression stream */
|
||||
int err;
|
||||
|
||||
@@ -355,11 +340,9 @@ void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
|
||||
|
||||
/* ===========================================================================
|
||||
* Test inflate() with large buffers
|
||||
*/
|
||||
void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen, uncomprLen;
|
||||
{
|
||||
*/
|
||||
void test_large_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
|
||||
uLong uncomprLen) {
|
||||
int err;
|
||||
z_stream d_stream; /* decompression stream */
|
||||
|
||||
@@ -397,10 +380,7 @@ void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
|
||||
/* ===========================================================================
|
||||
* Test deflate() with full flush
|
||||
*/
|
||||
void test_flush(compr, comprLen)
|
||||
Byte *compr;
|
||||
uLong *comprLen;
|
||||
{
|
||||
void test_flush(Byte *compr, uLong *comprLen) {
|
||||
z_stream c_stream; /* compression stream */
|
||||
int err;
|
||||
uInt len = (uInt)strlen(hello)+1;
|
||||
@@ -435,10 +415,7 @@ void test_flush(compr, comprLen)
|
||||
/* ===========================================================================
|
||||
* Test inflateSync()
|
||||
*/
|
||||
void test_sync(compr, comprLen, uncompr, uncomprLen)
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen, uncomprLen;
|
||||
{
|
||||
void test_sync(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen) {
|
||||
int err;
|
||||
z_stream d_stream; /* decompression stream */
|
||||
|
||||
@@ -479,10 +456,7 @@ void test_sync(compr, comprLen, uncompr, uncomprLen)
|
||||
/* ===========================================================================
|
||||
* Test deflate() with preset dictionary
|
||||
*/
|
||||
void test_dict_deflate(compr, comprLen)
|
||||
Byte *compr;
|
||||
uLong comprLen;
|
||||
{
|
||||
void test_dict_deflate(Byte *compr, uLong comprLen) {
|
||||
z_stream c_stream; /* compression stream */
|
||||
int err;
|
||||
|
||||
@@ -516,10 +490,8 @@ void test_dict_deflate(compr, comprLen)
|
||||
/* ===========================================================================
|
||||
* Test inflate() with a preset dictionary
|
||||
*/
|
||||
void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen, uncomprLen;
|
||||
{
|
||||
void test_dict_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
|
||||
uLong uncomprLen) {
|
||||
int err;
|
||||
z_stream d_stream; /* decompression stream */
|
||||
|
||||
@@ -567,10 +539,7 @@ void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
|
||||
* Usage: example [output.gz [input.gz]]
|
||||
*/
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
|
||||
uLong uncomprLen = comprLen;
|
||||
|
||||
@@ -102,9 +102,7 @@ void test_gzio _Z_OF((const char *fname,
|
||||
/* ===========================================================================
|
||||
* Test compress() and uncompress()
|
||||
*/
|
||||
void test_compress(compr, comprLen, uncompr, uncomprLen)
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen, uncomprLen;
|
||||
void test_compress(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)
|
||||
{
|
||||
int err;
|
||||
uLong len = (uLong)strlen(hello)+1;
|
||||
@@ -128,10 +126,8 @@ void test_compress(compr, comprLen, uncompr, uncomprLen)
|
||||
/* ===========================================================================
|
||||
* Test read/write of .gz files
|
||||
*/
|
||||
void test_gzio(fname, uncompr, uncomprLen)
|
||||
const char *fname; /* compressed file name */
|
||||
Byte *uncompr;
|
||||
uLong uncomprLen;
|
||||
void test_gzio(const char *fname /* compressed file name */, Byte *uncompr,
|
||||
uLong uncomprLen)
|
||||
{
|
||||
#ifdef NO_GZCOMPRESS
|
||||
fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n");
|
||||
@@ -214,9 +210,7 @@ void test_gzio(fname, uncompr, uncomprLen)
|
||||
/* ===========================================================================
|
||||
* Test deflate() with small buffers
|
||||
*/
|
||||
void test_deflate(compr, comprLen)
|
||||
Byte *compr;
|
||||
uLong comprLen;
|
||||
void test_deflate(Byte *compr, uLong comprLen)
|
||||
{
|
||||
z_stream c_stream; /* compression stream */
|
||||
int err;
|
||||
@@ -252,9 +246,7 @@ void test_deflate(compr, comprLen)
|
||||
/* ===========================================================================
|
||||
* Test inflate() with small buffers
|
||||
*/
|
||||
void test_inflate(compr, comprLen, uncompr, uncomprLen)
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen, uncomprLen;
|
||||
void test_inflate(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)
|
||||
{
|
||||
int err;
|
||||
z_stream d_stream; /* decompression stream */
|
||||
@@ -293,9 +285,8 @@ void test_inflate(compr, comprLen, uncompr, uncomprLen)
|
||||
/* ===========================================================================
|
||||
* Test deflate() with large buffers and dynamic change of compression level
|
||||
*/
|
||||
void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen, uncomprLen;
|
||||
void test_large_deflate(Byte *compr, uLong comprLen, Byte *uncompr,
|
||||
uLong uncomprLen)
|
||||
{
|
||||
z_stream c_stream; /* compression stream */
|
||||
int err;
|
||||
@@ -348,9 +339,8 @@ void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
|
||||
/* ===========================================================================
|
||||
* Test inflate() with large buffers
|
||||
*/
|
||||
void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen, uncomprLen;
|
||||
void test_large_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
|
||||
uLong uncomprLen)
|
||||
{
|
||||
int err;
|
||||
z_stream d_stream; /* decompression stream */
|
||||
@@ -389,9 +379,7 @@ void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
|
||||
/* ===========================================================================
|
||||
* Test deflate() with full flush
|
||||
*/
|
||||
void test_flush(compr, comprLen)
|
||||
Byte *compr;
|
||||
uLong *comprLen;
|
||||
void test_flush(Byte *compr, uLong comprLen)
|
||||
{
|
||||
z_stream c_stream; /* compression stream */
|
||||
int err;
|
||||
@@ -427,9 +415,7 @@ void test_flush(compr, comprLen)
|
||||
/* ===========================================================================
|
||||
* Test inflateSync()
|
||||
*/
|
||||
void test_sync(compr, comprLen, uncompr, uncomprLen)
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen, uncomprLen;
|
||||
void test_sync(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)
|
||||
{
|
||||
int err;
|
||||
z_stream d_stream; /* decompression stream */
|
||||
@@ -471,9 +457,7 @@ void test_sync(compr, comprLen, uncompr, uncomprLen)
|
||||
/* ===========================================================================
|
||||
* Test deflate() with preset dictionary
|
||||
*/
|
||||
void test_dict_deflate(compr, comprLen)
|
||||
Byte *compr;
|
||||
uLong comprLen;
|
||||
void test_dict_deflate(Byte *compr, uLong comprLen)
|
||||
{
|
||||
z_stream c_stream; /* compression stream */
|
||||
int err;
|
||||
@@ -508,9 +492,8 @@ void test_dict_deflate(compr, comprLen)
|
||||
/* ===========================================================================
|
||||
* Test inflate() with a preset dictionary
|
||||
*/
|
||||
void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen, uncomprLen;
|
||||
void test_dict_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
|
||||
uLong uncomprLen)
|
||||
{
|
||||
int err;
|
||||
z_stream d_stream; /* decompression stream */
|
||||
@@ -559,9 +542,7 @@ void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
|
||||
* Usage: example [output.gz [input.gz]]
|
||||
*/
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Byte *compr, *uncompr;
|
||||
uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
|
||||
|
||||
@@ -82,8 +82,7 @@
|
||||
The strwinerror function does not change the current setting
|
||||
of GetLastError. */
|
||||
|
||||
static char *strwinerror (error)
|
||||
DWORD error;
|
||||
static char *strwinerror(DWORD error)
|
||||
{
|
||||
static char buf[1024];
|
||||
|
||||
@@ -121,8 +120,7 @@ static char *strwinerror (error)
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void pwinerror (s)
|
||||
const char *s;
|
||||
static void pwinerror (const char *s)
|
||||
{
|
||||
if (s && *s)
|
||||
fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ()));
|
||||
@@ -198,11 +196,7 @@ const char *mode;
|
||||
return gz_open(NULL, fd, mode);
|
||||
}
|
||||
|
||||
gzFile gz_open(path, fd, mode)
|
||||
const char *path;
|
||||
int fd;
|
||||
const char *mode;
|
||||
{
|
||||
gzFile gz_open(const char *path, int fd, const char *mode) {
|
||||
gzFile gz;
|
||||
int ret;
|
||||
|
||||
@@ -238,11 +232,7 @@ gzFile gz_open(path, fd, mode)
|
||||
|
||||
int gzwrite _Z_OF((gzFile, const void *, unsigned));
|
||||
|
||||
int gzwrite(gz, buf, len)
|
||||
gzFile gz;
|
||||
const void *buf;
|
||||
unsigned len;
|
||||
{
|
||||
int gzwrite(gzFile gz, const void *buf, unsigned len) {
|
||||
z_stream *strm;
|
||||
unsigned char out[BUFLEN];
|
||||
|
||||
@@ -262,11 +252,7 @@ int gzwrite(gz, buf, len)
|
||||
|
||||
int gzread _Z_OF((gzFile, void *, unsigned));
|
||||
|
||||
int gzread(gz, buf, len)
|
||||
gzFile gz;
|
||||
void *buf;
|
||||
unsigned len;
|
||||
{
|
||||
int gzread(gzFile gz, void *buf, unsigned len) {
|
||||
int ret;
|
||||
unsigned got;
|
||||
unsigned char in[1];
|
||||
@@ -299,9 +285,7 @@ int gzread(gz, buf, len)
|
||||
|
||||
int gzclose _Z_OF((gzFile));
|
||||
|
||||
int gzclose(gz)
|
||||
gzFile gz;
|
||||
{
|
||||
int gzclose(gzFile gz) {
|
||||
z_stream *strm;
|
||||
unsigned char out[BUFLEN];
|
||||
|
||||
@@ -328,9 +312,7 @@ int gzclose(gz)
|
||||
|
||||
const char *gzerror _Z_OF((gzFile, int *));
|
||||
|
||||
const char *gzerror(gz, err)
|
||||
gzFile gz;
|
||||
int *err;
|
||||
const char *gzerror(gzFile gz, int *err)
|
||||
{
|
||||
*err = gz->err;
|
||||
return gz->msg;
|
||||
@@ -353,8 +335,7 @@ int main _Z_OF((int argc, char *argv[]));
|
||||
/* ===========================================================================
|
||||
* Display error message and exit
|
||||
*/
|
||||
void error(msg)
|
||||
const char *msg;
|
||||
void error(const char *msg)
|
||||
{
|
||||
fprintf(stderr, "%s: %s\n", prog, msg);
|
||||
exit(1);
|
||||
@@ -364,9 +345,7 @@ void error(msg)
|
||||
* Compress input to output then close both files.
|
||||
*/
|
||||
|
||||
void gz_compress(in, out)
|
||||
FILE *in;
|
||||
gzFile out;
|
||||
void gz_compress(FILE *in, gzFile out)
|
||||
{
|
||||
local char buf[BUFLEN];
|
||||
int len;
|
||||
@@ -397,10 +376,7 @@ void gz_compress(in, out)
|
||||
/* Try compressing the input file at once using mmap. Return Z_OK if
|
||||
* if success, Z_ERRNO otherwise.
|
||||
*/
|
||||
int gz_compress_mmap(in, out)
|
||||
FILE *in;
|
||||
gzFile out;
|
||||
{
|
||||
int gz_compress_mmap(FILE *in, gzFile out) {
|
||||
int len;
|
||||
int err;
|
||||
int ifd = fileno(in);
|
||||
@@ -432,10 +408,7 @@ int gz_compress_mmap(in, out)
|
||||
/* ===========================================================================
|
||||
* Uncompress input to output then close both files.
|
||||
*/
|
||||
void gz_uncompress(in, out)
|
||||
gzFile in;
|
||||
FILE *out;
|
||||
{
|
||||
void gz_uncompress(gzFile in, FILE *out) {
|
||||
local char buf[BUFLEN];
|
||||
int len;
|
||||
int err;
|
||||
@@ -459,10 +432,7 @@ void gz_uncompress(in, out)
|
||||
* Compress the given file: create a corresponding .gz file and remove the
|
||||
* original.
|
||||
*/
|
||||
void file_compress(file, mode)
|
||||
char *file;
|
||||
char *mode;
|
||||
{
|
||||
void file_compress(char *file, char *mode) {
|
||||
local char outfile[MAX_NAME_LEN];
|
||||
FILE *in;
|
||||
gzFile out;
|
||||
@@ -494,9 +464,7 @@ void file_compress(file, mode)
|
||||
/* ===========================================================================
|
||||
* Uncompress the given file and remove the original.
|
||||
*/
|
||||
void file_uncompress(file)
|
||||
char *file;
|
||||
{
|
||||
void file_uncompress(char *file) {
|
||||
local char buf[MAX_NAME_LEN];
|
||||
char *infile, *outfile;
|
||||
FILE *out;
|
||||
@@ -546,10 +514,7 @@ void file_uncompress(file)
|
||||
* -1 to -9 : compression level
|
||||
*/
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
int copyout = 0;
|
||||
int uncompr = 0;
|
||||
gzFile file;
|
||||
|
||||
@@ -11,9 +11,7 @@
|
||||
/* gzclose() is in a separate file so that it is linked in only if it is used.
|
||||
That way the other gzclose functions can be used instead to avoid linking in
|
||||
unneeded compression or decompression routines. */
|
||||
int ZEXPORT gzclose(file)
|
||||
gzFile file;
|
||||
{
|
||||
int ZEXPORT gzclose(gzFile file) {
|
||||
#ifndef NO_GZCOMPRESS
|
||||
gz_statep state;
|
||||
|
||||
|
||||
+20
-73
@@ -33,9 +33,7 @@ local gzFile gz_open _Z_OF((const void *, int, const char *));
|
||||
|
||||
The gz_strwinerror function does not change the current setting of
|
||||
GetLastError. */
|
||||
char ZLIB_INTERNAL *gz_strwinerror (error)
|
||||
DWORD error;
|
||||
{
|
||||
char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
|
||||
static char buf[1024];
|
||||
|
||||
wchar_t *msgbuf;
|
||||
@@ -75,9 +73,7 @@ char ZLIB_INTERNAL *gz_strwinerror (error)
|
||||
#endif /* UNDER_CE */
|
||||
|
||||
/* Reset gzip file state */
|
||||
local void gz_reset(state)
|
||||
gz_statep state;
|
||||
{
|
||||
local void gz_reset(gz_statep state) {
|
||||
state.state->x.have = 0; /* no output data available */
|
||||
if (state.state->mode == GZ_READ) { /* for reading ... */
|
||||
state.state->eof = 0; /* not at end of file */
|
||||
@@ -91,11 +87,7 @@ local void gz_reset(state)
|
||||
}
|
||||
|
||||
/* Open a gzip file either by name or file descriptor. */
|
||||
local gzFile gz_open(path, fd, mode)
|
||||
const void *path;
|
||||
int fd;
|
||||
const char *mode;
|
||||
{
|
||||
local gzFile gz_open(const void *path, int fd, const char *mode) {
|
||||
gz_statep state;
|
||||
z_size_t len;
|
||||
int oflag;
|
||||
@@ -270,26 +262,17 @@ local gzFile gz_open(path, fd, mode)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
gzFile ZEXPORT gzopen(path, mode)
|
||||
const char *path;
|
||||
const char *mode;
|
||||
{
|
||||
gzFile ZEXPORT gzopen(const char *path, const char *mode) {
|
||||
return gz_open(path, -1, mode);
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
gzFile ZEXPORT gzopen64(path, mode)
|
||||
const char *path;
|
||||
const char *mode;
|
||||
{
|
||||
gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
|
||||
return gz_open(path, -1, mode);
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
gzFile ZEXPORT gzdopen(fd, mode)
|
||||
int fd;
|
||||
const char *mode;
|
||||
{
|
||||
gzFile ZEXPORT gzdopen(int fd, const char *mode) {
|
||||
char *path; /* identifier for error messages */
|
||||
gzFile gz;
|
||||
|
||||
@@ -307,19 +290,13 @@ gzFile ZEXPORT gzdopen(fd, mode)
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
#ifdef WIDECHAR
|
||||
gzFile ZEXPORT gzopen_w(path, mode)
|
||||
const wchar_t *path;
|
||||
const char *mode;
|
||||
{
|
||||
gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
|
||||
return gz_open(path, -2, mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzbuffer(file, size)
|
||||
gzFile file;
|
||||
unsigned size;
|
||||
{
|
||||
int ZEXPORT gzbuffer(gzFile file, unsigned size) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure and check integrity */
|
||||
@@ -343,9 +320,7 @@ int ZEXPORT gzbuffer(file, size)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzrewind(file)
|
||||
gzFile file;
|
||||
{
|
||||
int ZEXPORT gzrewind(gzFile file) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
@@ -366,11 +341,7 @@ int ZEXPORT gzrewind(file)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
z_off64_t ZEXPORT gzseek64(file, offset, whence)
|
||||
gzFile file;
|
||||
z_off64_t offset;
|
||||
int whence;
|
||||
{
|
||||
z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
|
||||
unsigned n;
|
||||
z_off64_t ret;
|
||||
gz_statep state;
|
||||
@@ -443,11 +414,7 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
z_off_t ZEXPORT gzseek(file, offset, whence)
|
||||
gzFile file;
|
||||
z_off_t offset;
|
||||
int whence;
|
||||
{
|
||||
z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
|
||||
z_off64_t ret;
|
||||
|
||||
ret = gzseek64(file, (z_off64_t)offset, whence);
|
||||
@@ -455,9 +422,7 @@ z_off_t ZEXPORT gzseek(file, offset, whence)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
z_off64_t ZEXPORT gztell64(file)
|
||||
gzFile file;
|
||||
{
|
||||
z_off64_t ZEXPORT gztell64(gzFile file) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure and check integrity */
|
||||
@@ -472,9 +437,7 @@ z_off64_t ZEXPORT gztell64(file)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
z_off_t ZEXPORT gztell(file)
|
||||
gzFile file;
|
||||
{
|
||||
z_off_t ZEXPORT gztell(gzFile file) {
|
||||
z_off64_t ret;
|
||||
|
||||
ret = gztell64(file);
|
||||
@@ -482,9 +445,7 @@ z_off_t ZEXPORT gztell(file)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
z_off64_t ZEXPORT gzoffset64(file)
|
||||
gzFile file;
|
||||
{
|
||||
z_off64_t ZEXPORT gzoffset64(gzFile file) {
|
||||
z_off64_t offset;
|
||||
gz_statep state;
|
||||
|
||||
@@ -505,9 +466,7 @@ z_off64_t ZEXPORT gzoffset64(file)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
z_off_t ZEXPORT gzoffset(file)
|
||||
gzFile file;
|
||||
{
|
||||
z_off_t ZEXPORT gzoffset(gzFile file) {
|
||||
z_off64_t ret;
|
||||
|
||||
ret = gzoffset64(file);
|
||||
@@ -515,9 +474,7 @@ z_off_t ZEXPORT gzoffset(file)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzeof(file)
|
||||
gzFile file;
|
||||
{
|
||||
int ZEXPORT gzeof(gzFile file) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure and check integrity */
|
||||
@@ -532,10 +489,7 @@ int ZEXPORT gzeof(file)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
const char * ZEXPORT gzerror(file, errnum)
|
||||
gzFile file;
|
||||
int *errnum;
|
||||
{
|
||||
const char * ZEXPORT gzerror(gzFile file, int *errnum) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure and check integrity */
|
||||
@@ -553,9 +507,7 @@ const char * ZEXPORT gzerror(file, errnum)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
void ZEXPORT gzclearerr(file)
|
||||
gzFile file;
|
||||
{
|
||||
void ZEXPORT gzclearerr(gzFile file) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure and check integrity */
|
||||
@@ -579,11 +531,7 @@ void ZEXPORT gzclearerr(file)
|
||||
memory). Simply save the error message as a static string. If there is an
|
||||
allocation failure constructing the error message, then convert the error to
|
||||
out of memory. */
|
||||
void ZLIB_INTERNAL gz_error(state, err, msg)
|
||||
gz_statep state;
|
||||
int err;
|
||||
const char *msg;
|
||||
{
|
||||
void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
|
||||
/* free previously allocated message and clear */
|
||||
if (state.state->msg != NULL) {
|
||||
if (state.state->err != Z_MEM_ERROR)
|
||||
@@ -625,8 +573,7 @@ void ZLIB_INTERNAL gz_error(state, err, msg)
|
||||
available) -- we need to do this to cover cases where 2's complement not
|
||||
used, since C standard permits 1's complement and sign-bit representations,
|
||||
otherwise we could just use ((unsigned)-1) >> 1 */
|
||||
unsigned ZLIB_INTERNAL gz_intmax()
|
||||
{
|
||||
unsigned ZLIB_INTERNAL gz_intmax() {
|
||||
unsigned p, q;
|
||||
|
||||
p = 1;
|
||||
|
||||
+17
-58
@@ -29,12 +29,8 @@ local z_size_t gz_read _Z_OF((gz_statep, voidp, z_size_t));
|
||||
state.state->fd, and update state.state->eof, state.state->err, and state.state->msg as appropriate.
|
||||
This function needs to loop on read(), since read() is not guaranteed to
|
||||
read the number of bytes requested, depending on the type of descriptor. */
|
||||
local int gz_load(state, buf, len, have)
|
||||
gz_statep state;
|
||||
unsigned char *buf;
|
||||
unsigned len;
|
||||
unsigned *have;
|
||||
{
|
||||
local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
|
||||
unsigned *have) {
|
||||
ssize_t ret;
|
||||
unsigned get, max = ((unsigned)-1 >> 2) + 1;
|
||||
|
||||
@@ -64,8 +60,7 @@ local int gz_load(state, buf, len, have)
|
||||
If strm->avail_in != 0, then the current data is moved to the beginning of
|
||||
the input buffer, and then the remainder of the buffer is loaded with the
|
||||
available data from the input file. */
|
||||
local int gz_avail(state)
|
||||
gz_statep state;
|
||||
local int gz_avail(gz_statep state)
|
||||
{
|
||||
unsigned got;
|
||||
z_streamp strm = &(state.state->strm);
|
||||
@@ -99,9 +94,7 @@ local int gz_avail(state)
|
||||
case, all further file reads will be directly to either the output buffer or
|
||||
a user buffer. If decompressing, the inflate state will be initialized.
|
||||
gz_look() will return 0 on success or -1 on failure. */
|
||||
local int gz_look(state)
|
||||
gz_statep state;
|
||||
{
|
||||
local int gz_look(gz_statep state) {
|
||||
z_streamp strm = &(state.state->strm);
|
||||
|
||||
/* allocate read buffers and inflate memory */
|
||||
@@ -184,9 +177,7 @@ local int gz_look(state)
|
||||
data. If the gzip stream completes, state.state->how is reset to LOOK to look for
|
||||
the next gzip stream or raw data, once state.state->x.have is depleted. Returns 0
|
||||
on success, -1 on failure. */
|
||||
local int gz_decomp(state)
|
||||
gz_statep state;
|
||||
{
|
||||
local int gz_decomp(gz_statep state) {
|
||||
int ret = Z_OK;
|
||||
unsigned had;
|
||||
z_streamp strm = &(state.state->strm);
|
||||
@@ -238,9 +229,7 @@ local int gz_decomp(state)
|
||||
looked for to determine whether to copy or decompress. Returns -1 on error,
|
||||
otherwise 0. gz_fetch() will leave state.state->how as COPY or GZIP unless the
|
||||
end of the input file has been reached and all data has been processed. */
|
||||
local int gz_fetch(state)
|
||||
gz_statep state;
|
||||
{
|
||||
local int gz_fetch(gz_statep state) {
|
||||
z_streamp strm = &(state.state->strm);
|
||||
|
||||
do {
|
||||
@@ -268,10 +257,7 @@ local int gz_fetch(state)
|
||||
}
|
||||
|
||||
/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */
|
||||
local int gz_skip(state, len)
|
||||
gz_statep state;
|
||||
z_off64_t len;
|
||||
{
|
||||
local int gz_skip(gz_statep state, z_off64_t len) {
|
||||
unsigned n;
|
||||
|
||||
/* skip over len bytes or reach end-of-file, whichever comes first */
|
||||
@@ -303,11 +289,7 @@ local int gz_skip(state, len)
|
||||
input. Return the number of bytes read. If zero is returned, either the
|
||||
end of file was reached, or there was an error. state.state->err must be
|
||||
consulted in that case to determine which. */
|
||||
local z_size_t gz_read(state, buf, len)
|
||||
gz_statep state;
|
||||
voidp buf;
|
||||
z_size_t len;
|
||||
{
|
||||
local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
|
||||
z_size_t got;
|
||||
unsigned n;
|
||||
|
||||
@@ -384,11 +366,7 @@ local z_size_t gz_read(state, buf, len)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzread(file, buf, len)
|
||||
gzFile file;
|
||||
voidp buf;
|
||||
unsigned len;
|
||||
{
|
||||
int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
@@ -420,12 +398,8 @@ int ZEXPORT gzread(file, buf, len)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
z_size_t ZEXPORT gzfread(buf, size, nitems, file)
|
||||
voidp buf;
|
||||
z_size_t size;
|
||||
z_size_t nitems;
|
||||
gzFile file;
|
||||
{
|
||||
z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
|
||||
gzFile file) {
|
||||
z_size_t len;
|
||||
gz_statep state;
|
||||
|
||||
@@ -468,9 +442,7 @@ ZEXTERN int ZEXPORT gzgetc _Z_OF((gzFile file));
|
||||
ZEXTERN int ZEXPORT gzgetc_ _Z_OF((gzFile file));
|
||||
#endif
|
||||
|
||||
int ZEXPORT gzgetc(file)
|
||||
gzFile file;
|
||||
{
|
||||
int ZEXPORT gzgetc(gzFile file) {
|
||||
int ret;
|
||||
unsigned char buf[1];
|
||||
gz_statep state;
|
||||
@@ -497,17 +469,12 @@ int ZEXPORT gzgetc(file)
|
||||
return ret < 1 ? -1 : buf[0];
|
||||
}
|
||||
|
||||
int ZEXPORT gzgetc_(file)
|
||||
gzFile file;
|
||||
{
|
||||
int ZEXPORT gzgetc_(gzFile file) {
|
||||
return gzgetc(file);
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzungetc(c, file)
|
||||
int c;
|
||||
gzFile file;
|
||||
{
|
||||
int ZEXPORT gzungetc(int c, gzFile file) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
@@ -564,11 +531,7 @@ int ZEXPORT gzungetc(c, file)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
char * ZEXPORT gzgets(file, buf, len)
|
||||
gzFile file;
|
||||
char *buf;
|
||||
int len;
|
||||
{
|
||||
char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
|
||||
unsigned left, n;
|
||||
char *str;
|
||||
unsigned char *eol;
|
||||
@@ -628,9 +591,7 @@ char * ZEXPORT gzgets(file, buf, len)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzdirect(file)
|
||||
gzFile file;
|
||||
{
|
||||
int ZEXPORT gzdirect(gzFile file) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
@@ -648,9 +609,7 @@ int ZEXPORT gzdirect(file)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzclose_r(file)
|
||||
gzFile file;
|
||||
{
|
||||
int ZEXPORT gzclose_r(gzFile file) {
|
||||
int ret, err;
|
||||
gz_statep state;
|
||||
|
||||
|
||||
+18
-58
@@ -19,9 +19,7 @@ local z_size_t gz_write _Z_OF((gz_statep, voidpc, z_size_t));
|
||||
/* Initialize state for writing a gzip file. Mark initialization by setting
|
||||
state.state->size to non-zero. Return -1 on a memory allocation failure, or 0 on
|
||||
success. */
|
||||
local int gz_init(state)
|
||||
gz_statep state;
|
||||
{
|
||||
local int gz_init(gz_statep state) {
|
||||
int ret;
|
||||
z_streamp strm = &(state.state->strm);
|
||||
|
||||
@@ -75,10 +73,7 @@ local int gz_init(state)
|
||||
deflate() flush value. If flush is Z_FINISH, then the deflate() state is
|
||||
reset to start a new gzip stream. If gz->direct is true, then simply write
|
||||
to the output file without compressing, and ignore flush. */
|
||||
local int gz_comp(state, flush)
|
||||
gz_statep state;
|
||||
int flush;
|
||||
{
|
||||
local int gz_comp(gz_statep state, int flush) {
|
||||
int ret, writ;
|
||||
unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
|
||||
z_streamp strm = &(state.state->strm);
|
||||
@@ -147,10 +142,7 @@ local int gz_comp(state, flush)
|
||||
|
||||
/* Compress len zeros to output. Return -1 on a write error or memory
|
||||
allocation failure by gz_comp(), or 0 on success. */
|
||||
local int gz_zero(state, len)
|
||||
gz_statep state;
|
||||
z_off64_t len;
|
||||
{
|
||||
local int gz_zero(gz_statep state, z_off64_t len) {
|
||||
int first;
|
||||
unsigned n;
|
||||
z_streamp strm = &(state.state->strm);
|
||||
@@ -180,11 +172,7 @@ local int gz_zero(state, len)
|
||||
|
||||
/* Write len bytes from buf to file. Return the number of bytes written. If
|
||||
the returned value is less than len, then there was an error. */
|
||||
local z_size_t gz_write(state, buf, len)
|
||||
gz_statep state;
|
||||
voidpc buf;
|
||||
z_size_t len;
|
||||
{
|
||||
local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
|
||||
z_size_t put = len;
|
||||
|
||||
/* if len is zero, avoid unnecessary operations */
|
||||
@@ -248,11 +236,7 @@ local z_size_t gz_write(state, buf, len)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzwrite(file, buf, len)
|
||||
gzFile file;
|
||||
voidpc buf;
|
||||
unsigned len;
|
||||
{
|
||||
int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
@@ -276,12 +260,8 @@ int ZEXPORT gzwrite(file, buf, len)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)
|
||||
voidpc buf;
|
||||
z_size_t size;
|
||||
z_size_t nitems;
|
||||
gzFile file;
|
||||
{
|
||||
z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
|
||||
gzFile file) {
|
||||
z_size_t len;
|
||||
gz_statep state;
|
||||
|
||||
@@ -307,10 +287,7 @@ z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzputc(file, c)
|
||||
gzFile file;
|
||||
int c;
|
||||
{
|
||||
int ZEXPORT gzputc(gzFile file, int c) {
|
||||
unsigned have;
|
||||
unsigned char buf[1];
|
||||
gz_statep state;
|
||||
@@ -355,10 +332,7 @@ int ZEXPORT gzputc(file, c)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzputs(file, str)
|
||||
gzFile file;
|
||||
const char *str;
|
||||
{
|
||||
int ZEXPORT gzputs(gzFile file, const char *str) {
|
||||
int ret;
|
||||
z_size_t len;
|
||||
gz_statep state;
|
||||
@@ -382,8 +356,7 @@ int ZEXPORT gzputs(file, str)
|
||||
#include <stdarg.h>
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
|
||||
{
|
||||
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
|
||||
int len;
|
||||
unsigned left;
|
||||
char *next;
|
||||
@@ -454,8 +427,7 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
|
||||
return len;
|
||||
}
|
||||
|
||||
int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
|
||||
{
|
||||
int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) {
|
||||
va_list va;
|
||||
int ret;
|
||||
|
||||
@@ -468,13 +440,10 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
|
||||
#else /* !STDC && !Z_HAVE_STDARG_H */
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
|
||||
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
||||
gzFile file;
|
||||
const char *format;
|
||||
int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
|
||||
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
|
||||
{
|
||||
int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
|
||||
int a4, int a5, int a6, int a7, int a8, int a9, int a10,
|
||||
int a11, int a12, int a13, int a14, int a15, int a16,
|
||||
int a17, int a18, int a19, int a20) {
|
||||
unsigned len, left;
|
||||
char *next;
|
||||
gz_statep state;
|
||||
@@ -556,10 +525,7 @@ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
|
||||
#endif
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzflush(file, flush)
|
||||
gzFile file;
|
||||
int flush;
|
||||
{
|
||||
int ZEXPORT gzflush(gzFile file, int flush) {
|
||||
gz_statep state;
|
||||
|
||||
/* get internal structure */
|
||||
@@ -588,11 +554,7 @@ int ZEXPORT gzflush(file, flush)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzsetparams(file, level, strategy)
|
||||
gzFile file;
|
||||
int level;
|
||||
int strategy;
|
||||
{
|
||||
int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
|
||||
gz_statep state;
|
||||
z_streamp strm;
|
||||
|
||||
@@ -630,9 +592,7 @@ int ZEXPORT gzsetparams(file, level, strategy)
|
||||
}
|
||||
|
||||
/* -- see zlib.h -- */
|
||||
int ZEXPORT gzclose_w(file)
|
||||
gzFile file;
|
||||
{
|
||||
int ZEXPORT gzclose_w(gzFile file) {
|
||||
int ret = Z_OK;
|
||||
gz_statep state;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user